skip to Main Content

We want to migrate a Website from Asp.Net Webforms to Asp.Net Core Webapplication (Razor Pages). We now have readable Urls without visible identifiers (for readability, SEO and to prevent changing Urls after possible database migrations…).

For that i generated dynamically Routes in the Global.Asax at Startup:

RouteTable.Routes.MapPageRoute("myroute1",
    "banana/",
     "~/content.aspx", false, new RouteValueDictionary { { "id", "4711" }, , { "otherid", "4812" }
     
RouteTable.Routes.MapPageRoute("myroute2",
    "apple/",
     "~/content.aspx", false, new RouteValueDictionary { { "id", "4913" }, , { "otherid", "5014" }  

That way users could call the content.aspx like this:

https://example.com/banana
https://example.com/apple

In the content.aspx i got the mapped "id" and "otherid" from the RouteValues.

How can i achieve this in Razor Pages?

Now i have a "Content.cshtml" and there i need access to id and otherid. I added this at the top:

@page "/content/{id:int}/{otherid:int}/{title:string}"

The above code allows mit to call Urls like this:

https://example.com/content/4711/4812/banana // still have the ids in it and prefix "content"

Is there a possibility to add all Routes at Startup with fixed Parameters? I have not been able to find anything similar.

Greetings
cpt.oneeye

2

Answers


  1. Chosen as BEST ANSWER

    I found a solution thanks to this thread:

    Is there a way to do dynamic routing with Razor Pages?

    Another full example can be found here:

    https://github.com/dotnet/AspNetCore.Docs/issues/12997

    According to my example at the top you first make your own DynamicRouteValueTransformer (see Namespace Microsoft.AspNetCore.Mvc.Routing):

    public class NavigationTransformer : DynamicRouteValueTransformer
    {
        private readonly MyDatabaseContext _repository;
    
        public NavigationTransformer(MyDatabaseContext repository)
        {
            _repository = repository;
        }
    
        public override async ValueTask<RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values)
        {
            // all requests which are incoming and fit a specific pattern will go through this method
            
            var slug = values["slug"] as string;
    
            // just get your needed info according to the "slug"
            // in my case i have to map according to NavigationNodes that are stored in the Database
            var myNavigationNode = _repository.NavigationNodes.FirstOrDefault(nn => nn.Name == slug);
    
            if (node == null)
            {
                // User will get a 404
                return null;
            }
            
            // set Path to Page according to Type (or whatever fits your logic)
            string pagename = "";
            
            if(node.Type == "ContentPage")
            {
                pagename = "/Content"  // Pages/Content.cshtml
            }
            else if(node.Type == "ContactForm")
            {
                pagename = "/Contact" // Pages/Contact.cshtml
            } 
            else 
            {
                pagename = "/Someotherpage"
            } 
    
            // return all RouteValues you need on your Page
            return new RouteValueDictionary()
            {
                { "page", pagename },
                { "id", node.Id },
                { "otherid", node.OtherId }
            };
        }
    }
    

    In the Startup.ConfigureServices() you register the new Service:

    services.AddScoped<NavigationTransformer>();
    

    In the Startup.Configure() you add the NavigationTransformer to Endpoints:

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapDynamicPageRoute<NavigationTransformer>("{slug}"); // just "slug" so that every request will be handled by NavigationTransformer, you can also add a prefix-folder
    });
    

    Now when you call a url like the following you will came through the Transformer and you are able to reroute on the fly:

    https://example.com/banana
    https://example.com/apple
    

    Be aware the Routings of existing Pages are stronger. So if we have a Apple.cshtml the second Url will still be routed to Apple.cshtml and not to Content.cshtml


  2. To have a static url, you can put your routes in startup class. for example:

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
             name: "default1",
             pattern: "{controller=Home}/{action=Index}/{id?}"
        );
    });
    

    In this case, you can define the endpoints as much as you want. For example, for your routes, you can write like this:

    endpoints.MapControllerRoute(
         name: "default",
         pattern: "{content}/{id?}/{id?}/{banana}"
    );
    

    Or you can use Attribute Routing that you can use for each of your controllers. read more about that in

    sorry for my English🙏

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search