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

във вашия bootstrapclass трябва да заредите пружинния контейнер

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