如何在另一个页面中展示一个页面?
How to feature a page in another page?
在我的主页(索引)页面上,如果用户未登录,我希望登录表单直接位于我的主页中,但如果用户已经登录,则将显示索引页面。如果我使用 _LoginPartial
此页面按预期加载,但对于文件夹中的其他页面(例如帐户)我会收到错误消息
CSHTML:
@if (SignInManager.IsSignedIn(User))
{
<p> Welcome to my website</p>
}
else
{
@await Html.PartialAsync("Account/Login")
}
`InvalidOperationException: The model item passed into the
ViewDataDictionary is of type 'CS.Pages.Manifest.IndexModel', but this
ViewDataDictionary instance requires a model item of type
'CS.Pages.Account.LoginModel'.
登录模型构造函数:
public LoginModel(SignInManager<ApplicationUser> signInManager, ILogger<LoginModel> logger)
{
_signInManager = signInManager;
_logger = logger;
}
尝试将 LoginModel 实例传递给局部视图
@if (SignInManager.IsSignedIn(User))
{
<p> Welcome to my website</p>
}
else
{
@await Html.PartialAsync("Account/Login", new LoginModel())
}
当您加载部分内容时:
@await Html.PartialAsync("Account/Login")
您从中调用它的视图模型是隐式传递的,就好像您已经这样做了一样:
@await Html.PartialAsync("Account/Login", Model)
因此,您收到了错误。部分需要类型 LoginModel
的模型,但您向它传递的是类型 IndexModel
的模型。解决方案当然是传入一个正确类型的模型,即 LoginModel
。但是,您的 LoginModel
必须使用 SignInManager<ApplicationUser>
和 ILogger<LoginModel
类型的参数构造。因此,当您尝试仅通过 new LoginModel()
.
时收到第二个错误的原因
所有这一切实际上归结为首先是对部分的不当使用。需要这种复杂实例化的部分实际上应该是 view component,这会给你更多的设置灵活性 和 允许你进行注入,这就是你这里需要。
本质上,您只是创建一个继承自 ViewComponent
的 class 并实现方法 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
实例,然后returns一个使用该模型的视图。因为,在这里,没有实际的异步工作需要完成,GetModelAsync
方法只是 returns 一个 Task
从更新一个 LoginModel
的结果创建的。必须这样做才能满足 InvokeAsync
的 Task
-返回性质。如果你真的需要一些异步的东西,你可以简单地在这里等待。
有了这些,您只需创建视图 Views\Shared\Components\Login\Default.cshtml
。其中包含您当前正在使用的部分视图的内容。 Login\Default.cshtml
部分是约定俗成的。该目录是视图组件的名称 class,减去 ViewComponent
后缀,Default.cshtml
是它将在那里查找的默认视图。如果你愿意,这可以定制,但真的没有理由。
最后,您只需调用:
@await Component.InvokeAsync("Login");
使用这种方法,所有功能(包括模型的创建和传入)都是独立的,因此可以在单独的视图中任何地方调用,甚至您的布局。
在我的主页(索引)页面上,如果用户未登录,我希望登录表单直接位于我的主页中,但如果用户已经登录,则将显示索引页面。如果我使用 _LoginPartial
此页面按预期加载,但对于文件夹中的其他页面(例如帐户)我会收到错误消息
CSHTML:
@if (SignInManager.IsSignedIn(User))
{
<p> Welcome to my website</p>
}
else
{
@await Html.PartialAsync("Account/Login")
}
`InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'CS.Pages.Manifest.IndexModel', but this ViewDataDictionary instance requires a model item of type 'CS.Pages.Account.LoginModel'.
登录模型构造函数:
public LoginModel(SignInManager<ApplicationUser> signInManager, ILogger<LoginModel> logger)
{
_signInManager = signInManager;
_logger = logger;
}
尝试将 LoginModel 实例传递给局部视图
@if (SignInManager.IsSignedIn(User))
{
<p> Welcome to my website</p>
}
else
{
@await Html.PartialAsync("Account/Login", new LoginModel())
}
当您加载部分内容时:
@await Html.PartialAsync("Account/Login")
您从中调用它的视图模型是隐式传递的,就好像您已经这样做了一样:
@await Html.PartialAsync("Account/Login", Model)
因此,您收到了错误。部分需要类型 LoginModel
的模型,但您向它传递的是类型 IndexModel
的模型。解决方案当然是传入一个正确类型的模型,即 LoginModel
。但是,您的 LoginModel
必须使用 SignInManager<ApplicationUser>
和 ILogger<LoginModel
类型的参数构造。因此,当您尝试仅通过 new LoginModel()
.
所有这一切实际上归结为首先是对部分的不当使用。需要这种复杂实例化的部分实际上应该是 view component,这会给你更多的设置灵活性 和 允许你进行注入,这就是你这里需要。
本质上,您只是创建一个继承自 ViewComponent
的 class 并实现方法 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
实例,然后returns一个使用该模型的视图。因为,在这里,没有实际的异步工作需要完成,GetModelAsync
方法只是 returns 一个 Task
从更新一个 LoginModel
的结果创建的。必须这样做才能满足 InvokeAsync
的 Task
-返回性质。如果你真的需要一些异步的东西,你可以简单地在这里等待。
有了这些,您只需创建视图 Views\Shared\Components\Login\Default.cshtml
。其中包含您当前正在使用的部分视图的内容。 Login\Default.cshtml
部分是约定俗成的。该目录是视图组件的名称 class,减去 ViewComponent
后缀,Default.cshtml
是它将在那里查找的默认视图。如果你愿意,这可以定制,但真的没有理由。
最后,您只需调用:
@await Component.InvokeAsync("Login");
使用这种方法,所有功能(包括模型的创建和传入)都是独立的,因此可以在单独的视图中任何地方调用,甚至您的布局。