ASP.NET MVC: создается ли контроллер для каждого запроса?

112

Очень простой вопрос: создаются ли контроллеры в ASP.NET для каждого HTTP-запроса или они создаются при запуске приложения и повторно используются во всех запросах?

Будет ли контроллер создаваться только для определенного HTTP-запроса?

Если мои предыдущие предположения верны, могу ли я полагаться на это? Я хочу создать контекст базы данных (Entity Framework), который будет жить только для одного запроса. Если я создаю его как свойство, инициализированное в конструкторе контроллера, предоставляется ли, что новый экземпляр контекста будет создаваться для каждого запроса?

Расто
источник
16
Поместите точку останова в свой конструктор и посмотрите, что вы сможете узнать ...
Грег Б.
10
@Greg B: отличная идея, за исключением того, что он не скажет мне, всегда ли он так себя ведет - если обстоятельства изменятся и какой-то контроллер изменит свое поведение, у меня есть ошибка, которую может быть действительно трудно найти ...
Расто
@drasto как вы проверите, всегда ли так работает? Проверять каждый запрос к вашему приложению?
Greg B
4
@Todd Smith, пожалуйста, какую-нибудь ссылку или хотя бы полное имя. Буквы дерева IoC сложно гуглить. Спасибо.
Rasto
2
@drasto IoC = Инверсия управления en.wikipedia.org/wiki/Inversion_of_control
Bala R

Ответы:

103

Контроллер создается для каждого запроса объектом ControllerFactory(который по умолчанию является DefaultControllerFactory).

http://msdn.microsoft.com/en-us/library/system.web.mvc.defaultcontrollerfactory.aspx

Обратите внимание, что Html.ActionHtml Helper создаст еще один контроллер.

Краткая версия - это то, что ControllerActivator.Createвызывается (для каждого запроса) для создания Контроллера (который запускает новый Контроллер либо через DependencyResolver, либо через Активатор, если Резолвер не был настроен):

public IController Create(RequestContext requestContext, Type controllerType) 
{
    try 
    {
        return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
    }

Более длинная версия такова (вот код из источника из MvcHandler):

protected internal virtual void ProcessRequest(HttpContextBase httpContext)
{
    SecurityUtil.ProcessInApplicationTrust(() =>
    {
        IController controller;
        IControllerFactory factory;
        ProcessRequestInit(httpContext, out controller, out factory);

        try
        {
            controller.Execute(RequestContext);
        }
        finally
        {
            factory.ReleaseController(controller);
        }
    });
}

private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
    // non-relevant code
    // 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));
    }
}

Вот заводской код контроллера:

public virtual IController CreateController(RequestContext requestContext, string controllerName) 
{
    Type controllerType = GetControllerType(requestContext, controllerName);
    IController controller = GetControllerInstance(requestContext, controllerType);
    return controller;
}

Что в основном называет это:

protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType) 
{
    return ControllerActivator.Create(requestContext, controllerType);
}

Что вызывает этот метод в ControllerActivator(Этот код пытается запросить экземпляр DependencyResolver или просто использует класс Activator):

public IController Create(RequestContext requestContext, Type controllerType) 
{
    try 
    {
        return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
    }

Это может подпадать под слишком много информации ... Но я хотел показать, что вы действительно получаете новый контроллер для КАЖДОГО запроса.

Линкгорон
источник
@Daniel @drasto вот цитата aspnet.codeplex.com/SourceControl/changeset/view/63930#266503
Bala R
32

Я создал пустой конструктор для контроллера и поставил в конструкторе точку останова. Он попадал каждый раз, когда поступал новый запрос. Думаю, он создан для каждого запроса.

Бала Р
источник
3
+1 Надеюсь, вы правы, но мне бы хотелось получить более достоверные знания, чем просто «во всех случаях, которые я пробовал, это сработало». Если иногда по каким-то причинам так не получается, значит, ошибка.
Rasto
6
@drasto: Не о чем беспокоиться. Контроллер создается для каждого запроса. Однако некоторая память используется повторно, но вам не стоит беспокоиться о состоянии контроллера (если он у вас есть). Он будет инициализирован, как ожидалось. Но может возникнуть ситуация, когда будет создано более одного контроллера. И тогда представления вызывают действия контроллера (т.е. Html.RenderAction("action", "controller");)
Роберт Коритник,
@RobertKoritnik & Bala R, у меня вопрос, пожалуйста. Что происходит с объектами, созданными, например, Student или List <Student>, после того, как метод действия передал его или их представлению? Они избавляются? А что происходит с этими объектами, когда приходит новый запрос?
Махди Алхатиб
3

Контроллер будет создан при выполнении любого действия в конкретном контроллере.

У меня есть проект, в котором все мои контроллеры наследуются от, ApplicationControllerи каждый раз, когда выполняется действие, точка останова попадает внутри ApplicationController- независимо от его « текущего » контроллера.

Я инициализирую свой агент (который работает как мой контекст) всякий раз, когда мой контроллер создается следующим образом:

    public IWidgetAgent widgetAgent { get; set; }

    public WidgetController()
    {
        if (widgetAgent == null)
        {
            widgetAgent = new WidgetAgent();
        }

    }

Очевидно, это не то, что вам нужно - как вы упомянули, вам нужен только один экземпляр при каждом его вызове. Но это хорошее место, чтобы каждый раз проверять, что происходит, и убедиться, что другой экземпляр вашего контекста в настоящее время не существует.

Надеюсь это поможет.

Рион Уильямс
источник
2

Контроллеры создаются под каждый запрос. Волшебство происходит в маршрутизации в gobal.aspx. Пути сопоставления указывают MVC, какой контроллер нужно создать и какое действие на контроллере вызывать, а также параметры для передачи им.

http://www.asp.net/mvc/tutorials/asp-net-mvc-routing-overview-vb

Черный лед
источник
необходима ссылка - не удается найти подтверждающую информацию в связанном документе. Спасибо
Rasto