Asp.Net WebApi核心对象解析(一)

    生活需要自己慢慢去体验和思考,对于知识也是如此。匆匆忙忙的生活,让人不知道自己一天到晚都在干些什么,似乎每天都在忙,但又好似不知道自己到底在忙些什么。不过也无所谓,只要我们知道最后想要什么就行。不管怎么样,我们还是得学习,让自己不断的向前,这样才可以渐渐看到自己的追求,发发感叹,谁让楼主以前是写小说的呢(想看楼主以前的小说可以私聊我,以前绝对货真价实的文艺青年,可惜现在已经是屌丝了。)

    不扯淡,还是来聊正经事,什么正经事勒?对于程序员来说,当然代码才是正经事了。

    在我们的项目开发中,很多时候需要使用到多系统的数据交互,以及一些功能的分布式开发。在.NET的体系中的分布式技术主要有webservice,.net remoting,MSMQ,WCF等等,但是今天介绍的是Asp.Net WebApi,对于Asp.Net WebApi技术,估计很多人都不会陌生,或者经常使用,因为对于其他的分布式技术的问题,在使用的时候会比较的繁琐,但是Asp.Net WebApi可能会简便和快捷很多。下面具体介绍一下Asp.Net WebApi技术。

一.WebApi概述:

     ASP.NET Web API是在.NET Framework之上构建的Web的API的框架,ASP.NET Web API是一个编程接口,用于操作可通过标准HTTP方法和标头访问的系统,ASP.NET Web API需要基于.NET 3.5或更高版本才可以进行开发。我们在学习ASP.NET Web API时,需要对HTTP协议、web知识有一个比较深入的认识,这样在学习ASP.NET Web API时会比较快速的上手和应用。这里就不介绍HTTP协议和Web相关的基础知识,需要了解的可以自行百度搜索学习。

   ASP.NET Web API可提供各种HTTP客户端使用,可以使用web基础设施提供的服务。

   1.ASP.NET Web API具有以下的几个特点:

      (1).可供多种客户端使用。

      (2).支持标准的HTTP方法。

      (3).支持浏览器友好的格式。(支持浏览器以及任何其它HTTP客户端容易支持的格式,例如json,xml等数据格式)

      (4).支持浏览器友好的认证方式。

   2.ASP.NET Web API所需的软件包:

      (1).System.Net.Http:提供核心HTTP编程模型。

      (2).System.AspNet.WebApi:提供在ASP.NET中安装和托管所需的安装的所有软件包的一个引用。

      (3).System.AspNet.WebApi.Core:包含核心WebApi编程模型和运行时组件。

      (4).System.AspNet.WebApi.Client:包含核心.NET HTTP客户端库的扩展。

      (5).System.AspNet.WebApi.WebHost:包含在ASP.NET运行时中托管WebApi所需的全部运行时组件。

    对于ASP.NET Web API的简单demo、安全认证、异常处理、内容协商、寄宿方式、错误处理等等,在这里就不再过于介绍,如果有时间博主会单独讲解这些内容。

二.WebApi路由机制的简要概述:

    对于ASP.NET Web API路由的介绍会比较简单,因为对于熟悉asp.net mvc的人来说不是什么难事,而且本次博文的重点并不是在这里,所以在这里只会做一个简单的介绍。ASP.NET WebAPI使用HTTP方法,而不是URI路径,以此来选择动作。还可以使用MVC样式路由的WebAPI。

在ASP.NET Web API中,一个控制器是处理HTTP请求的类。控制器的公共方法被称为动作方法或简单的动作。当Web API框架接收到一个请求,它请求路由到一个动作。要确定调用哪个动作,框架使用的路由表。如下代码:

routes.MapHttpRoute(
    name: "API Default",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

    我们在设置WebAPI路由时,已尽量注意与AspNet Mvc的路由发生冲突,这一点在ASP.NET Web API中做了一个防范。

     ASP.NET Web API的路由运行机制如下:

      (1).找到控制器,网络API将“控制器”的值 {}控制变量。

      (2).查找的动作,网络API着眼于HTTP方法,然后寻找一个动作名称以该HTTP方法名。例如,用GET请求,WebAPI查找与“获取...”,例如“GetContact”或“GetAllContacts”开头的动作。该公约只适用于GET,POST,PUT和DELETE方法。您可以通过使用控制器上的属性启用其他HTTP方法。

      (3).在路由模板其他占位符变量,诸如{ID},被映射到动作的参数。

   对于ASP.NET Web API的路由机制就讲解这么多,更多的内容大家可以自己去了解。

三.WebApi核心对象ApiController:

    在我们的asp.net webapi项目中,在顶层目录App_Start下,有一个WebApiConfig类,该类只包含一个方法Register,由Global.asax中的Application_Start方法调用代码,如下代码:

 GlobalConfiguration.Configure(WebApiConfig.Register);

    路由的映射方法只是一个扩展方法,如果需要了解“扩展方法”的相关知识,可以阅读以下:http://www.cnblogs.com/pengze0902/p/6110094.html,在这里就做介绍了,创建一个路由实例,并把这个实例添加到与宿主相关的路由集合之中。

    现在这里着重介绍一下ApiController类。

     ApiController是ValuesController类的父类,是整个ASP.NET Web API的核心类,继承该类可以用来创建ASP.NET Web API控制器。ApiController类中的公共静态(在Visual Basic中共享)成员是线程安全的,任何实例成员都不能保证是线程安全的。下面介绍一下ApiController在ASP.NET Web API中所承担的任务如下:

  (1).选择和运行控制器类上的一个操作方法。

  (2).将HTTP请求消息的各元素转换成控制器操作方法的参数,并将操作方法的返回值转换为有效的HTTP响应正文。(HTTP响应body的数据格式可以客户端和服务器进行协商,默认为json格式,对于json格式的好处,在这里就不做介绍,但是个人觉得json格式应该会成为以后数据格式的重心。)

  (3).运行各种筛选器,这些筛选器可以是为操作方法或控制器配置,也可以是全局的。

  (4).为控制器类的操作方法提供适当的上下文状态。

    以上是ApiController类的作用的简单介绍,下面我们具体看一下实现代码。

    首先,我们先来预览一下ApiController类的方法和属性:  

      1.属性摘要:

         ActionContext:获取操作上下文;

         Configuration和ControllerContext:获取当前 ApiController 的 HttpConfiguration对象;

         ModelState:在模型绑定过程之后获取模型状态;

         Request:获取或设置当前 ApiController 的 HttpRequestMessage;

         RequestContext: 获取请求上下文;

         Url:用于生成指向其他 API 的 URL;

         User:返回与此请求关联的当前主体;

      2.方法摘要:

         ExecuteAsync(): 异步执行单个 HTTP 操作,该方法为虚方法,可在子类中重写;

         Validate<TEntity>():验证给定实体并使用空前缀将验证错误添加到模型状态;

         Initialize():使用指定的 controllerContext 初始化 System.Web.Http.ApiController 实例;

         BadRequest():创建具有指定的InvalidModelStateResult模型状态。

         Created():创建一个CreatedNegotiatedContentResult`1(201表示已创建)具有指定的值。

         Redirect():创建具有指定值的重定向结果(302 Found)。

         ResponseMessage():创建具有指定响应的ResponseMessageResult。

      3.详细代码介绍:

       ApiController类实现了IHttpController和IDisposable接口。在ASP.NET Web API中如果需要创建控制器,只需要实现IHttpController接口即可,我们看一下IHttpController接口的实现代码:   

    //表示 HTTP 控制器
    public interface IHttpController
    {
        // 执行用于同步的控制器。
        //参数:controllerContext:测试控制器的当前上下文。cancellationToken:取消操作的通知。
        //返回结果:控制器。
        Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken);
    }

      可以看到该接口只有一个方法ExecuteAsync(),该方法为一个异步方法,HttpControllerContext表示一个HTTP请求对象,CancellationToken表示一个传递一个消息,为HTTP操作分配的取消令牌,Task<HttpResponseMessage>可以看出该方法返回一个异步的HTTP对象。我们看一下ApiController类中队该类的实现代码:

     /// <summary>
    /// 异步执行单个 HTTP 操作。
    /// </summary>
    /// <returns>
    /// 新启动的任务。
    /// </returns>
    /// <param name="controllerContext">单个 HTTP 操作的控制器上下文。</param><param name="cancellationToken">为 HTTP 操作分配的取消标记。</param>
    public virtual Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
    {
      if (this._initialized)
        throw Error.InvalidOperation(SRResources.CannotSupportSingletonInstance, new object[2]
        {
          (object) typeof (ApiController).Name,
          (object) typeof (IHttpControllerActivator).Name
        });
      this.Initialize(controllerContext);
      if (this.Request != null)
        HttpRequestMessageExtensions.RegisterForDispose(this.Request, (IDisposable) this);
      ServicesContainer services = controllerContext.ControllerDescriptor.Configuration.Services;      //根据HTTP请求内容选择动作
      HttpActionDescriptor actionDescriptor = ServicesExtensions.GetActionSelector(services).SelectAction(controllerContext);
      this.ActionContext.ActionDescriptor = actionDescriptor;
      if (this.Request != null)
        HttpRequestMessageExtensions.SetActionDescriptor(this.Request, actionDescriptor);
      FilterGrouping filterGrouping = actionDescriptor.GetFilterGrouping();      //获取动作过滤器
      IActionFilter[] actionFilters = filterGrouping.ActionFilters;      //获取授权过滤器
      IAuthenticationFilter[] authenticationFilters = filterGrouping.AuthenticationFilters;
      IAuthorizationFilter[] authorizationFilters = filterGrouping.AuthorizationFilters;      //获取异常过滤器
      IExceptionFilter[] exceptionFilters = filterGrouping.ExceptionFilters;
      IHttpActionResult innerResult = (IHttpActionResult) new ActionFilterResult(actionDescriptor.ActionBinding, this.ActionContext, services, actionFilters);
      if (authorizationFilters.Length > 0)
        innerResult = (IHttpActionResult) new AuthorizationFilterResult(this.ActionContext, authorizationFilters, innerResult);
      if (authenticationFilters.Length > 0)
        innerResult = (IHttpActionResult) new AuthenticationFilterResult(this.ActionContext, this, authenticationFilters, innerResult);
      if (exceptionFilters.Length > 0)
      {
        IExceptionLogger logger = ExceptionServices.GetLogger(services);
        IExceptionHandler handler = ExceptionServices.GetHandler(services);
        innerResult = (IHttpActionResult) new ExceptionFilterResult(this.ActionContext, exceptionFilters, logger, handler, innerResult);
      }
      return innerResult.ExecuteAsync(cancellationToken);
    }

    由以上的实现代码可以看出,含有三个类型的过滤器,分别是 IActionFilter、IAuthenticationFilter、IExceptionFilter,该方法在获取到消息请求后,初始化消息和请求,调用 HttpRequestMessageExtensions.RegisterForDispose(this.Request, (IDisposable) this)该方法进行注册,该方法会对请求信息进行过滤操作。

    我们接下来看一下Request和RequestContext属性的具体代码:

     /// <summary>
    /// 获取或设置当前ApiController的 HttpRequestMessage。
    /// </summary>
    /// <returns>
    /// 当前ApiController的 HttpRequestMessage。
    /// </returns>
    public HttpRequestMessage Request
    {
      get
      {
        return this.ControllerContext.Request;
      }
      set
      {
        if (value == null)
          throw Error.PropertyNull();
        HttpRequestContext requestContext1 = HttpRequestMessageExtensions.GetRequestContext(value);
        HttpRequestContext requestContext2 = this.RequestContext;
        if (requestContext1 != null && requestContext1 != requestContext2)
          throw new InvalidOperationException(SRResources.RequestContextConflict);
        this.ControllerContext.Request = value;
        HttpRequestMessageExtensions.SetRequestContext(value, requestContext2);
        RequestBackedHttpRequestContext httpRequestContext = requestContext2 as RequestBackedHttpRequestContext;
        if (httpRequestContext == null)
          return;
        httpRequestContext.Request = value;
      }
    }

    /// <summary>
    /// 获取请求上下文。
    /// </summary>
    /// <returns>
    /// 请求上下文。
    /// </returns>
    public HttpRequestContext RequestContext
    {
      get
      {
        return this.ControllerContext.RequestContext;
      }
      set
      {
        if (value == null)
          throw Error.PropertyNull();
        HttpRequestContext requestContext1 = this.ControllerContext.RequestContext;
        HttpRequestMessage request = this.Request;
        if (request != null)
        {
          HttpRequestContext requestContext2 = HttpRequestMessageExtensions.GetRequestContext(request);
          if (requestContext2 != null && requestContext2 != requestContext1 && requestContext2 != value)
            throw new InvalidOperationException(SRResources.RequestContextConflict);
          HttpRequestMessageExtensions.SetRequestContext(request, value);
        }
        this.ControllerContext.RequestContext = value;
      }
    }

    Request和RequestContext属性分别用于设置和获取HttpRequestMessage对象和RequestContext对象,

    ASP.NET Web API除了可以根据HTTP方法来选择操作方法,还可以根据请求的其他元素选择操作方法。ASP.NET Web API框架支持从请求元素到操作方法参数的绑定。对于HTTP响应值转换成适当的HTTP响应消息正文。

四.总结:

   以上是对ASP.NET Web API背景和使用方法,以及对ASP.NET Web API核心对象的简要介绍,下篇会主要介绍HttpRequestMessage、HttpResponseMessage、HttpClient等三个对象的解析。如果文中有不足和讲解错误之处,还望大家多多指正。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏ASP.NETCore

在VS中使用TinyFox调试OWIN应用(转)

 在很早一段时间之前,我曾经写过一篇关于Katana的使用方法的文章《如何安装并简单的使用OwinHost——Katana》,上面就有介绍如何在VS中调试使用K...

704
来自专栏GuZhenYin

使用OWIN作为WebAPI的宿主

前言 好吧,也没什么好说的,就是个技术的总结,直接生成MVC的项目,感觉好重,虽然各种东西很全 ...也许我是处女座? - -, OWIN呃,这里我就不解释了,...

1805
来自专栏张善友的专栏

基于OWin的Web服务器Katana发布版本3

当 ASP.NET 首次在 2002 年发布时,时代有所不同。 那时,Internet 仍处于起步阶段,大约有 5.69 亿用户,每个用户平均每天访问 Inte...

1935
来自专栏mwangblog

python类(三)

913
来自专栏企鹅号快讯

快速教程:使用Cython来扩展Python/NumPy库

北京 | 深度学习与人工智能研修 12月23-24日 ? 再设经典课程 重温深度学习 正文共2583个字,7张图,预计阅读时间:7分钟。 前言 整个快速教程直接...

2119
来自专栏GIS讲堂

PostGIS+QGIS+GeoServer+OpenLayers实现数据的存储、服务的发布以及地图的显示

为方便大家下载,我将所有软件上传的百度网盘里了,有需要的可以上网盘直接下载,地址为:http://pan.baidu.com/s/1ntJrf8P,此外,ope...

1723
来自专栏张善友的专栏

安装 IronPython

IronPython 1.0发布了 IronPython是Python编程语言在.NET平台上的实现。它支持一个可交互的控制台,该控制台支持完全的动态编译,并且...

2707
来自专栏张善友的专栏

使用 OWIN Self-Host ASP.NET Web API 2

Open Web Interface for .NET (OWIN)在Web服务器和Web应用程序之间建立一个抽象层。OWIN将网页应用程序从网页服务器分离出来...

25810
来自专栏GIS讲堂

Openlayers 2.X加载天地图

在前面的章节,讲到了Arcgis for js加载天地图,在本节讲述如何在Openlayers 2.X的版本中加载天地图,并添加自己的wms服务。

572
来自专栏c#开发者

ASP.NET MVC 5 Authentication Breakdown

In my previous post, "ASP.NET MVC 5 Authentication Breakdown", I broke down all ...

33710

扫码关注云+社区