为什么值在回发中不持久?

时间:2019-04-23 16:05:03

标签: c# asp.net-core razor-pages asp.net-core-identity

我的主页上有一个产品选项列表,每个选项都为用户提供了不同的注册帐户级别。每个选项都会显示一个“注册”按钮,该按钮会将用户带到/Identity/Account/Register页进行注册。

我需要向“注册”页面传达用户选择的选项。

  1. 我无法使用会话,因为它显然已被删除
  2. 我无法使用Cookie,因为它显然已经被拿走了
  3. 提交表单时,ViewData值不会保留
  4. 我提交表单时查询字符串值不持久
  5. 提交表单时,全局变量值不会保留
  6. 最初加载页面时,我无法设置viewmodel的属性(NullReferenceException)

加载“注册”页面时,该值在那里,但是当我提交表单时,它消失了。

我很茫然。我是通过什么机制来传达这些必需信息的?

在大多数情况下,我的代码几乎只是标准样板内容:

[AllowAnonymous]
public class RegisterModel : PageModel
{
    private readonly SignInManager<ApplicationUser> _signInManager;
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly ILogger<RegisterModel> _logger;
    private readonly IEmailSender _emailSender;

    public RegisterModel(
        UserManager<ApplicationUser> userManager,
        SignInManager<ApplicationUser> signInManager,
        ILogger<RegisterModel> logger,
        IEmailSender emailSender)
    {
        _userManager = userManager;
        _signInManager = signInManager ?? throw new ArgumentNullException(nameof(signInManager));
        _logger = logger;
        _emailSender = emailSender;
    }

    [BindProperty]
    public InputModel Input { get; set; }
    [BindProperty]
    public int AccountLevel { get; set; }
    public string ReturnUrl { get; set; }

    public void OnGet(string returnUrl = null, int acclevel = 1)
    {
        AccountLevel = acclevel;
        ReturnUrl = returnUrl;
    }

    public async Task<IActionResult> OnPostAsync(string returnUrl = null, int acclevel = 0)
    {
        returnUrl = returnUrl ?? Url.Content("~/");

        if (ModelState.IsValid)
        {
            if (acclevel == 0) throw new ArgumentException(nameof(acclevel));

            Input.LicenseCount = acclevel * 10;

            var user = new ApplicationUser { UserName = Input.Email, Email = Input.Email, Name = Input.FirstName, Surname = Input.Surname, PhoneNumber = Input.PhoneNumber, SaIdNumber = Input.IdNumber, LicensesCount = Input.LicenseCount };

            var result = await _userManager.CreateAsync(user, Input.Password);
            await _userManager.AddToRoleAsync(user, nameof(SystemRoles.AppUser));
            if (result.Succeeded)
            {
                _logger.LogInformation("User created a new account with password.");

                var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                var callbackUrl = Url.Page(
                    "/Account/ConfirmEmail",
                    pageHandler: null,
                    values: new { userId = user.Id, code = code },
                    protocol: Request.Scheme);

                await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                    $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");

                //await _signInManager.SignInAsync(user, isPersistent: false);
                return LocalRedirect(returnUrl);
            }
            foreach (var error in result.Errors)
            {
                ModelState.AddModelError(string.Empty, error.Description);
            }
        }

        // If we got this far, something failed, redisplay form
        return Page();
    }
}

这是Page(出于某种原因,它使用PageModel而不是Views和Controllers,而是出于某种原因使用PageModel-当我添加Identity时,它采用这种方式)。

@page
@model RegisterModel
@{
    ViewData["Title"] = "Register";
}

<h1>@ViewData["Title"]</h1>

<div class="row">
    <div class="col-md-4">
        <form asp-route-returnUrl="@Model.ReturnUrl" method="post">
            <h4>Create a new account.</h4>
            <hr />
            <div asp-validation-summary="All" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Input.FirstName"></label>
                <input asp-for="Input.FirstName" class="form-control" />
                <span asp-validation-for="Input.FirstName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Input.Surname"></label>
                <input asp-for="Input.Surname" class="form-control" />
                <span asp-validation-for="Input.Surname" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Input.PhoneNumber"></label>
                <input asp-for="Input.PhoneNumber" class="form-control" />
                <span asp-validation-for="Input.PhoneNumber" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Input.IdNumber"></label>
                <input asp-for="Input.IdNumber" class="form-control" />
                <span asp-validation-for="Input.IdNumber" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Input.Email"></label>
                <input asp-for="Input.Email" class="form-control" />
                <span asp-validation-for="Input.Email" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Input.Password"></label>
                <input asp-for="Input.Password" class="form-control" />
                <span asp-validation-for="Input.Password" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Input.ConfirmPassword"></label>
                <input asp-for="Input.ConfirmPassword" class="form-control" />
                <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
            </div>
            <button type="submit" class="btn btn-primary">Register</button>
        </form>
    </div>
</div>

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

2 个答案:

答案 0 :(得分:1)

注意:我不使用Razor Pages,因此了解该技术的人可能会得到更好的答案。

您可以在表单中使用隐藏字段以将值保留在POST-back上:

<form asp-route-returnUrl="@Model.ReturnUrl" method="post">
    @Html.HiddenFor(model => model.AccountLevel)
    @*OR, TagHelper way*@
    <input asp-for="AccountLevel" type="hidden"/>
    <h4>Create a new account.</h4>
    ....
</form>

使用会话after you enable them也很容易做到:

public void OnGet(string returnUrl = null, int acclevel = 1)
{
    HttpContext.Session.SetInt32("AccountLevel", acclevel);
    ReturnUrl = returnUrl;
}

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    int accountLevel = HttpContext.Session.GetInt32("AccountLevel");
    ...
}

答案 1 :(得分:0)

请求后唯一存在的数据是随请求一起发送的数据。即使在会话的情况下,客户端也必须在请求中将关键会话标识符传输到服务器,以恢复该会话。

您从数据库中检索到的任何数据都必须发布或再次查询。此外,不应发布任何数据,明确禁止用户更改。因此,应再次查询大多数数据。

对于用户选择的选项,应该将其张贴。但是,应该通过再次查询该数据库来获取所选计划和其他计划选项的实际详细信息。例如,如果由于验证错误而需要在帖子后重新显示表单,这将是必需的。