MVC3 远程验证列表中的字段

发布于 2024-12-28 07:15:39 字数 1320 浏览 0 评论 0原文

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

例如,当调用我的远程验证方法(UniqueItemNo)时,字符串参数“id”始终为空。如果我要对 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>
}

For some reason, whenever I try to remotely validate a primitive property inside an array within my model, the value of the property is not passed as a parameter.

For example, when my remote validation method (UniqueItemNo) is called, the string parameter "id" is always null. If I were to perform validation on CartNumber instead of ItemNumber, the parameter is passed correctly.

Controller

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;
    }
}

Models

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; }
}

View

@{
    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>
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

辞慾 2025-01-04 07:15:39

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

就是根本原因。

当你执行 @Html.TextBoxFor(x=>xmItems[i].ItemNumber)
它输出类似这样的内容

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

,然后添加其他验证,例如用于验证的 data-* 属性。例如,远程验证 url data-remot-url 等

现在,当表单得到验证时,它会请求带有 key=xxx[1].propertyname 等数据的远程 url

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

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

 public JsonResult UniqueItemNo(list<string> propertyname)

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

唯一剩下的解决方案是从查询字符串中获取属性名称并将其映射到所需的变量。像这样

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

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

希望这会有所帮助

just solved the same problem. so for my type of people who are going to have this problem in future, here is the solution

here is the root cause.

when you do @Html.TextBoxFor(x=>x.m.Items[i].ItemNumber)
it outputs something like this

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

and then it adds the other validations like data-* attributes for validation. e.g. remote validation url data-remot-url and etc

now when form got validated it requested the remote url with data like key=xxx[1].propertyname

and this is not assignable to a single variable in remote action method that will receive this property.

if you will change the action arguments to something like this, then it will work

 public JsonResult UniqueItemNo(list<string> propertyname)

and even then you are not guranteed as it requires to have the parameters index start from 0 and without any gap. so xxx[1].ItemNumber will never get maped.

the only remaining solution is to get the property name from querystring and map it to your required variable. like this

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

it will search and map the required variables.

hope this will help

虚拟世界 2025-01-04 07:15:39

我希望您已经找到了答案,但如果您没有找到答案,请尝试以下操作:

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

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

请注意,@Mamoon ur Ra​​sheed 的答案几乎是正确的,但由于您使用的是 POST,因此您的参数将位于 Form 属性内,而不是 QueryString。

如果您对此仍有任何问题,请告诉我。

顺便说一句,你应该使用 try/catch。我写它并不是为了简单。

I hope you found an answer already, but in case you didn't, try this:

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

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

Note that @Mamoon ur Rasheed answer was almost correct, but since you're using POST your parameters will be inside the Form property, not QueryString.

Let me know if you still have any issues regarding this.

Btw, you should use a try/catch. I didn't wrote it just to keep it simple.

半夏半凉 2025-01-04 07:15:39

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

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

您仍然可以按照正常编码约定以小写字母开头(itemNumber 而不是 ItemNumberActionMethod 参数的名称。

编辑:您是否尝试过像这样编码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>
           }
        }

Try changing the parameter to match the model. Like this:

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

You can still start the name of the ActionMethod parameter with lowercase (itemNumber instead of ItemNumber) as per the normal coding conventions.

EDIT: Have you tried coding the View like this?

@{
    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>
           }
        }
鸵鸟症 2025-01-04 07:15:39

不幸的是,您没有对此的支持。

在客户端,远程验证由 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 数组的类型更改为字符串并拆分值。

我希望这会有所帮助,尽管距离您提问已经很长时间了。

Unfortunately you don't have support for this.

In client side the remote validation is handled by jquery.validate.unobtrusive.js which says

...
$.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();
    };
});
...

so you should notice that for each additional field it constructs just one parameter in query string (or in form if you do post). because of that you server side remote attribute should look like

[Remote("UniqueItemNo", AdditionalFields = "ItemNumber[0],ItemNumber[1],...")]

fact that you don't know at design time.

you could use a js hack and keep a hidden field named ItemNumber and with value a concatenated list of ids. on server side you should change the type of ItemNumber array into string and split the values.

I hope this helps although it's a long time since you asked.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文