MVC3 - Как правильно ввести зависимости с MVC3 и Ninject? - PullRequest
0 голосов
/ 10 июня 2011

Я пытаюсь перепроектировать существующее приложение, используя внедрение зависимостей с помощью Ninject в MVC3.Вот часть унаследованного поведения, с которым у меня возникают трудности (и да, я знаю, что это плохо, поэтому я пытаюсь его реорганизовать):

protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
    base.OnActionExecuting(filterContext);

    MyUserSession userSession = filterContext.HttpContext.Session[SESSIONKEY_USER] as MyUserSession;

    // if session  empty, rebuild user information
    if (userSession == null)
    {
        string userName = HttpContext.User.Identity.Name;
        userSession = new MyUserSession();

        using (ADSearcher ad = new ADSearcher(ldapPath, excludeOUString.Split(',')))
        {
            // get basic user information from Active Directory
            ADUserInfo aduser = MyActiveDirectorySearcher.GetUserRecord(userName);

            // ... set several properties queries from AD... 
            userSession.propertyXYZ = aduser.propXYZ
        }   

        // if user can proxy as another indivudual, set property
        using (EDMContainer db = new EDMContainer())
        {
            if (db.Proxies.Any(p => p.ProxyLogin == userSession.userLogin))
                userSession.CanProxy == true;
        }

        // save new user object to session
        filterContext.HttpContext.Session[SESSIONKEY_USER] = userSession;

        if(userSession.canProxy)
            filterContext.Result = RedirectToAction("Proxy", "Home");

        return;
    }
}

Итак, в настоящее время контроллер использует несколько объектовнапрямую: Session, ActiveDirectorySearch, EF Database.Я понимаю, что было бы лучше создать класс, который предоставляет единственный метод "GetUser", маскирующий всю сложность, но я борюсь с тем, как внедрить зависимости.

Если я создаю класс SomeUserProvider, он также будетнужен доступ к сеансу для проверки существующей пользовательской информации, а затем ActiveDirectorySearcher и базы данных для восстановления свойств пользователя, если сеанс был пустым.

Моя путаница связана с тем, что самому контроллеру потребуется доступ к ActiveDirectorySearcher в другомметоды действия и другие классы также будут использовать ту же базу данных.Ввести ли IActiveDirSearchrer в конструктор контроллера, а затем передать его в ISomeUserProvider?Что насчет IMyDatabase?Это также вводится в конструктор контроллера и передается вниз?

И последнее, но не аренда, ISessionWrapper?Я знаю, что сессия противоречива, но мне нужно отследить, кто является текущим пользователем и кто им проксируется во время каждого запроса (GET и POST).Итак, это тоже вводится?

Если ответ на каждый из них положительный, то плохо ли иметь 3+ введенных параметра contstuctor?

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

Спасибо.

1 Ответ

3 голосов
/ 10 июня 2011

Я не уверен, что это именно то, что вы ищете, но это должно помочь вам начать путь рефакторинга вашего приложения для DI

public class YourController : Controller
{
    private readonly ISessionWrapper _sessionWrapper;
    private readonly IActiveDirSearcher _adSearcher;
    private readonly IMyDatabase _database;

    public YourController(ISessionWrapper sessionWrapper,
        IActiveDirSearcher adSearcher, IMyDatabase database)
    {
        this._sessionWrapper = sessionWrapper;
        this._adSearcher = adSearcher;
        this._database = database;
    }

    // now all actions in this controller have a _sessionWrapper,
    // _adSearcher and _database
}

Тогда вам придется связать свои инъекцииИнъекционный путь.Подкласс вашего приложения от NinjectHttpApplication и переопределить OnApplicationStarted и CreateKernel

public class MvcApplication : NinjectHttpApplication
{
    // ...

    protected override void OnApplicationStarted()
    {
        base.OnApplicationStarted();

        AreaRegistration.RegisterAllAreas();
        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
    }

    protected override IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        kernel.Bind<ISessionWrapper>().To<YourSessionWrapperImplementation>();
        kernel.Bind<IActiveDirSearcher>().To<YourADImplementation>();
        kernel.Bind<IMyDataBase>().To<YourEDMContainerIThink>();

        return kernel;
    }
}

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

public class MyActiveDirImplementation : IActiveDirSearcher
{
    private readonly IMyDatabase _database;

    // injected automagically WOOHOO!
    public MyActiveDirImplementation(IMyDatabase database)
    {
        this._database = database;
    }

    public ADUserInfo GetUserRecord(string username)
    {
        return _database.GetSomeUserRecord(username);
    }
}

Вы, конечно, можете аналогичным образом реализовать свой ISessionWrapper или IMyDatabase

...