zoukankan      html  css  js  c++  java
  • 持续重构,其乐无穷。

    精简自己20%的代码

    持续重构,其乐无穷。

    一:发现问题

      先来说如何重构业务层的try{}catch{}finally{}代码块,我看过很多代码,异常处理这一块大致分为两种情况,一种是每个方法都大量的充斥着try{}catch{}finally{},这种方式的编程已经考虑到了异常处理,还有一种就是没有try{}catch{}finally{}的代码,因为根本就没有考虑代码的异常处理。每当我看到这样的代码,我都很忧伤。从程序的健壮性来看第一种还是要比第二种情况好,至少在编程意识中,随时想到了异常情况,有一种基本的编程思想。

      比如:一个业务单据的多表插入,关联修改,虚拟删除等都是一些基本的操作,但是又是比较容易引起错误的操作,在这些方法上都会加上try{}catch{}finally{}对代码进行有效的防错处理。早期的代码是这样的。

    复制代码
    public Boolean Save(AccountModel accountData)
    {
        Boolean result = false;
        try
        {
            //TODO ...
            result = true;
        }
        catch
        {
    
        }
        finally
        { 
                
        }
        return result;
    }
    
    public Boolean Edit(AccountModel accountData)
    {
        Boolean result = false;
        try
        {
            //TODO ...
            result = true;
        }
        catch
        {
    
        }
        finally
        {
    
        }
        return result;
    }
    
    public Boolean VirDelete(AccountModel accountData)
    {
        Boolean result = false;
        try
        {
            //TODO ...
            result = true;
        }
        catch
        {
    
        }
        finally
        {
    
        }
        return result;
    }
    复制代码

    仅仅定义了添加,修改,删除几个空方法,就写了三四十行代码,如果业务稍微复杂些,异常处理的代码很快就会突破百行大关。虽然复制,粘贴try{}catch{}finally{}很好使,但是业务逻辑代码大量充斥着这样的try{}catch{}finally{}代码,确实显得做事不够利落。

    二:解决问题

      那怎样来解决这件棘手的事呢,首先定义一个公用的try{}catch{}finally{},如下如示:

    复制代码
    public class Process
    {
        public static bool Execute(Action action)
        {
            try
            {
                action.Invoke();
                return true;
            }
            catch (Exception ex)
            {
                //1,异常隐藏
                //2,异常替换
                //3,异常封装
    
                //写日志
                return false;
            }
            finally
            {
    
            }
        }
    }
    复制代码

    上边的代码定义了公用的try{}catch{}finally{},最关键是怎么运用起来,如下代码:

    复制代码
    protected void Page_Load(object sender, EventArgs e)
    {
        AccountModel accountData = new AccountModel();     //准备传入的参数
        Boolean result = false;                            //接收返回的值
        Process.Execute(() => result = Save(accountData)); //执行方法
    }
    
    public Boolean Save(AccountModel accountData)
    {
        Boolean result = false;
        //TODO ...
        result = true;
        return result;
    }
    
    public Boolean Edit(AccountModel accountData)
    {
        Boolean result = false;
        //TODO ...
        result = true;
        return result;
    }
    
    public Boolean VirDelete(AccountModel accountData)
    {
        Boolean result = false;
        //TODO ...
        result = true;
        return result;
    }
    复制代码

    这样的精简过的代码,是不是感觉心情很舒畅。

    三:提升与扩展

       对于知足者常乐的人来说,到第二个步骤就可以洗洗睡了。但是对于精益求精的人来说,问题仍然没有完。我们来说一个应用场景,在WCF中的应用,我们知道WCF服务端的异常,不经过<serviceDebug includeExceptionDetailInFaults="true"/>的设置,服务端的异常是无法抛到客户端的。但是在正式环境中,不可能对进行serviceDebug的配置。正确的处理是在服务端对异常进行隐藏,替换,或者封装。

      比如我们在服务端捕获了一个已知异常,但是这个异常会暴露一些敏感的信息,所以我们对异常进行替换,抛出新的异常后,我们还要把这个异常怎样传输给客户端。首先们要明确WCF中的一些基本常识,就是WCF中的数据传递要遵循WCF的数据契约,服务端抛到客户端的异常(异常其实也是数据),所以必须要给异常定义异常契约。

    复制代码
        [DataContract(Name = "WCFException")]
        public class WCFException
        {
            [DataMember(Name = "Type")]
            public String Type { get; set; }
    
            [DataMember(Name = "StackTrace")]
            public String StackTrace { get; set; }
    
            [DataMember(Name = "Message")]
            public String Message { get; set; }
        }
    复制代码

    然后处理异常的公共方法改写为:

    复制代码
    public static bool Execute(Action action)
    {
        try
        {
            action.Invoke();
            return true;
        }
        catch (Exception ex)
        {
            //1,异常隐藏
            //2,异常替换
            //3,异常封装
    
            //写日志
            WCFException exception = new WCFException
            {
                Type = "Error"
                ,
                StackTrace = ex.StackTrace
                ,
                Message = ex.Message
            };
            throw new FaultException<WCFException>(exception
                , new FaultReason("服务端异常:" + ex.Message)
                , new FaultCode(ex.TargetSite.Name));
        }
        finally
        {
    
        }
    }
    复制代码

    这样在服务端抛出的异常,就能在客户端捕捉到。现在是不是感觉自己又提升了一些,想成为编程高手是指日可待了。

    四:举一反三

      异常的处理也不过如此,那是不是应该举一反三,看看事务的处理应该怎么办?比如现在大量的访求都用到了事务,如下代码:

    复制代码
    public Boolean Save(AccountModel accountData)
    {
        OracleConnection conn = new OracleConnection("连接字符串");
        IDbTransaction trans = conn.BeginTransaction();
        Boolean result = false;
        try
        {
            //TODO ...
            trans.Commit();
            result = true;
        }
        catch
        {
            trans.Rollback();
        }
        finally
        {
    
        }
        return result;
    }
    复制代码

    特别是 trans.Commit();  trans.Rollback(); 这样的代码出现在每个与事务相关的方法中, 让我感觉到代码的臃肿,以及隐陷约约的失望。
    经过我几天的翻阅资料终于实现了事务的公用访求提取。使用方法如下代码所示:

    复制代码
    [TransactionAttribute]
    [ExceptionAttribute]
    public bool Save(DataContext dContext, Dictionary<string, string> dtoPara)
    {
        Boolean returnVal = true;
        //TODO ...
        return returnVal;
    }
    复制代码

    就是在一个方法上加[TransactionAttribute]就表示这个方法写在了事务中,反之,不在事务中,加[ExceptionAttribute]就表示这个方法作了异常处理,反之,不作异常处理。通过反射或者AOP都能实现Attribute编程的效果。最后,还有什么疑惑,可以在评论中给我留言,当然别忘记了点右下角的【推荐】。

    HttpClient消息处理器

     

    Asp.Net Web API 

    导航

        Asp.Net Web API第一课:入门http://www.cnblogs.com/aehyok/p/3432158.html

          Asp.Net Web API第二课:CRUD操作http://www.cnblogs.com/aehyok/p/3434578.html

          Asp.Net Web API第三课:.NET客户端调用Wep API http://www.cnblogs.com/aehyok/p/3439698.html

    前言

    消息处理器是一个接收HTTP请求,并返回HTTP响应的一个类。

    比较有代表性的时,一系列的消息处理被链接在一起。第一个处理器接收HTTP请求,做一些处理,然后将此请求传给下一个处理器。在某个点上,这个响应被创建,被进行回溯。这种模式就叫做委托处理器。

    在客户端,HTTPClient类使用一个消息处理器来处理请求。默认的处理器是HTTPClientHandler,它通过网络发送请求,并从服务器上获得响应。你可以把自定义消息处理器插入到客户端管道中。

    Asp.Net Web API也可以使用服务端的消息处理器。更多的信息请参考"HTTP消息处理器"(暂未实现。)

    自定义消息处理器

     要编写一个消息处理器,需要从System.Net.Http.DelegatingHandler进行派生,并重写SendAsync方法。以下是该方法的签名:

    System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken);

    这个方法以HttpRequestMessage参数作为输入,并异步地返回一个HttpResponseMessage。一种典型的实现如下:

      1.处理请求消息。

      2.调用base.SendAsync将请求发送给内部处理器。

      3.内部处理器返回一条响应消息。(这一步是异步的)

      4.处理响应,并把他返回给调用者。

    以下示例展示了一个消息处理器,它添加了一个自定义的标头给外部的请求。

    复制代码
        public class MessageHandler : DelegatingHandler
        {
            private int _count = 0;
            protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
            {
                _count++;
                request.Headers.Add("X-Custom-Header", _count.ToString());
                return base.SendAsync(request, cancellationToken);
            }
        }
    复制代码

    base.SendAsync的调用是异步的。如果处理器在调用之后还要做一些工作,需使用await关键字,以便在方法完成之后继续执行。

    以下示例展示了一个对错误码进行日志的处理器。如何进行日志没多大关系,但此例展示了如何得到处理器内部的响应。

    复制代码
        public class LoggingHandler : DelegatingHandler 
        { 
            StreamWriter _writer; 
            public LoggingHandler(Stream stream)
            { 
                _writer = new StreamWriter(stream);
            }
    
            protected override async System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
            {
                var response = await base.SendAsync(request, cancellationToken);
                if (!response.IsSuccessStatusCode) 
                { 
                    _writer.WriteLine("{0}	{1}	{2}", request.RequestUri,(int)response.StatusCode, response.Headers.Date); 
                } 
                return response; 
            }
            protected override void Dispose(bool disposing) 
            { 
                if (disposing) 
                { 
                    _writer.Dispose(); 
                } 
                base.Dispose(disposing); 
            } 
        }
    复制代码

    将消息处理器添加到客户端管线

     要将自定义处理器添加到HttpClient,需使用HttpClientFactory.Create方法:

    HttpClient client = HttpClientFactory.Create(new MessageHandler());

    消息处理器是按照它们传递给Create方法中的顺序来调用的。因此处理器是内嵌的,响应消息以反方向传递。即,最后一个处理器首先得到响应消息。

    总结

     本文主要讲解HTTPClient消息处理器。涉及到的代码在文中都有过展示,暂时就不进行上传了。

    本文参考链接http://www.asp.net/web-api/overview/web-api-clients/httpclient-message-handlers

     
     
     
     
     
  • 相关阅读:
    jquery ajax 赋值问题, 后面程序判断逻辑用
    jquery formValidator 表单验证插件, ajax无法传值到后台问题的解决
    学习写了一个点击按钮倒计时的jquery小插件
    点击按钮复制指定代码
    discuz 修改积分策略( 在周期中添加"每周" )
    php获取本周周一、周日时间,上周周一、周日时间,本月第一天,本月最后一天,上个月第一天,最后一天时间
    php用正则判断是否为数字
    discuz 标签详解
    用dwz时, 由于粗心产生的一些问题(记录方便自己查阅)
    yii mailer 扩展发送邮件
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3444475.html
Copyright © 2011-2022 走看看