Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I reuse a remote validation method when the parameter name needs to be different?

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?

like image 679
Glazed Avatar asked Oct 11 '22 07:10

Glazed


1 Answers

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.

like image 110
SmartDev Avatar answered Nov 02 '22 23:11

SmartDev