【发布时间】:2020-12-22 22:41:34
【问题描述】:
我有一个 ASP.NET Web API,.Net 4.6.1 项目,我需要在中间件中捕获一些信息,然后在将从控制器调用的代码中检索它。在 .Net 核心中,将我的自定义上下文类注册为 Scoped 并在消息处理的不同阶段对其进行解析非常容易。在 .Net Framework 中,看起来与它相似的是 Autofac 的 InstancePerRequest,所以我尝试了,但它并没有像我预期的那样工作。显然每次我做BeginScope() 它都会返回一个新实例,即使我在同一个请求中?我正在实现IAutofacContinuationActionFilter 接口,我在其中解析我的服务,注册InstancePerRequest,然后在控制器中我尝试再次解析它并获取新实例。我在这里错过了什么?
哦,在下面的控制器中,两个 IHomeService 实例:通过构造函数注入并手动解析正在创建新实例。
更新: 上面的代码是对真实情况的过度简化。我需要从过滤器传递的信息的调用位于一个单独的类中,并且调用通过一系列自动生成的代码进行。构造函数注入对我来说不是一个选项,所以我希望有一个类似于 .Net Core DI 的解决方案。
我的 WebApiConfig:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var container = MyContainerBuilder.Build(config);
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
我的容器构建器类:
public class MyContainerBuilder
{
public static IContainer Build(HttpConfiguration config)
{
var builder = new ContainerBuilder();
builder.RegisterWebApiFilterProvider(config);
builder
.Register(c => new MyCustomFilter())
.AsWebApiActionFilterForAllControllers()
.InstancePerRequest();
// var assembly = typeof(IHomeService).Assembly;
// builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces().InstancePerRequest();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).InstancePerRequest();
builder
.RegisterType<HomeService>()
.As<IHomeService>()
.InstancePerRequest();
return builder.Build();
}
}
过滤器:
public class MyCustomFilter : IAutofacContinuationActionFilter
{
public async Task<HttpResponseMessage> ExecuteActionFilterAsync(
HttpActionContext actionContext,
CancellationToken cancellationToken,
Func<Task<HttpResponseMessage>> next)
{
using (var scope = GlobalConfiguration.Configuration.DependencyResolver.BeginScope().GetRequestLifetimeScope())
{
var hs = scope.Resolve<IHomeService>();
++hs.Counter;
var hs1 = scope.Resolve<IHomeService>();
++hs1.Counter;
var r = next().Result;
return await Task.FromResult(r);
}
}
}
控制器:
[Route("home")]
public class HomeController : ApiController
{
public IHomeService HomeService { get; set; }
public HomeController(IHomeService homeService)
{
HomeService = homeService;
}
[HttpGet]
[Route("")]
public string Index()
{
var dr = GlobalConfiguration.Configuration.DependencyResolver as AutofacWebApiDependencyResolver;
using (var scope = dr.GetRequestLifetimeScope())
// This does not work either, returns new instance:
// using (var scope = GlobalConfiguration.Configuration.DependencyResolver.BeginScope().GetRequestLifetimeScope())
{
var hs = scope.Resolve<IHomeService>();
++hs.Counter;
}
return "Home";
}
}
我尝试解决的服务类:
public interface IHomeService
{
int Counter { get; set; }
}
public class HomeService : IHomeService
{
public HomeService()
{
Console.WriteLine("Yet another instance of HomeService!!!");
}
public int Counter { get; set; }
}
提前致谢
【问题讨论】:
-
为什么不使用构造函数注入而不是手动创建作用域?使用 (var scope = GlobalConfiguration.Configuration.DependencyResolver.BeginScope().GetRequestLifetimeScope())。我不确定这一行是做什么的,但它似乎创建了一个新的范围,而不是使用 http 请求的范围(为什么有 beginscope?)
标签: asp.net asp.net-web-api autofac