首页 > 解决方案 > 为什么 ComplexTypeModelBinder 无法创建自动生成的 RegisterModel 实例?

问题描述

我正在根据 OWIN 规范 MVC 架构在 asp.net 核心上编写应用程序。使用 Visual Studio 的 UI 配置用户身份。做了一些更改,尝试注册用户,尝试注册用户后出现这样的错误:InvalidOperationException: Could not create an instance of type 'Forum.Areas.Identity.Pages.Account.RegisterModel'. Model bound complex types must not be abstract or value types and must have a parameterless constructor. Alternatively, give the 'model' parameter a non-null default value.

启动.cs

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.AddIdentity<ForumUser, ForumRole>(options => options.SignIn.RequireConfirmedAccount = true)
                .AddEntityFrameworkStores<ApplicationDbContext>();
            services.AddControllersWithViews();
            services.AddRazorPages();

            // other services configuration (MVC, Localization, EmailSending ...)
        }

        // 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.UseDatabaseErrorPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/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();

            // Localization, endpoints ...
        }
    }

ForumUserandForumRole是空端继承自IdentityUserand IdentityRole。我的RegisterModel

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

public RegisterModel(
    UserManager<ForumUser> userManager,
    SignInManager<ForumUser> signInManager,
    ILogger<RegisterModel> logger,
    IEmailSender emailSender)
{
    _userManager = userManager;
    _signInManager = signInManager;
    _logger = logger;
    _emailSender = emailSender;
}

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

public string ReturnUrl { get; set; }

public IList<AuthenticationScheme> ExternalLogins { get; set; }

public class InputModel
{
    [Required]
    [EmailAddress]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [Required]
    [Display(Name = "Username")]
    public string Username { get; set; }

    [Required]
    [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }
}

public async Task OnGetAsync(string returnUrl = null)
{
    ReturnUrl = returnUrl;
    ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
}

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    // Sending email confirmation
    return Page();
}
}

Register看法

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

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

<div class="row">
    <div class="col-md-4">
        <form asp-controller="Account" asp-action="Register"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.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.Username"></label>
                <input asp-for="Input.Username" class="form-control" />
                <span asp-validation-for="Input.Username" 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" />
}

有人可以告诉我为什么 ComplexTypeModelBinder 无法创建自动生成的(以及一些由我修改的)RegisterModel 的实例吗?我试图将 RegisterModel 回滚到其原始状态,但错误仍然存​​在。

标签: c#asp.net-coreasp.net-identity

解决方案


解决方案:我只是将方法的签名更改public async Task<IActionResult> Register(RegisterModel model, IEmailSender emailSender)public async Task<IActionResult> Register(RegisterModel.InputModel input)(将参数类型更改RegisterModelRegisterModel.InputModel并移至IEmailSender构造函数(因为它抛出了相同的异常)。所以问题解决了,但我仍然不知道为什么这个异常(Model bound complex types must not be abstract or value types and must have a parameterless constructor对于两者RegisterModelIEmailSender)都飞了. 有一个选项可以创建我自己的(自定义)数据绑定器,但我认为这是一个糟糕且有点拐杖的解决方案。


推荐阅读