wake-up-neo.com

Web Api-Start Ausnahmen mit IDependencyResolver-Implementierung

Ich entwickle eine Web-API und habe mich dafür entschieden, benutzerdefinierte DependencyResolver zu verwenden. Ich beziehe mich auf this [Abhängigkeitseinspritzung für Web-API-Controller] article. Bei der Abhängigkeitseinspritzung in Steuerungen funktioniert bisher alles gut. Code-Snippet meiner Konfiguration aus meiner Owin-Startklasse

private void RegisterIoC(HttpConfiguration config)
{
    _unityContainer = new UnityContainer();
    _unityContainer.RegisterType<IAccountService, AccountService>();
    .........
    .........
    config.DependencyResolver = new UnityResolver(_unityContainer);
}

Zum Zeitpunkt wenn Api zum allerersten Mal gestartet wird wurde einige ResolutionFailedException (aber abgefangen) innerhalb der UnityResolver'sGetService - Methode ausgelöst. Hier ist die Ausnahmemeldung

"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?**"

Über Same Ausnahmebedingung wird folgende Art ausgelöst

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

Ich weiß, dass diese ResolutionFailedException ausgelöst wird, weil ich in meiner Unity-Konfiguration keine Zuordnungen für die obigen Typen angegeben habe. 

Hier ist meine Frage: -, Wenn ich benutzerdefinierte Unity DependencyResolver implementiere, muss ich Zuordnungen der oben genannten Typen definieren. Wenn es notwendig ist, die entsprechenden Standard-Implementierungstypen OR zu definieren, gibt es eine Alternative Weg zur Implementierung von DependencyResolver. Ich bin wirklich besorgt, auch wenn die Anwendung jetzt einwandfrei läuft. Wenn Sie den obigen Typ nicht lösen, kann dies später zu ernsthaften Problemen führen. Bitte helfen Sie.

One final Addition: - Bei folgenden Typen wird dieselbe ResolutionFailedException ausgelöst, wenn ich eine Aktion in meiner Web-API angefordert habe

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

Ich hatte das gleiche Problem mit Unity mit WebApi und OWIN/Katana.

Die Lösung für mich war, den im Unity.WebApi Nuget-Paket definierten UnityDependencyResolver anstelle meiner eigenen benutzerdefinierten Implementierung zu verwenden (wie oben bei @Omar Alani).

Install-Package Unity.WebAPI

Beachten Sie, dass das Paket versucht, eine Datei mit dem Namen UnityConfig.cs in App_Start (den Dateinamen, den ich selbst verwendet habe) hinzuzufügen

In dieser UnityConfig.cs-Datei fügt das Paket Code hinzu, um den Container anhand von GlobalConfiguration.Configuration.DependencyResolver zu registrieren. Dies ist nicht das, was wir mit OWIN wollen. 

Also anstatt zu verwenden:

GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);

Ändern Sie zu verwenden:

config.DependencyResolver = new UnityDependencyResolver(container);

Zur Vollständigkeit:

Meine UnityConfig.cs

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

        // Your mappings here

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

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

Falls eine der oben genannten Lösungen für Menschen immer noch nicht funktioniert, habe ich sie hier gelöst.

Nachdem er diesen Fehler einen Tag lang gejagt hatte, stellte sich heraus, dass dies eine Art VS-Caching-Problem war. Aus Verzweiflung habe ich alle .suo-Dateien und force-get-latest gelöscht, was das Problem scheinbar gelöst hat.

6
Ben Hughes

Dies wurde vor langer Zeit gefragt, aber ich bin auf eine Lösung gestoßen, die hier nicht erwähnt wurde. Vielleicht ist also noch jemand interessiert.

In meinem Fall wurden diese Ausnahmen bereits von Unity (oder was auch immer) intern erfasst, aber meine Ausnahme-Einstellungen in Visual Studio ließen sie immer noch erscheinen. Ich musste nur das Kontrollkästchen "Unterbrechen, wenn dieser Ausnahmetyp angezeigt wird" deaktivieren und die Anwendung funktionierte normal.

4
Munir Husseini

Die Implementierung von Unity.WebAPI unterscheidet sich nicht sehr von der in der Frage genannten. Ich mochte die Version, auf die sich das OP bezieht, da es nur ResultionFailedException ignoriert und den Rest auf den Stack ausbreitet. Unity.WebAPI unterdrückt alle Ausnahmen. Was ich tun würde, ist, Fehler zu ignorieren, von denen wir wissen, dass sie sicher sind, und andere protokollieren (oder erneut starten).

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

Normalerweise brauchen Sie nicht mit Unity zu arbeiten ... Ich benutze diese Implementierung für IDependencyResolver mit Unity, und ich muss keine anderen Schnittstellen oder Services registrieren oder zuordnen.

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

wo Disposable nur eine Basisklasse ist, implementiert IDispoable.

Hoffentlich hilft das.

2
Omar.Alani

Da dies immer noch umstritten zu sein scheint, hier meine Version des Codes ...

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

und 

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

Zu den Bits gehören schließlich die Erweiterungen für die Verwendung des Bereichscontainers in der Owin-Middleware sowie für die direkte 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);
        }
    }
}

Der Grund dafür ist das Original MVC Work Item wo wir sehen

kichalla schrieb am 27. Oktober 2014 um 17:34 Uhr

Ja ... richtig ... Die UseWebApi-Erweiterung sollte nur mit .__ verwendet werden. Self-Hosting-Szenarien ... da wir uns alle auf derselben Seite befinden, bin ich Schließen Sie diese Ausgabe als Nebenprodukt ab ... bitte teilen Sie uns mit, falls Sie irgendwelche haben mehr Fragen...

Danke, Kiran

und 

kichalla schrieb am 29. Oktober 2014 um 18:28 Uhr

@thebothead: Danke, dass du das herausgefunden hast! ... richtig, dieses Beispiel sollte nicht Microsoft.AspNet.WebApi.Owin in IIS als .__ verwendet haben. war nie dazu gedacht, in diesem Host verwendet zu werden ... wir werden die .__ untersuchen. Frage weiter, um zu sehen, warum diese Ausnahme auftritt ... aber in der Zwischenzeit Sie. könnte dem Ansatz folgen, der in dem von mir angegebenen Beispiel angegeben ist vorhin...

Danke, Kiran

Wenn Sie diese Form des Codes nicht verwenden, funktioniert sie aus eigener Erfahrung in Debug usw., wird jedoch nicht skaliert und verhält sich nicht merkwürdig.

0
Paul Hatcher