Исключения при запуске Web Api с реализацией IDependencyResolver
Я разрабатываю веб-интерфейс и решил использовать пользовательский DependencyResolver. Я ссылаюсь на эту статью [Внедрение зависимостей для контроллеров веб-API]. Пока все работает хорошо с точки зрения внедрения зависимостей в контроллеры. Фрагмент кода моей конфигурации из моего класса запуска Owin
private void RegisterIoC(HttpConfiguration config)
{
_unityContainer = new UnityContainer();
_unityContainer.RegisterType<IAccountService, AccountService>();
.........
.........
config.DependencyResolver = new UnityResolver(_unityContainer);
}
Но в то время, когда Api запускается в первый раз , возникает некоторое разрешение ResolutionFailedException (но перехватывается) внутри метода GetService UnityResolver. Вот сообщение об исключении
"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 выбрасываются, потому что я не предоставил сопоставления в конфигурации Unity для вышеуказанных типов.
Теперь вот мой вопрос:- Если я реализую пользовательское единство DependencyResolver, мне нужно определить сопоставления вышеуказанных типов и, если нужно, определить, какие будут соответствующие им типы реализации по умолчанию ИЛИ есть какой-то альтернативный способ реализации DependencyResolver. Я действительно обеспокоен тем, что, несмотря на то, что приложение теперь работает нормально, невозможность решить вышеупомянутый тип может вызвать серьезную проблему позже. Пожалуйста, помогите.
Одно последнее дополнение:- Для следующих типов, то же исключение ResolutionFailedException выдается, когда я делаю запрос на любое действие в мой веб-API
System.Web.Http.Dispatcher.IHttpControllerActivator
System.Web.Http.Validation.IModelValidatorCache
System.Web.Http.Controllers.IHttpActionInvoker
7 ответов
Я столкнулся с той же проблемой, используя Unity с WebApi и OWIN/Katana.
Решением для меня было использование UnityDependencyResolver, определенного в пакете Nuget Unity.WebApi, вместо моей собственной пользовательской реализации (как @Omar Alani выше)
Install-Package Unity.WebAPI
Обратите внимание, что пакет попытается добавить файл с именем UnityConfig.cs в App_Start (имя файла, которое я использовал сам).
В этот файл 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);
}
}
}
Если какое-либо из вышеперечисленных решений все еще не работает для людей, вот как я это решил.
Потратив целый день на поиски этой ошибки, она оказалась проблемой кеширования VS. В отчаянии я удалил все файлы.suo и force-get-latest, что, похоже, решило проблему.
Это было задано давно, но я столкнулся с решением, которое здесь не упоминалось, так что, возможно, кто-то все еще заинтересован.
В моем случае эти исключения уже были перехвачены внутри Unity (или чем-то еще), но мои настройки исключений в Visual Studio заставили их все еще появляться. Мне просто пришлось снять флажок "Перерыв, когда отображается этот тип исключения", и приложение продолжало нормально функционировать.
Реализация Unity.WebAPI
не сильно отличается от упомянутого в вопросе. Мне понравилась версия, на которую ссылается ОП, поскольку она игнорирует только 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;
}
Обычно вам не нужно с 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.
Надеюсь, это поможет.
Поскольку это, кажется, все еще оспаривается, вот моя версия кода...
/// <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://stackru.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://stackru.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
}
}
}
Наконец, биты являются расширениями для использования контейнера с областью действия в промежуточном программном обеспечении 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, в котором мы видим
kichalla написал 27 октября 2014 в 16:34
Да... правильно... Расширение UseWebApi следует использовать только в сценариях с самостоятельным размещением... так как мы все на одной странице, я закрываю этот вопрос как зарисовку... пожалуйста, дайте нам знать, если у вас есть еще есть вопросы...
Спасибо, Киран
а также
kichalla написал 29 октября 2014 в 17:28
@thebothead: Спасибо, что узнали об этом!... верно, этот образец не должен был использовать Microsoft.AspNet.WebApi.Owin в IIS, поскольку он никогда не предназначался для использования на этом хосте... мы рассмотрим проблему далее, чтобы понять, почему происходит это исключение... но тем временем вы могли бы следовать подходу, упомянутому в примере, который я предоставил ранее...
Спасибо, Киран
Из моего собственного опыта, если вы не используете эту форму кода, он будет работать в режиме отладки и т. Д., Но не будет масштабироваться и вести себя странно.
Я удалил зависимость Resolver и эта проблема была решена
public static class UnityConfig
{
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
// Your mappings here
config.DependencyResolver = null;
}
}