I am validating using jQuery:
$el.rules("add", {
remote: {
url: `/api/distributors/KeywordExists`,
type: "post",
data: {
id: @Model.Distributor.DistributorId
}
}
});
The $el
is an input element generated by Razor Pages from a string[]
, so it is rendered like this:
<input type="text" id="Distributor_Keywords_0_" name="Distributor.Keywords[0]" >
After that there is the next element in the string[]
:
<input type="text" id="Distributor_Keywords_1_" name="Distributor.Keywords[1]" >
etc.
In order to validate, the rules
say to check /api/distributors/KeywordExists
. This method looks like this:
[AcceptVerbs("GET","POST"), Route("KeywordExists")]
public JsonResult KeywordExists(long id, string keyword)
{
if (!string.IsNullOrEmpty(keyword))
{
var match = CheckDbIfKeywordIsMatch();
if (match is not null)
{
return new JsonResult(!match.Exists) ;
}
}
return new JsonResult(true);
}
The actual API works perfectly, the problem is that it only works when the parameters are id
and keyword
However the jQuery validation sends the following Form Data in its payload:
Distributor.Keywords[0]:
Amazon
id:
1
Therefore, the URL is Distributor.Keywords[0]=Amazon&id=1
which the Controller does not recognize.
If I could write KeywordExists(long id, string Distributor.Keyword*)
that would catch the params being sent but obviously I can't.
I have tried adding [Bind] attributes to no avail
CodePudding user response:
You can try to use custom model binding to bind Distributor.Keywords[x]
with keyword
,here is a demo:
url:
https://localhost:xxxx/A/KeywordExists?Distributor.Keywords[0]=Amazon&id=1
custom model binder:
public class CustomBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
//get Keyword data with the following code
var data= bindingContext.HttpContext.Request.QueryString.ToString().Split("&")[0].Split("=")[1];
bindingContext.Result = ModelBindingResult.Success(data);
return Task.CompletedTask;
}
}
action:
[AcceptVerbs("GET","POST"), Route("KeywordExists")]
public JsonResult KeywordExists(long id, [ModelBinder(typeof(CustomBinder))]string keyword)
{
if (!string.IsNullOrEmpty(keyword))
{
var match = CheckDbIfKeywordIsMatch();
if (match is not null)
{
return new JsonResult(!match.Exists) ;
}
}
return new JsonResult(true);
}
CodePudding user response:
I didn't manage to change the param with a dot. But I solved the problem a different way. I made jQuery validate pass another param called keyword, with the same value as the validated element:
$el.rules("add", {
remote: {
url: `/api/distributors/KeywordExists`,
type: "post",
data: {
id: () => @Model.Distributor.DistributorId,
keyword: () => $el.val()
}
}
});
As these were sent as Form Data in the body, I had to add the following attributes to the controller method otherwise they were null: KeywordExists([FromForm] long id, [FromForm] string keyword)
The Distributor.Keyword[i]
was still being sent in the request body, but as there was also a param called keyword, the framework identified this as the correct method.