web-dev-qa-db-ja.com

IDependencyResolver実装を使用したWeb API起動例外

Web Apiを開発しているので、カスタムDependencyResolverを使用することにしました。 この[Web 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?**"

上記のsame例外は次のタイプでスローされます

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を実装する場合、上記のタイプのマッピングを定義する必要があり、対応するものを定義する必要がある場合デフォルトの実装タイプOR DependencyResolverを実装するいくつかの代替方法があります。アプリケーションは現在正常に実行されていますが、上記のタイプを解決しないと、深刻な問題を引き起こす可能性があります。助けてください

最後の1つの追加:-次のタイプでは、Web APIに何らかのアクションを要求すると同じResolutionFailedExceptionがスローされます

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

WebApiとOWIN/KatanaでUnityを使用して同じ問題に遭遇しました。

私にとっての解決策は、独自のカスタム実装(上記の@Omar Alaniなど)ではなく、Unity.WebApi Nugetパッケージで定義されたUnityDependencyResolverを使用することでした

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);
    }
  }
}
21
James

上記のソリューションのいずれかがまだ人々のために機能しない場合は、ここで私はそれを解決した方法です。

このエラーを追いかけて一日を費やした後、それは何らかのVSキャッシュの問題であることが判明しました。必死になって、すべての.suoファイルとforce-get-latestを削除し、問題を解決したようです。

6
Ben Hughes

これはかなり前に尋ねられましたが、ここで言及されていない解決策に遭遇したので、誰かがまだ興味を持っているかもしれません。

私の場合、これらの例外は既にUnity(または何でも)によって内部的にキャッチされていましたが、Visual Studioの例外設定がまだ表示されていました。 [この例外の種類が表示されたらブレークする]チェックボックスをオフにするだけで、アプリケーションは正常に機能し続けました。

5
Munir Husseini

Unity.WebAPIの実装は、質問で言及された実装とそれほど変わりません。 OPがResultionFailedExceptionのみを無視し、残りをスタックまで伝播できるため、OPが参照するバージョンが好きでした。 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;
}
3
Duoc Tran

通常、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を実装する基本クラスにすぎません。

お役に立てば幸いです。

2
Omar.Alani

これはまだ議論されているようですので、ここにコードの私のバージョンがあります...

/// <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 Work Item である

kichallaは2014年10月27日午後4時34分に書いた

はい...右... UseWebApi拡張機能はセルフホスティングのシナリオでのみ使用する必要があります...私たちはすべて同じページにいるので、この問題を設計どおりに終了しています...お持ちの場合はお知らせください他に質問は...

ありがとう、キラン

そして

kichallaは2014年10月29日午後5時28分に書いた

@thebothead:これを見つけてくれてありがとう!...右、このサンプルはMicrosoft.AspNet.WebApi.OwinをIISで使用することを意図していなかったため、ホスト...この問題をさらに調査して、この例外が発生する理由を確認します...しかし、以前に提供したサンプルで言及されているアプローチに従うことができます...

ありがとう、キラン

私自身の経験から、この形式のコードを使用しない場合、デバッグなどで機能しますが、スケーリングせず、奇妙な動作を開始します。

0
Paul Hatcher