MVC3远程验证列表中的字段

时间:2012-01-20 23:00:54

标签: asp.net-mvc-3 list remote-validation

出于某种原因,每当我尝试远程验证模型中数组内的基本属性时,该属性的值不会作为参数传递。

例如,当调用我的远程验证方法(UniqueItemNo)时,字符串参数“id”始终为null。如果我要在CartNumber而不是ItemNumber上执行验证,则参数将正确传递。

控制器

public class HomeController : Controller
{
    public ActionResult Index()
    {
        CartModel cart = new CartModel();
        cart.Items.Add(new ItemModel() { ItemNumber = "12345" });
        return View(cart);
    }

    [HttpPost]
    public JsonResult UniqueItemNo(string id)
    {
        /** Do Work **/
        return null;
    }
}

模型

public class ItemModel
{
    [Remote("UniqueItemNo", "Home", HttpMethod="POST")]
    public string ItemNumber { get; set; }
}

public class CartModel
{
    public CartModel()
    {
        Items = new List<ItemModel>();
    }

    public List<ItemModel> Items { get; set; }
    public string CartNumber { get; set; }
}

视图

@{
    ViewBag.Title = "Home Page";
}

<h2>@ViewBag.Message</h2>
@using(Html.BeginForm()) {
    <p>
        @for(int i = 0; i < Model.Items.Count; i++)
        {
            @Html.TextBoxFor(m => m.Items[i].ItemNumber);
            @Html.ValidationMessageFor(m => m.Items[i].ItemNumber);                                    
        }
    </p>
}

4 个答案:

答案 0 :(得分:6)

刚刚解决了同样的问题。所以对于我将来会遇到这个问题的那类人来说,这就是解决方案

这是根本原因。

当你@Html.TextBoxFor(x=>x.m.Items[i].ItemNumber)时 它输出类似这样的东西

<input type=text value='value' name='items[index].ItemNumber' ...

然后它添加其他验证,如data- *属性进行验证。例如远程验证url data-remot-url等

现在,当表单得到验证时,它请求远程URL,其中包含key = xxx [1] .propertyname

等数据

并且这不能分配给将接收此属性的远程操作方法中的单个变量。

如果您将动作参数更改为类似的内容,那么它将起作用

 public JsonResult UniqueItemNo(list<string> propertyname)

即便如此,您也不需要保证,因为它需要让参数索引从0开始并且没有任何间隙。所以xxx [1] .ItemNumber永远不会被maped。

唯一剩下的解决方案是从querystring获取属性名称并将其映射到您需要的变量。像这样

    if(Request.QueryString.AllKeys.FirstOrDefault(p => p.ToLower().Contains("propertyname"))!=null)
    {
                     propertyname = Request.QueryString[Request.QueryString.AllKeys.First(p => p.ToLower().Contains("propertyname"))];
}

它将搜索并映射所需的变量。

希望这会有所帮助

答案 1 :(得分:1)

我希望你已经找到了答案,但如果你没有,请试试这个:

[HttpPost]
public JsonResult UniqueItemNo()
{
    var itemNumber = Request.Form[Request.Form.AllKeys.First(p => p.Contains("ItemNumber"))];

    /** Do Work **/
    return Json(true);
}

请注意@Mamoon你的Rasheed答案几乎是正确的,但由于你正在使用POST,你的参数将在Form属性中,而不是QueryString。

如果您对此仍有任何疑问,请与我们联系。

顺便说一句,你应该使用try / catch。我没有写它只是为了保持简单。

答案 2 :(得分:0)

尝试更改参数以匹配模型。像这样:

    [HttpPost]
    public JsonResult UniqueItemNo(ItemModel itemModel)
    {
        // look at itemModel.ItemNumber...
        /** Do Work **/
        return null;
    }

您仍然可以按照正常的编码惯例以小写(ActionMethod而不是itemNumber)开始ItemNumber参数的名称。

编辑:您是否尝试过这样编码View

@{
    ViewBag.Title = "Home Page";
}

<h2>@ViewBag.Message</h2>
        @foreach (var item in Items)
        {
           @using(Html.BeginForm()) {
              <p>
                 @Html.HiddenFor(m=>m.CartNumber)
                 @Html.TextBoxFor(m => item.ItemNumber);
                 @Html.ValidationMessageFor(m => item.ItemNumber);                                    
              </p>
           }
        }

答案 3 :(得分:0)

不幸的是,你没有这方面的支持。

在客户端,远程验证由jquery.validate.unobtrusive.js处理,后面写着

...
$.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
    var paramName = appendModelPrefix(fieldName, prefix);
    value.data[paramName] = function () {
        return $(options.form).find(":input[name='" + escapeAttributeValue(paramName) + "']").val();
    };
});
...

因此您应该注意到,对于每个附加字段,它只在查询字符串中构造一个参数(如果您发布,则在表单中)。因为你的服务器端远程属性应该看起来像

[Remote("UniqueItemNo", AdditionalFields = "ItemNumber[0],ItemNumber[1],...")]
事实上你在设计时并不知道。

你可以使用一个js hack并保留一个名为ItemNumber的隐藏字段,并且值为一个连接的id列表。在服务器端,您应该将ItemNumber数组的类型更改为字符串并拆分值。

我希望这会有所帮助,尽管你问过很长时间。