我不确定这种行为是否是预期的,但是当绑定分配给接口类型时,似乎自定义模型绑定不起作用.有人试过这个吗?
public interface ISomeModel {}
public class SomeModel : ISomeModel {}
public class MvcApplication : HttpApplication {
protected void Application_Start(object sender, EventArgs e) {
ModelBinders.Binders[typeof(ISomeModel)] = new MyCustomModelBinder();
}
}
Run Code Online (Sandbox Code Playgroud)
使用上面的代码,当我绑定到SomeModel类型的模型时,MyCustomModelBinder永远不会被击中; 但是,如果我改变了上面的代码,并替代typeof(ISomeModel)了typeof(SomeModel)预期并张贴完全相同的形式MyCustomModelBinder被调用.那似乎对吗?
编辑
在我最初提出这个问题一年后,我发现自己已经陷入了这种困境,现在我有一个有效的解决方案.谢谢Matt Hidinger!
是否有[Bind(Exclude = "Id")](相关问题)的替代方案?
我能写一个模型活页夹吗?
此处描述的行为现在似乎是ASP.NET MVC 2的默认行为(至少对于预览1).
当像这样对一个查询字符串进行模型绑定时:
?Foo=&Bar=cat
Run Code Online (Sandbox Code Playgroud)
发生以下绑定(假设您绑定到具有'Foo'和'Bar'字符串属性的模型)
ASP.NET MVC 1
model.Foo = "";
model.Bar = "cat":
Run Code Online (Sandbox Code Playgroud)
ASP.NET MVC 2(预览1到RC)
model.Foo = null;
model.Bar = "cat":
Run Code Online (Sandbox Code Playgroud)
想要给任何正在玩V2的人提供一个单挑,因为这在' gu-notes '中没有提到.同样好奇的是,知道的任何人都可以评论这是否是最终实施或可配置功能?无论哪种方式我都很好但只是希望他们不要回到过去的方式!可配置会更好.
编辑:从这一点学习的教训是你正在开发的任何版本,不要编写代表Foo.Length == 0来测试空字符串或Foo.Length> 3以检查最小长度.使用string.IsNullOrEmpty(Foo)和/或首先检查null.
更新:这个问题激起了我对他们为什么会真正做出这种改变的好奇心.我认为在研究残疾人控制时我偶然发现了答案.W3 HTML规范定义了" 成功控制 ",如下所示:
成功的控制对于提交是"有效的".每个成功的控件都将其控件名称与其当前值配对,作为提交的表单数据集的一部分.必须在FORM元素中定义成功的控件,并且必须具有控件名称.
换句话说 - 成功的控件是将其作为查询字符串参数返回服务器的控件.现在,如果控件没有有效值,那么根据规范:
如果控件 在提交表单时没有当前值,则用户代理不需要将其视为成功控件.
(在这里找到'开放式解释'语言'不要求......')
所以我认为通过发送null而不是空字符串,它可以减少某些浏览器可能发送的浏览器不兼容性,Foo=&Bar=而其他浏览器可能甚至不会发送该查询字符串参数.通过总是解释Foo=好像Foo不存在,所以你要更加防守.
我认为我至少在正确的轨道上找到了原因 - 至少在某种程度上与'成功控制'的概念有关.
我试图找到一些为我需要处理的独特绑定场景构建自定义模型绑定器的示例,但我发现的所有文章都是针对MVC2中不再相关的旧版MVC.我一直在引用DefaultModelBinder源代码,试图对我需要做的事情有一个普遍的感觉,但它比我的场景更复杂,我无法隔离我需要实现的特定逻辑.
我的目标是获取一组Checkbox/Textbox对,并且对于所有Checked对,我想创建Checkbox值和关联Textbox值的键/值对.在聚合这些数据之后,我需要对集合进行一些字符串序列化,这样我就可以将它存储在所需Model类型的字符串属性中.我已经以可管理的格式从表单发送数据,这将允许我将给定的复选框与特定的文本框相关联,这只是找出如何获取所需的所有部分的问题.
有谁知道一些最新的教程可以让我开始构建自定义模型绑定器?
我在ASP.NET MVC 2中使用自定义模型绑定器,如下所示:
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
if (bindingContext == null)
{
throw new ArgumentNullException("bindingContext");
}
BaseContentObject obj = (BaseContentObject)base.BindModel(controllerContext, bindingContext);
if(string.IsNullOrWhiteSpace(obj.Slug))
{
// creating new object
obj.Created = obj.Modified = DateTime.Now;
obj.ModifiedBy = obj.CreatedBy = controllerContext.HttpContext.User.Identity.Name;
// slug is not provided thru UI, derivate it from Title; property setter removes chars that are not allowed
obj.Slug = obj.Title;
ModelStateDictionary modelStateDictionary = bindingContext.ModelState;
modelStateDictionary.SetModelValue("Slug", new ValueProviderResult(obj.Slug, obj.Slug, …Run Code Online (Sandbox Code Playgroud) 我在编写一些单元测试时遇到了一些困难,无法测试我创建的自定义ModelBinder.我正在尝试单元测试的ModelBinder是我在这里发布的JsonDictionaryModelBinder .
我遇到的问题是使用Moq进行Mocking所有设置.由于HttpContextBase没有被正确模拟,我一直得到Null Exceptions.我认为.
有人能帮我搞清楚我不做的事情吗?
这是我试图编写的单元测试样本不起作用:
[TestMethod()]
public void BindModelTest()
{
JsonDictionaryModelBinder target = new JsonDictionaryModelBinder();
NameValueCollection nameValueCollection = new NameValueCollection() {
{"First", "1"},
{"Second", "2"},
{"Name", "Chris"},
{"jsonValues", "{id: 200, name: 'Chris'}"}
};
HttpContextBase httpContext = MockHelper.FakeHttpContext(HttpVerbs.Post, nameValueCollection);
ControllerContext controllerContext =
new ControllerContext(new RequestContext(httpContext, new RouteData()), new Mock<Controller>().Object);
Predicate<string> predicate = propertyName => (propertyName == "jsonValues");
ModelBindingContext bindingContext = new ModelBindingContext()
{
Model = null,
ModelType = typeof(JsonDictionary),
ModelState = new ModelStateDictionary(),
PropertyFilter = predicate,
ValueProvider = …Run Code Online (Sandbox Code Playgroud) 我正在尝试将JSON数据发布到Web Api方法,但JSON数据未绑定到模型.
这是我的模特:
[DataContract]
public class RegisterDataModel
{
[DataMember(IsRequired = true)]
public String SiteKey { get; set; }
[DataMember(IsRequired = true)]
public String UserId { get; set; }
[DataMember(IsRequired = true)]
public String UserName { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
这是我的Web Api动作:
public class RegisterController : ApiController
{
public Guid Post([ModelBinder] RegisterDataModel registerDataModel)
{
if (!ModelState.IsValid)
{
throw new ModelStateApiException(ModelState);
}
var userProfileDataContract = userProfileBusinessLibrary.GetNewOne();
userProfileDataContract.UserId = registerDataModel.UserId;
userProfileDataContract.UserName = registerDataModel.UserName;
var userKey = userProfileBusinessLibrary.Register(registerDataModel.SiteKey, userProfileDataContract);
return userKey;
}
}
Run Code Online (Sandbox Code Playgroud)
在我添加[ModelBinder]之前,registerDataModel为null.添加[ModelBinder]后,registerDataModel是RegisterDataModel实例,但所有属性值都为null. …
我希望在我的视图中使用RenderPartial两次,并关联不同的模型.问题是两个模型中都存在一些属性(昵称,密码).它们没有前缀,所以即使id或名称在输出中也是相同的.现在,如果我有昵称或密码的模型错误,则两个字段都会突出显示.
主要观点:
<div>
<% Html.RenderPartial("Register", Model.RegisterModel); %>
</div>
<div>
<% Html.RenderPartial("Login", Model.LoginModel); %>
</div>
Run Code Online (Sandbox Code Playgroud)
登录PartialView:
<% using (Html.BeginForm("Login", "Member")) { %>
<fieldset>
<legend>Login</legend>
<p>
<%= Html.LabelFor(x => x.Nickname) %>
<%= Html.TextBoxFor(x => x.Nickname) %>
</p>
<p>
<%= Html.LabelFor(x => x.Password) %>
<%= Html.PasswordFor(x => x.Password) %>
</p>
<input type="submit" value="Login" />
</fieldset>
<% } %>
Run Code Online (Sandbox Code Playgroud)
注册PartialView:
<% using (Html.BeginForm("Register", "Member")) { %>
<fieldset>
<legend>Register</legend>
<p>
<%= Html.LabelFor(x => x.Nickname) %>
<%= Html.TextBoxFor(x => x.Nickname) %>
</p>
<p>
<%= Html.LabelFor(x => …Run Code Online (Sandbox Code Playgroud) 我希望能够从cookie中获取键/值并使用它来绑定模型.
我认为DefaultModelBinder不是构建自定义的ModelBinder,而是开箱即用,选择值来自哪里的最佳方法是设置它使用的IValueProvider.
为此,我不想创建自定义ValueProviderFactory并将其全局绑定,因为我只希望在特定的操作方法中使用此ValueProvider.
我已经构建了一个执行此操作的属性:
/// <summary>
/// Replaces the current value provider with the specified value provider
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class SetValueProviderAttribute : ActionFilterAttribute
{
public SetValueProviderAttribute(Type valueProviderType)
{
if (valueProviderType.GetInterface(typeof(IValueProvider).Name) == null)
throw new ArgumentException("Type " + valueProviderType + " must implement interface IValueProvider.", "valueProviderType");
_ValueProviderType = valueProviderType;
}
private Type _ValueProviderType;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
IValueProvider valueProviderToAdd = GetValueProviderToAdd();
filterContext.Controller.ValueProvider = valueProviderToAdd;
}
private IValueProvider GetValueProviderToAdd()
{ …Run Code Online (Sandbox Code Playgroud) 在ASP.NET MVC 3 RC2中,默认的ModelBinder将自动解析请求正文(如果Content-Type设置为)application/json.问题是,这留下Request.InputStream了流的末尾.这意味着如果您尝试使用自己的代码读取输入流,则首先将其重置为开头:
// client sends HTTP request with Content-Type: application/json and a JSON
// string in the body
// requestBody is null because the stream is already at the end
var requestBody = new StreamReader(Request.InputStream).ReadToEnd();
// resets the position back to the beginning of the input stream
var reader = new StreamReader(Request.InputStream);
reader.BaseStream.Position = 0;
var requestBody = reader.ReadToEnd();
Run Code Online (Sandbox Code Playgroud)
因为我正在使用Json.NET序列化/反序列化,所以我想禁用默认的ModelBinder进行额外的解析.有没有办法做到这一点?
modelbinders ×10
asp.net-mvc ×7
c# ×2
asp.net ×1
interface ×1
moq ×1
preview ×1
unit-testing ×1
viewmodel ×1