0

在我的主页(索引)页面上,如果用户未登录但如果用户已经登录,我希望登录表单直接位于我的主页中,但如果用户已经登录,则将显示索引页面。如果我使用_LoginPartial此页面按预期加载,但在文件夹中的其他页面(例如帐户)我收到错误

CSHTML:

@if (SignInManager.IsSignedIn(User))
{
    <p> Welcome to my website</p>
}
else
{
    @await Html.PartialAsync("Account/Login")
}

`InvalidOperationException:传递到 ViewDataDictionary 的模型项的类型为“CS.Pages.Manifest.IndexModel”,但此 ViewDataDictionary 实例需要“CS.Pages.Account.LoginModel”类型的模型项。

登录模型构造函数:

public LoginModel(SignInManager<ApplicationUser> signInManager, ILogger<LoginModel> logger)
{
    _signInManager = signInManager;
    _logger = logger;
}
4

2 回答 2

3

当您加载部分内容时:

@await Html.PartialAsync("Account/Login")

您从中调用它的视图模型是隐式传入的,就像您已经完成一样:

@await Html.PartialAsync("Account/Login", Model)

因此,您收到的错误。partial 需要一个 type 的模型,LoginModel但你传递给它一个 type 的模型IndexModel。解决方案当然是传入正确类型的模型,即LoginModel. 但是,您LoginModel 必须使用类型参数SignInManager<ApplicationUser>ILogger<LoginModel. 因此,为什么您在尝试通过时收到第二个错误new LoginModel()

首先,所有这一切实际上归结为对部分的不当使用。需要这种复杂实例化的部分实际上应该是一个视图组件,这将为您提供更多的设置灵活性允许您进行注入,这正是您在这里需要的。

本质上,您只需创建一个继承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从新 a 的结果中创建的 a LoginModel。必须这样做以满足Task-returning 的性质InvokeAsync。如果你真的需要异步的东西,你可以在这里简单地等待。

有了它,您只需要创建视图Views\Shared\Components\Login\Default.cshtml。这将包含您当前正在使用的部分视图的内容。这Login\Default.cshtml部分是按照惯例。该目录是视图组件类的名称,减去ViewComponent后缀,Default.cshtml是它将在那里查找的默认视图。如果您愿意,可以自定义,但实际上没有理由这样做。

最后,在您希望它出现的地方,您只需调用:

@await Component.InvokeAsync("Login");

使用 is 方法,所有功能(包括模型的创建和传入)都是独立的,因此可以在任何地方调用,无论是在单个视图中,甚至是您的布局中。

于 2017-11-09T14:08:01.513 回答
1

尝试将 LoginModel 实例传递给局部视图

@if (SignInManager.IsSignedIn(User))
{
    <p> Welcome to my website</p>
}
else
{
    @await Html.PartialAsync("Account/Login", new LoginModel())
}
于 2017-11-09T12:15:37.173 回答