Search code examples
c#asp.net-coredynamic-routing

MapDynamicControllerRoute in ASP.NET Core only selectively working


I'm trying to use dynamic routing in ASP.NET Core. In Startup.cs I'm setting things up as follows

app.UseRouting()
app.UseEndpoints(endpoints =>
    {
        endpoints.MapDynamicControllerRoute<PluginSelectorTransformer>("api/{controller}/{action}");
        endpoints.MapControllers();
    });

My PluginSelectorTransformer look as follows:

public class PluginSelectorTransformer : DynamicRouteValueTransformer
{

    private readonly IPluginSelector pluginSelector;

    public PluginSelectorTransformer(IPluginSelector pluginSelector)
    {
        this.pluginSelector = pluginSelector;
    }

    public override ValueTask<RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values)
    {
        var controllerName = values["controller"] as string;
        var pluginId = pluginSelector.FindPlugin(controllerName);

        if (pluginId == null)
            return new ValueTask<RouteValueDictionary>(values);

        values = new RouteValueDictionary
        {
            ["action"] = "GetPluginConfiguration",
            ["controller"] = "PluginConfig",
            ["id"] = pluginId
        };

        return new ValueTask<RouteValueDictionary>(values);
    }
}

And the PluginController looks like this:

[Route("api/[controller]")]
[ApiController]
public class PluginConfigController :ControllerBase
{
    [HttpGet]
    [Route("{id}")]
    public IActionResult GetPluginConfiguration(Guid id)
    {
        // implementation omitted
    }
    
    [HttpGet]
    [Route("{id}/PluginUiConfig")]
    public IActionResult GetPluginUiConfig(Guid id)
    {
        // implementation omitted
    }
}

Now, if I run the code and access this URI:

https://localhost:5001/api/SomePlugin/UIConfig

then the transformer does what it's supposed to - pluginId being dd856ae1-1912-43c0-be70-fb98eb4a7cec, we end up in the same place as if I were to access https://localhost:5001/#/admin/PluginConfig/dd856ae1-1912-43c0-be70-fb98eb4a7cec (so I end up in the GetPluginConfiguration method as expected).

If I modify the PluginSelectorTransformer and set action to "PluginUiConfig" instead of "GetPluginConfiguration", I get a 404 instead.

So, what do I need to change in my PluginSelectorTransformer to make it work for both cases?


Solution

  • It seems that you didn't set the action to GetPluginUiConfig, I think you can try adding a new filter in TransformAsync:

    public override ValueTask<RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values)
        {
            var controllerName = values["controller"] as string;
            var actionName = values["action"] as string;
    
            if (actionName == "UIConfig")
            {
                // Map the "UIConfig" action to the PluginConfigController
                values = new RouteValueDictionary
                {
                    ["action"] = "GetPluginUiConfig",
                    ["controller"] = "PluginConfig",
                    ["id"] = values["id"]
                };
            }
            else
            {
                var pluginId = pluginSelector.FindPlugin(controllerName);
    
                if (pluginId == null)
                    return new ValueTask<RouteValueDictionary>(values);
    
                values = new RouteValueDictionary
                {
                    ["action"] = "GetPluginConfiguration",
                    ["controller"] = "PluginConfig",
                    ["id"] = pluginId
                };
            }
    
            return new ValueTask<RouteValueDictionary>(values);
        }