您的位置:首页 > 理论基础 > 计算机网络

Asp.net web Api源码分析-如何获取IHttpHandler

2012-12-03 12:28 441 查看
我们知道任何asp.net web程序的处理都是由IHttpHandler来实现的,那么这里我看看web api是如何让获取IHttpHandler的。这里假设你已经能熟练的使用web api,我还是沿用以前的风格以一个简单的demo来说明吧。默认在我们的Global.asax.cs有这么一句

  WebApiConfig.Register(GlobalConfiguration.Configuration);而WebApiConfig.Register的默认实现也很简单:

 public static void Register(HttpConfiguration config)

        {

            config.Routes.MapHttpRoute(

                name: "DefaultApi",

                routeTemplate: "api/{controller}/{id}",

                defaults: new { id = RouteParameter.Optional }

            );

        }

一看这个方法我们就知道这是在注册一个路由信息,同时也提示我们以后自己开发asp.net mvc的时候,尽量把web api的路由分来处理,这里单独放到WebApiConfig.Register来处理的。

首先我们还是来看看这里的HttpConfiguration是个什么东东,在GlobalConfiguration中有这么一句

HttpConfiguration config = new HttpConfiguration(new HostedHttpRouteCollection(RouteTable.Routes));

其中这里用到的HostedHttpRouteCollection、HttpConfiguration构造函数如下:

  private readonly RouteCollection _routeCollection;

        public HostedHttpRouteCollection(RouteCollection routeCollection)

        {

            if (routeCollection == null)

            {

                throw Error.ArgumentNull("routeCollection");

            }

            _routeCollection = routeCollection;

        }

  public HttpConfiguration(HttpRouteCollection routes)

        {

            if (routes == null)

            {

                throw Error.ArgumentNull("routes");

            }

            _routes = routes;

            Services = new DefaultServices(this);

            ParameterBindingRules = DefaultActionValueBinder.GetDefaultParameterBinders();
        }

到这里我们可以知道HttpConfiguration是可以操作路由的,里面有一个  public HttpRouteCollection Routes属性。

现在我们来看看路由究竟是怎么添加的,MapHttpRoute方法具体实现如下:

 public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler)

        {

            if (routes == null)

            {

                throw Error.ArgumentNull("routes");

            }

            HttpRouteValueDictionary defaultsDictionary = new HttpRouteValueDictionary(defaults);

            HttpRouteValueDictionary constraintsDictionary = new HttpRouteValueDictionary(constraints);

            IHttpRoute route = routes.CreateRoute(routeTemplate, defaultsDictionary, constraintsDictionary, dataTokens: null, handler: handler);

            routes.Add(name, route);

            return route;

        }

    }

这里的routes是HostedHttpRouteCollection实例,其CreateRoute方法实现如下:

 public override IHttpRoute CreateRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler)

        {

            return new HostedHttpRoute(uriTemplate, defaults, constraints, dataTokens, handler);

        }

其中HostedHttpRoute的构造函数如下:

  public HostedHttpRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler)

        {

            RouteValueDictionary routeDefaults = defaults != null ? new RouteValueDictionary(defaults) : null;

            RouteValueDictionary routeConstraints = constraints != null ? new RouteValueDictionary(constraints) : null;

            RouteValueDictionary routeDataTokens = dataTokens != null ? new RouteValueDictionary(dataTokens) : null;

            OriginalRoute = new HttpWebRoute(uriTemplate, routeDefaults, routeConstraints, routeDataTokens, HttpControllerRouteHandler.Instance, this);

            Handler = handler;

        }

HostedHttpRoute的OriginalRoute属性有点特殊,是一个HttpWebRoute实例,HttpWebRoute的构造函数如下:

  internal class HttpWebRoute : Route

 public HttpWebRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler, IHttpRoute httpRoute)

            : base(url, defaults, constraints, dataTokens, routeHandler)

        {

            if (httpRoute == null)

            {

                throw Error.ArgumentNull("httpRoute");

            }

            HttpRoute = httpRoute;

        }

我们知道路由信息表里面的实例都是Route,看来这个的HttpWebRoute实例是我们真正需要的路由信息。这个路由处理的handler是HttpControllerRouteHandler,其中HttpControllerRouteHandler实现了一个单例模式:

  public class HttpControllerRouteHandler : IRouteHandler

    {

        private static readonly Lazy<HttpControllerRouteHandler> _instance =

            new Lazy<HttpControllerRouteHandler>(() => new HttpControllerRouteHandler(), isThreadSafe: true);

     

         public static HttpControllerRouteHandler Instance

        {

            get { return _instance.Value; }

        }

     }

现在我们回到MapHttpRoute方法中来,这里已经获取到了一个IHttpRoute的实例(HostedHttpRoute实例),现在剩下就只有一句了 routes.Add(name, route);,它的实现如下:

  public override void Add(string name, IHttpRoute route)

        {

            _routeCollection.Add(name, route.ToRoute());

        }

在HostedHttpRouteCollection的构造函数中曾把 _routeCollection设置为RouteTable.Routes,这里实际是在往RouteTable.Routes添加路由信息。这里的route的IHttpRoute方法实现如下:

  public static Route ToRoute(this IHttpRoute httpRoute)

        {

            if (httpRoute == null)

            {

                throw Error.ArgumentNull("httpRoute");

            }

            HostedHttpRoute hostedHttpRoute = httpRoute as HostedHttpRoute;

            if (hostedHttpRoute != null)

            {

                return hostedHttpRoute.OriginalRoute;

            }

            return new HttpWebRoute(

                httpRoute.RouteTemplate,

                MakeRouteValueDictionary(httpRoute.Defaults),

                MakeRouteValueDictionary(httpRoute.Constraints),

                MakeRouteValueDictionary(httpRoute.DataTokens),

                HttpControllerRouteHandler.Instance,

                httpRoute);

        }

到这里我们应该知道web api 默认的Route其实就是HttpWebRoute,其对应的IRouteHandler默认是HttpControllerRouteHandler,至于程序是如何通过路由信息表来找到路由这里我们就忽略了,大家可以参考

asp.net mvc源码分析-路由篇 如何找到 IHttpHandler
asp.net mvc源码分析-Route的GetRouteData

找到了IRouteHandler那么后面就调用它的GetHttpHandler来获取IHttpHandler实例,这里HttpControllerRouteHandler的GetHttpHandler实现非常简单:

 return new HttpControllerHandler(requestContext.RouteData);

那么我们来看看HttpControllerHandler的构造函数:

 public class HttpControllerHandler : IHttpAsyncHandler

 public HttpControllerHandler(RouteData routeData)

        {

            if (routeData == null)

            {

                throw Error.ArgumentNull("routeData");

            }

            _routeData = new HostedHttpRouteData(routeData);

        }

而HostedHttpRouteData的构造函数如下:

  public HostedHttpRouteData(RouteData routeData)

        {

            if (routeData == null)

            {

                throw Error.ArgumentNull("routeData");

            }

            OriginalRouteData = routeData;

            HttpWebRoute route = routeData.Route as HttpWebRoute;

            Route = route == null ? null : route.HttpRoute;

        }

至于这里的HostedHttpRoute 为什么需要一个OriginalRoute ,HostedHttpRouteData 需要一个OriginalRouteData 属性,在这里我就不多说了吧,相信大家应该都知道他们的作用吧,在后面需要的地方我再说说这2个属性干什么东东了。

这里我们还是总结一下吧:web api默认的路由都是在WebApiConfig.Register方法中添加,默认的route是HttpWebRoute实例,默认的IRouteHandler是HttpControllerRouteHandler实例,它返回的handler是一个实现IHttpAsyncHandler接口HttpControllerHandler实例。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: