Before Core, when the controllers for MVC and Web API were separate, it was easy to target a a global action at one framework or the other. Now with mvcOptions.Filters.Add<T>();
it'll apply across your MVC view rendering actions and you're API-only actions.
I can see roughly that when you use [ApiController]
(docs), you're opted in to several conventions/behaviours, but it's not super clear how/if I could add to that convention easily. Potentially I need to create my own additional ApiBehaviorApplicationModelProvider
, like the one here? I'm looking for something a little simpler, like mvcOptions.ApiConvention.Filters.Add(x)
.
Another approach is to have all my API controllers inherit my own ApiControllerBase
and annotate that, but I'd prefer to extend the convention if possible.
It'd also be nice to go the other way without having to have a MvcControllerBase
either that's for views.
CodePudding user response:
There's no built-in extensibility for the [ApiController]
conventions that I know of, but you can achieve what you're looking for with the application model.
Here's an example implementation of an IControllerModelConvention
that looks for the [ApiController]
attribute, which you can fill in with your specific implementation:
public class ExampleControllerModelConvention : IControllerModelConvention
{
public void Apply(ControllerModel controllerModel)
{
if (controllerModel.Attributes.OfType<ApiControllerAttribute>().Any())
{
// ...
}
}
}
You can register this convention in Startup.ConfigureServices
or Program.cs for .NET 6 :
// Startup.ConfigureServices
services.AddControllers(options =>
{
options.Conventions.Add(new SampleControllerModelConvention());
});
// Program.cs
builder.Services.AddControllers(options =>
{
options.Conventions.Add(new SampleControllerModelConvention());
});
The IsApiController
method in the ApiBehaviorApplicationModelProvider
class you linked to handles the check a little differently:
private static bool IsApiController(ControllerModel controller)
{
if (controller.Attributes.OfType<IApiBehaviorMetadata>().Any())
{
return true;
}
var controllerAssembly = controller.ControllerType.Assembly;
var assemblyAttributes = controllerAssembly.GetCustomAttributes();
return assemblyAttributes.OfType<IApiBehaviorMetadata>().Any();
}
This implementation supports the [ApiController]
attribute being applied to the assembly the controller lives in. You likely don't need this if you're also using Views, but it's worth noting the difference in this approach.