我有一个Presenter,它将Service和View Contract作为其构造函数中的参数:
public FooPresenter : IFooPresenter {
private IFooView view;
private readonly IFooService service;
public FooPresenter(IFooView view, IFooService service) {
this.view = view;
this.service = service;
}
}我用Autofac解决了我的服务:
private ContainerProvider BuildDependencies() {
var builder = new ContainerBuilder();
builder.Register<FooService>().As<IFooService>().FactoryScoped();
return new ContainerProvider(builder.Build());
}在我的ASPX页面(查看实现)中:
public partial class Foo : Page, IFooView {
private FooPresenter presenter;
public Foo() {
// this is straightforward but not really ideal
// (IoCResolve is a holder for how I hit the container in global.asax)
this.presenter = new FooPresenter(this, IoCResolve<IFooService>());
// I would rather have an interface IFooPresenter so I can do
this.presenter = IoCResolve<IFooPresenter>();
// this allows me to add more services as needed without having to
// come back and manually update this constructor call here
}
}问题是FooPresenter的构造函数期望特定的Page,而不是容器创建新的Page。
我是否可以为容器提供视图的特定实例,即当前页面,仅用于此分辨率?这样做有意义吗,或者我应该用另一种方式来做这件事?
发布于 2009-12-18 15:25:28
在Autofac中解析依赖关系时,传递我喜欢称为数据工厂参数的方法是使用generated 。
(更新:this question讨论了同样的问题,my article展示了如何避免大量的工厂委托)。
您的问题的解决方案如下所示:
首先,声明一个只接受数据参数的工厂委托:
public delegate IFooPresenter FooPresenterFactory(IFooView view);演示者保持不变:
public FooPresenter : IFooPresenter {
private IFooView view;
private readonly IFooService service;
public FooPresenter(IFooView view, IFooService service) {
this.view = view;
this.service = service;
}
}接下来设置Autofac容器:
var builder = new ContainerBuilder();
builder.Register<FooService>().As<IFooService>().FactoryScoped();
builder.Register<FooPresenter>().As<IFooPresenter>().FactoryScoped();
builder.RegisterGeneratedFactory<FooPresenterFactory>();现在,在您的页面中,您可以输入两行代码来解析呈现器,方法是首先获取工厂,然后调用工厂为您进行解析:
public partial class Foo : Page, IFooView {
private FooPresenter presenter;
public Foo() {
var factory = IoCResolve<FooPresenterFactory>();
this.presenter = factory(this);
}
}发布于 2009-12-18 14:20:20
我实际上解决了这个问题,并围绕它构建了一个框架。我使用Autofac parameters将现有视图传递给presenter解析调用。
首先,我定义了一个从Autofac派生的自定义分辨率接口:
public interface IMvpContext : IContext
{
T View<T>();
}这允许我注册一个演示者来解析视图:
builder.RegisterPresenter(c => new FooPresenter(
c.View<IFooView>(),
c.Resolve<IFooService>()));在IMvpContext的实现中使用包装Autofac的IContext的扩展方法
public static IConcreteRegistrar RegisterPresenter<T>(
this ContainerBuilder builder,
Func<IMvpContext, T> creator)
{
return builder
.Register((context, parameters) => creator(new MvpContext(context, parameters)))
.FactoryScoped();
}我定义了一个表示视图参数的参数类型:
public class MvpViewParameter : NamedParameter
{
public static readonly string ParameterName = typeof(MvpViewParameter).AssemblyQualifiedName;
public MvpViewParameter(object view) : base(ParameterName, view)
{}
}它使用自己的程序集限定类型名称作为参数名称。这与合法参数冲突的可能性非常低。
MvpContext将所有标准解析调用传递到基本上下文。对于视图,它使用众所周知的名称解析参数:
public sealed class MvpContext : IMvpContext
{
private IContext _context;
private IEnumerable<Parameter> _resolutionParameters;
public MvpContext(IContext context, IEnumerable<Parameter> resolutionParameters)
{
_context = context;
_resolutionParameters = resolutionParameters;
}
#region IContext
// Pass through all calls to _context
#endregion
#region IMvpContext
public T View<T>()
{
return _resolutionParameters.Named<T>(MvpViewParameter.ParameterName);
}
#endregion
}解析presenter的调用提供了view参数:
public partial class Foo : Page, IFooView
{
private readonly FooPresenter presenter;
public Foo()
{
this.presenter = IoCResolve<IFooPresenter>(new MvpViewParameter(this));
}
}https://stackoverflow.com/questions/1926437
复制相似问题