1

在我的 MVC 项目中,我有很多控制器,它们都有一个共同点。它们都有一个 currentUser 属性和一个 currentSettings 属性。我已经使用 DI 做到了这一点,如下所示:

[Authorize]
public class _UsersController : Controller
{

    #region Fields

    private readonly ProfileService service;
    private readonly Profile currentUser;
    private readonly Settings currentSettings;

    #endregion

    #region Constructors

    public _UsersController()
    {
        var companyWrapper = new CompanyWrapper();
        var profileWrapper = new ProfileWrapper();
        var settingsWrapper = new SettingsWrapper();

        var companyId = companyWrapper.CurrentCompanyId();

        service = new ProfileService(companyId);
        currentUser = profileWrapper.CurrentUser();
        currentSettings = settingsWrapper.CurrentSiteSettings();
    }

    #endregion

}

有没有更好的方法让 currentUser 和 current 设置保持不变?我认为这样做的一种方法是将它放在自定义 AtributeFilter 类中并将当前用户/设置存储在会话中。我只想得到一个简洁的设计模式来满足我的需求。

4

2 回答 2

2

您可以轻松地为您的项目创建一个基本控制器类:

public abstract class ProjectBaseController : Controller
{

    #region Fields

    protected readonly ProfileService service;
    protected readonly Profile currentUser;
    protected readonly Settings currentSettings;

    #endregion

    #region Constructor

    public ProjectBaseController()
    {
        var companyWrapper = new CompanyWrapper();
        var profileWrapper = new ProfileWrapper();
        var settingsWrapper = new SettingsWrapper();

        var companyId = companyWrapper.CurrentCompanyId();

        service = new ProfileService(companyId);
        currentUser = profileWrapper.CurrentUser();
        currentSettings = settingsWrapper.CurrentSiteSettings();
    }

    #endregion

}

然后只记得让你继承的类调用基本构造函数:

public class _UserController : ProjectBaseController
{
    _UserController() : base()
    {
        // _UserConroller Specific initalization here...
    }
}
于 2013-08-28T17:46:38.987 回答
0

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

创建代码现在开始看起来像这样(CompanyWrapperProfileService现在隐藏在Profile类中:

var profileWrapper = new ProfileWrapper();
var settingsWrapper = new SettingsWrapper();

var currentUser = profileWrapper.CurrentUser();
var currentSettings = settingsWrapper.CurrentSiteSettings();

new _UsersController(currentUser, currentSettings);

第 4 步:开始使用依赖注入容器:

创建一个自定义控制器工厂只是解决了问题,这个类很快就会成为维护的噩梦。因此,您可以使用依赖注入框架,而不是编写自己的控制器。

由于我非常习惯于使用Simple Injector,我将展示这个框架,但请注意还有很多其他框架(AutofacCastle WindsorStructureMapNinject)可以做同样的事情。

我们可以执行以下操作,而不是编写自定义控制器工厂:

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 包。

因为我们在容器中注册了ProfileSettings类,所以它能够_UsersController代表我们创建

很好的是,您只需注册一次Profileand Settings,DI 框架会将这些类型注入依赖于这些服务的所有控制器(以及系统中的所有其他类)中。

第 5 步:为您的注册应用适当的生活方式。

由于当前用户在单个 Web 请求期间不会更改,因此创建一个新用户并一遍又一遍地ProfileWrapper调用是很不方便的。CurrentUser()该用户对象可以在该请求期间被缓存。另一方面,当前站点设置可能在应用程序的整个生命周期内都不会改变,因此重新创建SettingsWrapper和调用CurrentSiteSettings只是愚蠢的。

我们应该做的是应用这些对象的适当缓存。这可以按如下方式完成:

container.RegisterPerWebRequest<Profile>(() => new ProfileWrapper().CurrentUser());
container.RegisterSingle<Settings>(() => new SettingsWrapper().CurrentSiteSettings());

在这里,我们将调用从 更改RegisterRegisterPerWebRequestRegisterSingle。该框架将为我们完成其余的工作。

哟嗬。听说你喜欢图案,所以我在你的图案里放了一个图案,让你一边抽象一边抽象。

在此处输入图像描述

于 2013-08-29T08:22:34.083 回答