Web API应用架构在Winform混合框架中的应用(2)--自定义异常结果的处理

在上篇随笔《Web API应用架构在Winform混合框架中的应用(1)》中我介绍了关于如何在Winfrom里面整合WebAPI,作为一个新型数据源的接入方式,从而形成了三种不同的数据提供来源,前文在介绍整体性框架方面,着笔较多,注重整合的统一性,但是在Web API方面还不算很具体,本系列将继续这个主题,介绍Web API开发中常见到的一些问题,对其中各个技术要点进行总结,本文主要介绍Web API自定义异常结果的处理。

1、常规的异常处理

统一的异常处理,把正确的信息返回给调用者很重要,可以让接口开发人员或者用户,了解具体的原因所在,这样可以得到有效的错误处理。

参考微信API的处理,微信API,对于调用都有一个错误信息返回,不会直接裸露未经处理的异常,因此它们都是经过了一定的拦截处理,然后把错误信息包装提供给接口调用方的。如下是微信的一些接口处理错误。

错误时微信会返回错误码等信息,JSON数据包示例如下(该示例为AppID无效错误):

{"errcode":40013,"errmsg":"invalid appid"}

我们根据自己的需要,定义了一个统一的错误信息实体类,如下所示。

    /// <summary>
    /// 接口返回的错误信息
    /// </summary>
    public class BaseResultJson
    {
        /// <summary>
        /// 错误代码
        /// </summary>
        public int errcode { get; set; }

        /// <summary>
        /// 如果不成功,返回的错误信息
        /// </summary>
        public string errmsg { get; set; }

        /// <summary>
        /// 是否成功
        /// </summary>
        public bool success { get; set; }
    }

这样我们就可以把拦截到的错误信息,转换为这样一个方便使用的实体类信息了。

拦截Web API的调用异常,一般可以结合Try Catch的方法,以及异常拦截器进行处理,如下是主动抛出的一些异常信息处理。

            //如果没有通过,则抛出异常,由异常过滤器统一处理
            if (!result.success)
            {
                throw new MyApiException(result.errmsg, result.errcode);
            }

其中MyApiException是自定义的一个异常信息,用来承载自定义错误信息的异常类。

异常拦截器,我们在Web API里面可以通过Attribute这种标签特性进行处理,如下是我在Web API的基类里面定义了一个异常处理器。

    /// <summary>
    /// 所有接口基类
    /// </summary>

    [ExceptionHandling]
    public class BaseApiController : ApiController

这个特性对象的定义,它的代码如下所示。

    /// <summary>
    /// API自定义错误过滤器属性
    /// </summary>
    public class ExceptionHandlingAttribute : ExceptionFilterAttribute
    {
        /// <summary>
        /// 统一对调用异常信息进行处理,返回自定义的异常信息
        /// </summary>
        /// <param name="context">HTTP上下文对象</param>
        public override void OnException(HttpActionExecutedContext context)
        {
            //自定义异常的处理
            MyApiException ex = context.Exception as MyApiException;
            if (ex != null)
            {
                throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
                {
                    //封装处理异常信息,返回指定JSON对象
                    Content = new StringContent(new BaseResultJson(ex.Message, false, ex.errcode).ToJson()),
                    ReasonPhrase = "Exception"
                });

            }

            //记录关键的异常信息
            Debug.WriteLine(context.Exception);

            //常规异常的处理
            string msg = string.IsNullOrEmpty(context.Exception.Message) ? "接口出现了错误,请重试或者联系管理员" : context.Exception.Message;
            throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
            {
                Content = new StringContent(msg),
                ReasonPhrase = "Critical Exception"
            });
        }
    }

根据这些代码,我们就可以实现对调用异常的统一封装处理,让它给我们返回统一的对象信息了,如下是其中一个调用异常,转换为自定义异常信息后的结果输出。

{"errcode":404,"errmsg":"请求的资源不支持 http 方法“POST”。","success":false}

这样我们在处理Web API的返回结果的时候,可以先处理它的异常信息,具体的处理代码如下所示。

            HttpHelper helper = new HttpHelper();
            helper.ContentType = "application/json";

            string content = helper.GetHtml(url, postData, true);
            VerifyErrorCode(content);

            T result = JsonConvert.DeserializeObject<T>(content);
            return result;

我们在上面红色部分的代码就是先处理异常定义信息,如果有这些异常,我们可以在界面中进行异常处理显示了。

例如,如果自定义异常存在,我们转换后,把对应的信息显示出来,重新抛出异常即可。

                BaseResultJson errorResult = JsonConvert.DeserializeObject<BaseResultJson>(content);
                //非成功操作才记录异常,因为有些操作是返回正常的结果({"errcode": 0, "errmsg": "ok"})
                if (errorResult != null && !errorResult.success)
                {
                    string error = string.Format("请求发生错误!错误代码:{0},说明:{1}", (int)errorResult.errcode, errorResult.errmsg);
                    LogTextHelper.Error(errorResult.ToJson());

                    throw new Exception(error);//抛出错误
                }

2、地址接口异常处理

对于常规的异常,我们通过上面的处理方式,就可以很好进行拦截并处理了,如果接口异常是全局性的,如访问地址簿正确,或者参数多了几个信息,那么调用的接口就不是有效的地址,这样的话,返回的信息就不会被上面的拦截器进行处理了。

如我们给一个无效的API调用路径,在浏览器中获得下面错误结果。

上面结果就无法被我们的常规异常拦截器所捕获,因此不会输出经过封装好的异常信息。

如果需要拦截,我们需要增加自己的消息代理处理,用来捕获这些特殊的异常信息。

    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {

            ..............

            config.MessageHandlers.Add(new CustomErrorMessageDelegatingHandler());

上面红色部分就是我们自己添加的消息代理处理类,用来处理一些特殊的异常信息,如下代码所示。

    /// <summary>
    /// API自定义错误消息处理委托类。
    /// 用于处理访问不到对应API地址的情况,对错误进行自定义操作。
    /// </summary>
    public class CustomErrorMessageDelegatingHandler : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            return base.SendAsync(request, cancellationToken).ContinueWith<HttpResponseMessage>((responseToCompleteTask) =>
            {
                HttpResponseMessage response = responseToCompleteTask.Result;
                HttpError error = null;
                if (response.TryGetContentValue<HttpError>(out error))
                {
                    //添加自定义错误处理
                    //error.Message = "Your Customized Error Message";
                }

                if (error != null)
                {
                    //获取抛出自定义异常,有拦截器统一解析
                    throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound)
                    {
                        //封装处理异常信息,返回指定JSON对象
                        Content = new StringContent(new BaseResultJson(error.Message, false, 404).ToJson()),
                        ReasonPhrase = "Exception"
                    });
                }
                else
                {
                    return response;
                }
            });
        }
    }

经过了上面的处理后,我们进一步测试一下不存在的地址的异常处理结果,可以看到输出的内容是经过了自定义对象的转换了。

常规的调用,如果接口不对应,那么错误也是类似下面的消息

{"errcode":404,"errmsg":"找不到与请求 URI“http://localhost:9001/api/SystemType/Delete?signature=72f8d706c79dc14d70fc3f080d4706748d754021&timestamp=1443194061&nonce=0.650359861855563&appid=website_9A39C2A8&token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIxIiwiaWF0IjoxNDQzMTk0MDM4LCJqdGkiOiI1YmEyYmE5Ni0yZTA4LTQ1ZTgtYTAwNy01MmY3OTkzYTg2NzEiLCJuYW1lIjoiYWRtaW4iLCJjaGFubmVsIjoiMCIsInNoYXJlZGtleSI6IjEyMzRhYmNkIn0.RRXQmmSCJzDK5Or6rmBL5wjd-YIJoEQFc0pOzqhR6IU”匹配的 HTTP 资源。","success":false}

有了这些信息,我们就可以统一我们的调用规则,并进行异常记录和显示了,非常方便。

系列文章如下所示:

Web API应用架构在Winform混合框架中的应用(1)

Web API应用架构在Winform混合框架中的应用(2)--自定义异常结果的处理

Web API接口设计经验总结 

Web API应用架构在Winform混合框架中的应用(3)--Winfrom界面调用WebAPI的过程分解

Web API应用架构在Winform混合框架中的应用(4)--利用代码生成工具快速开发整套应用

本文转自博客园伍华聪的博客,原文链接:Web API应用架构在Winform混合框架中的应用(2)--自定义异常结果的处理,如需转载请自行联系原博主。

时间: 2024-07-31 10:32:20

Web API应用架构在Winform混合框架中的应用(2)--自定义异常结果的处理的相关文章

Web API应用架构在Winform混合框架中的应用(1)

在<Web API应用架构设计分析(1)>和<Web API应用架构设计分析(2)>中对WebAPI的架构进行了一定的剖析,在当今移动优先的口号下,传统平台都纷纷开发了属于自己的Web API平台,方便各种终端系统的接入,很多企业的需求都是以Web API优先的理念来设计整个企业应用体系的.Web API作为整个纽带的核心,在整个核心层需要考虑到统一性.稳定性.以及安全性等方面因素.本文主要介绍,Web API应用架构,在Winform整合中的角色,以及如何实现在Winform混合

Web API应用架构在Winform混合框架中的应用(5)--系统级别字典和公司级别字典并存的处理方式

在我这个系列中,我主要以我正在开发的云会员管理系统为例进行介绍Web API的应用,由于云会员的数据设计是支持多个商家公司,而每个公司又可以包含多个店铺的,因此一些字典型的数据需要考虑这方面的不同.如对于证件类型,收费处理状态,民族,职称等这些固定化的内容,我们可以放到全局字典里面,但是对于一些如会员相关的字典数据,如产品单位.产品类型等内容,如果也全部规定为全局的系统字典,那么就缺乏灵活性,这些数据应该可以由各自进行差异化处理. 1.云会员系统的字典数据模型 我们先来了解下基于Web API接

Web API应用架构概括分析和设计实例教程

1.Web API的核心层设计 在目前发达的应用场景下,我们往往需要接入Winform客户端.APP程序.网站程序.以及目前热火朝天的微信应用等,这些数据应该可以由同一个服务提供,这个就是我们所需要构建的Web API平台,基于上述的需求,很多企业的需求都是以Web API优先的理念来设计整个企业应用体系的.Web API作为整个纽带的核心,在整个核心层需要考虑到统一性.稳定性.以及安全性等方面因素. 从上图我们可以看到,整个外围的应用场景围绕着Web API核心层构建,如果我们把它换一种方式表

Web API应用架构设计分析(1)

Web API 是一种应用接口框架,它能够构建HTTP服务以支撑更广泛的客户端(包括浏览器,手机和平板电脑等移动设备)的框架, ASP.NET Web API 是一种用于在 .NET Framework 上构建 RESTful 应用程序的理想平台.本文主要以ASP.NET Web API 的框架实现来介绍整个Web API应用架构设计,但不局限于.NET的技术. 1.Web API的核心层设计 在目前发达的应用场景下,我们往往需要接入Winform客户端.APP程序.网站程序.以及目前热火朝天的

混合框架中Oracle数据库的还原处理操作

在较早期的随笔<Oracle如何实现创建数据库.备份数据库及数据导出导入的一条龙操作>粗略介绍了Oracle数据库的备份还原操作,本文想从开发框架的基础上介绍Oracle数据库的脚本或者还原操作. 我们在Winform开发框架.混合式开发框架.Web开发框架等各种开发框架,底层都是支持多种数据库的,如MS SQLServer.Oracle.MySQL.SQLite.PostgreSQL等等,如下图所示. 其中SQLServer支持最为常用,而且也是最为方便备份还原的操作,而Oracle数据库这

可否把arcgis api for javascript整合到primefaces框架中?

问题描述 primefaces框架是基于jsf的,很漂亮!!!如果可以,可否给个实例代码?如果不可以,那为什么呢? 解决方案 解决方案二: 自己搞定了.

Winform混合式开发框架访问Web API接口的处理

在我的混合式开发框架里面,集成了WebAPI的访问,这种访问方式不仅可以实现简便的数据交换,而且可以在多种平台上进行接入,如Winform程序.Web网站.移动端APP等多种接入方式,Web API的处理方式和微信提供的接口处理规则类似,也是通过向服务器获得访问令牌(AccessToken),然后传递给每个Web API接口,实现数据的交换处理.本篇随笔主要介绍混合框架中Winform对Web API访问的处理. 1.Web API接入方式介绍 <混合式开发框架>混合了Web API接口访问.

Web API项目中使用Area对业务进行分类管理

在之前开发的很多Web API项目中,为了方便以及快速开发,往往把整个Web API的控制器放在基目录的Controllers目录中,但随着业务越来越复杂,这样Controllers目录中的文件就增加很快,难以管理,而且如果有不同业务模块有重复的控制器名的话,还需要尽量避免.引入Area的作用就是把控制器按照不同的业务模块进行区分,方便管理,而且控制器名称可以重名. 1.Web API项目引入Area进行分类 Area在项目中可以称之为区域,每个Area代表应用程序的不同功能模块,Area 使每

Web API接口设计经验总结

在Web API接口的开发过程中,我们可能会碰到各种各样的问题,我在前面两篇随笔<Web API应用架构在Winform混合框架中的应用(1)>.<Web API应用架构在Winform混合框架中的应用(2)--自定义异常结果的处理>也进行了总的介绍,在经过我的大量模块实践并成功运行后,总结了这篇随笔,希望对大家有所帮助. 1.在接口定义中确定MVC的GET或者POST方式 由于我们整个Web API平台是基于MVC的基础上进行的API开发,因此整个Web API的接口,在定义的时