Shomaail
Shomaail

Reputation: 493

Using remote attribute in .net core razor pages. The Parameter does not get value in Action Method of Controller

I am using Remote Attribute validation The method is invoked successfully on textchange event. However, the parameters in the action method of the controller does not get the value of the field.

Here is the Action Method in the HomeController.cs. When invoked the Name parameter remains null. I will be pleased if someone solve this problem

    [AcceptVerbs("Get", "Post")]
    public async Task<ActionResult> IsExist(string Name)
    {
        List<Keywords> keywords = new List<Keywords>();
        HttpClient client = _api.Initial();
        HttpResponseMessage res = await client.GetAsync("api/Keywords");
        if (res.IsSuccessStatusCode)
        {
            var result = res.Content.ReadAsStringAsync().Result;
            keywords = JsonConvert.DeserializeObject<List<Keywords>>(result);
        }
        if (keywords.FirstOrDefault(x => x.Name == Name) == null)
        {
            return Json(false);
        }
        else
        {
            return Json(true);
        }}

Here is the Model

 public partial class Keywords
{
    public int Id { get; set; }
    [Display(Name = "Name of Keyword")]
    [Required]   
    [Remote(action: "IsExist",controller: "Home", ErrorMessage = "Keyword already present!")]
    public string Name { get; set; }}

Here is the razor page in which I want to implement validation

    @page
    @model Consumer.Pages.Keyword.CreateModel

    @{
        ViewData["Title"] = "Create";
     }
<h1>Create</h1>

<h4>Keywords</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Keywords.Name" class="control-label"></label>
                <input asp-for="Keywords.Name" class="form-control" />
                <span asp-validation-for="Keywords.Name" class="text-danger"></span>
            </div>

            <div class="form-group">
                <label asp-for="Keywords.Department" class="control-label"></label>
                <select asp-for="Keywords.DepartmentId" class="form-control" asp-items="ViewBag.Department"></select>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-page="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Upvotes: 0

Views: 524

Answers (2)

Shomaail
Shomaail

Reputation: 493

I found the solution. It is to

  1. Remove partial in the model class definition.
  2. Replace in the Razor Page
<input asp-for="Keywords.Name" class="form-control" />

with

<input asp-for="Keywords.Name" name="Name" class="form-control" />

Upvotes: 1

Chris Pratt
Chris Pratt

Reputation: 239400

The [Remote] attribute is all but useless. There's a long-standing problem from the ASP.NET MVC days that migrated its way into ASP.NET Core unabated, as well. Namely, the action that handles the remote must take a param that matches the input name of what what's being validated. In other words, your action takes a param, name, but what's being sent to it is Keywords.Name, which cannot bind to name. You'd have to do something like:

public async Task<ActionResult> IsExist(Keywords keywords)

And then, then the value will be available via keywords.Name. This obviously makes the usage highly dependent on the particular implementation, so if there's a situation with a different input name like Foo.Keywords.Name, then you'd need an entirely different action, to match that binding, and basically duplicate the logic (though you could factor out the majority the logic into some common method all the actions could utilize).

Long and short, you're probably better off just handling this yourself manually. Just bind to the input event on the name input, and then call your method via AJAX. Then you can explicitly control the key that's sent in the request body, such that it will always match your action. Just note that you'll also want to debounce sending that AJAX request so that it only happens every few keystrokes or so. Otherwise, you're going to hammer your action.

Upvotes: 0

Related Questions