0
votes

I have 2 routes defined:

app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
            endpoints.MapControllerRoute("api", "{controller=Home}/api/v1/{action=Index}/{id?}");
        });

In the controller, if I don't specify a route in the controller it will use either one. Both urls work:

https://myapp/mymodel/api/v1/id/123

https://myapp/mymodel/id/123

I want it to work only with the first url, but if add for example [Route("api")] to the controller none of the above routes work.

[Route("api")] //with this line it returns 404
public mymodel ID(int? id)
{
  //some code
 }
1
I've read that, so it seemed that adding the route name should work. I must be missing something.vvuser
You are not adding a route name, you are adding a route template for attribute-based routing. UseEndpoints is used for convention-based routing. Two separate conceptsNkosi
If I add the route directly to the controller it works as I want to [Route("[controller]/api/v1/id/{id?}")], but I wanted to be able to select the template from the startup class instead of writing the whole route in the controller.vvuser

1 Answers

0
votes

From the official doc :

Route names can be used to generate a URL based on a specific route. Route names have no impact on the URL matching behavior of routing and are only used for URL generation. Route names must be unique application-wide.

Here is a workaround on customizing a actionfilter attribute that checks if the url matches the route template for api , you could refer to:

ApiRouteTemplateAttribute

 public class ApiRouteTemplateAttribute:ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        var routeTemplate = "{controller=Home}/api/v1/{action=Index}/{id?}";
        var template = TemplateParser.Parse(routeTemplate);

        var matcher = new TemplateMatcher(template, GetDefaults(template));
        var routeValues = new RouteValueDictionary();
        string LocalPath = context.HttpContext.Request.Path;

        var result = matcher.TryMatch(LocalPath, routeValues);
        //if the match is false ,return a exception information.
        if (!result)
        {
            context.Result = new BadRequestObjectResult(new Exception("The url is incorrect!"));
        }
    }

    private RouteValueDictionary GetDefaults(RouteTemplate parsedTemplate)
    {
        var result = new RouteValueDictionary();

        foreach (var parameter in parsedTemplate.Parameters)
        {
            if (parameter.DefaultValue != null)
            {
                result.Add(parameter.Name, parameter.DefaultValue);
            }
        }

        return result;
    }
}

Controller

    [ApiRouteTemplate]
    public Exam ID(int? id)
    {
        return _context.Exams.Find(id);
    }

Result

enter image description here