0
votes

Suppose I have these actions

- http://thesite.com/Cats/product/1 
- http://thesite.com/Cats/1

My customer wants a dynamic way to define custom URL for these actions because of SEO things. So I cant use Redirects!

Ex.

  • http://thesite.com/aaaaaa to open http://thesite.com/Cats/product/1
  • http://thesite.com/bbbbbb to open http://thesite.com/Cats/product/1, Again!
  • http://thesite.com/cccccc to open http://thesite.com/Cats/1

How do you setup routing for this dynamic behavior. Again, I CANT USE RedirectToAction

Bests,
Thank you in advance.

2
you must define route for each URL. or if URL is dynamic you most write a route engine and read route from db and map it to defined action - foad abdollahi
Im going to try it. - Sepehr Davarnia

2 Answers

1
votes

You need to create a custom DynamicRouteValueTransformer

public class AppDynamicRouteValueTransformer : DynamicRouteValueTransformer
{
    private readonly IList<AliasRouteMap> _aliasMaps;

    public AppDynamicRouteValueTransformer()
    {
        //--you can retrieve it from database table, from config....
        //--for demo I will do it manually
        _aliasMaps = new List<AliasRouteMap>(
            new[]
            {
                new AliasRouteMap("aaaaaa", "Cats", "product", 1),
                new AliasRouteMap("bbbbbb", "Cats", "product", 1)
            }
        );
    }
    public override async ValueTask<RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values)
    {
        await Task.CompletedTask;

        if (!values.ContainsKey("alias"))
            return values;

        var alias = (string)values["alias"];

        var aliasMap = _aliasMaps.FirstOrDefault(x => x.Alias.ToLower() == alias.ToLower());
        if (aliasMap is null)
            return values;

        values["controller"] = aliasMap.Controller;
        values["action"] = aliasMap.Action;

        if (aliasMap.Values != null)
        {
            foreach (var kvp in aliasMap.Values)
                values[kvp.Key] = kvp.Value;
        }

        return values;
    }
}

public class AliasRouteMap
{
    public AliasRouteMap(string alias, string controller, string action, object id)
        : this(alias, controller, action, new Dictionary<string, object> { { "id", id } })
    { }

    public AliasRouteMap(string alias, string controller, string action = "Index", IDictionary<string, object> values = null)
    {
        Alias = alias;
        Controller = controller;
        Action = action;
        Values = values;
    }

    public string Alias { get; set; }
    public string Controller { get; }
    public string Action { get; }
    public IDictionary<string, object> Values { get; }
}

The register the service and configure the routing in Startup class.

...
public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<AppDynamicRouteValueTransformer>();
    ...
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ...
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDynamicControllerRoute<AppDynamicRouteValueTransformer>("{alias}");
        ...
    }
    ...
}
...
0
votes

According to your description, I suggest you could also use custom middleware to achieve your requirement.

You could check the request's path in the custom middleware and modify the request path.

More details, you could refer to below codes:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }

            app.Use(async (context, next) => {
                if (context.Request.Path.Value.Contains("/aaaaaa")                     
                    ||context.Request.Path.Value.Contains("/bbbbbb") )
                {
                    context.Request.Path = "/Cats/product/1";
                }
                if (context.Request.Path.Value.Contains("/cccccc"))
                {
                    context.Request.Path = "/Cats/1";
                }

                await next();
            });

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}