如何在每个控制器动作中使用异步 ViewModel?
How to use asynchronous ViewModel in every controller action?
我是 asp.net mvc (5) 的新手,我的网站遇到了问题。
基本上,所有 aspnet_users
都通过 guid
.
链接到我的特定 user
table
我有一个 BaseController
class 和一个 UnitOfWork
和一个 ViewModelBase
:
public class BaseController : Controller
{
protected UnitOfWork UnitOfWork { get; private set; }
public ViewModelBase ViewModel { get; set; }
}
(Extract of) ViewModelBase
class,包含布局页面中需要的信息:
public class ViewModelBase
{
public User User { get; set; }
public bool IsAuthentified { get; set; }
public bool Loaded { get; set; }
}
以及使用它的布局:
@model Project.ViewModels.ViewModelBase
<html>
<body>
Some very cool layout stuff related to the User in the ViewModelBase
</body>
</html>
这里有一个使用 HomeController
的例子:
public class HomeController : BaseController
{
private new HomeViewModel ViewModel
{
get { return (HomeViewModel)base.ViewModel; }
}
public HomeController()
{
ViewModel = new HomeViewModel();
}
public ActionResult Index()
{
// I need to get the MembershipUser here to retrieve the related User and set it in the ViewModel
return View(ViewModel);
}
}
HomeViewModel
:
public class HomeViewModel : ViewModelBase
{
public string HomeSpecificProperty { get; set; }
}
和视图:
@model Project.ViewModels.HomeViewModel
@{
ViewBag.Title = "Home";
Layout = "~/Views/Shared/Layout.cshtml";
}
Welcome @Model.User.UserName !
<br />
@Model.HomeSpecificProperty
这是我的问题。问题是所有页面都有一个继承自 ViewModelBase
的视图模型,因为它用于布局,但我不知道在哪里以及如何在其中设置 User
属性。
由于 Membership
用于检索 User
它必须在 Action
中,我不能在 ViewModelBase
构造函数中执行此操作。
因此我在 BaseController
中添加了这段代码,它在第一个 get
上设置了 ViewModelBase
属性:
private ViewModelBase viewModel;
protected ViewModelBase ViewModel
{
get
{
if (!viewModel.Loaded)
LoadBaseContext();
return viewModel;
}
set { viewModel = value; }
}
private void LoadBaseContext()
{
viewModel.IsAuthentified = HttpContext.User.Identity.IsAuthenticated;
if (viewModel.IsAuthentified)
{
MembershipUser user = Membership.GetUser();
viewModel.Player = UnitOfWork.UserRepo.Get((Guid)user.ProviderUserKey);
}
viewModel.Loaded = true;
}
可能不是很漂亮,但是很管用。然而,由于其中有一些数据库访问(特别是获取 User
),我想我应该把 LoadBaseContext
函数放在 async
中。
我试过了,因为所有的动作都使用 ViewModelBase
我也把每个动作都异步了。但是 @Html.ActionLink
不再起作用,因为调用的操作是 async
.
最后,我的问题是:ViewModelBase
和 User
属性 是正确的做法吗?如果是, LoadBaseContext
应该是 async 吗?那么,如何让它配合动作呢?
非常感谢。
更新
布局摘录:
@if (!Model.IsAuthentified)
{
@Html.Action("Index", "Authentification", null) // display login partial view
}
else
{
@Html.Action("Index", "UserInfos", null) // display userinfos partial view
}
认证控制器索引的动作:
public ActionResult Index()
{
ViewModel = new AuthentificationViewModel();
// loads the ViewModelBase properties here
return PartialView("~/Views/Shared/Partials/Login.cshtml", ViewModel);
}
如果您在所有视图中都有您一直想要的东西,您可以确保每个视图都采用包含或扩展该核心数据集的视图模型,或 你可以简单地将数据放在 ViewBag
.
要执行后者,您可以覆盖基本控制器中的 OnActionExecuting
,并在那里设置 ViewBag
内容。
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
this.ViewBag["IsAuthenticated"] = this.Request.IsAuthenticated;
// ...
}
如果您想要 async
行为,那么您可以 this post 适应您的需要。
要在不覆盖 OnActionExecuting
的情况下执行此操作,您可以在控制器基础 class 中放置一个 async
方法来设置 ViewBag
中的数据:
protected async virtual Task PopulateViewBag()
{
this.ViewBag["foo"] = await MyAsyncMethod();
// ...
}
... 然后只需从您的每个控制器操作中调用它:
public async Task<ActionResult> MyAction()
{
await this.PopulateViewBag();
// ... more code
}
不过会有点乏味。
最后一句话: 取决于你希望有多少用户等等。获取用户信息可能更容易一次 ,然后缓存它(例如在 Session
中),而不是在每次请求时重复获取它。大概大多数用户信息不会在请求之间发生变化...
我是 asp.net mvc (5) 的新手,我的网站遇到了问题。
基本上,所有 aspnet_users
都通过 guid
.
user
table
我有一个 BaseController
class 和一个 UnitOfWork
和一个 ViewModelBase
:
public class BaseController : Controller
{
protected UnitOfWork UnitOfWork { get; private set; }
public ViewModelBase ViewModel { get; set; }
}
(Extract of) ViewModelBase
class,包含布局页面中需要的信息:
public class ViewModelBase
{
public User User { get; set; }
public bool IsAuthentified { get; set; }
public bool Loaded { get; set; }
}
以及使用它的布局:
@model Project.ViewModels.ViewModelBase
<html>
<body>
Some very cool layout stuff related to the User in the ViewModelBase
</body>
</html>
这里有一个使用 HomeController
的例子:
public class HomeController : BaseController
{
private new HomeViewModel ViewModel
{
get { return (HomeViewModel)base.ViewModel; }
}
public HomeController()
{
ViewModel = new HomeViewModel();
}
public ActionResult Index()
{
// I need to get the MembershipUser here to retrieve the related User and set it in the ViewModel
return View(ViewModel);
}
}
HomeViewModel
:
public class HomeViewModel : ViewModelBase
{
public string HomeSpecificProperty { get; set; }
}
和视图:
@model Project.ViewModels.HomeViewModel
@{
ViewBag.Title = "Home";
Layout = "~/Views/Shared/Layout.cshtml";
}
Welcome @Model.User.UserName !
<br />
@Model.HomeSpecificProperty
这是我的问题。问题是所有页面都有一个继承自 ViewModelBase
的视图模型,因为它用于布局,但我不知道在哪里以及如何在其中设置 User
属性。
由于 Membership
用于检索 User
它必须在 Action
中,我不能在 ViewModelBase
构造函数中执行此操作。
因此我在 BaseController
中添加了这段代码,它在第一个 get
上设置了 ViewModelBase
属性:
private ViewModelBase viewModel;
protected ViewModelBase ViewModel
{
get
{
if (!viewModel.Loaded)
LoadBaseContext();
return viewModel;
}
set { viewModel = value; }
}
private void LoadBaseContext()
{
viewModel.IsAuthentified = HttpContext.User.Identity.IsAuthenticated;
if (viewModel.IsAuthentified)
{
MembershipUser user = Membership.GetUser();
viewModel.Player = UnitOfWork.UserRepo.Get((Guid)user.ProviderUserKey);
}
viewModel.Loaded = true;
}
可能不是很漂亮,但是很管用。然而,由于其中有一些数据库访问(特别是获取 User
),我想我应该把 LoadBaseContext
函数放在 async
中。
我试过了,因为所有的动作都使用 ViewModelBase
我也把每个动作都异步了。但是 @Html.ActionLink
不再起作用,因为调用的操作是 async
.
最后,我的问题是:ViewModelBase
和 User
属性 是正确的做法吗?如果是, LoadBaseContext
应该是 async 吗?那么,如何让它配合动作呢?
非常感谢。
更新
布局摘录:
@if (!Model.IsAuthentified)
{
@Html.Action("Index", "Authentification", null) // display login partial view
}
else
{
@Html.Action("Index", "UserInfos", null) // display userinfos partial view
}
认证控制器索引的动作:
public ActionResult Index()
{
ViewModel = new AuthentificationViewModel();
// loads the ViewModelBase properties here
return PartialView("~/Views/Shared/Partials/Login.cshtml", ViewModel);
}
如果您在所有视图中都有您一直想要的东西,您可以确保每个视图都采用包含或扩展该核心数据集的视图模型,或 你可以简单地将数据放在 ViewBag
.
要执行后者,您可以覆盖基本控制器中的 OnActionExecuting
,并在那里设置 ViewBag
内容。
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
this.ViewBag["IsAuthenticated"] = this.Request.IsAuthenticated;
// ...
}
如果您想要 async
行为,那么您可以 this post 适应您的需要。
要在不覆盖 OnActionExecuting
的情况下执行此操作,您可以在控制器基础 class 中放置一个 async
方法来设置 ViewBag
中的数据:
protected async virtual Task PopulateViewBag()
{
this.ViewBag["foo"] = await MyAsyncMethod();
// ...
}
... 然后只需从您的每个控制器操作中调用它:
public async Task<ActionResult> MyAction()
{
await this.PopulateViewBag();
// ... more code
}
不过会有点乏味。
最后一句话: 取决于你希望有多少用户等等。获取用户信息可能更容易一次 ,然后缓存它(例如在 Session
中),而不是在每次请求时重复获取它。大概大多数用户信息不会在请求之间发生变化...