Home > OS >  ASP.NET MVC : controller does not redirect to another page
ASP.NET MVC : controller does not redirect to another page

Time:11-01

I have a Blazor Server that has a local controller for authentication on the same project. I want to sign-in users through this controller and then redirect to homepage or previous page.

However, the Redirect("~/") function on the local controller does not seem to work. I tried with different urls including external urls but no success. I tried to solve it many times but was not able. Any help will be appreciated.

Login submit:

result = await httpClient.PostAsJsonAsync("Account/Login", loginParameters);

Controller:

public class AccountController : Controller
{
    [HttpPost]
    public async Task<IActionResult> Login([FromBody]LoginParameters loginParameters)
    {
        string userName = loginParameters.UserName;
        string password = loginParameters.Password;
        string redirectUrl = loginParameters.RedirectUrl;
            
        if (env.EnvironmentName == "Development" && userName == "admin" && password == "admin")
        {
            var claims = new List<Claim>
            {
                new(ClaimTypes.Name, "admin"),
                new(ClaimTypes.Email, "admin")
            };
            roleManager.Roles.ToList().ForEach(r => claims.Add(new Claim(ClaimTypes.Role, r.Name)));
            await signInManager.SignInWithClaimsAsync(new ApplicationUser { UserName = userName, Email = userName }, false, claims);

            //return Redirect("https://localhost:5001/");
            //return Redirect("https://www.google.com/");
            return Redirect($"~/{redirectUrl}");
        }

        // More stuff
    }
}

Program.cs:

builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped(serviceProvider =>
{
    var uriHelper = serviceProvider.GetRequiredService<NavigationManager>();
    return new HttpClient { BaseAddress = new Uri(uriHelper.BaseUri) };
});
builder.Services.AddHttpClient();

//...
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
    app.Use((ctx, next) =>
    {
        ctx.Request.Scheme = "https";
        return next();
    });
}
else
    app.UseDeveloperExceptionPage();

app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute("default","{controller=Home}/{action=Index}/{id?}");
    endpoints.MapControllers();
    endpoints.MapBlazorHub();
    endpoints.MapFallbackToPage("/_Host");
});

app.Run();

Problem:

Animation cannot redirect from controller

CodePudding user response:

In what context are you calling your Account/Login endpoint from the client?
I'm not certain this is the case, but I imagine Blazor prevents automatic redirects as to not lose navigation state, as Blazor navigation is not handled in the conventional way (the entire site is essentially one page).

You could simply make your request to Account/Login, grab the Location header from the result, and then explicilty navigate to that URI using the injected NavigationManager. This, however, begs the question whether your backend API should be responsible for determining where to send the user (in this case some home-page). Since the user never leaves the Blazor app, something like this should suffice:

@inject NavigationManager UriHelper
...
loginResult = await httpClient.PostAsJsonAsync("Account/Login", loginParameters);
if (loginResult.IsSuccessStatusCode) // API should return 200 OK on login success
    UriHelper.NavigateTo("home");
else
  // Do something else
   

CodePudding user response:

I went back to using Radzen login component because I wanted to switch to MudBlazor but it seems calling the PostAsJsonAsync on a local controller doesn't redirect to homepage or any page.

By redirecting using the NavigationManager on front-end after returning post result does not solve the issue it does not somehow get the signing state of the user.

Therefore, went back to my original code which worked but will prefer if anyone has another solution instead.

Login:

<RadzenContent Container="main">
  <ChildContent>
    <RadzenHeading Size="H1" Text="Login">
    </RadzenHeading>
    <div >
      <div >
        <RadzenTemplateForm Action="account/login" Data="@("login")" Method="post">
          <ChildContent>
            <RadzenLogin Register="@LoginRegister" ResetPassword="@LoginResetPassword">
            </RadzenLogin>
          </ChildContent>
        </RadzenTemplateForm>
      </div>
    </div>
  </ChildContent>
</RadzenContent>

Controller:

public async Task<IActionResult> Login(string userName, string password, string redirectUrl)
{
    if (env.EnvironmentName == "Development" && userName == "admin" && password == "admin")
    {
        var claims = new List<Claim>()
        {
            new Claim(ClaimTypes.Name, "admin"),
            new Claim(ClaimTypes.Email, "admin")
        };

        roleManager.Roles.ToList().ForEach(r => claims.Add(new Claim(ClaimTypes.Role, r.Name)));
        await signInManager.SignInWithClaimsAsync(new ApplicationUser { UserName = userName, Email = userName }, isPersistent: false, claims);

        return Redirect($"~/{redirectUrl}");
    }
    
    //...
}
  • Related