MVC处理程序&Asp.Net路由机制

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

MVC也是其中之一,打开机器上C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\web.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;
}

本文参考文档:

posted @ 2020-11-03 15:03  德乌姆列特  阅读(106)  评论(0编辑  收藏  举报