我正在尝试使用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参数是不是很糟糕?
我意识到我的问题可能含糊不清,所以请在需要时要求澄清。我对所有建议和建议持开放态度。我的目标是学习如何正确地做到这一点。
感谢。
答案 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
对您的申请进行细分,并覆盖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
中的绑定将处理应用程序中其他地方缺少的依赖项。 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);
}
}
您当然可以类似地实施ISessionWrapper
或IMyDatabase