在.NET Core 2.2日志中间件中不依赖ControllerContext获取控制器与动作名称的方案咨询
Hey there! I've tackled this exact scenario with .NET Core 2.2 middleware before, so let me break down how to grab controller and action names when ControllerContext isn't accessible. Unlike .NET Core 3.1+, 2.2 doesn't have the Endpoint abstraction, but we can still get this info using MVC's internal features.
Solution 1: Use IActionFeature for reliable, detailed data
This is the most robust approach because it pulls directly from MVC's action descriptor system, which holds all metadata about the matched controller and action.
Here's how to implement it in your middleware:
public class YourCustomMiddleware { private readonly RequestDelegate _next; public YourCustomMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { // First, let the rest of the pipeline run so routing completes await _next(context); // Fetch the action feature from HttpContext features var actionFeature = context.Features.Get<IActionFeature>(); if (actionFeature != null) { // Cast to ControllerActionDescriptor to access controller/action details var controllerActionDescriptor = actionFeature.ActionDescriptor as ControllerActionDescriptor; if (controllerActionDescriptor != null) { string controllerName = controllerActionDescriptor.ControllerName; string actionName = controllerActionDescriptor.ActionName; // Pass these values to your logging method await LogResponse(controllerName, actionName, context); } } } private async Task LogResponse(string controllerName, string actionName, HttpContext context) { // Example usage: set your ServiceName to controller.action ServiceName = $"{controllerName}.{actionName}"; // Add your existing logging logic here // ... } }
Critical note about middleware order
Make sure you register your middleware after app.UseMvc() in your Startup.cs Configure method. This ensures the MVC routing system has already processed the request and populated the IActionFeature:
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { // ... other middleware (like exception handling, static files) app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); // Register your middleware HERE, after UseMvc app.UseMiddleware<YourCustomMiddleware>(); }
Solution 2: Fallback to RouteData (simpler, less reliable)
If you're using standard MVC routing with {controller} and {action} parameters in your route templates, you can pull the names directly from RouteData. This is quicker but won't work if you have custom routes that don't expose these parameters.
public async Task Invoke(HttpContext context) { await _next(context); var routeData = context.GetRouteData(); if (routeData != null) { string controllerName = routeData.Values["controller"]?.ToString(); string actionName = routeData.Values["action"]?.ToString(); if (!string.IsNullOrEmpty(controllerName) && !string.IsNullOrEmpty(actionName)) { await LogResponse(controllerName, actionName, context); } } }
Which one to choose?
- Use Solution 1 if you need guaranteed access to controller/action names, even with custom routes or attribute routing. It also gives you access to other metadata like action parameters, filters, etc.
- Use Solution 2 only for simple, standard routing scenarios where you know the
controllerandactionroute parameters are always present.
内容的提问来源于stack exchange,提问作者शेखर

