WebApi 2, OWIN和autofacc -改变HttpContextBase依赖

本文关键字:改变 HttpContextBase 依赖 autofacc OWIN WebApi | 更新日期: 2023-09-27 18:12:22

最近我决定要集成测试我的WebApi 2应用程序。我决定将我的应用程序转换为OWIN兼容。我已经包含了所有的NuGet包,并将其与AutoFac中间件等连接起来。

然而,当我尝试在示例程序的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)"
    }
  }
}

我隔离了原因:这是我的服务,它依赖于HttpContextBase来存储和提取cookie中的内容:

public CookieUserService(HttpContextBase httpContext)

和autofacc不能初始化这个类。当我尝试另一个实现,没有HttpContextBase,依赖它工作。

所以问题是:是否有一种方法可以在使用OWIN时访问cookie,这样我就可以重构服务并摆脱HttContextBase(和Web.dll)依赖关系?

WebApi 2, OWIN和autofacc -改变HttpContextBase依赖

切换到OWIN时,所有依赖于System。Web等变得无效,因为它们将应用程序与IIS托管环境紧密耦合。因此AutoFac不能将HttpContextBase作为依赖注入到我的服务中,因为它不能实例化。

为了克服这个问题,而不是使用System。Web依赖,如HttpContextBase,服务应该依赖于OWIN特定的接口,它提供了应用程序和托管环境之间的抽象。

在我的具体情况下,我改变了服务依赖于IOwinContext,像这样:

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

添加两个额外的NuGet包后:

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

我能够在我的启动类中将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);
   }
}

在我的AutoFac映射中,我有以下例程来定义我的服务依赖:

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

基本上就是这样!我不需要专门为OWIN接口和类设置映射,它只是工作。我希望这对你们中的一些人将来有所帮助。