我正在使用通用存储库模式来持久化数据。在PageLoad上,我正在从IRepository创建一个新的Repository对象,在PageUnload上,我将其丢弃。

母版页/页面应负责实例化要传递给演示者的对象,还是由演示者来负责?与页面( View )相比,我更关心测试演示者,因为模拟传递给演示者的接口(interface)更容易。

示例页面

public partial class _Default : System.Web.UI.Page
{
    private IRepository _repo;
    protected void Page_Load(object sender, EventArgs e)
    {
        if (_repo == null)
            _repo = new Repository();
        ConnectPresenter();
    }

    private void ConnectPresenter()
    {
        _DefaultPresenter presenter = new _DefaultPresenter(_repo);
    }

    private void Page_Unload(object sender, EventArgs e)
    {
        if (_repo != null)
            _repo.Dispose();
    }
}

在这种情况下,诸如StructureMap或Ninject之类的DI框架会有所帮助吗?它会负责处理这样的对象吗?

最佳答案

Page类和演示者都不必直接处理管理其任何依赖项的构造或生命周期-所有这些都应由您的容器处理。由于构造函数注入(inject)不适用于WebForms,因此您需要将所需的依赖项公开为类的属性。例如,您可以将您的类(class)更改为:

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
    }

    public _DefaultPresenter Presenter { get; set; }
}

该页面不需要对存储库的任何引用,因为它将注入(inject)到演示者中。

此答案的其余部分特定于StructureMap-其他容器的详细信息可能有所不同。

要启用setter注入(inject),您需要告诉StructureMap要填充哪些属性。一种方法是将[SetterProperty]属性应用于属性本身。但是,在您的类(class)中拥有StructureMap详细信息可能会有点侵入。另一种方法是配置StructureMap,以便它知道要注入(inject)的属性类型。例如:
protected void Application_Start(object sender, EventArgs e)
{
    ObjectFactory.Initialize(x =>
    {
        x.Scan(scan =>
        {
            scan.TheCallingAssembly();
            scan.WithDefaultConventions();
        });
        x.ForRequestedType<IRepository>().TheDefaultIsConcreteType<Repository>().CacheBy(InstanceScope.Hybrid);
        x.SetAllProperties(set => set.WithAnyTypeFromNamespaceContainingType<IRepository>());
    });
}

SetAllProperties方法允许您告诉StructureMap如何识别应填充的属性。在这种情况下,我要让StructureMap注入(inject)所有演示者(假设它们都在同一个命名空间中)。

您仍然需要对每个请求执行setter注入(inject)。通过StructureMap,您可以使用BuildUp()方法将依赖项注入(inject)到现有实例中。您可以在每个页面或页面基类的Init或Load事件中执行此操作,但是同样,这会带来侵入性。为了使容器完全不属于页面类,可以使用应用程序的PreRequestHandlerExecute事件(在global.asax或IHttpModule中):
protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
    var application = (HttpApplication)sender;
    var page = application.Context.CurrentHandler as Page;
    if (page == null) return;
    ObjectFactory.BuildUp(page);
}

最后,如果您想显式地处置IRepository,则可以在EndRequest事件中进行处理:
protected void Application_EndRequest(object sender, EventArgs e)
{
    var disposable = ObjectFactory.GetInstance<IRepository>() as IDisposable;
    if (disposable != null) disposable.Dispose();
}

请注意,这是正确的,因为在初始化中我们告诉StructureMap通过Hybrid缓存IRepository,这意味着“为每个HTTP请求(或线程,如果不在网站内运行)给我相同的实例”。当您在EndRequest中检索IRepository时,您会收到在整个请求中使用的同一资源,并且可以对其进行处置。

关于webforms - 使用Webforms和DI对象实例化的MVP模式,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/869199/

10-11 01:35