我正在开发Web Api,我决定使用自定义DependencyResolver。我引用this [Dependency Injection for Web API Controllers]文章。到目前为止,依赖注入控制器的所有方面都运行良好。我的Owin启动类
的配置代码片段private void RegisterIoC(HttpConfiguration config)
{
_unityContainer = new UnityContainer();
_unityContainer.RegisterType<IAccountService, AccountService>();
.........
.........
config.DependencyResolver = new UnityResolver(_unityContainer);
}
但当时当Api首次启动时某些ResolutionFailedException在 UnityResolver 内抛出(但已捕获) GetService 方法。这是异常消息
"Exception occurred while: while resolving.
Exception is: InvalidOperationException -
The current type, System.Web.Http.Hosting.IHostBufferPolicySelector,
**is an interface and cannot be constructed. Are you missing a type mapping?**"
以下类型
引发的相同异常System.Web.Http.Hosting.IHostBufferPolicySelector
System.Web.Http.Tracing.ITraceWriter
System.Web.Http.Metadata.ModelMetadataProvider
System.Web.Http.Tracing.ITraceManager
System.Web.Http.Dispatcher.IHttpControllerSelector
System.Web.Http.Dispatcher.IAssembliesResolver
System.Web.Http.Dispatcher.IHttpControllerTypeResolver
System.Web.Http.Controllers.IHttpActionSelector
System.Web.Http.Controllers.IActionValueBinder
System.Web.Http.Validation.IBodyModelValidator
System.Net.Http.Formatting.IContentNegotiator
我知道抛出这些ResolutionFailedException是因为我没有在上面的类型的单位配置中提供映射。
现在这里是我的问题: - ,如果我实现了自定义统一DependencyResolver我需要定义上述类型的映射,如果需要定义它们对应的默认实现类型,还是有一些替代方法实现DependencyResolver的方法。即使应用程序运行正常,我真的很担心,未能解决上述类型可能会导致严重问题。 请帮助。
最后一个补充: - 对于以下类型,当我向web api请求任何操作时抛出相同的ResolutionFailedException
System.Web.Http.Dispatcher.IHttpControllerActivator
System.Web.Http.Validation.IModelValidatorCache
System.Web.Http.Controllers.IHttpActionInvoker
答案 0 :(得分:21)
我使用Unity与WebApi和OWIN / Katana一起讨论同样的问题。
我的解决方案是使用Unity.WebApi Nuget包中定义的UnityDependencyResolver而不是我自己的自定义实现(如上面的@Omar Alani)
Install-Package Unity.WebAPI
请注意,程序包将尝试在App_Start中添加名为UnityConfig.cs的文件(我自己使用的文件名)。
在UnityConfig.cs文件中,包将添加代码以针对GlobalConfiguration.Configuration.DependencyResolver
注册容器,这不是我们想要的OWIN。
所以不要使用:
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
更改使用:
config.DependencyResolver = new UnityDependencyResolver(container);
为了完整性:
我的UnityConfig.cs
public static class UnityConfig
{
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
// Your mappings here
config.DependencyResolver = new UnityDependencyResolver(container);
}
}
我的Startup.cs
[assembly: OwinStartup(typeof(UnityTest.BusinessLayer.Api.ApiStartup))]
namespace UnityTest.BusinessLayer.Api
{
public partial class ApiStartup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
HttpConfiguration httpConfig = new HttpConfiguration();
UnityConfig.Register(httpConfig);
ConfigureAuth(app); //In App_Start ->Startup.Auth
WebApiConfig.Register(httpConfig);
app.UseWebApi(httpConfig);
}
}
}
答案 1 :(得分:6)
如果上述任何一种解决方案仍无法为人们所用,我就是这样解决的。
花了一天时间追逐这个错误,结果证明是某种VS缓存问题。出于绝望,我删除了所有.suo文件和force-get-latest,这似乎解决了这个问题。
答案 2 :(得分:4)
很久以前就问过了,但我遇到了一个没有在这里提到的解决方案,所以也许有人仍然感兴趣。
在我的情况下,Unity(或其他)已经在内部捕获了这些异常,但Visual Studio中的异常设置使它们仍然显示出来。我只需取消选中“显示此异常类型时中断”复选框,应用程序继续正常运行。
答案 3 :(得分:3)
Unity.WebAPI
的实施与问题中提到的实施没有太大差别。我喜欢OP引用的版本,因为它只忽略ResultionFailedException
并让其余的传播到堆栈中。 Unity.WebAPI
会抑制所有异常。我要做的就是忽略我们知道可以安全执行的错误并记录(或重新抛出)其他错误。
public object GetService(Type serviceType)
{
try
{
return container.Resolve(serviceType);
}
catch(ResolutionFailedException ex)
{
if (!(typeof(System.Web.Http.Tracing.ITraceWriter).IsAssignableFrom(serviceType))
|| typeof(System.Web.Http.Metadata.ModelMetadataProvider).IsAssignableFrom(serviceType)
//...
))
{
// log error
}
}
return null;
}
答案 4 :(得分:2)
通常情况下,您不需要使用Unity。 我将此实现用于IDependencyResolver,并且我不需要注册或映射除我的接口/服务之外的其他内容。
public class UnityDependencyInjectionResolver : Disposable, IDependencyResolver
{
protected IUnityContainer Container;
public UnityDependencyInjectionResolver(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
Container = container;
}
public object GetService(Type serviceType)
{
try
{
return Container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
public T GetService<T>()
{
try
{
var serviceType = typeof(T);
return (T)Container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return default(T);
}
}
public T GetService<T>(string name)
{
try
{
var serviceType = typeof (T);
return (T) Container.Resolve(serviceType, name);
}
catch (ResolutionFailedException)
{
return default(T);
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return Container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
public IDependencyScope BeginScope()
{
var child = Container.CreateChildContainer();
return new UnityDependencyInjectionResolver(child);
}
protected override void DisposeManagedResources()
{
if (Container == null)
{
return;
}
Container.Dispose();
Container = null;
}
}
其中Disposable只是一个实现IDispoable的基类。
希望有所帮助。
答案 5 :(得分:0)
由于这似乎仍有争议,这是我的代码版本......
/// <summary>
/// Specifies the Unity configuration for the main container.
/// </summary>
public class UnityConfig
{
private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
/// <summary>
/// Gets the configured Unity container.
/// </summary>
public static IUnityContainer GetConfiguredContainer()
{
return container.Value;
}
public static void RegisterTypes(IUnityContainer container)
{
// Keeping this separate allows easier unit testing
// Your type mappings here
}
}
和
[assembly: OwinStartup(typeof(UnityTest.BusinessLayer.Api.ApiStartup))]
namespace UnityTest.BusinessLayer.Api
{
public static HttpConfiguration Config { get; private set; }
public partial class ApiStartup
{
public void Configuration(IAppBuilder app)
{
// IoC
var container = UnityConfig.GetConfiguredContainer();
var resolver = new UnityHierarchicalDependencyResolver(container); // Gets us scoped resolution
app.UseDependencyResolverScope(resolver); // And for the OWIN
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
// NB Must be before WebApiConfig.Register
ConfigureAuth(app); //In App_Start ->Startup.Auth
// See http://stackoverflow.com/questions/33402654/web-api-with-owin-throws-objectdisposedexception-for-httpmessageinvoker
// and http://aspnetwebstack.codeplex.com/workitem/2091
#if SELFHOST
// WebAPI configuration
Config = new HttpConfiguration
{
DependencyResolver = resolver
};
WebApiConfig.Register(Config);
app.UseWebApi(Config);
#else
GlobalConfiguration.Configuration.DependencyResolver = resolver;
// http://stackoverflow.com/questions/19907226/asp-net-webapi-2-attribute-routing-not-working
// Needs to be before RouteConfig.RegisterRoutes(RouteTable.Routes);
GlobalConfiguration.Configure(WebApiConfig.Register);
Config = GlobalConfiguration.Configuration;
#endif
// Now do MVC configuration if appropriate
}
}
}
最后,bit是在Owin中间件和直接WebAPI中使用作用域容器的扩展
public static class AppBuilderExtensions
{
public static IAppBuilder UseDependencyResolverScope(this IAppBuilder app, IDependencyResolver resolver)
{
return app.Use<DependencyResolverScopeMiddleware>(resolver);
}
}
/// <summary>
/// Wraps middleware in a <see cref="IDependencyResolver"/> scope.
/// </summary>
public class DependencyResolverScopeMiddleware : OwinMiddleware
{
private readonly IDependencyResolver resolver;
public DependencyResolverScopeMiddleware(OwinMiddleware next, IDependencyResolver resolver) : base(next)
{
this.resolver = resolver;
}
public override async Task Invoke(IOwinContext context)
{
using (var scope = resolver.BeginScope())
{
context.SetDependencyScope(scope);
await Next.Invoke(context);
}
}
}
这个理由是我们看到的原始MVC Work Item
kichalla于2014年10月27日下午4:34写道
是......正确... UseWebApi扩展名只能用于 自托管场景...因为我们都在同一页面,我是 以设计方式结束这个问题...如果您有任何问题,请告诉我们 更多问题......
谢谢,Kiran
和
kichalla于2014年10月29日下午5:28写道
@thebothead:谢谢你找到了这个!...对,这个样本 不应该在IIS中使用Microsoft.AspNet.WebApi.Owin 从来没有打算用在那个东道主...我们将调查 进一步问题,看看为什么会发生这种异常...但同时你 可以按照我提供的样本中提到的方法进行操作 较早...
谢谢,Kiran
根据我自己的经验,如果你不使用这种形式的代码,它将在调试等工作但不会扩展并开始表现奇怪。