Autofac InstancePerRequest返回新的Istance



我有一个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 = actionContext.Request.GetDependencyScope();

Autofac文档中显示了一个示例过滤器

然而,由于您使用的是Autofac接口,它们是由Autofac为每个请求注入的——如果您的过滤器需要每个请求的服务,最好将其作为过滤器上的构造函数参数。您只需要在而不是使用Autofac过滤器接口的情况下进行服务定位。

如果您非常需要过滤器中的服务位置,您仍然可以使用构造函数来简化操作——向过滤器构造函数添加ILifetimeScope参数,您将获得作为参数的请求范围。

对于控制器,同样的事情:在构造函数中注入您需要的东西,而不是使用服务位置。如果由于无法转义服务位置而需要请求作用域,请将ILifetimeScope注入控制器构造函数,或者从HttpRequestMessage中获取请求生存期。

最新更新