ViewBag 作为会话模型的持有者
本文关键字:持有者 模型 会话 ViewBag | 更新日期: 2023-09-27 18:33:27
这更像是一个高级问题。
我有一个MVC项目,除其他外,它管理用户。我目前坚持一种更严格的方法,在我的视图页面上,我只使用声明的模型,这意味着我有一个:
@model MVCApp.Models.SomeModel
在每个视图的顶部.cshtml
有些页面需要 1 个以上的模型。此时,我将 2 个模型合并为 1,并将其作为一个模型发送到视图中。
棘手的部分来了。假设我有一些保存用户数据的模型。该用户数据存储在会话 Cookie(典型的表单身份验证(中。对我来说,现在必须将我使用的每个模型都包装在一起,该模型包含用户模型和我想在该视图中使用的模型。
我问自己的问题是,为什么不将用户模型传递给 ViewBag 并在视图中使用它。为什么这被认为是不好的做法?它允许我将该模型附加到每个页面,而无需最终复制我的所有模型。
我很想得到一些指导。我可能以错误的方式看待这个问题。任何帮助都将是非常有义务的。
谢谢
应该避免使用ViewBag有几个原因:
- ViewBag 是弱类型化的
- 您不会在视图中获得智能感知
- 您的视图是 ViewBag 和视图模型的混合体,您的视图从不同位置获取信息,而不是将所有内容集中到强类型视图模型中
- ViewBag 不适用于强类型帮助程序和表达式,因为动态类型不能与扩展方法一起使用(这不是 MVC ASP.NET 的限制,它是 .NET => 您无法在动态类型上调度扩展方法(
- 由于 ViewBag 的这种弱类型特性,您将不得不在视图中投射将它们转换为意大利面条代码,因为 HTML 帮助程序希望特定类型作为参数传递
- 。这个列表还在继续(我真的没有时间填写它,但它是非常大的列表(
因此,既然我们知道 ViewBag 不好,不应该使用,那么您可以通过使用视图模型来解决此需求的不同方法。
一种可能性是使用 Html.Action 帮助程序,它允许您通过完整的控制器/模型/视图生命周期在视图中插入 HTML 的某些部分。这样,您就可以拥有一个常用的小部件,而不会干扰您的主视图模型。
另一种可能性是拥有一个基本视图模型,该模型将包含一个表示用户详细信息的属性,并且将由自定义全局操作筛选器填充,该筛选器可以在控制器操作完成执行并返回视图结果时执行。操作筛选器可以截获此视图结果,读取身份验证 Cookie 信息并设置视图模型属性。这假定所有视图模型都派生自公共基础视图模型。如果您需要在每个页面上显示此用户信息,这显然是有意义的。
例如:
public class UserInfoInjectorAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var result = filterContext.Result as ViewResultBase;
if (result == null)
{
// the controller action didn't return any view result => no need to continue
return;
}
var model = result.Model as BaseViewModel;
if (model == null)
{
// the controller action didn't pass a model or the model passed to the view
// doesn't derive from the common base view model that will contain
// the user info property => no need to continbue any further
return;
}
model.UserInfo = ... go ahead and read the forms authentication cookie
userData portion and extract the information
you are looking for
}
}
现在剩下的就是将此操作筛选器注册为全局操作筛选器,它将应用于所有控制器操作。
现在,如果您的所有视图模型都派生自此BaseViewModel
您将知道,一旦您到达视图,UserInfo 属性将使用相关信息进行填充,而不会使用执行此属性提取的代码污染所有控制器操作。而且你仍然在视图中得到强烈的输入=>没有ViewBag(youpeeee(。
当然,根据您的具体情况,可能还有其他方法可以实现这一点(显然不涉及任何ViewBag
(。
您可以使用 ActionFilterAttribute,并在那些加载需要特定 ViewBag 项的视图的操作中初始化它们。
我不推荐它,因为它会更难维护,但将是一种通用方法,可以解决您的问题。