ASP.Net WebAPI Get current controller name from inside MediaTypeFormatter
-
13-06-2021 - |
سؤال
I am writing a media type formatter for HTML to automatically generate a Razor view based on an html request from the user. I am doing this for use inside a SelfHosted service. I need to detect what controller/action was requested to allow me to pick the view to render into.
public class RazorHtmlMediaTypeFormatter : MediaTypeFormatter
{
public RazorHtmlMediaTypeFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
}
public override bool CanWriteType(Type type)
{
return true;
}
public override bool CanReadType(Type type)
{
return false;
}
public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContentHeaders contentHeaders, System.Net.TransportContext transportContext)
{
return Task.Factory.StartNew(() =>
{
var view = Razor.Resolve(String.Format("{0}.{1}.cshtml", something.Controller, something.Action), value);
byte[] buf = System.Text.Encoding.Default.GetBytes(view.Run(new ExecuteContext()));
stream.Write(buf, 0, buf.Length);
stream.Flush();
});
}
}
المحلول
Web API Contrib has a working RazorViewFormatter in here.
نصائح أخرى
Why not wrapping your returned objects in Metadata<T>
?
I.e. return, instead of MyCustomObject
, Metadata<MyCustomObject>
. As Metadata properties, you can set controller name and action. Then in the formatter, just decouple the Metadata and your custom object, and serialize just that custom object.
I blogged about this approach here - http://www.strathweb.com/2012/06/extending-your-asp-net-web-api-responses-with-useful-metadata/. While the purpose of the article is a bit different, I am sure you can relate it to your needs.
Edit: or if you are OK with a small hack, use a custom filter and headers:
public override void OnActionExecuting(HttpActionContext actionContext) { actionContext.Response.Headers.Add("controller", actionContext.ActionDescriptor.ControllerDescriptor.ControllerName); actionContext.Response.Headers.Add("action", actionContext.ActionDescriptor.ActionName;); base.OnActionExecuting(actionContext); }
then just read it from the headers in the formatter, and remove the header entries so that they don't get sent to the client.