0

I have a page with 2 buttons each one with their handler methods (OnPostAsync and OnPostResend) and 2 properties (LoginType and DocumentNumber) when OnPostAsync is called, properties have their values and the method works as expected but when the second button is clicked and OnPostResend is called properties are set to null. Why is this happenning and how can I prevent it?

This is the .cshtml file:

@page
@model SATCloudWebApp.Areas.Identity.Pages.Account.EnterOtpModel
@{
    ViewData["Title"] = $"Ingrese el código de confirmación";
    string device = TempData["PhoneNumber"]
    }
    
}
    <h2>@ViewData["Title"]</h2>
    
    <div class="row">
        <div class="col-md-6">
            <h4>Por favor digite el código enviado a su @device. </h4>
            <form method="post">
                <div asp-validation-summary="All" class="text-danger"></div>
                <div class="form-group">
                    <label asp-for="Input.OtpCode"></label>
                    <input asp-for="Input.OtpCode" class="form-control" />
                    <span asp-validation-for="Input.OtpCode" class="text-danger"></span>
                </div>
                <button type="submit" class="btn btn-info">Siguiente</button>
            </form>
            
            <href>
                <form asp-page-handler="resend" method="post">
                    <button id="resendToken" type="submit" class="btn btn-dark">Reenviar código</button>
                </form>
            </href>
        </div>
    
    </div>

This is the page model:

namespace Name
{
    [AllowAnonymous]
    public class EnterOtpModel : PageModel
    {
        // constructor goes here ...

        [BindProperty]
        public string LoginType { get; set; }

        [BindProperty]
        public string DocumentNumber { get; set; }

        [BindProperty]
        public InputModel Input { get; set; }

        public class InputModel
        {
            [Required(ErrorMessage = "Ingrese el código enviado.")]
            [Display(Name = "Código de inicio de sesión")]
            public string OtpCode { get; set; }

        }


        public IActionResult OnGet(string loginType, string documentNumber)
        {
            if (User.Identity.IsAuthenticated)
            {
                return RedirectToPage("~/LoginWithOtp");
            }
            else
            {
                LoginType = loginType;
                List<SATCloudUser> _users = new List<SATCloudUser>();
                _users = _userManager.Users.Where(x => x.DocumentNumber == documentNumber).ToList();
                SATCloudUser _satUser = _users[0];
                TempData["Username"] = _satUser.Email;
                TempData["PhoneNumber"] = _satUser.PhoneNumber;
                return Page();
            }
        }

        public async Task<IActionResult> OnPostAsync(string returnUrl = null)
        {
            List<SATCloudUser> _users = new List<SATCloudUser>();
            _users = _userManager.Users.Where(x => x.DocumentNumber == DocumentNumber).ToList();
            SATCloudUser _satUser = _users[0];
            if (ModelState.IsValid)
            {
                var result = await _userManager.VerifyTwoFactorTokenAsync(_satUser, "Email", Input.OtpCode);
                if (result)
                {   
                    returnUrl = returnUrl ?? Url.Content("~/Home/Index");
                    var auth = await HttpContext.AuthenticateAsync(IdentityConstants.ApplicationScheme);
                    var authenticationMethod = auth?.Principal?.FindFirstValue(ClaimTypes.AuthenticationMethod);
                    await _signInManager.SignInAsync(_satUser, false, authenticationMethod);
                    return LocalRedirect(returnUrl);
                }
                else
                {
                    TempData["Username"] = _satUser.Email;
                    TempData["PhoneNumber"] = _satUser.PhoneNumber;
                    TempData["messageEnterOtp"] = "InvalidToken";
                    return Page();

                }
            }
            else
            {
                return Page();
            }
        }

        public async void OnPostResendAsync()
        {
            List<SATCloudUser> _users = new List<SATCloudUser>();
            _users = _userManager.Users.Where(x => x.DocumentNumber == DocumentNumber).ToList();
            SATCloudUser _satUser = _users[0];
            var token = await _userManager.GenerateTwoFactorTokenAsync(_satUser, "Email");
            if(LoginType == "sms")
            {
                AlertsManager _alertManager = new AlertsManager();
                string phoneNumber = "+57" + _satUser.PhoneNumber;
                string message = $"Código de inicio de sesión en Better Together SE: {token}. Por favor no comparta este código.";
                await _alertManager.SendTextMessageAsync(phoneNumber, message);
            }
            else if(LoginType == "email")
            {
                EmailManager _emailManager = new EmailManager();
                await _emailManager.NewTokenEmail(_satUser.Email, token);
            }
        }
    }
}
Luz Vera
  • 1
  • 2

1 Answers1

0

A new instance of the EnterOtpModel class is created for each request. So the state of its properties is not preserved between different requests. You can add hidden input elements inside the resend form so that LoginType and DocumentNumber are re-sent again to the EnterOtpModel.

<form asp-page-handler="resend" method="post">
    <input type="hidden" asp-for="LoginType" />
    <input type="hidden" asp-for="DocumentNumber" />
    <button id="resendToken" type="submit" class="btn btn-dark">Reenviar código</button>
</form>
Dimitris Maragkos
  • 8,932
  • 2
  • 8
  • 26
  • You might also find this question useful: https://stackoverflow.com/questions/61189482/why-does-html-submit-form-re-instantiate-pagemodel-in-asp-net-core – Dimitris Maragkos Sep 26 '22 at 15:31