我似乎无法找到任何权威的,最新的(即1.0最终版)文档来了解ASP.NET MVC中标准模型绑定器的功能,特别是关于绑定涉及集合的复杂对象(以及它在HTML表单上的命名要求)
我发现了Phil Haack的博客文章(http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx),但它顶部有一个注释,说它是已过期,将会更新.这里也有一个有用的答案:复杂复合对象的自定义模型绑定器帮助但我无法弄清楚他是如何知道这些东西的.
此页面:http://www.asp.net/learn/mvc/#MVC_ActionFilters标题为"操作过滤器和模型绑定器",但只有实际包含有关过滤器的信息.
我是否擅长阅读消息来源或购买新的"额头帮"(并且希望它比我过去买错的其他Wrox书籍更好)?或者我错过了一个好的参考?
我想知道如何从MultiSelect框中将我的表单值绑定到我的强类型视图.
显然,当表单提交多选框时,会提交一个已选中的值的delittemered字符串...将这个值字符串转换回附加到我的模型要更新的对象列表的最佳方法是什么?
public class MyViewModel {
public List<Genre> GenreList {get; set;}
public List<string> Genres { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
在控制器内更新我的模型时,我正在使用UpdateModel,如下所示:
Account accountToUpdate = userSession.GetCurrentUser();
UpdateModel(accountToUpdate);
Run Code Online (Sandbox Code Playgroud)
但是我需要以某种方式将字符串中的值返回到对象中.
我相信它可能与模型粘合剂有关,但我找不到任何明确的如何做到这一点的例子.
谢谢!!保罗
我正在构建一个MVC应用程序,并正在为一个类设计一个自定义模型绑定器; 本质上,模型的一个字段是存在于数据库中的对象,但很难将其与HTML中的相应对象相关联.(因为选择列表只允许我选择一个int/string字段,我真的不能将'object'存储为Select List的'value').
我正在考虑使用存储在选择列表中的Id来查找我的Model Binder中的数据库中的对象 - 但是我的一位同事告诉我这通常是一个坏主意.这是真的,如果是的话,我还有其他选择吗?
我希望我不会错过一些非常明显的东西,但有没有理由为什么模型绑定器总是无法绑定从集合继承的视图模型?
假设我想显示一个分页列表并显示一个组合框并在其上方添加按钮(处理简单列表).涉及的类看起来像:
public class PagedList<T> : List<T>
{
public int TotalCount { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
然后是一个看起来像的视图模型:
public class MyViewModel : PagedList<ConcreteModel>
{
public IEnumerable<ChildModel> List { get; set; }
public int? SelectedChildModelId { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
所以在视图中(Razor):
@model MyViewModel
@using (Html.BeginForm())
{
@Html.DropDownListFor(model => model.SelectedChildModelId, new SelectList(Model.List, "ChildModelId", "DisplayName"))
}
Run Code Online (Sandbox Code Playgroud)
和控制器HttpPost动作:
public ActionResult(MyViewModel viewModel)
{
...
}
Run Code Online (Sandbox Code Playgroud)
以上将导致ActionResult中的viewModel为null.有合理的解释吗?据我所知,它仅限于查看从集合继承的模型.
我知道我可以使用自定义绑定器解决它,但涉及的属性是原始类型,甚至没有任何泛型或继承.
我重新设计了视图模型,使集合继承了类型作为属性,并修复了问题.然而,我仍然在摸着为什么粘合剂会破坏它.任何建设性的想法都赞赏.
这是模型绑定器中的好方法使用这样的代码:
TryParseDate(result.AttemptedValue, format, out parsedDate)
Run Code Online (Sandbox Code Playgroud)
然后"格式"是具有不同(客户特定)日期格式的变量.如2013年12月31日或2013年12月31日或其他.
我对格式绑定有很大的问题,因为如果用户只将日期设置为1位数:2014年1月1日它将不会解析,因为在"格式"值允许的格式:dd/MM/yyyy我知道它是可能的通过将此格式替换为d/M/yyyy进行解决,然后它适用于这两种情况,但它是好的方法还是危险的?
先感谢您!
在ASP.NET MVC中,有两种方法可以在操作中进行模型绑定.我们称之为"绑定参数方式"和"UpdateModel方式".它们两者几乎完全相同,它们以几乎完全相同的方式完成:
public ActionResult UpdateWithBindArguments(Foo model)
{
Repository.Update(model);
// error handling removed
return RedirectToAction(...)
}
public ActionResult UpdateWithUpdateModel()
{
Foo model;
UpdateModel(model); // part of MVC framework
Repository.Update(model);
// error handling removed
return RedirectToAction(...)
}
Run Code Online (Sandbox Code Playgroud)
正如我所说,这些几乎完全相同.第一个可能稍微更具可读性,但我可以克服它.
在重要的区别,我想,就是怎么你单位对其进行测试:
[TestMethod]
public void TestUpdateWithBindArguments()
{
var model = new Foo() { PropertyName = "Bar" };
var controller = new FooController();
var result = controller.UpdateWithBindArguments(model);
// assert
}
[TestMethod]
public void TestUpdateWithUpdateModel()
{
var formData = new FormCollection() …Run Code Online (Sandbox Code Playgroud) 我修改了Nerd Dinner应用程序,允许通过将以下代码添加到DinnerForm.ascx来编辑子记录
<p>
<%int i = 0;
foreach (NerdDinner.Models.RSVP rsvp in this.Model.Dinner.RSVPs)
{ %>
<%= Html.Hidden("Dinner.RSVPs[" + i + "].RsvpID", rsvp.RsvpID)%>
<%= Html.Hidden("Dinner.RSVPs[" + i + "].DinnerID", rsvp.DinnerID)%>
<%= Html.TextBox("Dinner.RSVPs[" + i + "].AttendeeName", rsvp.AttendeeName)%>
<% i += 1;
} %>
</p>
Run Code Online (Sandbox Code Playgroud)
它呈现这个:
<p>
<input id="Dinner_RSVPs[0]_RsvpID" name="Dinner.RSVPs[0].RsvpID" type="hidden" value="36" />
<input id="Dinner_RSVPs[0]_DinnerID" name="Dinner.RSVPs[0].DinnerID" type="hidden" value="63" />
<input id="Dinner_RSVPs[0]_AttendeeName" name="Dinner.RSVPs[0].AttendeeName" type="text" value="kp" />
<input id="Dinner_RSVPs[1]_RsvpID" name="Dinner.RSVPs[1].RsvpID" type="hidden" value="37" />
<input id="Dinner_RSVPs[1]_DinnerID" name="Dinner.RSVPs[1].DinnerID" type="hidden" value="63" />
<input id="Dinner_RSVPs[1]_AttendeeName" name="Dinner.RSVPs[1].AttendeeName" type="text" …Run Code Online (Sandbox Code Playgroud) 第一; 我知道我不需要测试MVC的内部,但我真的需要套件测试流入我们系统的数据.
我希望如何在不模仿所有HTTP上下文的情况下,测试objectA(表单集合,字典,集合,对象等)是否符合objectAModel?
我不想实例化我的控制器或调用操作.我只是想测试我的新对象是否使模型状态无效.
我希望我能简单地写一下
var modelState = new ModelBindingContext<objectAModel>().validate(objectA);
Run Code Online (Sandbox Code Playgroud) asp.net-mvc unit-testing defaultmodelbinder modelbinders modelstate
我有一个控制器动作,看起来像:
public ActionResult DoSomethingCool(int[] someIdNumbers)
{
...
}
Run Code Online (Sandbox Code Playgroud)
我希望能够使用自定义模型绑定器从客户端的复选框列表中创建该ID数组.有没有办法绑定到那个参数?另外,有没有办法让模型绑定器发现正在使用的参数的名称?例如,在我的模型绑定器中,我很想知道参数的名称是"someIdNumbers".
我们的ASP.NET MVC应用程序允许经过身份验证的用户管理链接到其帐户的一个或多个"站点".
我们的网址是高度猜测的,因为我们在网址而不是Id中使用网站友好名称,例如:
/sites/mysite/
/sites/mysite/settings
/sites/mysite/blog/posts
/sites/mysite/pages/create
Run Code Online (Sandbox Code Playgroud)
如您所见,我们需要在多个路线中访问站点名称.
我们需要为所有这些操作执行相同的行为:
我们始终可以通过ISiteContext对象使用当前帐户.以下是我如何使用普通路由参数实现上述所有操作并直接在我的操作中执行查询:
private readonly ISiteContext siteContext;
private readonly IRepository<Site> siteRepository;
public SitesController(ISiteContext siteContext, IRepository<Site> siteRepository)
{
this.siteContext = siteContext;
this.siteRepository = siteRepository;
}
[HttpGet]
public ActionResult Details(string id)
{
var site =
siteRepository.Get(
s => s.Account == siteContext.Account && s.SystemName == id
);
if (site == null)
return HttpNotFound();
return Content("Viewing details for site " + site.Name);
}
Run Code Online (Sandbox Code Playgroud)
这不是太糟糕,但我需要在20个左右的动作方法上做这个,所以想尽可能保持干燥.
我没有做过自定义模型粘合剂,所以我想知道这是否是一个更适合他们的工作.一个关键要求是我可以将我的依赖项注入模型绑定器(对于ISiteContext和IRepository - 如果需要,我可以回退到DependencyResolver).
非常感谢,
本
更新 …
modelbinders ×10
asp.net-mvc ×8
unit-testing ×2
asp.net ×1
c# ×1
collections ×1
modelstate ×1
multi-select ×1
razor ×1
updatemodel ×1
viewmodel ×1