当你加载一个像这样的部分时:
@await Html.PartialAsync("Account/Login")
您从中调用它的视图模型是隐式传入的,就像您已经完成一样:
@await Html.PartialAsync("Account/Login", Model)
因此,您收到的错误。部分需要LoginModel 类型的模型,但您传递给它的是IndexModel 类型的模型。解决方案当然是传入正确类型的模型,即LoginModel。但是,您的LoginModel 必须使用SignInManager<ApplicationUser> 和ILogger<LoginModel 类型的参数构造。因此,为什么您在尝试仅传递 new LoginModel() 时收到第二个错误。
首先,所有这一切实际上归结为对部分的不当使用。需要这种复杂实例化的部分实际上应该是view component,这将为您提供更多的设置灵活性并且允许您进行注入,这就是您需要的在这里。
本质上,您只需创建一个继承自ViewComponent 并实现方法InvokeAsync 的类:
public class LoginViewComponent : ViewComponent
{
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly ILogger<LoginModel> _logger;
public LoginViewComponent(SignInManager<ApplicationUser> signInManager, ILogger<LoginModel> logger)
{
_signInManager = signInManager;
_logger = logger;
}
public async Task<IViewComponentResult> InvokeAsync()
{
var model = await GetModelAsync().ConfigureAwait(false);
return View(model);
}
public Task<LoginModel> GetModelAsync()
{
return Task.FromResult(new LoginModel(_signInManager, _logger));
}
}
请注意,视图组件的构造函数采用实例化LoginModel 所需的参数。这允许框架注入这些依赖项。然后,构造函数只是将这些存储在一些私有字段中。
InvokeAsync 方法调用GetModelAsync 来获取LoginModel 实例,然后返回一个使用该模型的视图。因为这里不需要做任何实际的异步工作,所以GetModelAsync 方法只返回一个Task,它是根据更新LoginModel 的结果创建的。必须这样做以满足Task-returning InvokeAsync 的性质。如果你真的需要异步的东西,你可以在这里简单地等待。
有了这些,您只需要创建视图Views\Shared\Components\Login\Default.cshtml。这将包含您当前正在使用的部分视图的内容。 Login\Default.cshtml 部分是按照惯例。该目录是视图组件类的名称,减去ViewComponent 后缀,Default.cshtml 是它将在那里查找的默认视图。如果您愿意,这可以自定义,但实际上没有理由这样做。
最后,在您希望它出现的地方,您只需调用:
@await Component.InvokeAsync("Login");
使用 is 方法,所有功能(包括模型的创建和传入)都是自包含的,因此可以在任何地方调用它,无论是在单独的视图中,还是在您的布局中.