繁体   English   中英

使用依赖注入(Autofac)并避免服务定位器模式

[英]Using Dependency Injection (Autofac) and avoiding Service Locator pattern

我在尝试使用Autofac在Xamarin Android应用程序中正确实现DI时遇到问题,但是在理解如何处理需要将数据传递到其构造函数的实例化对象方面遇到问题。 例如,我们的一个视图模型需要一个字符串和一个guid传入其构造函数。 看起来很有希望的是Autofac提供的Delegate Functions 至少在我看来,这是服务定位器和DI之间的界限似乎模糊的地方。 为了使用委托函数,必须调用container.Resolve,或者建议使用IComponentContext.Resolve。 许多博客建议不要在引导程序/主入口点之外使用Resolve。 我在这里缺少什么吗? 有没有更好的方法使用DI创建对象? 我对创建对象的Factory模式很熟悉,但是我感觉失去了DI顺其自然的优势,因为我回到了将服务/对象手动传递给新创建的对象的过程中。 感谢您的任何反馈!

建议调用container.Resolve()使用委托工厂。 正确的方法显示在您已经链接到的代表工厂页面上

public class Portfolio
{
  Shareholding.Factory ShareholdingFactory { get; set; }
  IList<Shareholding> _holdings = new List<Shareholding>();

  public Portfolio(Shareholding.Factory shareholdingFactory)
  {
    ShareholdingFactory = shareholdingFactory;
  }

  public void Add(string symbol, uint holding)
  {
    _holdings.Add(ShareholdingFactory(symbol, holding));
  }
}

当文档显示对container.Resolve()的显式调用时,您应该意识到它们没有显示最佳实践,他们只是证明可以解决该问题,而无需编写一个全新的类(例如Portfolio )来使用它。

为了使用委托函数,您必须调用container.Resolve

不,至少在这种情况下不行。

假设您已经注册了Shareholding 现在,您可以询问对Func<Shareholding>的依赖关系,即。 当您调用某件帽子时,它会返回一个Shareholding

但是,由于Shareholding构造函数具有两个参数,因此如果不提供这些参数就无法解析它。 只需将它们添加到这样的声明中即可: Func<string, uint, Shareholding> 现在,您可以在提供这些参数时解决依赖性。

这是一个更好的例子

我最近(昨天)遇到了同样的问题,我使用下面的代码中看到的ServiceClient对象结束了工作。 该对象解决了有关在引导程序之外使用容器的问题。 我读过一些论点,说不要绕过容器,我认为它们基本上是有效的。 但是在我的情况下,ServiceClient类代表了进入我的服务层的单个入口点,因此我认为传递容器是适当的。

我目前使用的方法是将ServiceClient实例传递到我的BaseController中:

// In Global.asax.cs  
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterType<ServiceClient>().As<IServiceClient>();

BaseController:

public abstract class BaseController<T> : Controller where T :class
{

    public IServiceClient ServiceClient { get; set; }

    public BaseController(IServiceClient serviceClient)
    {
        ServiceClient = serviceClient;
    }
}

在我的控制器中,我可以解析,实例化和调用仅使用以下一行使用非托管资源的服务:

myViewModel = await ServiceClient.OfType<ICustomerService>().TryAsync(x => x.GetCustomerByID(id));

ServiceClient:

public class ServiceClient : IServiceClient 
{
    private IComponentContext _container;

    public ServiceClient(IComponentContext container)
    {
        _container = container;
    }

    public ServiceCallWrapper<T> OfType<T>() where T : class, IDisposable
    {
        return new ServiceCallWrapper<T>(_container);
    }
}

public class ServiceCallWrapper<T> : IServiceCallWrapper<T> where T : class, IDisposable
{
    private IComponentContext _container;

    internal ServiceCallWrapper(IComponentContext container)
    {
        _container = container;
    }

    public void Try(Action<T> method) 
    {
        // consider try/catch/log/throw here
        using (T client = _container.Resolve<T>())
        {
            method(client);
        }
    }

    public TResult Try<TResult>(Func<T, TResult> method)
    {
        using (T client = _container.Resolve<T>())
        {
            return method(client);
        }
    }

    public async Task TryAsync(Func<T, Task> method)
    {
        using (T client = _container.Resolve<T>())
        {
            await method(client);
        }
    }

    public async Task<TResult> TryAsync<TResult>(Func<T, Task<TResult>> method) 
    {
        using (T client = _container.Resolve<T>())
        {
            return await method(client);
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM