MVC3 - 如何使用MVC3和Ninject正确注入依赖项?

时间:2011-06-10 13:07:03

标签: asp.net-mvc design-patterns asp.net-mvc-3 c#-4.0 ninject-2

我正在尝试使用MVC3中的Ninject依赖注入重新设计现有应用程序。以下是我遇到困难的遗留行为的一部分(是的,我知道它很糟糕,这就是为什么我要重构它):

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类,它还需要访问Session以检查现有用户信息,然后ActiveDirectorySearcher和Database在会话为空时重建用户属性。

我的困惑在于控制器本身需要在其他操作方法中访问ActiveDirectorySearcher,然后其他类也将使用相同的数据库。我是否将IActiveDirSearchrer注入控制器的构造函数,然后将其传递给ISomeUserProvider? IMyDatabase怎么样?它是否也在控制器构造函数中注入并传递下来?

最后但不是租赁,ISessionWrapper?我知道会话是有争议的,但我需要在每个请求(GET和POST)期间跟踪当前用户是谁以及他们代理谁。那么,这也会被注入吗?

如果对每个人的答案都是肯定的,那么有3个注入的contstuctor参数是不是很糟糕?

我意识到我的问题可能含糊不清,所以请在需要时要求澄清。我对所有建议和建议持开放态度。我的目标是学习如何正确地做到这一点。

感谢。

1 个答案:

答案 0 :(得分:3)

我不确定这是否正是您正在寻找的,但这应该让您开始重构您的应用程序以进行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
}

然后你必须以Ninject的方式绑定你的注射。从NinjectHttpApplication对您的申请进行细分,并覆盖OnApplicationStartedCreateKernel

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中的绑定将处理应用程序中其他地方缺少的依赖项。 e.g。

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);
    }
}

您当然可以类似地实施ISessionWrapperIMyDatabase