问题
How can I retrieve the api controller name and api action name inside a piece of custom OWIN middleware? I can do it inside of a message handler like so:
var config = request.GetConfiguration();
var routeData = config.Routes.GetRouteData(request);
var controllerContext = new HttpControllerContext(config, routeData, request);
request.Properties[HttpPropertyKeys.HttpRouteDataKey] = routeData;
controllerContext.RouteData = routeData;
var controllerDescriptor = new
DefaultHttpControllerSelector(config).SelectController(request);
controllerContext.ControllerDescriptor = controllerDescriptor;
var actionMapping = new ApiControllerActionSelector().SelectAction(controllerContext);
//controller name
controllerDescriptor.ControllerName
//action name
actionMapping.ActionName
Update: Here is my current piece of OWIN middleware. How can I get the controllerName and actionName within this code?
using AppFunc = Func<IDictionary<string, object>, Task>;
public class LoggingMiddleware
{
private readonly AppFunc _next;
private static readonly ILog RequestApiLogger = LogManager.GetLogger("RequestApiPacketLogger");
private static readonly ILog ResponseApiLogger = LogManager.GetLogger("ResponseApiPacketLogger");
public LoggingMiddleware(AppFunc next)
{
_next = next;
}
public async Task Invoke(IDictionary<string, object> environment)
{
var correlationId = Guid.NewGuid();
IOwinContext context = new OwinContext(environment);
// Buffer the request (body is a string, we can use this to log the request later
var requestBody = new StreamReader(context.Request.Body).ReadToEnd();
var requestData = Encoding.UTF8.GetBytes(requestBody);
context.Request.Body = new MemoryStream(requestData);
// Buffer the response
var responseBuffer = new MemoryStream();
var responseStream = context.Response.Body;
context.Response.Body = responseBuffer;
// add the "http-tracking-id" response header so the user can correlate back to this entry
var responseHeaders = (IDictionary<string, string[]>)environment["owin.ResponseHeaders"];
responseHeaders["http-tracking-id"] = new[] { correlationId.ToString("d") };
IDictionary<string, string[]> responseHeadersClone = new Dictionary<string, string[]>(responseHeaders);
//invoke the next piece of middleware in the pipeline
await _next.Invoke(environment);
// rewind the request and response buffers and record their content
responseBuffer.Seek(0, SeekOrigin.Begin);
var reader = new StreamReader(responseBuffer);
var responseBody = await reader.ReadToEndAsync();
// log the request/response as long at it wasn't preflight
if (context.Request.Method.ToUpper() != "OPTIONS")
{
RequestApiLogger.LogHttpRequestAsync(context, correlationId, requestBody);
ResponseApiLogger.LogHttpResponseAsync(context, correlationId, responseBody, responseHeadersClone);
}
// You need to do this so that the response we buffered is flushed out to the client application.
responseBuffer.Seek(0, SeekOrigin.Begin);
await responseBuffer.CopyToAsync(responseStream);
}
}
回答1:
You really can't. OWIN middleware does not know about Web Api. It only knows about the environment that is passed to it. The idea of middleware is that it is independent of the hosting and application platforms.
You didn't provide a specific example of what you are trying to accomplish, so there might be a way of doing what you are trying to do.
Update to include response to the above statement:
You can reverse what you are trying to do. Kinda. The OWIN environment is available on the HttpRequest inside Web Api with the GetOwinEnvironmentExtension method. You could add an environment variable to the dictionary with the name of the controller and method inside the controller and then use that when your middleware is called after web api is finished. Lots of repetitive code, but it would work.
There is probably a way to intercept the method before it is called. Check out this answer from @mark-jones that might give you some insight to doing that.
Hope that helps.
来源:https://stackoverflow.com/questions/35561338/web-api-2-get-controller-and-action-name-in-owin-middleware