Продолжим рассматривать условно разделённые части конвейера обработки запросов ASP.NET MVC, показанного в
данной статье. В
предыдущей статье была подробно описана вторая часть (обработчик запроса), а в этой речь пойдёт о третьей части - фабрике контроллеров.
Ниже показана эта схема.
В прошлой статье мы остановились на методе BeginProcessRequest обработчика запроса MvcHandler. Напомню, что данный обработчик HTTP-данных реализует интрефейс IHttpAsyncHandler
#region IHttpAsyncHandler Members
IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context,
AsyncCallback cb, object extraData)
{
return BeginProcessRequest(context, cb, extraData);
}
void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
{
EndProcessRequest(result);
}
и следовательной выполняет код асинхронно. Внутренний метод BeginProcessRequest, который вызывается в конечном счёте и в котором создаётся фабрика контроллеров имеет следующую сигнатуру.
protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext,
AsyncCallback callback, object state)
{
IController controller;
IControllerFactory factory;
ProcessRequestInit(httpContext, out controller, out factory);
IAsyncController asyncController = controller as IAsyncController;
if(asyncController != null)
{
// asynchronous controller
BeginInvokeDelegate beginDelegate =
delegate(AsyncCallback asyncCallback, object asyncState)
{
try
{
return asyncController.BeginExecute(RequestContext, asyncCallback, asyncState);
}
catch
{
factory.ReleaseController(asyncController);
throw;
}
};
EndInvokeDelegate endDelegate = delegate(IAsyncResult asyncResult)
{
try
{
asyncController.EndExecute(asyncResult);
}
finally
{
factory.ReleaseController(asyncController);
}
};
SynchronizationContext syncContext =
SynchronizationContextUtil.GetSynchronizationContext();
AsyncCallback newCallback =
AsyncUtil.WrapCallbackForSynchronizedExecution(callback, syncContext);
return AsyncResultWrapper.Begin(newCallback,
state, beginDelegate, endDelegate, _processRequestTag);
}
else
{
// synchronous controller
Action action = delegate
{
try
{
controller.Execute(RequestContext);
}
finally
{
factory.ReleaseController(controller);
}
};
return AsyncResultWrapper.BeginSynchronous(callback, state, action, _processRequestTag);
}
}
В данной статье нас интересуют только эти три строки кода
IController controller;
IControllerFactory factory;
ProcessRequestInit(httpContext, out controller, out factory);
или точнее то, что они делают. И так, как видно из кода объявляются две пустые ссылки: IController и IControllerFactory. Первая будет в последующем указывать на объект контроллера, а вторая на объект фабрики контроллеров. После того как ссылки объявлены они передаются во внутренний метод ProcessRequestInit обработчика MvcHandler, в котором будут проинициализированы.
private void ProcessRequestInit(HttpContextBase httpContext,
out IController controller, out IControllerFactory factory)
{
HttpContext currentContext = HttpContext.Current;
if(currentContext != null)
{
bool? isRequestValidationEnabled = ValidationUtility.IsValidationEnabled(currentContext);
if(isRequestValidationEnabled == true)
{
ValidationUtility.EnableDynamicValidation(currentContext);
}
}
AddVersionHeader(httpContext);
RemoveOptionalRoutingParameters();
// Get the controller type
string controllerName = RequestContext.RouteData.GetRequiredString("controller");
// Instantiate the controller and call Execute
factory = ControllerBuilder.GetControllerFactory();
controller = factory.CreateController(RequestContext, controllerName);
if(controller == null)
{
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentCulture,
MvcResources.ControllerBuilder_FactoryReturnedNull,
factory.GetType(),
controllerName));
}
}
А создаётся объект фабрики и сам объект контроллера, как видно из высшеприведённого кода, всего лишь парой строкой кода.
factory = ControllerBuilder.GetControllerFactory();
controller = factory.CreateController(RequestContext, controllerName);
А вот на этом мы остановимся и рассмотрим процесс создания этих объектов намного подробно, но уже в отдельных статьях. Процесс создания экземпляра класса будет рассмотрен в статье посвещённой классу
ControllerBuilder, а создание экземпляра контроллера в статье, где будет описан класс
DefaultControllerFactory. Дело в том, что одной из важных точек расширения и изменения механизма обработки запросов в ASP.NET MVC являестя фабрика контроллеров (конечно же я не имею ввиду сам паттерн MVC, а только механизм обработки запросов). Безусловно таковыми также являютмя обработчик маршрута и обработчик HTTP-данных, но они относятся к конвейеру ASP.NET в целом, нежели к ASP.NET MVC. А вот сама фабрика контроллеров уже тесно привязана к механизму обработки запросов в стиле ASP.NET MVC.