Mehdi
Mehdi

Reputation: 598

Custom route and action names in asp.net core mvc

I'm working on an Asp.Net Core 3.1 MVC project and want to change some controllers and actions name in url. Almost all of answers is related to .net core API or mvc (without .net core) but I want to do it in Asp.Net Core Mvc application.

For example, The controller:

public class ProductCategoriesController : Controller
{

    private readonly DBContext _context;

    public async Task<IActionResult> Details(int? id)
    {
        // Some Codes ...
    }
}

What I want to do is when I call the action "Details", the url goes to be like (http://domain/product-category/power-tools) which "power tools" is one of categories but as common in Asp.Net Core MVC it is (http://domain/ProductCategories/Details/1).

I tried to change controller prefix name and Action name but it doesn't work. I also tried to define new route endpoint in startup such as below but neither it works.

endpoints.MapControllerRoute(
    name: "category",
    pattern: "product-category/{*title}",
    defaults: new { controller = "ProductCategories", action = "Details" });

Is it possible to change action names and controller name without using Api controllers? How do I do that? Thanks

Upvotes: 2

Views: 8897

Answers (3)

gurkan
gurkan

Reputation: 1480

You should add the id parameter in the pattern too because of your action have a nullable parameter.

endpoints.MapControllerRoute(
                name: "category",
                pattern: "product-category/{title}/{id?}",
                defaults: new { controller = "ProductCategories", action = "Details" });

UPDATE: added a simple test screen

enter image description here

Upvotes: 1

Mehdi
Mehdi

Reputation: 598

The best solution for what I wanted to do was not depends on changing routes in startup. With special thanks to author of this article https://rehansaeed.com/seo-friendly-urls-asp-net-core/, I changed my action like this and it's done.

    [HttpGet("ProductCategory/{id}/{title}", Name = "ProductsRelatedToCategory")]
    public async Task<IActionResult> ProductsRelatedToCategory(int? id, string title)
    {
        if (id == null || !await _productCategoryRepo.IsExists((int)id))
        {
            return NotFound();
        }

        var langId = _languageRepository.GetByCode(LanguageCode).Result.Id;

        var productsRelatedToThisCategory = await _productRepo.GetByCategoryId((int)id, langId);
        var productCategory = await _productCategoryRepo.GetById((int)id);
        var allCategories = await _productCategoryRepo.GetAll(2);

        ViewData["ProductCategory"] = productCategory;
        ViewData["AllProductCategories"] = allCategories.ToList();

        string friendlyTitle = FriendlyUrlHelper.GetFriendlyTitle(productCategory.Title);

        if (!string.Equals(friendlyTitle, title, StringComparison.Ordinal))
        {
            return this.RedirectToRoutePermanent("ProductsRelatedToCategory", new { id = id, title = friendlyTitle });
        }

        return View("~/Views/Products/ProductsRelatedToCategory.cshtml", productsRelatedToThisCategory.ToList());
    }

And to call the action :

<a asp-action="ProductsRelatedToCategory" asp-controller="ProductCategories" asp-route-id="14" asp-route-title="Power Tools"><b>Power tools</b></a>

Upvotes: 3

AnGG
AnGG

Reputation: 821

Net .Core have a bit different style, try this, you may need also to update your Startup.cs

[Route("/productcategories/")]
public class ProductCategoriesController : Controller
{

    private readonly DBContext _context;

    [HttpGet("details/{id}")] // here the id is not optional but you can set it to be
    public async Task<IActionResult> Details(int id) // id
    {
        // Some Codes ...
    }
}

and add to Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<TodoContext>(opt =>
           opt.UseInMemoryDatabase("TodoList"));
        services.AddControllers();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseAuthorization();

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

Read more about Asp.Net Core 3.1 MVC conventions

https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-web-api?view=aspnetcore-3.1&tabs=visual-studio

Upvotes: 0

Related Questions