Spring.NET и MVC3 на IIS7 - поведение области действия сеанса - PullRequest
2 голосов
/ 19 мая 2011

возможно, это глупый вопрос, и я просто не понял, как работают Spring и IIS, но давайте попробуем.

Я довольно новичок в ASP.NET и, насколько я понимаю,Обработка сеансов аналогична Apache / PHP:

Сеанс разделяется между вкладками браузера, но не между разными браузерами.Т.е. если я открою свою страницу в Firefox и положу что-то в корзину, в корзине все еще будут храниться мои товары в другой вкладке, но при открытии той же самой страницы в Internet Explorer должна появиться пустая корзина.

Однако я не могу воспроизвести это поведение с помощью Spring.NET.

Я создал hello-world с объектом корзины покупок, который отмечен в области видимости сеанса:

<objects xmlns="http://www.springframework.net">
  <object id="shoppingCart" type="DemoShop.Models.Cart.ShoppingCart, DemoShop" singleton="true" scope="session" />
</objects>

Если я добавлю что-то в корзину, она сохранится в любой вкладке и браузере.Поэтому мне кажется, что этот объект является реальным одноэлементным и, следовательно, постоянным во время выполнения приложения IIS.

Я знаю, что вы собираетесь сказать: почему я использовал атрибут singleton="true" вмой весенний конфиг?Хорошо, если я удалю его или установлю false, тогда объект не будет сохраняться в сеансе, но будет воссоздан при каждом запросе и, таким образом, потеряет свои данные.

Документация Spring.NETвообще не говоря об атрибуте singleton в контексте MVC, и мне потребовалось некоторое время, чтобы выяснить, что, по-видимому, это необходимо при использовании MVC3.

Мне удалось успешно создать объекты области приложения, используя

<object id="..." type="..., ..." singleton="true" scope="application" />

и запросите объект области видимости, используя

<object id="..." type="..., ..." scope="request" />

или

<object id="..." type="..., ..." singleton="false" scope="request" />

Однако, оставляя атрибут singleton вне, всегда помещайте мой объект в область запроса независимо от того,какую область я на самом деле отметил в атрибуте scope.

Я предполагаю, что сессия фактически не является общей для Firefox и IE, но объект корзины просто находится в области приложения, потому что я использую Springнеправильный путь.

Кто-нибудь может дать мне совет или намекнуть, что я делаю неправильно, или это проблема в IIS7?

1 Ответ

2 голосов
/ 08 июня 2011

Это ошибка.

После некоторой чрезмерной отладки исходного кода spring.net мы обнаружили:

  1. Поддержка объектов сессий предоставляется spring.web dll
  2. DLL spring.web.mvc не зависит от spring.web
  3. Это означает, что невозможно создать экземпляр MvcApplicationContext, который может разрешать объекты сессий

Следующее решение демонстрирует пользовательский MvcApplicationContext, который полностью включает объекты области сеанса в MVC3 с использованием spring.net.

Причина, по которой стандартный контекст приложения не может разрешить веб-области, заключается в том, что он использует класс RootObjectDefinition, поскольку он не знает об атрибуте scope (в конфигурации XML). Вместо этого WebApplicationContext создает экземпляры RootWebObjectDefinition типов, которые знают область действия.

WebObjectsFactory переопределяет метод CreateRootObjectDefinition, который возвращает экземпляры RootWebObjectDefinition. Это тот, который мы хотим вернуть из контекста нашего приложения. Это делается путем переопределения метода CreateObjectsFactory.

Следующая вещь, которую мы должны переопределить, это метод CreateXmlObjectDefinitionReader. Когда весна читает метаданные из конфигурации, она не будет анализировать дополнительные атрибуты, такие как scope, если мы не выберем определенного читателя. Поэтому мы будем использовать WebObjectDefinitionReader в контексте нашего приложения.

Для конфигурации объектов вашей области сеанса вы можете либо пропустить атрибут singleton, либо явно установить для него true. В противном случае со значением false область сеанса будет точно отключена.

* * Пример тысяча сорок-одиной: * +1042 *
<objects xmlns="http://www.springframework.net">
    <object id="shoppingCart" type="ShoppingCart, ..." singleton="true" scope="session" />
</objects>

Пошаговое решение:

  1. Создать MvcWebApplicationContext наследуя от MvcApplicationContext. Вам нужно будет переопределить два метода, упомянутых выше, и создать конструкторы по умолчанию.
  2. Создайте MvcWebContextHandler наследуя от MvcContextHandler. Это приведет к тому, что будет использоваться наш пользовательский контекст приложения.
  3. Используйте пользовательский контекстный обработчик в вашем web.config.
  4. Для поддержки IIS6 или встроенного веб-сервера Visual Studio: добавьте WebSupportModule в system.web раздел.
  5. Для поддержки IIS7: добавьте WebSupportModule в system.webserver раздел.

web.config:

<configSections>
    <sectionGroup name="spring">
        <section name="context" type="YourNamspace.MvcWebContextHandler, YourAssembly"/>    
        ....
    </sectionGroup>    
    ....
</configSections>

<!-- IIS6 -->
<system.web>
    <httpModules>
        <add name="Spring" type="Spring.Context.Support.WebSupportModule, Spring.Web"/>
    </httpModules>
</system.web>

<!-- IIS7 -->
<system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <modules runAllManagedModulesForAllRequests="true" >
        <add name="Spring" type="Spring.Context.Support.WebSupportModule, Spring.Web"/>
    </modules>
</system.webServer>

Класс пользовательского контекста приложения:

public class MvcWebApplicationContext: MvcApplicationContext {

    public MvcWebApplicationContext(string name, bool caseSensitive, params string[] configurationLocations)
    : this(new MvcApplicationContextArgs(name, null, configurationLocations, null, caseSensitive))
    { }

    public MvcWebApplicationContext(string name, bool caseSensitive, IApplicationContext parentContext, params string[] configurationLocations)
    : this(new MvcApplicationContextArgs(name, parentContext, configurationLocations, null, caseSensitive))
    { }

    public MvcWebApplicationContext(MvcApplicationContextArgs args)
    : base(args)
    { }

    public MvcWebApplicationContext(string name, bool caseSensitive, string[] configurationLocations, IResource[] configurationResources)
    : this(new MvcApplicationContextArgs(name, null, configurationLocations, configurationResources, caseSensitive))
    { }

    public MvcWebApplicationContext(params string[] configurationLocations)
    : this(new MvcApplicationContextArgs(string.Empty, null, configurationLocations, null, false))
    { }

    protected override XmlObjectDefinitionReader CreateXmlObjectDefinitionReader(DefaultListableObjectFactory objectFactory)
    {
        return new WebObjectDefinitionReader(GetContextPathWithTrailingSlash(), objectFactory, new XmlUrlResolver());
    }

    protected override DefaultListableObjectFactory CreateObjectFactory()
    {
        return new WebObjectFactory(GetContextPathWithTrailingSlash(), IsCaseSensitive);
    }

    private string GetContextPathWithTrailingSlash()
    {
        string contextPath = this.Name;
        if (contextPath == DefaultRootContextName)
        {
            contextPath = "/";
        }
        else 
        {
            contextPath = contextPath + "/";
        }
        return contextPath;
    }
}

Класс обработчика пользовательских контекстов:

public class MvcWebContextHandler : MvcContextHandler {

    protected override Type DefaultApplicationContextType
    {
        get { return typeof(MvcWebApplicationContext); }
    }  
}

Мы добавили эту ошибку в систему отслеживания проблем Spring.NET: https://jira.springsource.org/browse/SPRNET-1450

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...