简体   繁体   中英

Fail using Remote Validation, MVC, and Razor Pages .NET Core 2.2 ::: “InvalidOperationException: No URL for remote validation could be found”

Goal: Double-check Username for existence when making new account using Razor Pages .NET Core 2.2 and MVC.

Error: InvalidOperationException: No URL for remote validation could be found.

I have looked at other StackOverflow threads but I do not have any solution at this time.

My Data Annotation for UserName input:

[Microsoft.AspNetCore.Mvc.Remote("IsUserNameUsed", "ValidationsController", ErrorMessage = "Username is taken.")]
public string UserName { get; set; }

My code inside Controller ValidationsController:

  public IActionResult IsUserNameUsed([Bind(Prefix = "Accounts.UserName")] string username)
        { 
            string query = "SELECT UserName FROM Accounts WHERE UserName={0}";
            var found = _context.Accounts
            .FromSql(query, username)
            .FirstOrDefault();

            if (found.Equals(username))
            {
                return Json(true);
            }
            else
            { 
            return Json(false);
            }
        }

I get this error when trying to navigate to the Razor Page in question.

InvalidOperationException: No URL for remote validation could be found.
 <input asp-for="Accounts.UserName" class="form-control" />

I found mention of adding MVC route to a strictly Razor Pages application. I added the code below but I get the error no matter what I add.

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

I tried different route values using actual Controller name and it's task:

routes.MapRoute(
    name: "default",
    template: "{controller=Validations}/{action=IsUserNameUsed}/{username?}");

another try (no "?"):

  name: "default",
    template: "{controller=Validations}/{action=IsUserNameUsed}/{username}");

again another(no username):

name: "default",
template: "{controller=Validations}/{action=IsUserNameUsed}");

I know if it was a snake it would have bit me but I am totally dumbfounded.

I still get "InvalidOperationException: No URL for remote validation could be found."

This is the Data Annotation in my Accounts.cs Model for the UserName:

   [Required]
    [Remote("IsUserNameUsed", "Validations",ErrorMessage ="UserName already exists" ,HttpMethod ="post")]
    public string UserName { get; set; }

This is the UserName input on the .cshtml Razor Page:

<div class="form-group">
    <label asp-for="Accounts.UserName" class="control-label"></label>
    <input asp-for="Accounts.UserName" class="form-control" />
    <span asp-validation-for="Accounts.UserName" class="text-danger"></span>
</div>

This is the Action (JsonResult) in the Controller (ValidationsController). Notice inside the paranthesis the Binding of UserName field. Without this syntax returns null. And has to be set in the Controller/Json, not in the Model -- [Bind(Prefix = "Accounts.UserName")] string NameEntered :

public JsonResult IsUserNameUsed([Bind(Prefix = "Accounts.UserName")] string NameEntered)
{
    bool UserNameExists = _context.Accounts.Any(u => u.UserName.Equals(NameEntered));

    return new JsonResult(!UserNameExists);  //NOTICE OPPOSITE BOOLEAN
}

Also notice above how I hit the database table for existence with one line and return the JsonResult with only one other line. It's kind of a negative binary on off that you have to test to get it right because true(found) really means false(can't use).

Now, here is where I kept getting that error saying my route was wrong.

“InvalidOperationException: No URL for remote validation could be found”

So I tried referencing in the Model a custom named JsonResult("IsUserNameUsed") and in a custom name Controller("Validations") and giving that path in the Model:

[Remote("IsUserNameUsed", "Validations",ErrorMessage ="UserName already exists" ,HttpMethod ="post")]

I didn't know it but I was onto something. . . but . . . . . Since it is a Razor Pages .NET Core 2.2 app I still had to create a "using Microsoft.AspNetCore.Mvc" at the top of the Controller and put this in the Startup.cs file in Configure section.

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

Notice the above route is the default route that comes with an MVC application (website opens to the Index page). Funny how it is using "id?" even though I am validating a string.I excluded a HomeController I had added thinking it would trigger an error if it didn't exist. But. . .no error. . .just the default MVC route template is needed in Startup.cs and one custom named controller and 2 different routes.

However, the 2 routes is what makes my custom Controller JsonResult URL work coming from the Model's Data Annotation. Clear as mud? A default route needed to use MVC custom route, go figure.

and now you know the rest of the story.

Caveat: I am using 2.2 but if you have 3.0 there is now a "RemotePage" data annotation and MVC is not needed. You can find this on https://www.learnrazorpages.com/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM