Les Exceptions de démarrage de L'Api Web avec L'implémentation de IDependencyResolver

je développe une Api Web et j'ai décidé d'utiliser custom DependencyResolver. Je me réfère à cet article [injection de dépendances pour les contrôleurs D'API Web] . Tout fonctionne bien jusqu'à présent en termes d'injection de dépendances dans les contrôleurs. Extrait de code de ma configuration de ma classe de démarrage

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

mais à l'époque quand L'Api démarre pour la toute première fois quelques Résolutionfailedexception lancé (mais enclenché) à l'intérieur de la UnityResolver la méthode GetService la méthode. Voici le message d'exception

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

au-dessus de même exception lancée types suivants

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

je sais que ces ResolutionFailedException sont lancées parce que je n'ai pas fourni de mappages dans ma configuration d'unité pour les types ci-dessus.

maintenant voici ma question: - , si j'implémente custom unity DependencyResolver je dois définir les correspondances des types ci-dessus et si besoin de définir quels seront leurs types d'implémentation par défaut correspondants ou y a-t-il une autre façon d'implémenter DependencyResolver. Je suis vraiment préoccupé bien que l'application fonctionne bien maintenant, ne pas résoudre ci-dessus type peut causer des problèmes graves plus tard. s'il vous Plaît aider .

un dernier ajout: - Pour les types suivants, même ResolutionFailedException lancée lorsque je fais une demande d'action dans l'api my web

System.Web.Http.Dispatcher.IHttpControllerActivator
System.Web.Http.Validation.IModelValidatorCache
System.Web.Http.Controllers.IHttpActionInvoker
23
demandé sur Cœur 2014-06-09 10:43:43

7 réponses

je courais vers la même question en utilisant Unity avec WebApi et OWIN/Katana.

la solution pour moi était d'utiliser le UnityDependencyResolver défini dans L'Unité.WebAPI Nuget package au lieu de ma propre implémentation personnalisée (comme @Omar Alani ci-dessus)

Install-Package Unity.WebAPI

notez que le paquet va essayer d'ajouter un fichier nommé UnityConfig.cs dans App_Start (le nom de fichier que j'ai utilisé moi-même) .

In cette UnityConfig.cs fichier le paquet va ajouter du code pour enregistrer le conteneur contre le GlobalConfiguration.Configuration.DependencyResolver qui n'est pas ce que nous voulons avec OWIN.

donc au lieu d'utiliser:

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

changement d'utilisation:

config.DependencyResolver = new UnityDependencyResolver(container);

Pour l'exhaustivité:

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

Ma Start-Up.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);
    }
  }
}
19
répondu James 2018-06-11 10:33:41

au cas où l'une des solutions ci-dessus ne fonctionne toujours pas pour les gens, voici comment je l'ai résolu.

après avoir passé une journée à traquer cette erreur, il s'est avéré être une sorte de VS cache problème. En désespoir de cause, j'ai supprimé tous .suo files et force-get-latest, qui semble avoir résolu le problème.

6
répondu Ben Hughes 2016-07-28 04:49:49

cela a été demandé il y a longtemps, mais j'ai rencontré une solution qui n'a pas été mentionnée ici donc peut-être quelqu'un est toujours intéressé.

dans mon cas, ces exceptions étaient déjà capturées en interne par Unity (ou n'importe quoi d'autre), mais mes réglages D'Exception dans Visual Studio les ont fait apparaître encore. J'ai juste eu à décocher la case "Break when this exception type is shown" et l'application a continué à fonctionner normalement.

4
répondu Munir Husseini 2017-01-25 21:10:01

la mise en œuvre de Unity.WebAPI n'est pas très différente de celle mentionnée dans la question. J'ai aimé la version mentionnée par L'OP car elle ignore seulement ResultionFailedException et laisse le reste se propager dans la pile. Unity.WebAPI supprime toutes les exceptions. Ce que je ferais, c'est ignorer les erreurs dont nous savons qu'elles sont sûres et en enregistrer (ou en réécrire) d'autres.

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
répondu Duoc Tran 2015-08-03 13:02:30

normalement, vous n'avez pas besoin de L'Unité. J'utilise cette implémentation pour IDependencyResolver avec unity, et je n'ai pas besoin de m'enregistrer ou de cartographier autre que mes interfaces/services.

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

où jetable est juste une classe de base met en œuvre IDispoable.

Espère que ça aide.

2
répondu Omar.Alani 2017-11-30 00:16:39

comme cela semble encore être contesté, voici ma version du code...

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

et

[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 /q/web-api-with-owin-throws-objectdisposedexception-for-httpmessageinvoker-22311/"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);
        }
    }
}

La raison pour cela est l'original MVC Élément de Travail où l'on voit

kichalla a écrit le 27 Oct, 2014 à 4:34 PM

Oui...droit...L'extension UseWebApi ne doit être utilisée qu'avec l'auto-hébergement scénarios...puisque nous sommes tous sur le même page, je suis la clôture de cette question que par sa conception...s'il vous plaît laissez-nous savoir si vous avez des plus de questions...

Merci, Kiran

et

kichalla a écrit le 29 octobre, 2014 à 5:28 PM

@thebothead: merci de le découvrir!...droit, cet échantillon Je n'aurais pas dû utiliser Microsoft.AspNet.WebApi.Owin dans IIS comme il n'a jamais été destiné à être utilisé dans l'hôte...nous allons enquêter sur la question plus loin pour voir pourquoi cette exception se produit...mais en attendant, vous pourrait suivre l'approche mentionnée dans l'exemple que j'ai fourni antérieur...

Merci, Kiran

D'après ma propre expérience si vous n'utilisez pas cette forme de code, il fonctionnera dans debug etc mais ne sera pas échelle et commencer à se comporter étrangement.

0
répondu Paul Hatcher 2017-11-29 13:40:14

j'ai supprimé dependencyResolver et ce problème a été résolu

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

        // Your mappings here

        config.DependencyResolver = null;
    }
}
-9
répondu dmitry 2015-08-26 10:21:28