dependency-injection - net - mvc inject service into controller
Web Api Iniciar excepciones con implementación de IDependencyResolver (7)
Estoy desarrollando una Web Api y decidí usar DependencyResolver personalizado. Me refiero a este artículo [Inyección de dependencia para controladores de API web] . Todo está funcionando bien hasta ahora en términos de inyección de dependencia en los controladores. Fragmento de código de mi configuración de mi clase de inicio de Owin
private void RegisterIoC(HttpConfiguration config)
{
_unityContainer = new UnityContainer();
_unityContainer.RegisterType<IAccountService, AccountService>();
.........
.........
config.DependencyResolver = new UnityResolver(_unityContainer);
}
Pero en el momento en que Api se inicia por primera vez, se lanza una ( ResolutionFailedException) (pero se captura) dentro del método GetService de UnityResolver . Aquí está el mensaje de excepción
"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?**"
Por encima de la misma excepción se lanzan los siguientes tipos.
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
Sé que se emiten estas ResolutionFailedException porque no proporcioné asignaciones en mi configuración de unidad para los tipos anteriores.
Ahora, aquí está mi pregunta: - Si implemento la unidad personalizada DependencyResolver necesito definir asignaciones de los tipos anteriores y si necesito definir cuáles serán sus tipos de implementación predeterminados correspondientes O ¿existe alguna forma alternativa de implementar DependencyResolver? Estoy realmente preocupado a pesar de que la aplicación se está ejecutando bien ahora, no resolver el tipo anterior puede causar problemas graves más adelante. Por favor ayuda
Una adición final: - Para los siguientes tipos, se envía la misma ResolutionFailedException cuando hago una solicitud para cualquier acción en la API de mi web
System.Web.Http.Dispatcher.IHttpControllerActivator
System.Web.Http.Validation.IModelValidatorCache
System.Web.Http.Controllers.IHttpActionInvoker
Como parece que esto aún se disputa, aquí está mi versión del código ...
/// <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
}
}
y
[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://.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://.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
}
}
}
Finalmente, los bits son las extensiones para usar el contenedor de ámbito en el middleware de Owin, así como el WebAPI directo.
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 razón de esto es el aspnetwebstack.codeplex.com/workitem/2091 original donde vemos
Kichalla escribió 27 de octubre 2014 a las 4:34 PM
Sí ... correcto ... la extensión UseWebApi se debe usar solo en escenarios de hospedaje automático ... ya que todos estamos en la misma página, estoy solucionando este problema como un diseño ... por favor, háganos saber si tiene Alguna pregunta más...
Gracias kiran
y
kichalla escribió el 29 de octubre de 2014 a las 5:28 pm
@thebothead: ¡Gracias por descubrir esto! ... de acuerdo, esta muestra no debería haber estado utilizando Microsoft.AspNet.WebApi.Owin en IIS, ya que nunca se pretendió usar en ese host ... investigaremos el problema para ver por qué sucede esta excepción ... pero mientras tanto, podría seguir el enfoque mencionado en la muestra que proporcioné anteriormente ...
Gracias kiran
Desde mi propia experiencia, si no usa esta forma del código, funcionará en la depuración, etc., pero no se escalará y comenzará a comportarse de manera extraña.
En caso de que alguna de las soluciones anteriores todavía no funcione para la gente, así es como lo resolví.
Después de pasar un día persiguiendo este error, resultó ser una especie de problema de almacenamiento en caché de VS. Desesperado, borré todos los archivos .suo y force-get-latest, que parece haber resuelto el problema.
Esto se solicitó hace mucho tiempo, pero encontré una solución que no se mencionó aquí, por lo que quizás alguien todavía esté interesado.
En mi caso, estas excepciones ya fueron detectadas internamente por Unity (o lo que sea), pero mi Configuración de Excepciones en Visual Studio las hizo aparecer. Simplemente tuve que desmarcar la casilla de verificación "Interrumpir cuando se muestra este tipo de excepción" y la aplicación siguió funcionando normalmente.
He eliminado dependencyResolver y este problema fue resuelto
public static class UnityConfig
{
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
// Your mappings here
config.DependencyResolver = null;
}
}
La implementación de Unity.WebAPI
no es muy diferente de la mencionada en la pregunta. Me gustó la versión mencionada por el OP, ya que ignora solo la ResultionFailedException
y permite que el resto se propague por la pila. Unity.WebAPI
suprime todas las excepciones. Lo que haría es ignorar los errores que sabemos que son seguros de hacer y registrar (o volver a emitir) otros.
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;
}
Me estaba ejecutando en el mismo problema utilizando Unity con WebApi y OWIN / Katana.
La solución para mí fue usar UnityDependencyResolver definido en el paquete Unity.WebApi Nuget en lugar de mi propia implementación personalizada (como @Omar Alani arriba)
Install-Package Unity.WebAPI
Tenga en cuenta que el paquete intentará agregar un archivo llamado UnityConfig.cs en App_Start (el nombre de archivo que usé) .
En ese archivo UnityConfig.cs, el paquete agregará código para registrar el contenedor en GlobalConfiguration.Configuration.DependencyResolver
que no es lo que queremos con OWIN.
Así que en lugar de usar:
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
Cambiar para usar:
config.DependencyResolver = new UnityDependencyResolver(container);
Por completitud:
Mi UnityConfig.cs
public static class UnityConfig
{
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
// Your mappings here
config.DependencyResolver = new UnityDependencyResolver(container);
}
}
Mi 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);
}
}
}
Normalmente, no es necesario hacerlo con Unity. Utilizo esta implementación para IDependencyResolver con unity, y no tengo que registrarme o mapear más que mis interfaces / servicios.
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;
}
}
donde Desechable es solo una clase base implementa IDispoable.
Espero que ayude.