40

I am writing a middleware class within my project in order to log the request data into our database.

I do not see any easy way to get the controller name and action ? Any chance to do this easily in core?

I have something like this:

public class RequestResponseLoggingMiddleware
{
    private readonly RequestDelegate _next;

    public RequestResponseLoggingMiddleware(RequestDelegate next)
    {
        _next = next;            
    }

    public async Task Invoke(HttpContext context)
    {        
        //handle the request
        //something like: context.GetRouteData();

        await _next(context);                 

        //handle the response
    }       
}
abatishchev
  • 98,240
  • 88
  • 296
  • 433
Metalex
  • 471
  • 1
  • 5
  • 10
  • Possible duplicate of [Route controller and action in middleware](https://stackoverflow.com/questions/39335824/route-controller-and-action-in-middleware) – CodeCaster Aug 28 '17 at 14:07
  • 1
    [How to get the current ASP.NET core controller method name inside the controller using Reflection or another accurate method](https://stackoverflow.com/questions/35534337/how-to-get-the-current-asp-net-core-controller-method-name-inside-the-controller) – CodeCaster Aug 28 '17 at 14:09
  • I know but probably too old? – Metalex Aug 28 '17 at 14:15
  • None of the above works for .Net Core 1.1.2! – Metalex Aug 29 '17 at 09:14

5 Answers5

57

I had the same issue and this worked for me in .NetCore 3.1:

public async Task InvokeAsync(HttpContext httpContext)
{
    var controllerActionDescriptor = httpContext
        .GetEndpoint()
        .Metadata
        .GetMetadata<ControllerActionDescriptor>();

    var controllerName = controllerActionDescriptor.ControllerName;
    var actionName = controllerActionDescriptor.ActionName;
            
    await _next(httpContext);
}

In order for GetEndpoint() to return the actual endpoint instad of null, the following conditions have to be met.

  • Enable endpoint routing (AddControllers() instead of AddMvc())
  • Call your middleware between UseRouting() and UseEndpoints().
Ganesh
  • 571
  • 4
  • 4
  • 3
    if it wasn't for your last bullet point I would have still been banging my head against this! If you can be bothered it might be worth highlighting the importance of it somehow as this is not well documented IMHO – Ben Apr 29 '21 at 11:56
  • 1
    I agree with Ben. That second bullet point was the life-saver!! – CrazyWebDeveloper May 06 '21 at 20:30
  • 1
    This last point was not applicable for me in .net 6 world. But thanks, your answer worked! – Victor Zakharov Jan 27 '22 at 17:08
8

Adding to Ganesh's answer I'd like to add a few conditions.

  • Enable endpoint routing (AddControllers() instead of AddMvc())
  • Call your middleware between UseRouting() and UseEndpoints().

Otherwise GetEndpoint() returns null.

  • 1
    I gave you an upvote, but can you edit Ganesh's answer to include this important detail. I also don't understand why they complicated it with the try/catch. – carlin.scott Oct 14 '20 at 20:41
5

This works but you need to make sure to call _next(context) before you query the controller and action names.

public async Task InvokeAsync(HttpContext context)
{
    await _next(context);

    var controllerName = context.GetRouteData().Values["controller"];
    var actionName = context.GetRouteData().Values["action"];
}
Akira Yamamoto
  • 4,685
  • 4
  • 42
  • 43
3

In .NET Core 2.0 you can do this in Filter:

public class AuthorizationFilter : IAsyncAuthorizationFilter
    {
        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
            string controllerName = controllerActionDescriptor?.ControllerName;
            string actionName = controllerActionDescriptor?.ActionName;
        }
    }
tarn
  • 352
  • 6
  • 6
0

Controller and action data are available through filters so I implemented it this way. The controller and action data are available in the ActionExecutingContext object.

public class AsyncActionFilter : IAsyncActionFilter
{
     public AsyncActionFilter(IEntityContext entityContext)
     {
         _entityContext = entityContext;
     }

     public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
     {  
          //Handle the request
          await next();
     }
}
Metalex
  • 471
  • 1
  • 5
  • 10