1

I am trying to use interceptions on .Net Core 2.0 WebApi Application by using Autofac but I couldnt succeed it on Controllers. What I try is

First I created a basic webapi which has one default controller(ValuesController). Then I set up the autofac configuration as below. Project is working without any error, but interception doesnt seems to be running. What I am doing wrong ?

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)
    {
    }
} 
Cyril Durand
  • 15,834
  • 5
  • 54
  • 62
Barış Velioğlu
  • 5,709
  • 15
  • 59
  • 105
  • 2
    Please see [this answer](https://stackoverflow.com/a/40089164/455493). Controllers are not resolved via DI by default. You have to call `AddControllersAsService()` on the MvcBuilder to register controllers as services. Only then Autofac will do the resolving. without it, ASP.NET Core will inspect the constructor and resolve the dependencies manually from your IoC container – Tseng Jan 17 '18 at 08:22
  • 2
    The use of such `EnableClassInterceptors` is fragile, since forgetting to make a member `virtual` will skip your interceptor and make your application 'fail silently'. Instead, you're better of using a middleware component to apply logging, which is guaranteed to run. – Steven Jan 17 '18 at 10:03

1 Answers1

4

When working with interception of type, methods should be declared as virtual

Under the covers, EnableInterfaceInterceptors() creates an interface proxy that performs the interception, while EnableClassInterceptors() dynamically subclasses the target component to perform interception of virtual methods.
Autofac documentation - Enable interception on types

ie :

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

BTW you are trying to intercept method of ASP.net core controller. In this case controllers are not resolved by Autofac by default

By default, ASP.NET Core will resolve the controller parameters from the container but doesn’t actually resolve the controller from the container. This usually isn’t an issue but it does mean:

  • The lifecycle of the controller is handled by the framework, not the request lifetime.
  • The lifecycle of controller constructor parameters is handled by the request lifetime.
  • Special wiring that you may have done during registration of the controller (like setting up property injection) won’t work.

Autofac documentation - Controllers as services

you have to add the AddControllersAsServices method

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

and like Steven mentions on a comment it may be easier to rely on a middleware to intercept method call of controller

Cyril Durand
  • 15,834
  • 5
  • 54
  • 62