zoukankan      html  css  js  c++  java
  • MVC处理程序&Asp.Net路由机制

    通过Asp.Net构架(Http请求处理流程)HttpApplication处理对象与HttpModule处理模块Asp.net 处理程序&处理程序接口IHttpHandler
    前面三篇我们了解了Http请求在服务器端的处理流程,Http请求最终会由实现了IHttpHandler接口的类进行处理,针对不同的请求,Asp.net要有不同的处理。

    MVC也是其中之一,打开机器上C:WindowsMicrosoft.NETFrameworkv4.0.30319Configweb.config

    <httpModules>
        ...
        <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule"/>
        ...
    </httpModules>
    

    可以看到系统默认url路由解析模块(System.Web.Routing.UrlRoutingModule)

    // System.Web.Routing.UrlRoutingModule
    protected virtual void Init(HttpApplication application)
    {
    	if (application.Context.Items[UrlRoutingModule._contextKey] != null)
    	{
    		return;
    	}
    	application.Context.Items[UrlRoutingModule._contextKey] = UrlRoutingModule._contextKey;
    	application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
    }
    
    • 模块初始化时,在HttpApplication中PostResolveRequestCache注册了动作OnApplicationPostResolveRequestCache
    // System.Web.Routing.UrlRoutingModule
    private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
    {
    	HttpApplication httpApplication = (HttpApplication)sender;
    	HttpContextBase context = new HttpContextWrapper(httpApplication.Context);
    	this.PostResolveRequestCache(context);
    }
    public virtual void PostResolveRequestCache(HttpContextBase context)
    {
    	RouteData routeData = this.RouteCollection.GetRouteData(context);
    	if (routeData == null)
    	{
    		return;
    	}
    	IRouteHandler routeHandler = routeData.RouteHandler;
    	if (routeHandler == null)
    	{
    		throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0]));
    	}
    	if (routeHandler is StopRoutingHandler)
    	{
    		return;
    	}
    	RequestContext requestContext = new RequestContext(context, routeData);
    	context.Request.RequestContext = requestContext;
    	IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
    	if (httpHandler == null)
    	{
    		throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[]
    		{
    			routeHandler.GetType()
    		}));
    	}
    	if (!(httpHandler is UrlAuthFailureHandler))
    	{
    		context.RemapHandler(httpHandler);
    		return;
    	}
    	if (FormsAuthenticationModule.FormsAuthRequired)
    	{
    		UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this);
    		return;
    	}
    	throw new HttpException(401, SR.GetString("Assess_Denied_Description3"));
    }
    
    • 当程序触发PostResolveRequestCache时,根据url匹配路由,多个路由则按顺序匹配,取第一个匹配的路由
    // System.Web.Routing.RouteCollection
    public RouteData GetRouteData(HttpContextBase httpContext)
    {
    	if (httpContext == null)
    	{
    		throw new ArgumentNullException("httpContext");
    	}
    	if (httpContext.Request == null)
    	{
    		throw new ArgumentException(SR.GetString("RouteTable_ContextMissingRequest"), "httpContext");
    	}
    	if (base.Count == 0)
    	{
    		return null;
    	}
    	bool flag = false;
    	bool flag2 = false;
    	if (!this.RouteExistingFiles)
    	{
    		flag = this.IsRouteToExistingFile(httpContext);
    		flag2 = true;
    		if (flag)
    		{
    			return null;
    		}
    	}
    	using (this.GetReadLock())
    	{
    		foreach (RouteBase current in this)
    		{
    			RouteData routeData = current.GetRouteData(httpContext);
    			if (routeData != null)
    			{
    				RouteData result;
    				if (!current.RouteExistingFiles)
    				{
    					if (!flag2)
    					{
    						flag = this.IsRouteToExistingFile(httpContext);
    						flag2 = true;
    					}
    					if (flag)
    					{
    						result = null;
    						return result;
    					}
    				}
    				result = routeData;
    				return result;
    			}
    		}
    	}
    	return null;
    }
    

    打开RouteBase源码发现GetRouteData这是一个抽象方法,这就给程序提供了扩展空间,因此这套流程同样适用于MVC、WebApi、WebService、WebForm...只需要重写GetRouteData方法

    using System;
    using System.Runtime.CompilerServices;
    namespace System.Web.Routing
    {
    	[TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
    	public abstract class RouteBase
    	{
    		private bool _routeExistingFiles = true;
    		public bool RouteExistingFiles
    		{
    			get
    			{
    				return this._routeExistingFiles;
    			}
    			set
    			{
    				this._routeExistingFiles = value;
    			}
    		}
    		public abstract RouteData GetRouteData(HttpContextBase httpContext);
    		public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
    	}
    }
    
    // System.Web.Routing.Route
    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
    	string virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;
    	RouteValueDictionary routeValueDictionary = this._parsedRoute.Match(virtualPath, this.Defaults);
    	if (routeValueDictionary == null)
    	{
    		return null;
    	}
    	RouteData routeData = new RouteData(this, this.RouteHandler);
    	if (!this.ProcessConstraints(httpContext, routeValueDictionary, RouteDirection.IncomingRequest))
    	{
    		return null;
    	}
    	foreach (KeyValuePair<string, object> current in routeValueDictionary)
    	{
    		routeData.Values.Add(current.Key, current.Value);
    	}
    	if (this.DataTokens != null)
    	{
    		foreach (KeyValuePair<string, object> current2 in this.DataTokens)
    		{
    			routeData.DataTokens[current2.Key] = current2.Value;
    		}
    	}
    	return routeData;
    }
    

    在 Asp.net MVC中,路由处理程序必须实现接口IRouteHandler,这个处理程序的类是MvcRouteHandler

    using System;
    using System.Runtime.CompilerServices;
    namespace System.Web.Routing
    {
    	[TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
    	public interface IRouteHandler
    	{
    		IHttpHandler GetHttpHandler(RequestContext requestContext);
    	}
    }
    

    定义了一个获取处理程序的方法GetHttpHandler

    // System.Web.Mvc.MvcRouteHandler
    IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
    {
    	return this.GetHttpHandler(requestContext);
    }
    /// <summary>Returns the HTTP handler by using the specified HTTP context.</summary>
    /// <returns>The HTTP handler.</returns>
    /// <param name="requestContext">The request context.</param>
    protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
    	requestContext.HttpContext.SetSessionStateBehavior(this.GetSessionStateBehavior(requestContext));
    	return new MvcHandler(requestContext);
    }
    

    这里指定了MVC流程后续页面级处理为MvcHandler

    // System.Web.Mvc.MvcHandler
    /// <summary>Processes the request by using the specified HTTP request context.</summary>
    /// <param name="httpContext">The HTTP context.</param>
    protected virtual void ProcessRequest(HttpContext httpContext)
    {
    	HttpContextBase httpContext2 = new HttpContextWrapper(httpContext);
    	this.ProcessRequest(httpContext2);
    }
    /// <summary>Processes the request by using the specified base HTTP request context.</summary>
    /// <param name="httpContext">The HTTP context.</param>
    protected internal virtual void ProcessRequest(HttpContextBase httpContext)
    {
    	IController controller;
    	IControllerFactory controllerFactory;
    	this.ProcessRequestInit(httpContext, out controller, out controllerFactory);
    	try
    	{
    		controller.Execute(this.RequestContext);
    	}
    	finally
    	{
    		controllerFactory.ReleaseController(controller);
    	}
    }
    

    在MvcHandler中 ProcessRequestInit方法 由ControllerBuilder创建ControllerFactory,再由ControllerFactory创建Controller

    // System.Web.Mvc.MvcHandler
    private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
    {
    	HttpContext current = HttpContext.Current;
    	if (current != null)
    	{
    		bool? flag = ValidationUtility.IsValidationEnabled(current);
    		bool? flag2 = flag;
    		if (flag2.GetValueOrDefault() && flag2.HasValue)
    		{
    			ValidationUtility.EnableDynamicValidation(current);
    		}
    	}
    	this.AddVersionHeader(httpContext);
    	this.RemoveOptionalRoutingParameters();
    	string requiredString = this.RequestContext.RouteData.GetRequiredString("controller");
    	factory = this.ControllerBuilder.GetControllerFactory();
    	controller = factory.CreateController(this.RequestContext, requiredString);
    	if (controller == null)
    	{
    		throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.ControllerBuilder_FactoryReturnedNull, new object[]
    		{
    			factory.GetType(), 
    			requiredString
    		}));
    	}
    }
    // System.Web.Mvc.ControllerBuilder
    private Func<IControllerFactory> _factoryThunk = () => null;
    private HashSet<string> _namespaces = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
    internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver)
    {
    	IResolver<IControllerFactory> arg_6A_1 = serviceResolver;
    	if (serviceResolver == null)
    	{
    		arg_6A_1 = new SingleServiceResolver<IControllerFactory>(() => this._factoryThunk(), new DefaultControllerFactory
    		{
    			ControllerBuilder = this
    		}, "ControllerBuilder.GetControllerFactory");
    	}
    	this._serviceResolver = arg_6A_1;
    }
    

    MVC中DefaultControllerFactory是默认的控制器工厂

    // System.Web.Mvc.DefaultControllerFactory
    /// <summary>Creates the specified controller by using the specified request context.</summary>
    /// <returns>The controller.</returns>
    /// <param name="requestContext">The context of the HTTP request, which includes the HTTP context and route data.</param>
    /// <param name="controllerName">The name of the controller.</param>
    /// <exception cref="T:System.ArgumentNullException">The <paramref name="requestContext" /> parameter is null.</exception>
    /// <exception cref="T:System.ArgumentException">The <paramref name="controllerName" /> parameter is null or empty.</exception>
    public virtual IController CreateController(RequestContext requestContext, string controllerName)
    {
    	if (requestContext == null)
    	{
    		throw new ArgumentNullException("requestContext");
    	}
    	if (string.IsNullOrEmpty(controllerName) && !requestContext.RouteData.HasDirectRouteMatch())
    	{
    		throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName");
    	}
    	Type controllerType = this.GetControllerType(requestContext, controllerName);
    	return this.GetControllerInstance(requestContext, controllerType);
    }
    /// <summary>Retrieves the controller instance for the specified request context and controller type.</summary>
    /// <returns>The controller instance.</returns>
    /// <param name="requestContext">The context of the HTTP request, which includes the HTTP context and route data.</param>
    /// <param name="controllerType">The type of the controller.</param>
    /// <exception cref="T:System.Web.HttpException">
    ///   <paramref name="controllerType" /> is null.</exception>
    /// <exception cref="T:System.ArgumentException">
    ///   <paramref name="controllerType" /> cannot be assigned.</exception>
    /// <exception cref="T:System.InvalidOperationException">An instance of <paramref name="controllerType" /> cannot be created.</exception>
    protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
    	if (controllerType == null)
    	{
    		throw new HttpException(404, string.Format(CultureInfo.CurrentCulture, MvcResources.DefaultControllerFactory_NoControllerFound, new object[]
    		{
    			requestContext.HttpContext.Request.Path
    		}));
    	}
    	if (!typeof(IController).IsAssignableFrom(controllerType))
    	{
    		throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, MvcResources.DefaultControllerFactory_TypeDoesNotSubclassControllerBase, new object[]
    		{
    			controllerType
    		}), "controllerType");
    	}
    	return this.ControllerActivator.Create(requestContext, controllerType);
    }
    
    // System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator
    public IController Create(RequestContext requestContext, Type controllerType)
    {
    	IController result;
    	try
    	{
    		result = (IController)(this._resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
    	}
    	catch (Exception innerException)
    	{
    		throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.DefaultControllerFactory_ErrorCreatingController, new object[]
    		{
    			controllerType
    		}), innerException);
    	}
    	return result;
    }
    

    本文参考文档:

  • 相关阅读:
    js复习---工厂函数---构造函数的执行过程
    21年初的措不及防-------
    element ui checkbox实现多项全选反选功能
    vue 实现导航锚点联动
    this.$router.currentRoute 和 this.$route的 区别
    重置vue组件的data数据 this.$options.data()
    父组件中如何拿到引入的子组件里element-ui 的form表单ref对象
    线程笔记
    面向对象
    关于上传和下载的笔记
  • 原文地址:https://www.cnblogs.com/Dewumu/p/13920345.html
Copyright © 2011-2022 走看看