• ASP.NET Web API编程——异常捕获


    1 向客户端发送错误消息

    使用throw new HttpResponseException()向客户端抛出错误信息。

    HttpResponseException包含两个重载的构造函数,其中一个是构造函数参数类型为HttpResponseMessage,通过其设置状态码,错误消息短语以及消息体内容来向客户端抛出比较详细的错误信息。另一个参数类型为HttpStatusCode,只能设定状态码。

    2自定义异常过滤器

    扩展IExceptionFilter来定义异常过滤器。异常过滤器不会捕获类型为HttpResponseException的异常,下面的异常也无法被异常过滤器捕获:

    1)controller构造器抛出的异常

    2)消息处理器抛出的异常

    3)路由过程中抛出的异常

    4)响应内容序列化与反序列化过程中抛出的异常

    代码示例:

     

    public class CustomExceptionFilterAttribute : ExceptionFilterAttribute 
        {
            public override void OnException(HttpActionExecutedContext context)
            {
                if (context.Exception!=null)
                {
                    LogHelper.LogError(context.Exception);
                }
            }
        }

     

    3 扩展ExceptionHandler和ExceptionLogger

    扩展ExceptionHandler可以捕获大部分异常,包括一些无法被异常过滤器捕获的异常。但是HttpResponseException类型的异常不会被捕获。

    示例代码:

     

    /// <summary>
        /// 自定义的异常处理程序
        /// </summary>
        public class GlobalExceptionHandler : ExceptionHandler
        {
            /// <summary>
            /// 处理异常
            /// </summary>
            /// <param name="context"></param>
            /// <param name="cancellationToken"></param>
            /// <returns></returns>
            public override Task HandleAsync(ExceptionHandlerContext context,CancellationToken cancellationToken)
            {
                if (!ShouldHandle(context))
                {
                    return Task.FromResult(0);
                }
                context.Result = new ErrorResult
                {
                    Request = context.ExceptionContext.Request,
                    Content = "呀! 有异常,请联系管理员"
                };
                return Task.FromResult(0);
            }
            /// <summary>
            /// 判断是否应该处理
            /// 后期扩展,重写方法可过滤掉不需处理的异常
            /// </summary>
            /// <param name="context"></param>
            /// <returns></returns>
            public override bool ShouldHandle(ExceptionHandlerContext context)
            {
                return true;
            }
            private class ErrorResult : IHttpActionResult
            {
                public HttpRequestMessage Request { get; set; }
                public string Content { get; set; }
                public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
                {
                    HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.InternalServerError);
                    response.Content = new StringContent(Content);
                    response.RequestMessage = Request;
                    return Task.FromResult(response);
                }
            }
        }
    public class GlobalExceptionLogger : ExceptionLogger
        {
            public override Task LogAsync(ExceptionLoggerContext context,CancellationToken cancellationToken)
            {
                if (!ShouldLog(context))
                {
                    return Task.FromResult(0);
                }
                if (context.Exception != null)
                {
                    string msg = ClientInfoAnalysis.GetClientInfo();
                    LogHelper.LogError(context.Exception, msg);
                }
                return Task.FromResult(0);
            }
            /// <summary>
            /// 判断是否应记录异常
            /// 后期重写此方法,可过滤掉不需要记录的异常信息
            /// </summary>
            /// <param name="context"></param>
            /// <returns></returns>
            public override bool ShouldLog(ExceptionLoggerContext context)
            {
                if ((context.Exception is System.Web.HttpException))
                {
                    return false;
                }
                return true;
            }
    }
    public static class WebApiConfig
        {
            public static void Register(HttpConfiguration config)
            {
                // 加载log4net配置文件
                LogConfigLoading.Load(AppSettings.Log4netPathForWeb);
    
                // 加载Web API服务
                config.Services.Replace(typeof(IAssembliesResolver), new ServiceAssembliesResolver(AppSettings.ServicesLocation));
    
                // 全局异常信息处理
                config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());
    
                // 全局异常记录
                config.Services.Add(typeof(IExceptionLogger), new GlobalExceptionLogger());
    }
    }

     

    4某些异常无法被捕获的异常

    问题描述

    对于在服务加载过程中的异常,无法通过异常过滤器,即实现了System.Web.Http.Filters.IExceptionFilter接口的过滤器来捕获,也不能通过注册ExceptionLogger来达到目的。解决方法如下:

    public static class WebApiConfig
        {
            public static void Register(HttpConfiguration config)
            {
                try
                {
                    config.Services.Replace(typeof(IAssembliesResolver), new ServiceAssembliesResolver(SysSettings.ServicesLocation));
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
    
    //其他代码
    }
    }

    其中ServiceAssembliesResolver为:

    public class ServiceAssembliesResolver : DefaultAssembliesResolver
        {
            //服务插件路径
            private string path;
            public ServiceAssembliesResolver(string path):base()
            {
                this.path = path;
            }
            public override ICollection<Assembly> GetAssemblies()
            {
                //获得已有的服务
                ICollection<Assembly> baseAssemblies = base.GetAssemblies();
                //初始化
                List<Assembly> assemblies = new List<Assembly>(baseAssemblies);
                //加载每一个服务插件
                foreach (string file in Directory.GetFiles(path, "*.dll"))
                {
                    var controllersAssembly = Assembly.LoadFrom(file);
                    assemblies.Add(controllersAssembly);
                }
    
                return assemblies;
            }
        }

    但上述方法很可能不起作用,根本原因在于将config.Services.Replace(typeof(IAssembliesResolver), new ServiceAssembliesResolver(SysSettings.ServicesLocation));放入try-catch块中ServiceAssembliesResolver在实例化的时候不抛出异常,而是当调用GetAssemblies时抛出异常(例如服务插件存储文件夹被删除),此时无法记录异常。那么问题就在于GetAssemblies方法何时被调用,通过跟踪代码发现Register中的所有代码都执行完成才会加载服务解决办法ServiceAssembliesResolver.GetAssemblies中捕获异常并记录下来。

     

     

  • 相关阅读:
    ubuntu故障处理
    最全http状态码
    go故障排查集锦
    docker知识11---docker service
    docker知识10---docker secret
    windows安装mysql
    信息收集
    模块
    Django:中间件
    Django:ORM单表操作
  • 原文地址:https://www.cnblogs.com/hdwgxz/p/7856429.html
Copyright © 2020-2023  润新知