4
votes

I’m developing a web application using Razor Pages and Code First.

I know that in ASP.NET MVC, you can use Remote above a property referring to an action in a controller that validates the data without the whole page being posted back. But it doesn’t seem to work in Razor Pages as there’s no Controller and Action in ASP.NET Core Razor Pages.

So, How can I get remote validation done in Razor Pages?

5
The skills for ASP.NET MVC and ASP.NET Core (always "MVC", but different) are so not so easily transferable. Take some time (maybe a lot!) to read up on docs.microsoft.com/en-us/aspnet/core/razor-pages/…Mark Cooper
@BrianOgden The article you put out deals with Remote validation in Asp.Net Core MVC not Asp.Net Razor Pages! They're close but different! I'm looking for a way to implement Remote validation in Razor Pages.I already did quite a bit of searching before turning to community help as the last resort.Meisam Dehghan
Then adjust you internet search: binaryintellect.net/articles/…Brian Ogden
@meisamdehghan make an edit to your question then I can remove my downvote, add space after the comm in "So,How can I..."Brian Ogden
@BrianOgden Thanks for the answer.It appears that as of now there is no Razor Pages specific version of the [Remote] attribute in Asp.Net Core.Meisam Dehghan

5 Answers

4
votes

I added the following in my model class:

 [Remote(action: "IsNationalIdValid",controller:"Validations")]

I created 'Controllers' folder in my Razor Pages project and added a controller(ValidationsController) with the following method:

        public IActionResult IsNationalIdValid(string nationalId){}

However,when I tried to go to the page where this validation was supposed to work,I got the following exception:

No URL for remote validation could be found in asp.net core

Thanks to a reply to the same thread in Asp.Net forum,I figured out the answer: All I needed to do was to add the following code in Startup.cs file of my Razor Pages project in order to configure the route.

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

Hope this answer will help someone else as well.

4
votes

For anyone like me who finds this later and loses their mind trying to pass a property from their model onto the validation method, make the method signature look like so

public IActionResult IsCharacterNameAvailable([Bind(Prefix = "Character.Name")] string name)

Character is the model and Name is the property. Without adding the [Bind(Prefix = "")] before the parameter I was always receiving a null value. Hope this helps!

3
votes

In the base class that RemoteAttribute derives from there's a protected GetUrl() method than can be overriden. Therefore I created my own MyRemoteAttribute class

public class MyRemoteAttribute : RemoteAttribute
{
    /// <summary>
    /// Initialise an instance of the <see cref="MyRemoteAttribute"/>
    /// </summary>
    /// <param name="handler">The name of the Razor Page Handler</param>
    /// <param name="page">The Razor Page name</param>
    public MyRemoteAttribute(string handler = null, string page = null)
    {
        Handler = handler;
        Page = page;
    }

    /// <summary>
    /// Gets/sets the url to use for remote validation
    /// </summary>
    public string Url { get; set; }
    public string Page { get; private set; }
    public string Handler { get; private set; }

    protected override string GetUrl(ClientModelValidationContext context)
    {
        // Use an URL is specified
        if (!string.IsNullOrEmpty(Url)) return Url;

        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }
        if (string.IsNullOrEmpty(Handler))
        {
            throw new InvalidOperationException("No Handler specified");
        }

        var services = context.ActionContext.HttpContext.RequestServices;
        var factory = services.GetRequiredService<Microsoft.AspNetCore.Mvc.Routing.IUrlHelperFactory>();
        var urlHelper = factory.GetUrlHelper(context.ActionContext);

        var page = Page?? context.ActionContext.RouteData.Values["page"] as string;

        Url = urlHelper.Page(page, Handler);
        if (Url == null)
        {
            throw new InvalidOperationException();
        }

        return Url;
    }
}

In my app which is using areas, creates a url /BusinessPartners/Clients/Create?handler=CheckUnique

To use decorate your model property with [MyRemote(Url="/Something/Somecheck")] to use the specified URL, or [MyRemote("CheckUnique")] to specify the Razor Page Handler. The handler should be named OnGet<handlername> and needs to return a JsonResult with true for passing validation, false or null if validation fails.

The handler in the Razor Page is:

public IActionResult OnGetCheckUnique(string shortName)
{
    var found = db.Queryable<BusinessPartner>().Any(a => a.ShortName == shortName);
    return new JsonResult(!found);
}

This is the same as you would do for the RemoteAttribute with the exception on the slightly modified naming convention.

I like my validation to be close to the point where it is used so therefore I've put it in the same page. I also have use a single [BindProperty] for a model class just to keep things neat and manageable.

2
votes

Looks like there is a feature request for remote validation in ASP.NET Core Razor Pages but it is not priority:

https://github.com/aspnet/Mvc/issues/8245

1
votes

The PageRemoteValidation attribute was introduced in ASP.NET Core 3.0 and is designed specifically to work with a Razor Pages handler method.

So, if you are working with ASP.NET Core 2.x, or your validation endpoint is an MVC controller, you must use the RemoteValidation attribute. If you are working with ASP.NET Core 3.x or newer, AND your validation service is a Razor Pages handler method, you must use the PageRemoteValidation attribute.

Here is an example describing this in details: