skip to Main Content

I’m trying to create SEO friendly URL’s using .NET 6 and Razor Pages (not MVC). From a razor page view:

<a asp-page="/Post" asp-route-id="9">Test Link</a>

I link to a corresponding page handler:

[BindProperty]
public PostViewModel? Post { get; set; }

public async Task<IActionResult> OnGetAsync(int id)
{
    Post = new PostViewModel();
    Post = await _postService.GetPostAsync(id);

    return Page();
}

The page handler will fetch the post by the id parameter. In the page model PostViewModel there are properties for Category, Topic, and UrlTitle. I would like to use these properties to generate an SEO friendly URL, like:

https:/wwww.mysite.com/post/{id}/{category}/{topic}/{urltitle}

I’m not sure how to get these property values to the URL?

3

Answers


  1. Try this code:

    In a Razor Page View:

    <a asp-page="/Post" asp-route-id="@Post.Id" asp-route-category="@Post.Category" asp-route-topic="@Post.Topic" asp-route-urltitle="@Post.UrlTitle">Test Link</a>
    

    Update the OnGetAsync method to accept these additional route parameters:

    public async Task<IActionResult> OnGetAsync(int id, string category, string topic, string urltitle)
    {
        Post = new PostViewModel();
        Post = await _postService.GetPostAsync(id);
    
        if (category != Post.Category || topic != Post.Topic || urltitle != Post.UrlTitle)
        {
            return NotFound();
        }
    
        return Page();
    }
    

    And go to the Configure method of the Startup class using the endpoints.MapRazorPages method:

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapControllerRoute(
            name: "post",
            pattern: "/post/{id}/{category}/{topic}/{urltitle}",
            defaults: new { controller = "Post", action = "Index" }
        );
    });
    

    Here, the pattern parameter specifies the URL pattern to match, and the defaults parameter specifies the default controller and action to use for this route. You will also need to create a corresponding PostController with an Index action to handle the request.

    Login or Signup to reply.
  2. At the top of your post page (.cshtml file) add:

    @page "{id}/{category}/{topic}/{urltitle}"
    

    In your home page model (.cshtml.cs file) add:

    public List<PostViewModel> Posts { get; set; }
    
    public async Task<IActionResult> OnGetAsync()
    {
        Posts = await _postService.GetPostsAsync();
    
        return Page();
    }
    

    and then in your home page create the links using:

    @foreach (var post in Model.Posts)
    {
        <a asp-page="/Post"
           asp-route-id="@post.Id"
           asp-route-category="@post.Category"
           asp-route-topic="@post.Topic"
           asp-route-urltitle="@post.UrlTitle">@post.Description</a>
    }
    

    Check Route Templates

    Login or Signup to reply.
  3. In Asp.net core Razor page, to set the Friendly URLs, we could override routes template via the @page directive in the .cshtml page, like this:

    @page "/Post/{id?}/{category?}/{topic?}/{urlTitle?}"
    

    Or, we can configure the razor page convention like this:

    builder.Services
        .AddRazorPages()
        .AddRazorPagesOptions(options =>
        {
            options.Conventions.AddPageRoute("/Post", "Post/{id?}/{category?}/{topic?}/{urlTitle?}");
        });
    

    The first time the method is hit, just the id exists. It then
    populates the view model, but when it hits the method the second time,
    only the id, category, topic & urltitle properties are populated but
    the rest are empty?

    After that, in the Index page, you can use the following hyperlink to access the Get handler:

    @*href ="/Post/9"*@
    <a asp-page="/Post" asp-route-id="9">Test Link</a>
    
    @*href ="/Post/9/C1/T1/U1"*@
    <a asp-page="/Post" asp-route-id="9" asp-route-category="C1" asp-route-topic="T1" asp-route-urltitle="U1">Test Link</a>
    

    For the category, topic or urltitle parameters, if you want to edit them using textbox, you can use JavaScript to build the request url based on the parameters. code like this:

    @page "/Post/{id?}/{category?}/{topic?}/{urlTitle?}"
    @model RazorWebApp.Pages.PostModel
    @*<a asp-page="/Post" asp-route-id="9">Test Link</a>*@
    
    <h2>Test Post page</h2>
    
    
    <form method="get" asp-route-id="@Model?.Post?.Id">
        <p>
            <input type="hidden" id="txtId" asp-for="Post.Id" />
            Category: <input type="text" id="txtcategory" asp-for="Post.Category"  />
            Topic: <input type="text" id="txttopic" asp-for="Post.Topic"  />
            Url Title: <input type="text" id="txturltitle" asp-for="Post.UrlTitle"/>
    
            <input type="submit" value="Test Link (Submit Button)" />
    
    
            <a asp-page="/Post" asp-route-id="@Model?.Post?.Id" 
            asp-route-category="@Model?.Post?.Category" 
            asp-route-topic="@Model?.Post?.Topic" 
            asp-route-urltitle="@Model?.Post?.UrlTitle"
            onclick="return HyperLinkClick(this);"
            >Test Link (Hyperlink)</a>
        </p>
    </form>
    
    @section Scripts{
       <script>
            function HyperLinkClick(e) {
               event.preventDefault();
                var id = document.getElementById("txtId").value === "" ? "null" : parseInt(document.getElementById("txtId").value);
                var category = document.getElementById("txtcategory").value === "" ? "null" : document.getElementById("txtcategory").value;
                var topic = document.getElementById("txttopic").value === "" ? "null" : document.getElementById("txttopic").value;
                var urltitle = document.getElementById("txturltitle").value === "" ? "null" : document.getElementById("txturltitle").value;
    
                if (category != "null" && topic != "null" && urltitle != "null"){ 
                    window.location.href = "/Post/"+ id + "/" + category + "/" + topic + "/" + urltitle;
                }
           }
       </script> 
    }
    

    The result as below:

    enter image description here

    Update

    The category, topic and urltitle values are stored in a database not
    as user input forms

    In this scenario, you can modify the Post page code as below:

    public class PostModel : PageModel
    {
        //[BindProperty]
        [BindProperty(SupportsGet = true)]
        public PostViewModel? Post { get; set; }
    
        public async Task<IActionResult> OnGetAsync(int id)
        {
    
            //find the post based on the id.
            if (id==9)
            {
                //Post = await _postService.GetPostAsync(id);
                Post = new PostViewModel() { 
                    Id = id, Category="C1", 
                    Topic="T1", UrlTitle="U1" };
            }
    
            return Page();
        }
    }
    

    Post.cshtml page:

    @page "/Post/{id?}/{category?}/{topic?}/{urlTitle?}"
    @model RazorWebApp.Pages.PostModel
    @*<a asp-page="/Post" asp-route-id="9">Test Link</a>*@
    
    <h2>Test Post page</h2>
    
    <a asp-page="/Post" asp-route-id="@Model?.Post?.Id"
       asp-route-category="@Model?.Post?.Category"
       asp-route-topic="@Model?.Post?.Topic"
       asp-route-urltitle="@Model?.Post?.UrlTitle"
       onclick="return HyperLinkClick(this);">Test Link (Hyperlink)</a>
    

    Then, the result as below: please pay attention to the url of the hyperlink in the lower-left corner.

    enter image description here

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