2

I have two controllers in my application. One is an api controller, the other one a mvc controller. My routes are like this:

api: /api/account/login

mvc: /account/login

My controllers:

[ApiController]
[Route("api/[controller]")]
public class AccountController : ControllerBase
{
    private readonly IMediator _mediator;

    public AccountController(
        IMediator mediator)
    {
        _mediator = mediator;
    }

    [HttpPost("login")]
    public async Task<AuthenticationResultViewModel> Login(LoginRequest loginData, CancellationToken cancellationToken) 
        => await _mediator.Send(loginData, cancellationToken);
}

// this one's in a different namespace
[Route("[controller]")]
public class AccountController : Controller
{
    private readonly IMediator _mediator;

    public AccountController(
        IMediator mediator)
    {
        _mediator = mediator;
    }

    [HttpGet("login")]
    public IActionResult Login([FromQuery] string r)
        => View();

    [HttpPost("login")]
    public async Task<IActionResult> Login([FromQuery] string r, [FromForm] LoginRequest login, CancellationToken cancellationToken)
    {
        await _mediator.Send(login, cancellationToken);

        if (!string.IsNullOrWhiteSpace(r))
            return Redirect(r);
        
        return RedirectToAction("Index", "Home");
    }
}

My ServiceCollection:

//...
services.Configure<RouteOptions>(options => options.LowercaseUrls = true);
services.AddControllersWithViews()
//...

My pipeline is this:

app.UseResponseCaching();
app.UseResponseCompression();

app.UseCors();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

// here i tried defining my routes 
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
    // I have tried the following without success
    // I'm actually lost :'(
    //endpoints.MapControllerRoute("mvc", "{controller}/{action}/{id?}", new { controller = "Home", action = "Index" });
    //endpoints.MapControllerRoute("api", "api/{controller}/{action}/{id?}");
});

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.All,
    RequireHeaderSymmetry = false
});

Now my actual problem:

When I use the UrlHelper in my view it always returns the api route!

<form action="@Url.Action("Login", "Account")" method="post">
    <div class="form-group">
        <input asp-for="Username" type="text" placeholder="Username" />
    </div>
    <div class="form-group">
        <input asp-for="Password" type="password" placeholder="Password"/>
    </div>
    <div class="form-group">
        <button type="submit">Login</button>
    </div>
</form>

@Url.Action("Login", "Account") => /api/account/login

  • Why does this happen?
  • How can I make the UrlHelper return my MVC route in my views?
cmxl
  • 663
  • 12
  • 24
  • Some interesting answers on maybe not the problem you are having but quite similar topic https://stackoverflow.com/q/56074002/8065832 – Prolog Jul 10 '20 at 18:27
  • Could try making both controllers, different names, and see what happens, also try adding services.AddControllers(); – rizu Jul 10 '20 at 18:32
  • I think it just finds first matching route. – apocalypse Jul 10 '20 at 18:32
  • @apocalypse yep, but does someone know a way to force mvc routes in a view via the urlhelper, or should i then implement my own one? :< i was a bit confused at first. renaming the controllers fixes the problem, but the routes need to be like this :/ – cmxl Jul 10 '20 at 18:45
  • Hmm maybe add "route name" to Route attribute. Then use tag helpers in form. Like
    – apocalypse Jul 10 '20 at 19:07

1 Answers1

1

@Url.Action("Login", "Account") => /api/account/login

Why does this happen? How can I make the UrlHelper return my MVC route in my views?

It seems that by using the Url.Action method, it will auto using the API routing, instead of the MVC routing.

To make the UrlHelper return the MVC view, you could use the Url.RouteUrl() method to assign the route Name, or using Url.Content() to set the correct URL. Code as below:

  1. Using the Url.RouteUrl() method:

     <form action="@Url.RouteUrl("defaultmvc", new { controller="Account", action = "Login" })" method="post">
    

    Code in the StartUp.cs:

         app.UseEndpoints(endpoints =>
         {
             endpoints.MapControllerRoute(
                 name: "defaultmvc",
                 pattern: "{controller=Home}/{action=Index}/{id?}"); 
         });
    
  2. Using the Url.Content() method:

       <form action="@Url.Content("~/Account/login")" method="post">
    

Then, the html resource as below:

       <form action="/Account/login" method="post">
            ...
        </form>
Zhi Lv
  • 18,845
  • 1
  • 19
  • 30