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

时间:2016-04-14 17:14:40

标签: c# dependency-injection autofac service-locator

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

3 个答案:

答案 0 :(得分:3)

建议调用<div class="teams-body" id="teams-body"> <div class="faces"> <img src="http://assets.lolesports.com/player/lourlo-iatd1lge.png"> Lorem ipsumdolor sit amet consectetur adipiscing elit </div> <div class="faces"> <img src="http://assets.lolesports.com/player/iwdominate-4kjr1rn6.png"> Lorem ipsumdolor sit amet consectetur adipiscing elit </div> <div class="faces"> <img src="http://assets.lolesports.com/player/fenix-6cyhqz7w.png"> Lorem ipsumdolor sit amet consectetur adipiscing elit </div> </div>来使用委托工厂。 the delegate factories page that you already linked to上显示了正确的方法:

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() )消费它。

答案 1 :(得分:0)

  

要使用委托功能,您必须调用container.Resolve

不,至少在这种情况下不是这样。

假设您已注册Shareholding。现在你可以询问对Func<Shareholding>的依赖,即。当你调用它时,hat会返回Shareholding

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

这是better example

答案 2 :(得分:0)

我最近(昨天)面临同样的问题,我使用您在下面的代码中看到的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);
        }
    }
}