当参数名称需要不同时,如何重用远程验证方法?

发布于 2024-10-31 23:14:12 字数 2286 浏览 0 评论 0原文

我有两个类用作两个不同视图的模型。您可以看到第二个类包含第一个类的实例。第一个包含远程验证属性。

[MetadataType( typeof( ExceptionLogModel.EmailRecipientMetadata ) )]
public class EmailRecipientViewModel
{
    public int EmailRecipientID { get; set; }

    [Remote( "ValidateEmailRecipientNameUniqueness", "EmailRecipient", ErrorMessage = "Name is not unique." )]
    public string Name { get; set; }

    [Remote( "ValidateEmailRecipientEmailUniqueness", "EmailRecipient", ErrorMessage = "Email is not unique." )]
    public string Email { get; set; }
}

public class EmailRecipientChoices
{
    public List<EmailRecipient> UnselectedEmailRecipients { get; set; }
    public List<EmailRecipient> SelectedEmailRecipients { get; set; }
    public EmailRecipientViewModel EmailRecipient { get; set; }
}

当这些验证在浏览器中触发时,会根据视图使用的类发出两个不同的请求。您可以看到查询字符串参数名称不同:

http://localhost:55327/EmailRecipient/ValidateEmailRecipientNameUniqueness?Name=sdhsdgh

http://localhost:55327/EmailRecipient/ValidateEmailRecipientNameUniqueness?EmailRecipient.Name=sdhsdgh

这是我的操作方法的当前版本,它不适用于第二个 URL:

public JsonResult ValidateEmailRecipientNameUniqueness( string name )
{
    var isValid = !_emailRecipientRepo.NameExists( name );

    return Json( isValid, JsonRequestBehavior.AllowGet );
}

当使用第二个 URL 时,名称参数将为 null。我读过,我应该能够向该参数添加 Bind 属性并添加前缀,但这也不起作用。我什至尝试将前缀设置为 EmailRecipient. 以防万一它需要点。为了以防万一,我还尝试在名称中使用大写的 N。不去。添加此也会破坏其他 URL!

public JsonResult ValidateEmailRecipientNameUniqueness( [Bind( Prefix = "EmailRecipient")] string name )

可能的解决方案

我可以让该方法采用 EmailRecipientViewModel 的实例并为其创建一个 IModelBinder,我可以在其中查找任一命名约定并将其分配给该实例。这似乎比应有的工作量更多。

我可以使用 @Html.EditorFor() 的重载,并告诉它使用“Name”作为 htmlFieldName,也可以使用 @Html.ValidationMessage( "Name" )ValidationMessageFor。唯一的缺点是潜在的命名冲突,但这没什么大不了的。我只需为正在使用的此类的所有实例使用唯一的名称即可。 更新:实际上,如果我这样做,当我发布表单时会破坏一些东西,因为我更改了名称。那可不好。

...

我刚刚发现我可以让该方法不带参数,并手动访问查询字符串。这是一个非常简单的解决方案,但我没有得到很好的参数。

string name = Request.QueryString[ "Name" ] ?? Request.QueryString[ "EmailRecipient.Name" ];

这很简单,我可能只会使用它。但是,由于我已经输入了这个问题,所以我会问,是否有更优雅的解决方案?

I have two classes I'm using as the model of two different views. You can see that the second class contains an instance of the first. The first contains Remote validation attributes.

[MetadataType( typeof( ExceptionLogModel.EmailRecipientMetadata ) )]
public class EmailRecipientViewModel
{
    public int EmailRecipientID { get; set; }

    [Remote( "ValidateEmailRecipientNameUniqueness", "EmailRecipient", ErrorMessage = "Name is not unique." )]
    public string Name { get; set; }

    [Remote( "ValidateEmailRecipientEmailUniqueness", "EmailRecipient", ErrorMessage = "Email is not unique." )]
    public string Email { get; set; }
}

public class EmailRecipientChoices
{
    public List<EmailRecipient> UnselectedEmailRecipients { get; set; }
    public List<EmailRecipient> SelectedEmailRecipients { get; set; }
    public EmailRecipientViewModel EmailRecipient { get; set; }
}

When these validations trigger in the browser, two different requests are made depending on which class the view used. You can see that the query string parameter names are different:

http://localhost:55327/EmailRecipient/ValidateEmailRecipientNameUniqueness?Name=sdhsdgh

http://localhost:55327/EmailRecipient/ValidateEmailRecipientNameUniqueness?EmailRecipient.Name=sdhsdgh

Here is the current version of my action method which does not work with the second URL:

public JsonResult ValidateEmailRecipientNameUniqueness( string name )
{
    var isValid = !_emailRecipientRepo.NameExists( name );

    return Json( isValid, JsonRequestBehavior.AllowGet );
}

When the second URL is used, the name parameter will be null. I've read that I should be able to add a Bind attribute to that parameter and add a prefix, but this is not working either. I even tried setting the prefix to EmailRecipient. just in case it needed the dot. I also tried it with a capital N in Name just in case. No go. Adding this also breaks it for the other URL!

public JsonResult ValidateEmailRecipientNameUniqueness( [Bind( Prefix = "EmailRecipient")] string name )

Possible solutions

I could have the method take an instance of EmailRecipientViewModel and create an IModelBinder for it in which I could look for either naming convention and assign it to the instance. This seems like more work than it should be.

I could use the overload for @Html.EditorFor() and tell it to use "Name" for htmlFieldName, and also use @Html.ValidationMessage( "Name" ) rather than ValidationMessageFor. The only downside to this is potential naming conflicts, but that's not too big of a deal. I'd just have to use a unique name for all instances of this class being used. Update: Actually, if I do this, is breaks things when I post the form because I changed the names. That's no good.

...

I just figured out that I could have the method take no parameters, and access the Query String manually. This is a pretty simple solution, but I don't get the nice parameter.

string name = Request.QueryString[ "Name" ] ?? Request.QueryString[ "EmailRecipient.Name" ];

This is easy enough that I'm probably just going to use this. However, since I already have this question typed up, I'll ask, Is there a more elegant solution?

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

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

发布评论

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

评论(2

盗琴音 2024-11-07 23:14:12

好吧,我知道这已经晚了,但有一个更优雅的解决方案:

public JsonResult ValidateEmailRecipientNameUniqueness (EmailRecipient recipient)
{
    string name = recipient.Name;
    var isValid = !_emailRecipientRepo.NameExists(name);
    return Json(isValid, JsonRequestBehavior.AllowGet);
}

换句话说,使用模型本身。它将正确绑定 name 属性,您只需要这个值。

Well, I know this is late but there is a more elegant solution:

public JsonResult ValidateEmailRecipientNameUniqueness (EmailRecipient recipient)
{
    string name = recipient.Name;
    var isValid = !_emailRecipientRepo.NameExists(name);
    return Json(isValid, JsonRequestBehavior.AllowGet);
}

In other words, use the model itself. It will correctly bind the name property and you only need this value.

假情假意假温柔 2024-11-07 23:14:12

如果不滚动您自己的验证或模型绑定器,就没有真正干净的方法来做到这一点。将其视为模型绑定,模型绑定器需要知道传入内容的名称,对于远程验证也是如此。您可以采取的一种方法是在控制器中创建两个单独的远程验证方法,最终调用实际执行所有验证工作的一个方法。

There isn't really a clean way to do this without rolling your own validation or model binder. Think of it like model binding, the model binder needs to know the name of what is coming in, same for remote validation. One approach that you could take is to create two separate remote validation methods in your controller that end up calling the one method that actually does all of the validation work.

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