Reputation: 586
How do I bind a custom attribute value to a route?
What I want:
[ApiController]
[CustomAttribute("value")]
[Route("{customAttributeValue}/[controller")]
public class ExampleController : Controller
{
//...
}
Then my route should appear like this.
I saw that for the first time when versioning apis
[ApiController]
[ApiVersion("2")]
[Route("v{version:apiVersion}/[controller]")]
public class ExampleController : Controller
{
//...
}
So in swagger, this example controller looks like this:
Upvotes: 5
Views: 780
Reputation: 23369
Start by defining that custom attribute, which accepts the string
value that must be part of the route.
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class CustomValueAttribute : Attribute
{
public CustomValueAttribute(string value)
=> Value = value;
public string Value { get; }
}
Set up an IActionModelConvention
to apply that attribute value to the route of the controller being executed. Here you decide upon the name you want to apply as a placeholder in the route definition; the below example uses customValue
.
public sealed class CustomValueRoutingConvention : IActionModelConvention
{
public void Apply(ActionModel action)
{
var value = action.Controller.ControllerType.GetCustomAttribute<CustomValueAttribute>()?.Value;
if (value is not null)
{
action.RouteValues.Add("customValue", value);
}
}
}
Next step is to hook the above convention to the MvcOptions
.
You can do that when calling AddControllers
.
builder.Services.AddControllers(
mvcOptions => mvcOptions.Conventions.Add(new CustomValueRoutingConvention())
);
Finally, that CustomValueAttribute
and route placeholder get applied to the controller. Notice the [customValue]
placeholder in the route.
[ApiController]
[CustomValue("value")]
[Route("[customValue]/[controller]")]
public class ExampleController : ControllerBase
A view from Swagger
Upvotes: 4
Reputation: 716
You could use a custom route attribute to solve this.
Example code:
namespace Test.Controllers
{
public class MyCustomValueAttribute : RouteAttribute
{
public MyCustomValueAttribute(string route, string prefixRoute, int prefixRouteCustomValue) : base($"{prefixRoute}/{prefixRouteCustomValue}/{route}")
{
}
}
[ApiController]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
[MyCustomValue("[controller]", "value", 20)]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
}
Upvotes: 1