Je développe une API Web et j'ai décidé d'utiliser un DependencyResolver personnalisé. Je fais référence à this [Injection de dépendance pour les contrôleurs API Web] article. Jusqu'à présent, tout fonctionne bien en termes d'injection de dépendance dans les contrôleurs. Extrait de code de ma configuration de ma classe de démarrage Owin
private void RegisterIoC(HttpConfiguration config)
{
_unityContainer = new UnityContainer();
_unityContainer.RegisterType<IAccountService, AccountService>();
.........
.........
config.DependencyResolver = new UnityResolver(_unityContainer);
}
Mais à l'époque lorsque Api démarre pour la toute première fois} _ une exception ResolutionFailedException levée (mais capturée) dans la méthode UnityResolverGetService. 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 identique exception levée des 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 exceptions ResolutionFailedException sont levé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 l'unité personnalisée DependencyResolver, j'ai besoin de définir les mappages des types ci-dessus et, si besoin, de définir leurs types d'implémentation par défaut OR, existe-t-il une alternative manière de mettre en œuvre DependencyResolver. Je suis vraiment inquiet même si l'application fonctionne bien maintenant, ne pas résoudre le type ci-dessus peut causer un problème sérieux plus tard. _ {Aide s'il vous plaît} _.
Un dernier ajout: - Pour les types suivants, même exception ResolutionFailedException émise lorsque je demande une action dans l'action de mon api Web.
System.Web.Http.Dispatcher.IHttpControllerActivator
System.Web.Http.Validation.IModelValidatorCache
System.Web.Http.Controllers.IHttpActionInvoker
J'utilisais le même problème avec Unity avec WebApi et OWIN/Katana.
La solution pour moi a été d’utiliser le UnityDependencyResolver défini dans le package Unity.WebApi Nuget au lieu de ma propre implémentation personnalisée (comme @Omar Alani ci-dessus).
Install-Package Unity.WebAPI
Notez que le package va essayer d’ajouter un fichier nommé UnityConfig.cs dans App_Start (le nom du fichier que j’ai moi-même utilisé) .
Dans ce fichier UnityConfig.cs, le package ajoutera du code pour enregistrer le conteneur sur le GlobalConfiguration.Configuration.DependencyResolver
, ce qui n'est pas ce que nous souhaitons avec OWIN.
Donc au lieu d'utiliser:
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
Changer pour utiliser:
config.DependencyResolver = new UnityDependencyResolver(container);
Pour être complet:
Mon UnityConfig.cs
public static class UnityConfig
{
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
// Your mappings here
config.DependencyResolver = new UnityDependencyResolver(container);
}
}
Mon 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);
}
}
}
Si l'une des solutions ci-dessus ne fonctionne toujours pas pour les utilisateurs, voici comment j'ai résolu le problème.
Après avoir passé une journée à traquer cette erreur, il s’est avéré qu’il s’agissait d’un problème de mise en cache de VS En désespoir de cause, j'ai supprimé tous les fichiers .suo et force-get-latest, ce qui semble avoir résolu le problème.
Cela a été demandé il y a longtemps, mais j'ai rencontré une solution qui n'était pas mentionnée ici, alors peut-être que quelqu'un est toujours intéressé.
Dans mon cas, ces exceptions étaient déjà interceptées en interne par Unity (ou autre), mais mon Exception Settings dans Visual Studio les faisait toujours apparaître. Il me suffisait de décocher la case "Interrompre l'affichage de ce type d'exception" et l'application fonctionnait normalement.
L'implémentation 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 uniquement 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 que nous savons être sûres et enregistrer les autres (ou les rediffuser).
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;
}
Normalement, vous n'en avez pas besoin avec Unity . J'utilise cette implémentation pour IDependencyResolver avec unicité et je n'ai pas besoin d'enregistrer ni de mapper 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ù Disposable est juste une classe de base implémente IDispoable.
J'espère que cela pourra aider.
Comme cela semble toujours ê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 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
}
}
}
Enfin, bits sont les extensions permettant d’utiliser le conteneur scoped dans le middleware Owin, ainsi que WebAPI direct.
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);
}
}
}
La raison en est l'original Élément de travail MVC où nous voyons
kichalla a écrit sur 27 oct. 2014 à 16h34
Oui ... bien ... L'extension UseWebApi ne doit être utilisée qu'avec scénarios d'auto-hébergement ... puisque nous sommes tous sur la même page, je suis clôturant ce problème comme une construction ... veuillez nous en informer si vous en avez plus de questions...
Merci Kiran
et
kichalla a écrit le 29 octobre 2014 à 17:28
@thebothead: Merci d'avoir découvert cela! ... oui, cet échantillon n'aurait pas dû utiliser Microsoft.AspNet.WebApi.Owin dans IIS en tant que n’a jamais été destiné à être utilisé dans cet hôte ... nous étudierons le question plus loin pour voir pourquoi cette exception se produit ... mais en attendant vous pourrait suivre l’approche mentionnée dans l’échantillon que j’ai fourni plus tôt...
Merci Kiran
D'après ma propre expérience, si vous n'utilisez pas cette forme de code, cela fonctionnera dans le débogage, etc., mais ne sera pas redimensionné et commencera à se comporter étrangement.