14

我正在尝试对集合中项目的属性执行远程验证。验证适用于集合的第一项。验证方法的 http 请求如下所示:

/Validation/IsImeiAvailable?ImeiGadgets[0].ImeiNumber=123456789012345

但是,在 url 如下所示的第二个项目中,验证不起作用

/Validation/IsImeiAvailable?ImeiGadgets[1].ImeiNumber=123456789012345

现在我很确定这样做的原因是绑定不会在不以零索引开头的集合上工作。

我的验证方法具有如下签名:

public JsonResult IsImeiAvailable([Bind(Prefix = "ImeiGadgets")] Models.ViewModels.ImeiGadget[] imeiGadget)

因为我在集合中传递一个项目,所以我必须像这样绑定,但我真正传递的只是一个值。

除了将它绑定为普通的旧查询字符串之外,我是否可以处理这个问题。

谢谢

编辑:这是获取 Imei 变量的快速修复,但我宁愿使用模型绑定:

string imeiNumber = Request.Url.AbsoluteUri.Substring(Request.Url.AbsoluteUri.IndexOf("=")+1);

编辑:这是我的 ImeiGadget 课程:

public class ImeiGadget
{
    public int Id { get; set; }

    [Remote("IsImeiAvailable", "Validation")]
    [Required(ErrorMessage = "Please provide the IMEI Number for your Phone")]
    [RegularExpression(@"(\D*\d){15,17}", ErrorMessage = "An IMEI number must contain between 15 & 17 digits")]
    public string ImeiNumber { get; set; }
    public string Make { get; set; }
    public string Model { get; set; }
}
4

5 回答 5

8

您可以编写自定义模型绑定器:

public class ImeiNumberModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var modelName = bindingContext.ModelName;
        var request = controllerContext.HttpContext.Request;
        var paramName = request
            .Params
            .Keys
            .Cast<string>()
            .FirstOrDefault(
                x => x.EndsWith(modelName, StringComparison.OrdinalIgnoreCase)
            );

        if (!string.IsNullOrEmpty(paramName))
        {
            return bindingContext
                .ValueProvider
                .GetValue(request[paramName])
                .AttemptedValue;
        }

        return null;
    }
}

然后将其应用于控制器操作:

public ActionResult IsImeiAvailable(
    [ModelBinder(typeof(ImeiNumberModelBinder))] string imeiNumber
)
{
    return Json(!string.IsNullOrEmpty(imeiNumber), JsonRequestBehavior.AllowGet);
}

现在该ImeiGadgets[xxx]部分将从查询字符串中被忽略。

于 2012-05-29T14:53:01.273 回答
0

如果您将单个值发送到服务器进行验证,那么您的 Action Method 应该只接受一个标量(单值)参数,而不是一个集合。然后您的 URL 将如下所示(假设 {controller}/{action}/{id} 的默认路由表:

/Validation/IsImeiAvailable?ImeiNumber=123456789012345

相应的操作方法签名可能如下所示:

/* note that the param name has to matchthe prop name being validated */
public ActionResult IsImeiAvailable(int ImeiNumber)

编辑:然后您可以使用它来查找该特定 ID 是否可用。

如果要更改参数的名称,可以修改路由表,但这是另一个主题。

长话短说,如果您想验证 的集合ImeiGadget您将获取或发布该完整集合。对于单个值,发送或期望整个集合没有多大意义。

更新:根据新信息,我会查看远程验证属性的放置位置。听起来它可能被放置在类似的东西上IEnumerable<IMEiGadgets>,像这样:

[Remote("IsImeiAvailable", "Validation", "'ImeiNumber' is invalid"]
public IEnumerable<ImeiGadget> ImeiGadgets { get; set;}

是否可以移动该属性并将其修改为在ImeiGadget类上,而不是像这样?

[Remote("IsImeiAvailable", "Validation", "'ImeiNumber is invalid"]
public int ImeiNumber { get; set;}

从理论上讲,如果您还进行了我上面回答中建议的更改,则无需更改 HTML 模板或脚本上的任何内容即可使其正常工作。理论上。

于 2012-05-29T13:33:09.547 回答
0

如果您发布整个集合,但有一个非顺序索引,您可以考虑绑定到字典而不是 http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

如果您只发布单个项目或使用 GET 链接,那么您应该修改为

/Validation/IsImeiAvailable?ImeiNumber=123456789012345

public JsonResult IsImeiAvailable(string imeiNumber)
于 2012-05-29T14:11:59.910 回答
0

除非您在许多地方都需要此绑定功能并且您可以控制IsImeiAvailable验证方法,否则我认为创建自定义模型绑定器是一种开销

你为什么不尝试这样一个简单的解决方案,

// need little optimization?
public JsonResult IsImeiAvailable(string imeiNumber)
{
  var qParam = Request.QueryString.Keys
     .Cast<string>().FirstOrDefault(a => a.EndsWith("ImeiNumber"));

  return Json(!string.IsNullOrEmpty(imeiNumber ?? Request.QueryString[qParam]), JsonRequestBehavior.AllowGet);
}
于 2012-05-31T06:15:41.640 回答
0

您可以添加一个带有.Index后缀的额外隐藏字段以允许任意索引。

看法:

<form method="post" action="/Home/Create">
    <input type="hidden" name="products.Index" value="cold" />
    <input type="text" name="products[cold].Name" value="Beer" />
    <input type="text" name="products[cold].Price" value="7.32" />

    <input type="hidden" name="products.Index" value="123" />
    <input type="text" name="products[123].Name" value="Chips" />
    <input type="text" name="products[123].Price" value="2.23" />

    <input type="hidden" name="products.Index" value="caliente" />
    <input type="text" name="products[caliente].Name" value="Salsa" />
    <input type="text" name="products[caliente].Price" value="1.23" />

    <input type="submit" />
</form>

模型:

public class Product{
    public string Name{get; set;}
    public decimal Price{get; set;}
}

控制器:

public ActionResult Create(Product[] Products)
{
    //do something..
}

有关更多信息,请参阅:您已被黑客攻击:模型绑定到列表

于 2020-02-27T08:11:14.250 回答