ASP.Net MVC - 模型和用户控件
我有一个带有母版页的视图。用户控件使用模型:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<BudgieMoneySite.Models.SiteUserLoginModel>" %>
此用户控件显示在所有屏幕上(母版页的一部分)。如果用户已登录,它会显示特定文本,如果用户未登录,它会提供一个登录框。
工作正常。
现在,我正在添加我的第一个功能屏幕。所以我创建了一个新视图...并且,当我选择控制器方法并说“创建视图”时,我为我生成了基本视图代码。
我的控制器有这个代码:
public ActionResult Transactions()
{
List<AccountTransactionDetails> trans = GetTransactions();
return View(trans);
}
private List<AccountTransactionDetails> GetTransactions()
{
List<AccountTransactionDto> trans = Services.TransactionServices.GetTransactions();
List<AccountTransactionDetails> reply = new List<AccountTransactionDetails>();
foreach(var t in trans)
{
AccountTransactionDetails a = new AccountTransactionDetails();
foreach (var line in a.Transactions)
{
AccountTransactionLine l = new AccountTransactionLine();
l.Amount = line.Amount;
l.SubCategory = line.SubCategory;
l.SubCategoryId = line.SubCategoryId;
a.Transactions.Add(l);
}
reply.Add(a);
}
return reply;
}
所以,我的视图是这样生成的:
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<System.Collections.Generic.List<BudgieMoneySite.Models.AccountTransactionDetails>>" %>
找到<%=Model.Count() %>交易。
我现在想要显示的只是将要显示的记录数。
当我运行它时,出现错误:
“传递到字典中的模型项的类型为‘System.Collections.Generic.List`1[BudgieMoneySite.Models.AccountTransactionDetails]’,但该字典需要类型为‘的模型项BudgieMoneySite.Models.SiteUserLoginModel'。”
看起来用户控件首先被渲染,并且由于控制器中的模型是我的 List<>,它正在崩溃!
我做错了什么?
I have a View with a Master Page. The user control makes use of a Model:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<BudgieMoneySite.Models.SiteUserLoginModel>" %>
This user control is shown on all screens (Part of the Master Page). If the user is logged in, it shows a certain text, and if the user isn't logged in, it offers a login box.
That is working OK.
Now, I am adding my first functional screen. So I created a new view... and, well, i generated the basic view code for me when I selected the controller method, and said 'Create View'.
My Controller has this code:
public ActionResult Transactions()
{
List<AccountTransactionDetails> trans = GetTransactions();
return View(trans);
}
private List<AccountTransactionDetails> GetTransactions()
{
List<AccountTransactionDto> trans = Services.TransactionServices.GetTransactions();
List<AccountTransactionDetails> reply = new List<AccountTransactionDetails>();
foreach(var t in trans)
{
AccountTransactionDetails a = new AccountTransactionDetails();
foreach (var line in a.Transactions)
{
AccountTransactionLine l = new AccountTransactionLine();
l.Amount = line.Amount;
l.SubCategory = line.SubCategory;
l.SubCategoryId = line.SubCategoryId;
a.Transactions.Add(l);
}
reply.Add(a);
}
return reply;
}
So, my view was generated with this:
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<System.Collections.Generic.List<BudgieMoneySite.Models.AccountTransactionDetails>>" %>
Found <%=Model.Count() %> Transactions.
All I want to show for now is the number of records I will be displaying.
When I run it, I get an error:
"The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[BudgieMoneySite.Models.AccountTransactionDetails]', but this dictionary requires a model item of type 'BudgieMoneySite.Models.SiteUserLoginModel'."
It looks like the user control is being rendered first, and as the Model from the controller is my List<>, it's breaking!
What am I doing wrong?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
LoginModel 不应设置为页面的模型,而应仅设置为部分视图的模型。您可以使用 RenderAction 显示带有未连接到页面模型的模型的部分视图。以下是我如何实现出现在母版页上的登录状态控件。
部分视图 (Views/Auth/LoginStatus.ascx):
在母版页中,没有强类型模型:
在控制器 (AuthController) 中
LoginModel should not be set as the model for the page but for the partial view only. You can use RenderAction to display a partial view with a model that is not connected to the model for the page. Here's how I have implemented a login status control that appears on the master page.
The partial view (Views/Auth/LoginStatus.ascx):
In the master page, which does not have a strongly typed model:
And in the controller (AuthController)
这并不是说它本身是“首先”渲染的,而是所有视图都采用控制器传递下来的模型,除非另有指定。
为了解决这个问题,您可以创建一个所有视图模型都继承的基类,定义 Master 及其部分视图所需的内容(然后将适当的属性传递到 RenderPartial 重载之一),或者您可以使用非类型化的 ViewData 包来做类似的事情。
* 编辑 *
所以我意识到我正在回答你所提出的问题,而不是我本来可以解决的问题。上面的回答是正确的,如果您想在母版页中处理模型内容,您需要将它们填充到 ViewData 字典中(例如 ViewData["myData"] = mydata;)或者您必须为所有内容创建一个基类继承的模型。
也就是说,在大多数情况下(特别是像你举的 profiel 这样的例子)我也不这样做。在大多数情况下,我会使用渲染操作,它会调用另一个控制器的部分视图。然后,另一个控制器可以向其部分提供任何适当的数据。有些人认为这违反了 MVC,我认为这是一种组合视图并实际上保持逻辑结构完整的好方法,而不是通过要求控制器知道母版页需要什么来搅浑水,即使它与我们无关。 / 控制器的工作。通常的解决方案是也有一个基本控制器,或者使用动作过滤器,但我发现这只是你必须维护的更多臃肿。
It's not that it's rendered "first" per se, it's more that all the views take the Model that the controller passes down, unless otherwise specified.
To solve this, you can either create a base class that all your view models will inherit from, defining things that the Master and its partial views need (and then you'd pass the appropriate property into one of the RenderPartial overloads), or you can use the untyped ViewData bag to do something similar.
* EDIT *
So I realized that I was answering your question as-asked, not as I would have solved it. The above response is true, if you want to handle model stuff in your master page you need to either stuff them into the ViewData dictionary (e.g. ViewData["myData"] = mydata;) Or you have to create a base class for all your models to inherit from.
That said, in most cases (esp. something like profiel that you gave as an example) I don't do either. In most cases like this, I use a render action instead, which calls for a partial view from another controller. That other controller then can feed its partial whatever data is appropriate. Some folks consider this a violation of MVC, I tihnk it's a good way to compose views and actually keep your logical structures intact, rather than muddying the waters by requiring a controller to know what the master page needs even when it's got nothing to do w/ that controller's job. The usual solution to that is to also have a base controller, or else use action filters, but I find that to be just more bloat that you have to maintain.