Веб-Api Запуск Исключения с IDependencyResolver implimentation

Я разрабатываю Web Api, и я решил использовать пользовательский DependencyResolver. Я ссылаюсь на эту статью [Зависимость для веб-API-контроллеров]. В настоящее время все работает хорошо в терминах внедрения зависимостей в контроллеры. Код фрагмента моей конфигурации из моего класса запуска 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. Я действительно обеспокоен, даже несмотря на то, что приложение работает нормально сейчас, неспособность разрешить вышеуказанный тип может вызвать серьезную проблему позже. Пожалуйста, помогите.

Одно последнее дополнение: - Для следующих типов, такое же ResolutionFailedException, которое вызывается, когда я делаю запрос на любое действие в мой веб-api

System.Web.Http.Dispatcher.IHttpControllerActivator
System.Web.Http.Validation.IModelValidatorCache
System.Web.Http.Controllers.IHttpActionInvoker

Ответы

Ответ 1

Я работал с той же проблемой, используя Unity с WebApi и OWIN/Katana.

Решение для меня состояло в том, чтобы использовать UnityDependencyResolver, определенный в пакете Unity.WebApi Nuget, вместо моей собственной пользовательской реализации (например, @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);

Для полноты:

My UnityConfig.cs

public static class UnityConfig
{
    public static void Register(HttpConfiguration config)
    {
        var container = new UnityContainer();

        // Your mappings here

        config.DependencyResolver = new UnityDependencyResolver(container);
    }
}

My 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);
    }
  }
}

Ответ 2

Если какое-либо из вышеперечисленных решений по-прежнему не работает для людей, вот как я его решил.

Проведя день, преследуя эту ошибку, он оказался своего рода проблемой кэширования VS. Из отчаяния я удалил все файлы .suo и принудительно-последние, что, похоже, решило проблему.

Ответ 3

Это было задано давно, но я столкнулся с решением, которое не упоминалось здесь, поэтому, возможно, кому-то все еще интересно.

В моем случае эти исключения уже были обнаружены внутри Unity (или что-то еще), но мои настройки исключения в Visual Studio сделали их все еще отображаемыми. Мне просто нужно было снять флажок "Перерыв, когда этот тип исключения показан", и приложение нормально функционировало.

Ответ 4

Обычно вам не нужно с 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;
    }
}

где одноразовый - это только базовый класс, реализующий IDispoable.

Надеюсь, что это поможет.

Ответ 5

Реализация 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;
}

Ответ 6

Как кажется, все еще оспаривается, вот моя версия кода...

/// <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
        }
    }
}

Наконец, биты - это расширения для использования контейнера с областью в промежуточном программном обеспечении 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, поскольку он никогда не предназначалось для использования в этом хосте... мы будем исследовать еще раз выясните, почему это исключение происходит... но пока вы может следовать подходу, указанному в образце, который я представил раньше...

Спасибо, Киран

Из моего собственного опыта, если вы не используете эту форму кода, он будет работать в отладке и т.д., но не будет масштабироваться и начнет вести себя странно.

Ответ 7

Я удалил dependencyResolver, и эта проблема была решена.

public static class UnityConfig
{
    public static void Register(HttpConfiguration config)
    {
        var container = new UnityContainer();

        // Your mappings here

        config.DependencyResolver = null;
    }
}