MVC ASP.Netプロセスソース分析
85778 ワード
AppDomainFactory.cs
1. public Object Create(String appId, String appPath)
HttpRuntime
1.ProcessRequestNow().ProcessRequestInternal()
1.HttpContext 2を作成する.HttpApplicationFactoryクラスのインスタンスにHttpApplication 3を申請する.HttpApplicationのInitalModuleを呼び出す
IHttpHandler app = HttpApplicationFactory.GetApplicationInstance(context);
HttpApplication
RouteData routeData = RouteCollection.GetRouteData(context)
RouteCollection
RouteData routeData = route.GetRouteData(httpContext);
Route
Controller
ControllerActionInvoker
1. public Object Create(String appId, String appPath)
public Object Create(String appId, String appPath) {
try {
//
// Fill app a Dictionary with 'binding rules' -- name value string pairs
// for app domain creation
//
//
if (appPath[0] == '.') {
System.IO.FileInfo file = new System.IO.FileInfo(appPath);
appPath = file.FullName;
}
if (!StringUtil.StringEndsWith(appPath, '\\')) {
appPath = appPath + "\\";
}
// Create new app domain via App Manager
#if FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
throw new NotImplementedException("ROTORTODO");
#else // FEATURE_PAL
//
ISAPIApplicationHost appHost = new ISAPIApplicationHost(appId, appPath, false /*validatePhysicalPath*/);
// ISAPIRuntime
ISAPIRuntime isapiRuntime = (ISAPIRuntime)_appManager.CreateObjectInternal(appId, typeof(ISAPIRuntime), appHost,
false /*failIfExists*/, null /*hostingParameters*/);
isapiRuntime.StartProcessing();
return new ObjectHandle(isapiRuntime);
#endif // FEATURE_PAL
}
catch (Exception e) {
Debug.Trace("internal", "AppDomainFactory::Create failed with " + e.GetType().FullName + ": " + e.Message + "\r
" + e.StackTrace);
throw;
}
}
2.appManager.Create._appManager.CreateObjectInternal
internal IRegisteredObject CreateObjectInternal(
String appId,
Type type,
IApplicationHost appHost,
bool failIfExists,
HostingEnvironmentParameters hostingParameters) {
// check that type is as IRegisteredObject
if (!typeof(IRegisteredObject).IsAssignableFrom(type))
throw new ArgumentException(SR.GetString(SR.Not_IRegisteredObject, type.FullName), "type");
// get hosting environment
HostingEnvironment env = GetAppDomainWithHostingEnvironment(appId, appHost, hostingParameters);
// create the managed object in the worker app domain
// When marshaling Type, the AppDomain must have FileIoPermission to the assembly, which is not
// always the case, so we marshal the assembly qualified name instead
ObjectHandle h = env.CreateWellKnownObjectInstance(type.AssemblyQualifiedName, failIfExists);
return (h != null) ? h.Unwrap() as IRegisteredObject : null;
}
ISAPIRuntime
public int ProcessRequest(IntPtr ecb, int iWRType) {
IntPtr pHttpCompletion = IntPtr.Zero;
if (iWRType == WORKER_REQUEST_TYPE_IN_PROC_VERSION_2) {
pHttpCompletion = ecb;
ecb = UnsafeNativeMethods.GetEcb(pHttpCompletion);
}
ISAPIWorkerRequest wr = null;
try {
bool useOOP = (iWRType == WORKER_REQUEST_TYPE_OOP);
wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);
wr.Initialize();
// check if app path matches (need to restart app domain?)
String wrPath = wr.GetAppPathTranslated();
String adPath = HttpRuntime.AppDomainAppPathInternal;
if (adPath == null ||
StringUtil.EqualsIgnoreCase(wrPath, adPath)) {
HttpRuntime.ProcessRequestNoDemand(wr);
return 0;
}
else {
// need to restart app domain
HttpRuntime.ShutdownAppDomain(ApplicationShutdownReason.PhysicalApplicationPathChanged,
SR.GetString(SR.Hosting_Phys_Path_Changed,
adPath,
wrPath));
return 1;
}
}
catch(Exception e) {
try {
WebBaseEvent.RaiseRuntimeError(e, this);
} catch {}
// Have we called HSE_REQ_DONE_WITH_SESSION? If so, don't re-throw.
if (wr != null && wr.Ecb == IntPtr.Zero) {
if (pHttpCompletion != IntPtr.Zero) {
UnsafeNativeMethods.SetDoneWithSessionCalled(pHttpCompletion);
}
// if this is a thread abort exception, cancel the abort
if (e is ThreadAbortException) {
Thread.ResetAbort();
}
// IMPORTANT: if this thread is being aborted because of an AppDomain.Unload,
// the CLR will still throw an AppDomainUnloadedException. The native caller
// must special case COR_E_APPDOMAINUNLOADED(0x80131014) and not
// call HSE_REQ_DONE_WITH_SESSION more than once.
return 0;
}
// re-throw if we have not called HSE_REQ_DONE_WITH_SESSION
throw;
}
}
HttpRuntime
1.ProcessRequestNow().ProcessRequestInternal()
1.HttpContext 2を作成する.HttpApplicationFactoryクラスのインスタンスにHttpApplication 3を申請する.HttpApplicationのInitalModuleを呼び出す
private void ProcessRequestInternal(HttpWorkerRequest wr) {
// Count active requests
Interlocked.Increment(ref _activeRequestCount);
if (_disposingHttpRuntime) {
// Dev11 333176: An appdomain is unloaded before all requests are served, resulting in System.AppDomainUnloadedException during isapi completion callback
//
// HttpRuntim.Dispose could have already finished on a different thread when we had no active requests
// In this case we are about to start or already started unloading the appdomain so we will reject the request the safest way possible
try {
wr.SendStatus(503, "Server Too Busy");
wr.SendKnownResponseHeader(HttpWorkerRequest.HeaderContentType, "text/html; charset=utf-8");
byte[] body = Encoding.ASCII.GetBytes("<html><body>Server Too Busy</body></html>");
wr.SendResponseFromMemory(body, body.Length);
// this will flush synchronously because of HttpRuntime.ShutdownInProgress
wr.FlushResponse(true);
wr.EndOfRequest();
} finally {
Interlocked.Decrement(ref _activeRequestCount);
}
return;
}
// Construct the Context on HttpWorkerRequest, hook everything together
HttpContext context;
try {
context = new HttpContext(wr, false /* initResponseWriter */);
}
catch {
try {
// If we fail to create the context for any reason, send back a 400 to make sure
// the request is correctly closed (relates to VSUQFE3962)
wr.SendStatus(400, "Bad Request");
wr.SendKnownResponseHeader(HttpWorkerRequest.HeaderContentType, "text/html; charset=utf-8");
byte[] body = Encoding.ASCII.GetBytes("<html><body>Bad Request</body></html>");
wr.SendResponseFromMemory(body, body.Length);
wr.FlushResponse(true);
wr.EndOfRequest();
return;
} finally {
Interlocked.Decrement(ref _activeRequestCount);
}
}
wr.SetEndOfSendNotification(_asyncEndOfSendCallback, context);
HostingEnvironment.IncrementBusyCount();
try {
// First request initialization
try {
EnsureFirstRequestInit(context);
}
catch {
// If we are handling a DEBUG request, ignore the FirstRequestInit exception.
// This allows the HttpDebugHandler to execute, and lets the debugger attach to
// the process (VSWhidbey 358135)
if (!context.Request.IsDebuggingRequest) {
throw;
}
}
// Init response writer (after we have config in first request init)
// no need for impersonation as it is handled in config system
context.Response.InitResponseWriter();
// Get application instance
IHttpHandler app = HttpApplicationFactory.GetApplicationInstance(context);
if (app == null)
throw new HttpException(SR.GetString(SR.Unable_create_app_object));
if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, context.WorkerRequest, app.GetType().FullName, "Start");
if (app is IHttpAsyncHandler) {
// asynchronous handler
IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler)app;
context.AsyncAppHandler = asyncHandler;
asyncHandler.BeginProcessRequest(context, _handlerCompletionCallback, context);
}
else {
// synchronous handler
app.ProcessRequest(context);
FinishRequest(context.WorkerRequest, context, null);
}
}
catch (Exception e) {
context.Response.InitResponseWriter();
FinishRequest(wr, context, e);
}
}
IHttpHandler app = HttpApplicationFactory.GetApplicationInstance(context);
internal static IHttpHandler GetApplicationInstance(HttpContext context) {
if (_customApplication != null)
return _customApplication;
// Check to see if it's a debug auto-attach request
if (context.Request.IsDebuggingRequest)
return new HttpDebugHandler();
_theApplicationFactory.EnsureInited();
_theApplicationFactory.EnsureAppStartCalled(context); return _theApplicationFactory.GetNormalApplicationInstance(context);
}
private HttpApplication GetNormalApplicationInstance(HttpContext context) {
HttpApplication app = null;
lock (_freeList) {
if (_numFreeAppInstances > 0) {
app = (HttpApplication)_freeList.Pop();
_numFreeAppInstances--;
if (_numFreeAppInstances < _minFreeAppInstances) {
_minFreeAppInstances = _numFreeAppInstances;
}
}
}
if (app == null) {
// If ran out of instances, create a new one
app = (HttpApplication)HttpRuntime.CreateNonPublicInstance(_theApplicationType);
using (new ApplicationImpersonationContext()) {
app.InitInternal(context, _state, _eventHandlerMethods);
}
}
if (AppSettings.UseTaskFriendlySynchronizationContext) {
// When this HttpApplication instance is no longer in use, recycle it.
app.ApplicationInstanceConsumersCounter = new CountdownTask(1); // representing required call to HttpApplication.ReleaseAppInstance
app.ApplicationInstanceConsumersCounter.Task.ContinueWith((_, o) => RecycleApplicationInstance((HttpApplication)o), app, TaskContinuationOptions.ExecuteSynchronously);
}
return app;
}
HttpApplication
internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers) {
Debug.Assert(context != null, "context != null");
// Remember state
_state = state;
PerfCounters.IncrementCounter(AppPerfCounter.PIPELINES);
try {
try {
// Remember context for config lookups
_initContext = context;
_initContext.ApplicationInstance = this;
// Set config path to be application path for the application initialization
context.ConfigurationPath = context.Request.ApplicationPathObject;
// keep HttpContext.Current working while running user code
using (new DisposableHttpContextWrapper(context)) {
// Build module list from config
if (HttpRuntime.UseIntegratedPipeline) {
Debug.Assert(_moduleConfigInfo != null, "_moduleConfigInfo != null");
Debug.Assert(_moduleConfigInfo.Count >= 0, "_moduleConfigInfo.Count >= 0");
try {
context.HideRequestResponse = true;
_hideRequestResponse = true;
InitIntegratedModules();
}
finally {
context.HideRequestResponse = false;
_hideRequestResponse = false;
}
}
else {
InitModules(); // this is used exclusively for integrated mode
Debug.Assert(null == _moduleContainers, "null == _moduleContainers");
}
// Hookup event handlers via reflection
if (handlers != null)
HookupEventHandlersForApplicationAndModules(handlers); // Initialization of the derived class
_context = context;
if (HttpRuntime.UseIntegratedPipeline && _context != null) {
_context.HideRequestResponse = true;
}
_hideRequestResponse = true;
try {
Init();
}
catch (Exception e) {
RecordError(e);
}
}
if (HttpRuntime.UseIntegratedPipeline && _context != null) {
_context.HideRequestResponse = false;
}
_hideRequestResponse = false;
_context = null;
_resumeStepsWaitCallback= new WaitCallback(this.ResumeStepsWaitCallback);
// Construct the execution steps array
if (HttpRuntime.UseIntegratedPipeline) {
_stepManager = new PipelineStepManager(this);
}
else {
_stepManager = new ApplicationStepManager(this);
}
_stepManager.BuildSteps(_resumeStepsWaitCallback);
}
finally {
_initInternalCompleted = true;
// Reset config path
context.ConfigurationPath = null;
// don't hold on to the context
_initContext.ApplicationInstance = null;
_initContext = null;
}
}
catch { // Protect against exception filters
throw;
}
}
private void HookupEventHandlersForApplicationAndModules(MethodInfo[] handlers) {
_currentModuleCollectionKey = HttpApplicationFactory.applicationFileName;
if(null == _pipelineEventMasks) {
Dictionary<string, RequestNotification> dict = new Dictionary<string, RequestNotification>();
BuildEventMaskDictionary(dict);
if(null == _pipelineEventMasks) {
_pipelineEventMasks = dict;
}
}
for (int i = 0; i < handlers.Length; i++) {
MethodInfo appMethod = handlers[i];
String appMethodName = appMethod.Name;
int namePosIndex = appMethodName.IndexOf('_');
String targetName = appMethodName.Substring(0, namePosIndex);
// Find target for method
Object target = null;
if (StringUtil.EqualsIgnoreCase(targetName, "Application"))
target = this;
else if (_moduleCollection != null)
target = _moduleCollection[targetName];
if (target == null)
continue;
// Find event on the module type
Type targetType = target.GetType();
EventDescriptorCollection events = TypeDescriptor.GetEvents(targetType);
string eventName = appMethodName.Substring(namePosIndex+1);
EventDescriptor foundEvent = events.Find(eventName, true);
if (foundEvent == null
&& StringUtil.EqualsIgnoreCase(eventName.Substring(0, 2), "on")) {
eventName = eventName.Substring(2);
foundEvent = events.Find(eventName, true);
}
MethodInfo addMethod = null;
if (foundEvent != null) {
EventInfo reflectionEvent = targetType.GetEvent(foundEvent.Name);
Debug.Assert(reflectionEvent != null);
if (reflectionEvent != null) {
addMethod = reflectionEvent.GetAddMethod();
}
}
if (addMethod == null)
continue;
ParameterInfo[] addMethodParams = addMethod.GetParameters();
if (addMethodParams.Length != 1)
continue;
// Create the delegate from app method to pass to AddXXX(handler) method
Delegate handlerDelegate = null;
ParameterInfo[] appMethodParams = appMethod.GetParameters();
if (appMethodParams.Length == 0) {
// If the app method doesn't have arguments --
// -- hookup via intermidiate handler
// only can do it for EventHandler, not strongly typed
if (addMethodParams[0].ParameterType != typeof(System.EventHandler))
continue;
ArglessEventHandlerProxy proxy = new ArglessEventHandlerProxy(this, appMethod);
handlerDelegate = proxy.Handler;
}
else {
// Hookup directly to the app methods hoping all types match
try {
handlerDelegate = Delegate.CreateDelegate(addMethodParams[0].ParameterType, this, appMethodName);
}
catch {
// some type mismatch
continue;
}
}
// Call the AddXXX() to hook up the delegate
try {
addMethod.Invoke(target, new Object[1]{handlerDelegate});
}
catch {
if (HttpRuntime.UseIntegratedPipeline) {
throw;
}
}
if (eventName != null) {
if (_pipelineEventMasks.ContainsKey(eventName)) {
if (!StringUtil.StringStartsWith(eventName, "Post")) {
_appRequestNotifications |= _pipelineEventMasks[eventName];
}
else {
_appPostNotifications |= _pipelineEventMasks[eventName];
}
}
}
}
}
private void RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers) { RequestNotification requestNotifications; RequestNotification postRequestNotifications; // register an implicit filter module RegisterIntegratedEvent(appContext, IMPLICIT_FILTER_MODULE, RequestNotification.UpdateRequestCache| RequestNotification.LogRequest /*requestNotifications*/, 0 /*postRequestNotifications*/, String.Empty /*type*/, String.Empty /*precondition*/, true /*useHighPriority*/); // integrated pipeline will always use serverModules instead of <httpModules> _moduleCollection = GetModuleCollection(appContext); if (handlers != null) { HookupEventHandlersForApplicationAndModules(handlers); } // 1643363: Breaking Change: ASP.Net v2.0: Application_OnStart is called after Module.Init (Integarted mode) HttpApplicationFactory.EnsureAppStartCalledForIntegratedMode(context, this); // Call Init on HttpApplication derived class ("global.asax") // and process event subscriptions before processing other modules. // Doing this now prevents clearing any events that may // have been added to event handlers during instantiation of this instance. // NOTE: If "global.asax" has a constructor which hooks up event handlers, // then they were added to the event handler lists but have not been registered with IIS yet, // so we MUST call ProcessEventSubscriptions on it first, before the other modules. _currentModuleCollectionKey = HttpApplicationFactory.applicationFileName; try { _hideRequestResponse = true; context.HideRequestResponse = true; _context = context; Init(); } catch (Exception e) { RecordError(e); Exception error = context.Error; if (error != null) { throw error; } } finally { _context = null; context.HideRequestResponse = false; _hideRequestResponse = false; } ProcessEventSubscriptions(out requestNotifications, out postRequestNotifications); // Save the notification subscriptions so we can register them with IIS later, after // we call HookupEventHandlersForApplicationAndModules and process global.asax event handlers. _appRequestNotifications |= requestNotifications; _appPostNotifications |= postRequestNotifications; for (int i = 0; i < _moduleCollection.Count; i++) { _currentModuleCollectionKey = _moduleCollection.GetKey(i); IHttpModule httpModule = _moduleCollection.Get(i); ModuleConfigurationInfo moduleInfo = _moduleConfigInfo[i]; #if DBG Debug.Trace("PipelineRuntime", "RegisterEventSubscriptionsWithIIS: name=" + CurrentModuleCollectionKey + ", type=" + httpModule.GetType().FullName + "
"); // make sure collections are in sync Debug.Assert(moduleInfo.Name == _currentModuleCollectionKey, "moduleInfo.Name == _currentModuleCollectionKey"); #endif httpModule.Init(this); ProcessEventSubscriptions(out requestNotifications, out postRequestNotifications); // are any events wired up? if (requestNotifications != 0 || postRequestNotifications != 0) { RegisterIntegratedEvent(appContext, moduleInfo.Name, requestNotifications, postRequestNotifications, moduleInfo.Type, moduleInfo.Precondition, false /*useHighPriority*/); } } // WOS 1728067: RewritePath does not remap the handler when rewriting from a non-ASP.NET request // register a default implicit handler RegisterIntegratedEvent(appContext, IMPLICIT_HANDLER, RequestNotification.ExecuteRequestHandler | RequestNotification.MapRequestHandler /*requestNotifications*/, RequestNotification.EndRequest /*postRequestNotifications*/, String.Empty /*type*/, String.Empty /*precondition*/, false /*useHighPriority*/); }
UrlRoutingModule
protected virtual void Init(HttpApplication application) {
//////////////////////////////////////////////////////////////////
// Check if this module has been already addded
if (application.Context.Items[_contextKey] != null) {
return; // already added to the pipeline
}
application.Context.Items[_contextKey] = _contextKey;
// Ideally we would use the MapRequestHandler event. However, MapRequestHandler is not available
// in II6 or IIS7 ISAPI Mode. Instead, we use PostResolveRequestCache, which is the event immediately
// before MapRequestHandler. This allows use to use one common codepath for all versions of IIS.
application.PostResolveRequestCache += OnApplicationPostResolveRequestCache;
}
public virtual void PostResolveRequestCache(HttpContextBase context) {
// Match the incoming URL against the route table
RouteData routeData = RouteCollection.GetRouteData(context);
// Do nothing if no route found
if (routeData == null) {
return;
}
// If a route was found, get an IHttpHandler from the route's RouteHandler
IRouteHandler routeHandler = routeData.RouteHandler;
if (routeHandler == null) {
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentCulture,
SR.GetString(SR.UrlRoutingModule_NoRouteHandler)));
}
// This is a special IRouteHandler that tells the routing module to stop processing
// routes and to let the fallback handler handle the request.
if (routeHandler is StopRoutingHandler) {
return;
}
RequestContext requestContext = new RequestContext(context, routeData);
// Dev10 766875 Adding RouteData to HttpContext
context.Request.RequestContext = requestContext;
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);// MVCHandler RequestContext
if (httpHandler == null) {
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentUICulture,
SR.GetString(SR.UrlRoutingModule_NoHttpHandler),
routeHandler.GetType()));
}
if (httpHandler is UrlAuthFailureHandler) {
if (FormsAuthenticationModule.FormsAuthRequired) {
UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this);
return;
}
else {
throw new HttpException(401, SR.GetString(SR.Assess_Denied_Description3));
}
}
// Remap IIS7 to our handler
context.RemapHandler(httpHandler);// MVCHandler HttpContext }
RouteData routeData = RouteCollection.GetRouteData(context)
RouteCollection
public RouteData GetRouteData(HttpContextBase httpContext) {
if (httpContext == null) {
throw new ArgumentNullException("httpContext");
}
if (httpContext.Request == null) {
throw new ArgumentException(SR.GetString(SR.RouteTable_ContextMissingRequest), "httpContext");
}
// Optimize performance when the route collection is empty. The main improvement is that we avoid taking
// a read lock when the collection is empty. Without this check, the UrlRoutingModule causes a 25%-50%
// regression in HelloWorld RPS due to lock contention. The UrlRoutingModule is now in the root web.config,
// so we need to ensure the module is performant, especially when you are not using routing.
// This check does introduce a slight
if (Count == 0) {
return null;
}
bool isRouteToExistingFile = false;
bool doneRouteCheck = false; // We only want to do the route check once
if (!RouteExistingFiles) {
isRouteToExistingFile = IsRouteToExistingFile(httpContext);
doneRouteCheck = true;
if (isRouteToExistingFile) {
// If we're not routing existing files and the file exists, we stop processing routes
return null;
}
}
// Go through all the configured routes and find the first one that returns a match
using (GetReadLock()) {
foreach (RouteBase route in this) {
RouteData routeData = route.GetRouteData(httpContext);
if (routeData != null) {
// If we're not routing existing files on this route and the file exists, we also stop processing routes
if (!route.RouteExistingFiles) {
if (!doneRouteCheck) {
isRouteToExistingFile = IsRouteToExistingFile(httpContext);
doneRouteCheck = true;
}
if (isRouteToExistingFile) {
return null;
}
}
return routeData;
}
}
}
return null;
}
RouteData routeData = route.GetRouteData(httpContext);
Route
public override RouteData GetRouteData(HttpContextBase httpContext) {
// Parse incoming URL (we trim off the first two chars since they're always "~/")
string requestPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;
RouteValueDictionary values = _parsedRoute.Match(requestPath, Defaults);
if (values == null) {
// If we got back a null value set, that means the URL did not match
return null;
}
RouteData routeData = new RouteData(this, RouteHandler);
// Validate the values
if (!ProcessConstraints(httpContext, values, RouteDirection.IncomingRequest)) {
return null;
}
// Copy the matched values
foreach (var value in values) {
routeData.Values.Add(value.Key, value.Value);
}
// Copy the DataTokens from the Route to the RouteData
if (DataTokens != null) {
foreach (var prop in DataTokens) {
routeData.DataTokens[prop.Key] = prop.Value;
}
}
return routeData;
}
Controller
protected override void ExecuteCore()
{
this.PossiblyLoadTempData();
try
{
string requiredString = this.RouteData.GetRequiredString("action");
if (this.ActionInvoker.InvokeAction(this.ControllerContext, requiredString))
return;
this.HandleUnknownAction(requiredString);
}
finally
{
this.PossiblySaveTempData();
}
}
ControllerActionInvoker
/// <summary>
/// 。
/// </summary>
///
/// <returns>
/// 。
/// </returns>
/// <param name="controllerContext"> 。</param><param name="actionName"> 。</param><exception cref="T:System.ArgumentNullException"><paramref name="controllerContext"/> null。</exception><exception cref="T:System.ArgumentException"><paramref name="actionName"/> null 。</exception><exception cref="T:System.Threading.ThreadAbortException"> 。</exception><exception cref="T:System.Exception"> 。</exception>
public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)
{
if (controllerContext == null)
throw new ArgumentNullException("controllerContext");
if (string.IsNullOrEmpty(actionName))
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext);
ActionDescriptor action = this.FindAction(controllerContext, controllerDescriptor, actionName);
if (action == null)
return false;
FilterInfo filters = this.GetFilters(controllerContext, action);
try
{
AuthorizationContext authorizationContext = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, action);
if (authorizationContext.Result != null)
{
this.InvokeActionResult(controllerContext, authorizationContext.Result);
}
else
{
if (controllerContext.Controller.ValidateRequest)
ControllerActionInvoker.ValidateRequest(controllerContext);
IDictionary<string, object> parameterValues = this.GetParameterValues(controllerContext, action);
ActionExecutedContext actionExecutedContext = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, action, parameterValues);
this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, actionExecutedContext.Result);
}
}
catch (ThreadAbortException ex)
{
throw;
}
catch (Exception ex)
{
ExceptionContext exceptionContext = this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, ex);
if (!exceptionContext.ExceptionHandled)
throw;
else
this.InvokeActionResult(controllerContext, exceptionContext.Result);
}
return true;
}
/// <summary>
/// IHttpHandler 。
/// </summary>
public class MvcRouteHandler : IRouteHandler {
private IControllerFactory _controllerFactory;
/// <summary>
/// <see cref="T:System.Web.Mvc.MvcRouteHandler"/> 。
/// </summary>
public MvcRouteHandler()
{
}
/// <summary>
/// <see cref="T:System.Web.Mvc.MvcRouteHandler"/> 。
/// </summary>
/// <param name="controllerFactory"> 。</param>
public MvcRouteHandler(IControllerFactory controllerFactory)
{
this._controllerFactory = controllerFactory;
}
/// <summary>
/// HTTP HTTP 。
/// </summary>
///
/// <returns>
/// HTTP 。
/// </returns>
/// <param name="requestContext"> 。</param>
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) {
requestContext.HttpContext.SetSessionStateBehavior(this.GetSessionStateBehavior(requestContext));
return (IHttpHandler) new MvcHandler(requestContext); }