Bubinga
Bubinga

Reputation: 703

How to connect a Controller to a Page in Razor Pages

I am trying to add Identity to my website and I have a controller that is currently just supposed to add a user to the database when they hit the register button on my register form whose URL is (localhost:44369/Account/Register). My issue is that I don't think that it is actually using the controller. I think it might be an issue with routing or endpoints, but I'm not sure. Here is my controller:

namespace ThinBlueLie.Controllers
{
    public class AccountController : Controller
    {
        private readonly UserManager<IdentityUser> userManager;
        private readonly SignInManager<IdentityUser> signInManager;

        public AccountController(UserManager<IdentityUser> userManager,
                                 SignInManager<IdentityUser> signInManager)
        {
            this.userManager = userManager;
            this.signInManager = signInManager;
        }

        [HttpGet]
        public IActionResult Register()
        {            
            return View();
        }
        [HttpPost]
        public async Task<IActionResult> Register(RegisterModel model)
        {
            var errors = ModelState.Values.SelectMany(v => v.Errors);
            if (ModelState.IsValid)
            {
                var user = new IdentityUser {UserName = model.Username, Email = model.Email};
                var result = await userManager.CreateAsync(user, model.Password);

                if (result.Succeeded)
                {
                    await signInManager.SignInAsync(user, isPersistent: false); //change isPersistent to true later
                    return RedirectToPage("./Index");
                }
                foreach (var error in result.Errors)
                {
                    ModelState.AddModelError("", error.Description);
                }
            }
            return View(model);
        }
    }
}

Here is my startup:

namespace ThinBlueLie
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {            
            services.AddDbContext<ThinbluelieContext>(options =>
            {
                options.UseMySql(Configuration.GetConnectionString("DefaultConnection"));
            });

            services.AddIdentity<IdentityUser, IdentityRole>()
                .AddEntityFrameworkStores<ThinbluelieContext>()
                .AddDefaultTokenProviders();

            services.AddMvc();
            services.AddControllersWithViews();
            services.AddRazorPages()
                .AddRazorRuntimeCompilation();

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseBrowserLink();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();


            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();
            //app.UseMvc(routes =>
            //{
            //    routes.MapRoute("default", "controller=Home}/{action=Index}/{id?}");
            //});
            
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapDefaultControllerRoute();
                endpoints.MapRazorPages();
            });
        }
    }
}

And here is my page:

@page
@model ThinBlueLie.Pages.RegisterModel

<div class="container-fluid h-100 row nogap">
    <div class="card border-secondary mx-auto center col-lg-3 col-md-4 p-0" style="margin-top:100px;">
        <div class="card-header">
            Register
            <a class="float-right" asp-page="/Login">Login</a>
        </div>
        <form asp-action="Register" asp-controller="Account" method="post">
            <div class="card-body text-secondary">
                <div asp-validation-summary="All" class="text-danger"></div>
                <div class="form-group">
                    <label asp-for="Email" class="control-label">Email</label>
                    <input asp-for="Email" class="form-control">
                    <span asp-validation-for="Email" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label  asp-for="Password"class="control-label"></label>
                    <input asp-for="Password" class="form-control" >
                    <span asp-validation-for="Password" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="ConfirmPassword" class="control-label"></label>
                    <input asp-for="ConfirmPassword" class="form-control">
                    <span asp-validation-for="ConfirmPassword" class="text-danger"></span>
                </div>                      
                <div class="form-group">
                    <label asp-for="Username" class="control-label"></label>
                    <input type="text" asp-for="Username" class="form-control">
                    <span asp-validation-for="Username" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <input type="submit" value="Register" class="btn btn-primary mb-1" style="float:right" />
                </div>
            </div>
        </form>
        <div class="card-footer">
            <a>Log in with Google</a>
        </div>
    </div>
</div>

@section Scripts {
        @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
    }

And finally my Model:

namespace ThinBlueLie.Pages
{
    public class RegisterModel : PageModel
    {
        
        [Required]
        [EmailAddress]
        public string Email { get; set; }
        
        [Required]
        [DataType(DataType.Password)]
        public string Password { get; set; }

        [Required]
        [DataType(DataType.Password)]
        [Display(Name = "Confirm Password")]
        [Compare("Password", ErrorMessage = "Passwords don't match.")]
        public string ConfirmPassword { get; set; }
        
        [Required]
        public string  Username { get; set; }
       
    }
}

Upvotes: 3

Views: 3926

Answers (1)

Michael Wang
Michael Wang

Reputation: 4022

Bubinga, it is using endpoints routing to navigate your url path to controller.

Routing is responsible for matching incoming HTTP requests. Net Core 3.1 uses endpoints route to decouple the route matching and resolution functionality from the endpoint dispatching functionality.

enter image description here

In conclusion, the request path(/Account/Register) matches AccountController/RegisterAction. When the action has been executed, it will redirect to View(same name with your action if not reassign) with Model finally.

You can learn the fundamentals of routing from here.

You can learn routing of MVC from here.

Upvotes: 1

Related Questions