Reputation: 3
Is it possible to access a custom attribute of a controller action from outside of that controller? I have a custom output formatter that should return a file with a specific name. I made a custom attribute that accepts a string (filename) and I'd like to try to access the value of that attribute from within the custom output formatter.
public class FileAttribute : Attribute
{
public ExcelTemplateAttribute(string fileName)
{
FileName = fileName;
}
public string FileName { get; }
}
My OutputFormatter
looks like this:
public class FileOutputFormatter : OutputFormatter
{
public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context)
{
// string filename = ???
}
}
My API action returns a service
[File("Template.txt")]
public IActionResult Get([FromQuery]int Id)
{
IEnumerable<int> data = _kenoReport.GetReportData(Id);
return Ok(data);
}
Upvotes: 0
Views: 192
Reputation: 50
Controller and/or action information is not easily accessible outside of the MVC-specific parts of the middleware pipeline without resorting to complex (and easy-to-break) code relying on reflection.
However, one workaround is to use an action filter to add the attribute details to the HttpContext.Items
dictionary (which is accessible throughout the entire middleware pipeline) and have the output formatter retrieve it later on in the middleware pipeline.
For example, you could make your FileAttribute
derive from ActionFilterAttribute
and have it add itself to HttpContext.Items
(using a unique object reference as the key) when executing:
public sealed class FileAttribute : ActionFilterAttribute
{
public FileAttribute(string filename)
{
Filename = filename;
}
public static object HttpContextItemKey { get; } = new object();
public string Filename { get; }
public override void OnActionExecuting(ActionExecutingContext context)
{
context.HttpContext.Items[HttpContextItemKey] = this;
}
}
Then in your output formatter you can retrieve the attribute instance and access the filename:
public sealed class FileOutputFormatter : OutputFormatter
{
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context)
{
if (context.HttpContext.Items.TryGetValue(FileAttribute.HttpContextItemKey, out var item)
&& item is FileAttribute attribute)
{
var filename = attribute.Filename;
// ...
}
}
}
Upvotes: 2