第 1 步:停止使用区域。说真的,不要使用它们。
第 2 步:开始使用依赖注入模式:
[Authorize]
public class _UsersController : Controller
{
private readonly ProfileService service;
private readonly Profile currentUser;
private readonly Settings currentSettings;
public _UsersController(ProfileService service, Profile currentUser,
Settings currentSettings)
{
this.service = service;
this.currentUser = currentUser;
this.currentSettings = currentSettings;
}
}
_UsersController
我们通过将类型实际需要的所有依赖项传入(注入)到构造函数中来简化。这些包装类对 是隐藏的_UsersController
,因为它不应该关心这一点。
创建_UsersController
遗嘱现在如下所示:
var companyWrapper = new CompanyWrapper();
var profileWrapper = new ProfileWrapper();
var settingsWrapper = new SettingsWrapper();
var companyId = companyWrapper.CurrentCompanyId();
var service = new ProfileService(companyId);
var currentUser = profileWrapper.CurrentUser();
var currentSettings = settingsWrapper.CurrentSiteSettings();
new _UsersController(service, currentUser, currentSettings);
您必须将此代码放在自定义控制器工厂中:
public class MyControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(
RequestContext requestContext, Type controllerType)
{
if (controllerType == typeof(_UsersController))
{
// Create controller here
new _UsersController(service, currentUser, currentSettings);
}
return base.GetControllerInstance(requestContext, controllerType);
}
}
并在启动期间在 MVC 中注册:
protected void Application_Start()
{
ControllerBuilder.Current.SetControllerFactory(typeof(MyControllerFactory));
}
第三步:分组相关服务。
公司和用户信息似乎高度相关。例如,当前公司可能始终是当前用户的公司。可能有多家公司的用户同时使用该网站。站点信息可能不太相关,并且可能包含在部署时固定的信息。根据具体情况,对这些类进行分组可能会更好,例如,将公司信息作为属性放在Profile
类下:
[Authorize]
public class _UsersController : Controller
{
private readonly Profile currentUser;
private readonly Settings currentSettings;
public _UsersController(Profile currentUser, Settings currentSettings)
{
this.currentUser = currentUser;
this.currentSettings = currentSettings;
}
}
创建代码现在开始看起来像这样(CompanyWrapper
和ProfileService
现在隐藏在Profile
类中:
var profileWrapper = new ProfileWrapper();
var settingsWrapper = new SettingsWrapper();
var currentUser = profileWrapper.CurrentUser();
var currentSettings = settingsWrapper.CurrentSiteSettings();
new _UsersController(currentUser, currentSettings);
第 4 步:开始使用依赖注入容器:
创建一个自定义控制器工厂只是解决了问题,这个类很快就会成为维护的噩梦。因此,您可以使用依赖注入框架,而不是编写自己的控制器。
由于我非常习惯于使用Simple Injector,我将展示这个框架,但请注意还有很多其他框架(Autofac、Castle Windsor、StructureMap、Ninject)可以做同样的事情。
我们可以执行以下操作,而不是编写自定义控制器工厂:
protected void Application_Start()
{
var container = new Container();
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.Register<Profile>(() => new ProfileWrapper().CurrentUser());
container.Register<Settings>(() => new SettingsWrapper().CurrentSiteSettings());
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}
这利用了SimpleInjector.MVC3 NuGet 包。
因为我们在容器中注册了Profile
和Settings
类,所以它能够_UsersController
代表我们创建
很好的是,您只需注册一次Profile
and Settings
,DI 框架会将这些类型注入依赖于这些服务的所有控制器(以及系统中的所有其他类)中。
第 5 步:为您的注册应用适当的生活方式。
由于当前用户在单个 Web 请求期间不会更改,因此创建一个新用户并一遍又一遍地ProfileWrapper
调用是很不方便的。CurrentUser()
该用户对象可以在该请求期间被缓存。另一方面,当前站点设置可能在应用程序的整个生命周期内都不会改变,因此重新创建SettingsWrapper
和调用CurrentSiteSettings
只是愚蠢的。
我们应该做的是应用这些对象的适当缓存。这可以按如下方式完成:
container.RegisterPerWebRequest<Profile>(() => new ProfileWrapper().CurrentUser());
container.RegisterSingle<Settings>(() => new SettingsWrapper().CurrentSiteSettings());
在这里,我们将调用从 更改Register
为RegisterPerWebRequest
和RegisterSingle
。该框架将为我们完成其余的工作。
哟嗬。听说你喜欢图案,所以我在你的图案里放了一个图案,让你一边抽象一边抽象。