Я прорабатывал детали реализации IoC в своих веб-приложениях, но таким образом, чтобы использовать Microsoft.Practices.ServiceLocation. Я специально использую Autofac и интеграцию asp.net, но я хотел оставить себя открытым для других контейнеров. По строкам этого вопроса меня беспокоило, как получить доступ к контейнеру в коде веб-приложения.
У меня есть «основная» библиотека, которая в первую очередь определяет интерфейсы, которые нужно разрешить. Эта основная библиотека используется моим веб-приложением, а также другими приложениями. Очень удобно определять общие интерфейсы. Я подумал, что это отличное место для доступа к контейнеру IoC, и сделал это со статическим классом. Уловка заключается во внедрении контейнера в статический класс.
В веб-среде это сложно, потому что контейнер может быть разным для каждого запроса, в то время как в не веб-приложении он, вероятно, будет все время одним и тем же. Сначала я попытался ввести контейнер с помощью метода, но при следующем веб-запросе это быстро не удалось! Итак, я придумал это:
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>();
Поэтому вместо того, чтобы передавать конкретный контейнер, я передаю делегату, который знает, как ПОЛУЧИТЬ контейнер. Для не веб-приложений делегат, вероятно, просто вернет то, что обслуживает builder.Build ().
Мой вопрос к экспертам: есть ли в этом смысл? У меня есть простой способ добраться до чего-то, что может разрешать зависимости, не зная, что это за контейнерный продукт или откуда сам контейнер. Что вы думаете?