代码之家  ›  专栏  ›  技术社区  ›  blu

演示者的依赖注入

  •  2
  • blu  · 技术社区  · 15 年前

    我有一个演示者在其构造函数中将服务和视图协定作为参数:

    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的构造函数需要特定的页面,而不是容器创建一个新页面。

    我可以为这个解析向容器提供视图的特定实例(当前页面)吗?这样做有意义吗?还是我应该换一种方式?

    2 回复  |  直到 15 年前
        1
  •  2
  •   Community gkalpak    7 年前

    解决传递我喜欢的调用的方法 数据 在autofac中解析依赖项时使用的参数是 发电厂 .

    (更新: 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);
        }
    }
    
        2
  •  0
  •   Bryan Watts    15 年前

    我确实解决了这个问题,并围绕它构建了一个框架。我用过 Autofac parameters 将现有视图传递给演示者解析调用。

    首先,我定义了一个从autofac派生的自定义分辨率接口:

    public interface IMvpContext : IContext
    {
        T View<T>();
    }
    

    它允许我注册一个解析视图的演示者:

    builder.RegisterPresenter(c => new FooPresenter(
        c.View<IFooView>(),
        c.Resolve<IFooService>()));
    

    使用包装autofac的扩展方法 IContext 在实现 IMvpContext :

    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
    }
    

    解析演示者的调用提供了视图参数:

    public partial class Foo : Page, IFooView
    {
        private readonly FooPresenter presenter;
    
        public Foo()
        {
            this.presenter = IoCResolve<IFooPresenter>(new MvpViewParameter(this));
        }
    }