Зависимости Spring.NET не внедряются

Я пытаюсь создать приложение ASP.NET MVC, используя Spring.NET для внедрения зависимостей. Приложение имеет три уровня: контроллер, сервис и данные.

Я определил объекты в файле "~\Resources\objects.xml".

Мой первый объект, UserAccountController, требует внедрения двух классов уровня службы: UserAccountService и DepartmentService. Итак, определение в objects.xml выглядит так:

<object id="UserAccountController" type="App.Controllers.UserAccountController, App">
    <constructor-arg index="0" ref="DepartmentService" />
    <constructor-arg index="1" ref="UserAccountService" />
</object>

<object id="UserAccountService" type="App.Service.UserAccountService, App">
    <property name="UserAccountDao" ref="UserAccountDao" />
</object>

<object id="UserAccountDao" type="App.Data.UserAccountDao, App" />

<object id="DepartmentService" type="App.Service.DepartmentService, App">
    <property name="DepartmentDao" ref="DepartmentDao" />
</object>

<object id="DepartmentDao" type="App.Data.DepartmentDao" />

Webconfig содержит это:

<sectionGroup name="spring">
        <section name="context" type="Spring.Context.Support.WebContextHandler, Spring.Web"/>
    </sectionGroup>
</configSections>
<spring>
    <context>
        <resource uri="~/Resources/objects.xml" />
    </context>
</spring>

Я бы предпочел использовать внедрение свойств, а не конструктор, но в настоящее время ни один из методов не работает.


person Jason    schedule 11.01.2010    source источник


Ответы (3)


Что ж, оказалось, что ASP.NET MVC и Spring.NET просто не уживаются...

Однако пакет MvcContrib (на самом деле пакет Extras), похоже, решил проблему. В пакете была заводская реализация Spring Controller, которая работала, и все было в порядке.

(Напоминает мне попытку заставить Struts 1.X и Spring работать на стороне Java...)

person Jason    schedule 11.01.2010

в вашем классе начальной загрузки вы должны загрузить контейнер spring

ContextRegistry.getContext();

кстати нужно указать имя сборки для DepartmentDao

<object id="DepartmentDao" type="App.Data.DepartmentDao, App" />
person Fabiano    schedule 11.01.2010
comment
На самом деле у меня есть класс SpringApplicationController и класс Spring ControllerFactory, и я ссылаюсь на них в Global.asax.cs: ControllerBuilder.Current.SetControllerFactory(typeof(App.Util.SpringControllerFactory)); Нужно ли мне получать контекст, если я использую этот метод? - person Jason; 11.01.2010
comment
честно, я не знаю. Но явно нет. Лучшей практикой для инверсии управления является загрузка контейнера в начале приложения и отсутствие других ссылок на контейнер. Если конфигурация выполнена правильно, вызов ContextRegistry.getContext(); должен справиться со всем - person Fabiano; 11.01.2010
comment
Ладно, я отказался от причудливых реализаций ControllerFactory и ApplicationContext в пользу простого вызова ContextRegistry.getContext() и переключился обратно на обычный ContextHandler в web.config. Еще не повезло с инъекцией. - person Jason; 11.01.2010
comment
как вы вводите/ссылаетесь на UserAccountController? - person Fabiano; 11.01.2010
comment
UserAccountController вызывается из действия формы. В этом случае у меня есть частичное представление с именем ViewCreate.ascx, которое вызывается через действие формы (из кнопки формы под названием «Создать учетную запись»). Нажмите кнопку, и будет вызвано частичное представление. К сожалению, он умирает из-за отсутствия внедряемой зависимости. - person Jason; 11.01.2010
comment
UserAccountController также необходимо внедрить в действие. или получен антишаблоном IApplicatonContext.GetObject(UserAccountController). или получен через статическую фабрику, в которую был внедрен UserAccountController - person Fabiano; 11.01.2010
comment
Я не знаю, понимаю ли я (пожалуйста, потерпите меня, я пытаюсь...). UserAccountController определен в objects.xml, но, поскольку я использую MVC с частичным представлением, нет кода программной части для внедрения контроллера. Контроллер — это высший уровень, выше его некуда вводить. Я попытался создать конструктор по умолчанию в UserAccountController, чтобы создать XmlApplicationContext, а затем получить из него объекты, но получил исключение Stackoverflow (вероятно, циклические ссылки). - person Jason; 11.01.2010
comment
хорошо, я не очень понимаю asp.net mvc. ваш первый подход мог быть правильным. возможно, это поможет weblogs.asp.net/fredriknormen/archive/2007/11/17/ . и да, если вы создаете applicationContext в конструкторе, есть циклическая ссылка - person Fabiano; 11.01.2010

Дополнительная информация: у меня также есть классы для SpringApplicationController и SpringControllerFactory:

SpringApplicationController.cs:

public static class SpringApplicationContext
{
    private static IApplicationContext Context { get; set; }

    /// <summary> 
    /// Returns a boolean value if the current application context contains an named object. 
    /// </summary> 
    /// <param name="objectName">Accepts the name of the object to check.</param> 
    public static bool Contains(string objectName)
    {
        SpringApplicationContext.EnsureContext();
        return SpringApplicationContext.Context.ContainsObject(objectName);
    }

    /// <summary> 
    /// Return a instance of an object in the context by the specified name. 
    /// </summary> 
    /// <param name="objectName">Accepts a string object name.</param> 
    public static object Resolve(string objectName)
    {
        SpringApplicationContext.EnsureContext();
        return SpringApplicationContext.Context.GetObject(objectName);
    }

    /// <summary> 
    /// Return a instance of an object in the context by the specified name and type. 
    /// </summary> 
    /// <typeparam name="T">Accepts the type of the object to resolve.</typeparam> 
    /// <param name="objectName">Accepts a string object name.</param> 
    public static T Resolve<T>(string objectName)
    {
        return (T)SpringApplicationContext.Resolve(objectName);
    }

    private static void EnsureContext()
    {
        if (SpringApplicationContext.Context == null)
        {
            SpringApplicationContext.Context = ContextRegistry.GetContext();
        }
    }
} 

SpringControllerFactory.cs:

public class SpringControllerFactory : DefaultControllerFactory
{
    public IController CreateController(RequestContext context, Type controllerType)
    {
        IResource input = new FileSystemResource(context.HttpContext.Request.MapPath("Resource\\objects.xml"));
        IObjectFactory factory = new XmlObjectFactory(input);

        return (IController) factory.GetObject(controllerType.Name);
    }

    public IController CreateController(RequestContext context, string controllerName)
    {
        IController controller = null;
        string controllerClassName = string.Format("{0}Controller", controllerName);

        if (SpringApplicationContext.Contains(controllerClassName))
        {
            controller = SpringApplicationContext.Resolve<IController>(controllerClassName);
            this.RequestContext = context;
        }
        else
        {
            controller = base.CreateController(context, controllerName);
        }
        return controller; 
    }

    public override void ReleaseController(IController controller)
    {
        IDisposable disposable = controller as IDisposable;
        if (disposable != null)
        {
            disposable.Dispose();
        }
    } 
}

Я ссылаюсь на это в своем Global.asax следующим образом:

    protected void Application_Start()
    {

        ControllerBuilder.Current.SetControllerFactory(typeof(App.Util.SpringControllerFactory));


        RegisterRoutes(RouteTable.Routes);
    }
person Jason    schedule 11.01.2010
comment
где контекст IApplicationContext установлен в SpringApplicationContext? - person Fabiano; 11.01.2010