Autofac、ASP.NET 和 Microsoft.Practices.ServiceLocation
我一直在研究在我的 Web 应用程序中实现 IoC 的细节,但采用的是利用 Microsoft.Practices.ServiceLocation 的方式。我专门使用 Autofac 和 asp.net 集成,但我想让自己对其他容器保持开放。沿着 这个问题,我担心如何访问我的网络应用程序代码中的容器。
我有一个“核心”库,主要定义要解析的接口。我的网络应用程序和其他应用程序也使用这个核心库。定义通用接口非常方便。我认为这是访问 IoC 容器的绝佳位置,并且我使用静态类来做到这一点。诀窍是将容器注入到静态类中。
在 Web 环境中这很棘手,因为每个请求的容器可能不同,而在非 Web 应用程序中它可能始终相同。起初,我尝试使用一种方法直接注入容器,但在下一个 Web 请求中很快就失败了!所以我想出了这个:
public static class IoCContainer
{
public static void SetServiceLocator(Func<IServiceLocator> getLocator)
{
m_GetLocator = getLocator;
}
static private Func<IServiceLocator> m_GetLocator = null;
public static T GetInstance<T>(string typeName)
{
return m_GetLocator().GetInstance<T>(typeName);
}
}
现在在我的 global.asax.cs 中,我这样做:
protected void Application_Start(object sender, EventArgs e)
{
var builder = new Autofac.Builder.ContainerBuilder();
... register stuff ...
var container = builder.Build();
_containerProvider = new Autofac.Integration.Web.ContainerProvider(container);
Xyz.Core.IoCContainer.SetServiceLocator(() =>
new AutofacContrib.CommonServiceLocator.AutofacServiceLocator
(_containerProvider.RequestContainer));
}
public IContainerProvider ContainerProvider
{
get { return _containerProvider; }
}
static IContainerProvider _containerProvider;
解决依赖关系的调用看起来像
var someService = Xyz.Core.GetInstance<ISomeService>();
因此,我不是传递特定的容器,而是传递一个知道如何获取容器的委托。对于非 Web 应用程序,委托可能只返回 builder.Build() 提供的内容。
我向专家提出的问题是,这有意义吗?我有一种简单的方法可以在不知道容器产品是什么或容器本身来自哪里的情况下解决依赖关系。你怎么认为?
I've been working thru the details of implementing IoC in my web apps but in a way that leverages Microsoft.Practices.ServiceLocation. I am specifically using Autofac and the asp.net integration, but I wanted to leave myself open to other containers. Along the lines of this question, i was concerned about how to access the container in my web app code.
I have a 'core' library that primarily defines interfaces to be resolved. This core library is used by my web app and other apps as well. Very handy to have common interfaces defined. I thought this was an excellent place to put access to the IoC container, and I did so with a static class. The trick is injecting the container into the static class.
It's tricky in a web environment becuase the container may be different for each request, while in a non-web app it will probably be the same all the time. At first I tried injecting the container direclty with a method but that quickly failed on the next web request! So I came up with this:
public static class IoCContainer
{
public static void SetServiceLocator(Func<IServiceLocator> getLocator)
{
m_GetLocator = getLocator;
}
static private Func<IServiceLocator> m_GetLocator = null;
public static T GetInstance<T>(string typeName)
{
return m_GetLocator().GetInstance<T>(typeName);
}
}
Now in my global.asax.cs I do this:
protected void Application_Start(object sender, EventArgs e)
{
var builder = new Autofac.Builder.ContainerBuilder();
... register stuff ...
var container = builder.Build();
_containerProvider = new Autofac.Integration.Web.ContainerProvider(container);
Xyz.Core.IoCContainer.SetServiceLocator(() =>
new AutofacContrib.CommonServiceLocator.AutofacServiceLocator
(_containerProvider.RequestContainer));
}
public IContainerProvider ContainerProvider
{
get { return _containerProvider; }
}
static IContainerProvider _containerProvider;
And calls to resolve dependences look like
var someService = Xyz.Core.GetInstance<ISomeService>();
So rather than pass a specific container I pass a delegate that knows how to GET a container. For non-web applications the delegate would probably just return what builder.Build() serves up.
My question to the experts is, does this make sense? I have an easy way to get to something that can resolve dependencies without knowing what the container product is or where the container itself comes from. What do you think?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我们使用类似的模式主要是因为 IoC 被引入到非 DI 架构中。因此需要能够显式调用容器来获取服务,这基本上就是工厂模式。
当所有依赖项都可以注入并且您的代码不再依赖于服务定位器时,IoC 的真正好处就实现了。 Autofac.Integration.Web 具有将执行注入到页面对象中的处理程序,这将使静态服务定位器过时。在我看来,这是首选方式,尽管(在我们的例子中也是如此)服务定位器不能总是避免。
也就是说,由于您已经使用 IoCContainer 类将应用程序与容器隔离,因此我认为没有理由在 IoCContainer 中添加 AutofacServiceLocator 的额外抽象。底线是 IoCContainer 已经是您的服务定位器,并且应该“允许”直接访问容器实现。
这是我对您的服务定位器类的看法:
We use a similar pattern mostly due to the fact that IoC was introduced into a non-DI architecture. Thus the need to be able to explicitly call the container to get services, which basically is the Factory pattern.
The true benefit of IoC is achieved when all dependencies can be injected and your code no longer have a dependency on the service locator. Autofac.Integration.Web have handlers that will perform injection into your page objects which will make the static service locator obsolete. Imo this is the preferred way, though (as in our case also) service locator cannot always be avoided.
That said, since you already have isolated your app from the container using IoCContainer class, I see no reason to have the additional abstraction of AutofacServiceLocator within IoCContainer. Bottom line is that IoCContainer is already your service locator and should be "allowed" direct access to the container implementation.
Here is my take on your service locator class: