【问题标题】:Interception on .NET Core 2.0 Web API Controller By Using Autofac使用 Autofac 拦截 .NET Core 2.0 Web API 控制器
【发布时间】:2018-01-18 04:11:06
【问题描述】:

我正在尝试使用 Autofac 在 .Net Core 2.0 WebApi 应用程序上使用拦截,但我无法在控制器上成功。我尝试的是

首先我创建了一个基本的 webapi,它有一个默认控制器(ValuesController)。然后我如下设置autofac配置。项目工作没有任何错误,但拦截似乎没有运行。我做错了什么?

Startup.cs

public void ConfigureContainer(ContainerBuilder builder)
{        
    builder.Register(c => new CallLogger());
    builder.RegisterType<ValuesController>()
           .EnableClassInterceptors()
           .InterceptedBy(typeof(CallLogger));
}

CallLogger.cs

public class CallLogger : IInterceptor
{
    public CallLogger()
    {
        System.Console.WriteLine("XXXXX");
    }
    public void Intercept(IInvocation invocation)
    {
        Console.WriteLine($"Calling method {invocation.Method.Name} with parameters {(string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray()))}... ");

        invocation.Proceed();

        Console.WriteLine("Done: result was {0}.", invocation.ReturnValue);
    }
}

ValuesController.cs

[Route("api/[controller]")]
[Intercept(typeof(CallLogger))]
public class ValuesController : Controller
{
    private readonly ITest _test;
    public ValuesController(ITest test)
    {
        _test = test;
    }
    // GET api/values
    [HttpGet]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }
    // GET api/values/5
    [HttpGet("{id}")]
    public string Get(int id, [FromHeader(Name = "TenantId")] string tenantId)
    {
        _test.Log("asdasdasda");             
        return tenantId + " => " + id;
    }

    // POST api/values
    [HttpPost]
    public void Post([FromBody]string value)
    {
    }

    // PUT api/values/5
    [HttpPut("{id}")]
    public void Put(int id, [FromBody]string value)
    {
    }

    // DELETE api/values/5
    [HttpDelete("{id}")]
    public void Delete(int id)
    {
    }
} 

【问题讨论】:

  • 请参阅this answer。默认情况下,控制器不通过 DI 解析。您必须在 MvcBuilder 上调用 AddControllersAsService() 才能将控制器注册为服务。只有这样 Autofac 才会进行解析。没有它,ASP.NET Core 将检查构造函数并从您的 IoC 容器中手动解析依赖项
  • 使用这种EnableClassInterceptors 是脆弱的,因为忘记创建成员virtual 会跳过你的拦截器并使你的应用程序“静默失败”。相反,您最好使用中间件组件来应用日志记录,这样可以保证运行。

标签: c# asp.net-core autofac interceptor asp.net-core-webapi


【解决方案1】:

当使用拦截类型时,方法应该被声明为虚拟的

在幕后,EnableInterfaceInterceptors() 创建了一个接口代理来执行拦截,而EnableClassInterceptors() 动态子类化目标组件以执行虚拟方法的拦截。
Autofac documentation - Enable interception on types p>

即:

// GET api/values
[HttpGet]
public virtual IEnumerable<string> Get()
{
    return new string[] { "value1", "value2" };
}

顺便说一句,您试图拦截 ASP.net 核心控制器的方法。在这种情况下,默认情况下 Autofac 不会解析控制器

默认情况下,ASP.NET Core 将从容器中解析控制器参数,但实际上并不从容器中解析控制器。这通常不是问题,但确实意味着:

  • 控制器的生命周期由框架处理,而不是请求生命周期。
  • 控制器构造函数参数的生命周期由请求生命周期处理。
  • 您在控制器注册期间可能进行的特殊接线(例如设置属性注入)将不起作用。

Autofac documentation - Controllers as services

你必须添加AddControllersAsServices方法

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddMvc()
        .AddControllersAsServices();
}

就像Steven 在评论中提到的那样,依靠中间件来拦截控制器的方法调用可能更容易

【讨论】:

  • @RyuKaplan 你添加了AddControllersAsService 吗?我尝试了一个虚拟项目,它对我有用
猜你喜欢
  • 2018-03-31
  • 2018-02-15
  • 2018-05-31
  • 2018-06-23
  • 2017-10-13
  • 1970-01-01
  • 2018-11-29
  • 2018-03-26
  • 2021-08-01
相关资源
最近更新 更多