我正在将一个Web应用程序从ASP.NET 3 Preview 1升级到RTM,我对更新的依赖注入方法感到困惑。我正在使用StructureMap,但这与我的问题无关。以前我需要做的就是如下:
x.For<IControllerFactory>().Use<DefaultControllerFactory>();
x.For<IServiceLocator>().Use(MvcServiceLocator.Current);
现在看来我需要提供IControllerActivator,IViewPageActivator和ModelMetadataProvider的实现,因为否则我从StructureMap收到错误,因为MVC尝试使用依赖项解析器来定位它们。从MVC源看,似乎没有公共默认实现。我在设置这些内容时遗漏了什么?当然这些应该按惯例配置吗?
需要配置什么以及如何使用StructureMap的例子。作为参考,我目前使用以下丑陋的kludge迫使MVC使用其内部默认值:
x.For<IControllerFactory>().Use<DefaultControllerFactory>();
x.For<IDependencyResolver>().Use(() => DependencyResolver.Current);
x.For<IControllerActivator>().Use(() => null);
x.For<IViewPageActivator>().Use(() => null);
x.For<ModelMetadataProvider>().Use(ModelMetadataProviders.Current);
编辑:为了清楚我有一个工作的依赖性解析器的StructureMap实现 - 问题是为什么MVC抱怨所有这些接口没有在容器中配置。
答案 0 :(得分:8)
通过创建依赖性解析器(IDependencyResolver)类,然后在global.asax中注册该类,我能够使StructureMap与ASP.NET MVC3一起使用。我还没有完全测试这段代码。但是,它在两个应用程序中一直没有任何问题。
StructureMapDependencyResolver.cs
using System.Linq;
using System.Web.Mvc;
using StructureMap;
namespace SomeNameSpace
{
public class StructureMapDependencyResolver : IDependencyResolver
{
private readonly IContainer container;
public StructureMapDependencyResolver(IContainer container)
{
this.container = container;
}
public object GetService(System.Type serviceType)
{
try
{
return this.container.GetInstance(serviceType);
}
catch
{
return null;
}
}
public System.Collections.Generic.IEnumerable<object> GetServices(System.Type serviceType)
{
return this.container.GetAllInstances<object>()
.Where(s => s.GetType() == serviceType);
}
}
}
的Global.asax.cs
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
DependencyResolver.SetResolver(new StructureMapDependencyResolver(InitContainer()));
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
private static IContainer InitContainer()
{
ObjectFactory.Initialize(x =>
{
x.Scan(y =>
{
y.WithDefaultConventions();
y.AssembliesFromApplicationBaseDirectory();
y.LookForRegistries();
});
});
return ObjectFactory.Container;
}
答案 1 :(得分:4)
我已经想到了这一点,感谢@Michael Carman发表评论他的回答。我不确定这里的礼节是否保证接受他的实际答案,因为它不太正确(我给他+1票)但我想我会发布自己的答案来解释究竟是什么问题是。
问题在于我的IDependencyResolver和我的容器配置的实现。原来我有:
public class StructureMapDependencyResolver : IDependencyResolver
{
public object GetService(Type serviceType)
{
return ObjectFactory.GetInstance(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
foreach (object obj in ObjectFactory.GetAllInstances(serviceType))
{
yield return obj;
}
}
}
但我现在根据与Steve Smith's blog post相关联的Jeremy Miller's blog post更改为此内容:
public class StructureMapDependencyResolver : IDependencyResolver
{
public object GetService(Type serviceType)
{
if (serviceType.IsAbstract || serviceType.IsInterface)
{
return ObjectFactory.TryGetInstance(serviceType);
}
else
{
return ObjectFactory.GetInstance(serviceType);
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
foreach (object obj in ObjectFactory.GetAllInstances(serviceType))
{
yield return obj;
}
}
}
它本身仍然无法解决问题,直到我删除此配置表达式:
x.For<IControllerFactory>().Use<DefaultControllerFactory>();
根据文档,TryGetInstance仅返回向容器注册的类型,如果不存在则返回null。我假设MVC 3代码依赖于这种行为来表明它应该使用它的默认值,因此在我原来的情况下我必须用我的容器注册这些默认值。整蛊一个!
答案 2 :(得分:0)
这适用于MVC和Web API ..
namespace Web.Utilities.DependencyResolvers
{
public class StructureMapResolver : IServiceLocator, IDependencyResolver
{
private readonly IContainer _container;
public StructureMapResolver(IContainer container)
{
if (container == null)
throw new ArgumentNullException("container");
this._container = container;
}
public IDependencyScope BeginScope()
{
return new StructureMapResolver(this._container.GetNestedContainer());
}
public object GetInstance(Type serviceType, string instanceKey)
{
if (string.IsNullOrEmpty(instanceKey))
{
return GetInstance(serviceType);
}
return this._container.GetInstance(serviceType, instanceKey);
}
public T GetInstance<T>()
{
return this._container.GetInstance<T>();
}
public object GetService(Type serviceType)
{
return GetInstance(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return this._container.GetAllInstances(serviceType).Cast<object>();
}
public T GetInstance<T>(string instanceKey)
{
return this._container.GetInstance<T>(instanceKey);
}
public object GetInstance(Type serviceType)
{
return serviceType.IsAbstract || serviceType.IsInterface ?
this._container.TryGetInstance(serviceType) : this._container.GetInstance(serviceType);
}
public IEnumerable<T> GetAllInstances<T>()
{
return this._container.GetAllInstances<T>();
}
public IEnumerable<object> GetAllInstances(Type serviceType)
{
return this._container.GetAllInstances(serviceType).Cast<object>();
}
public void Dispose()
{
this._container.Dispose();
}
}
}