简体   繁体   English

WebApi 2,OWIN和AutoFac-更改HttpContextBase依赖项

[英]WebApi 2, OWIN and AutoFac - change HttpContextBase dependency

Recently I decided that I would like to integrate test my WebApi 2 application. 最近,我决定要集成测试WebApi 2应用程序。 I decided to convert my application to OWIN compliant. 我决定将我的应用程序转换为OWIN兼容。 I have included all the NuGet packages and hooked it up with AutoFac middleware and so on. 我已经包含了所有的Nu​​Get程序包,并将其与AutoFac中间件等连接起来。

However when I try to test the application with HttpClient in in Main method of sample program, I get an error: 但是,当我尝试在示例程序的Main方法中使用HttpClient测试应用程序时,出现错误:

{
  "Message":"An error has occurred.",
  "ExceptionMessage":"An error occurred when trying to create a controller of type 'DinnerListController'. Make sure that the controller has a parameterless public constructor.",
  "ExceptionType":"System.InvalidOperationException",
  "StackTrace":"   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n   at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()",
  "InnerException":{
    "Message":"An error has occurred.",
    "ExceptionMessage":"An exception was thrown while executing a resolve operation. See the InnerException for details. ---> Value cannot be null.\r\nParameter name: httpContext (See inner exception for details.)",
    "ExceptionType":"Autofac.Core.DependencyResolutionException",
    "StackTrace":"   at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters)\r\n   at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)\r\n   at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance)\r\n   at Autofac.ResolutionExtensions.ResolveOptionalService(IComponentContext context, Service service, IEnumerable`1 parameters)\r\n   at Autofac.Integration.WebApi.AutofacWebApiDependencyScope.GetService(Type serviceType)\r\n   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)",
    "InnerException":{
      "Message":"An error has occurred.",
      "ExceptionMessage":"Value cannot be null.\r\nParameter name: httpContext",
      "ExceptionType":"System.ArgumentNullException",
      "StackTrace":"   at System.Web.HttpContextWrapper..ctor(HttpContext httpContext)\r\n   at Autofac.Integration.Mvc.AutofacWebTypesModule.<Load>b__0(IComponentContext c)\r\n   at Autofac.RegistrationExtensions.<>c__DisplayClass10`1.<Register>b__f(IComponentContext c, IEnumerable`1 p)\r\n   at Autofac.Builder.RegistrationBuilder.<>c__DisplayClass1`1.<ForDelegate>b__0(IComponentContext c, IEnumerable`1 p)\r\n   at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.<Execute>b__0()\r\n   at Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator)\r\n   at Autofac.Core.Resolving.InstanceLookup.Execute()\r\n   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)\r\n   at Autofac.Core.Registration.ExternalRegistrySource.<>c__DisplayClass8.<RegistrationsFor>b__3(IComponentContext c, IEnumerable`1 p)\r\n   at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.Execute()\r\n   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)\r\n   at Autofac.Core.Activators.Reflection.AutowiringParameter.<>c__DisplayClass2.<CanSupplyValue>b__0()\r\n   at Autofac.Core.Activators.Reflection.ConstructorParameterBinding.Instantiate()\r\n   at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.<Execute>b__0()\r\n   at Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator)\r\n   at Autofac.Core.Resolving.InstanceLookup.Execute()\r\n   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)\r\n   at Autofac.Core.Registration.ExternalRegistrySource.<>c__DisplayClass8.<RegistrationsFor>b__3(IComponentContext c, IEnumerable`1 p)\r\n   at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.Execute()\r\n   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)\r\n   at Autofac.Core.Activators.Reflection.AutowiringParameter.<>c__DisplayClass2.<CanSupplyValue>b__0()\r\n   at Autofac.Core.Activators.Reflection.ConstructorParameterBinding.Instantiate()\r\n   at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.<Execute>b__0()\r\n   at Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator)\r\n   at Autofac.Core.Resolving.InstanceLookup.Execute()\r\n   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)\r\n   at Autofac.Core.Registration.ExternalRegistrySource.<>c__DisplayClass8.<RegistrationsFor>b__3(IComponentContext c, IEnumerable`1 p)\r\n   at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.Execute()\r\n   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters)"
    }
  }
}

I isolated the cause: it's my service which has dependency on HttpContextBase for storing and extracting something from cookies: 我隔离了原因:这是我的服务依赖于HttpContextBase来存储和从cookie中提取某些内容:

public CookieUserService(HttpContextBase httpContext)

and AutoFac can't initialize this class. 并且AutoFac无法初始化此类。 When I tried another implementation, without HttpContextBase , dependency it works. 当我尝试另一个没有HttpContextBase实现时,它可以工作。

So the question is: is there a way to get access to cookies while using OWIN, so I could refactor the service and get rid of HttContextBase (and Web.dll ) dependecies? 因此,问题是:有一种方法可以在使用OWIN时访问cookie,以便我可以重构服务并摆脱HttContextBase (和Web.dll )依赖项?

While switching to OWIN, all dependencies on System.Web and so on become invalid, as they are coupling tight the application with IIS hosting environment. 切换到OWIN时,对System.Web等的所有依赖关系都将变为无效,因为它们会将应用程序与IIS托管环境紧密结合在一起。 Therefore AutoFac is not able to inject HttpContextBase as dependency to my service, because it can't instan. 因此,AutoFac无法将HttpContextBase作为对我的服务的依赖关系注入,因为它无法实例化。

In order to overcome the problem, instead of using System.Web dependencies like HttpContextBase , service should depend on OWIN specific interfaces, which provide abstraction between application and hosting environment. 为了解决该问题,服务应该使用OWIN特定的接口,而不是使用诸如HttpContextBase类的System.Web依赖项,后者在应用程序和托管环境之间提供抽象。

In my specific case, I changed the service to depend on IOwinContext, like so: 在我的特定情况下,我将服务更改为依赖于IOwinContext,如下所示:

public OwinCookieUserService(IOwinContext owinContext)
{
    if (owinContext == null) throw new ArgumentNullException(nameof(owinContext));  
    _owinContext = owinContext;
}

After adding two additional NuGet packages: 添加两个附加的NuGet软件包后:

  1. Autofac.Owin Autofac.Owin
  2. Autofac.WebApi2.Owin Autofac.WebApi2.Owin

I was able to glue together AutoFac and OWIN in my Startup class: 我可以在Startup类中将AutoFac和OWIN粘合在一起:

public class Startup
{
   public void Configuration(IAppBuilder appBuilder)
   {
       var httpConfiguration = new HttpConfiguration();
       ...
       AutoFacConfig.ConfigureAutoFac(httpConfiguration);
       appBuilder.UseAutofacMiddleware(AutoFacConfig.Container);
       appBuilder.UseAutofacWebApi(httpConfiguration);
       appBuilder.UseWebApi(httpConfiguration);
   }
}

In my AutoFac mappings, I have the following routine that where I define my service dependency: 在我的AutoFac映射中,我具有以下例程,用于在其中定义我的服务依赖项:

....
    builder.RegisterType<OwinCookieUserService>().AsImplementedInterfaces().InstancePerLifetimeScope();
....

That is basically it! 基本上就是这样! I didn't have to specifically setup mappings for OWIN interfaces and classes, it just works. 我不必专门为OWIN接口和类设置映射,它可以正常工作。 I hope that will help some of you folks in the future. 我希望这将对将来的某些人有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM