RemoteAttribute Verifier Does Not Start Server

It seems that the RemoteAttribute validator introduced in ASP.NET MVC 3 is not checked on the server side, only through JavaScript. If you disable JS in your browser, you will find that when you bind the model, the action of the validation controller (which you specified when decorating the model properties using the RemoteAttribute attribute) will not be affected. In fact, if you check the source code for the RemoteAttribute attribute, you will find that the IsValid methods simply return true in all cases.

This seems like an oversight - I think most people believe that RemoteAttribute will work, like all other built-in validators, and check both on the client side and the server side. Instead, you must manually invoke your remote validation logic in your controller action.

Do people know about this and did anyone try to solve it?

I have a subclassed RemoteAttribute and the IsValid method is overridden, where I have access to RouteData, RouteName and Routes, as well as the GetUrl method, which returns the action URL. I was thinking about using reflection to trigger an action and get the result, so that I can see if it really is or not, but are there any built-in methods that I can use without resorting to reflection?

+4
source share
5 answers

Maybe this is not the best code. If you have any recommendations, please let me know. Designed by @ MVC4

Model property with custom attribute

[CustomRemote("ValidateIP", "Validation", ErrorMessage = "Input is not a valid IP")] 

Subclass RemoteAttribute

 /// <summary> /// Custom Remote Attribute for Client an Server validation. /// </summary> public class CustomRemoteAttribute : RemoteAttribute { /// <summary> /// List of all Controllers on MVC Application /// </summary> /// <returns></returns> private static List<Type> GetControllerList() { return Assembly.GetCallingAssembly().GetTypes().Where(type => type.IsSubclassOf(typeof(Controller))).ToList(); } /// <summary> /// Constructor of base class. /// </summary> protected CustomRemoteAttribute() { } /// <summary> /// Constructor of base class. /// </summary> public CustomRemoteAttribute(string routeName) : base(routeName) { } /// <summary> /// Constructor of base class. /// </summary> public CustomRemoteAttribute(string action, string controller) : base(action, controller) { } /// <summary> /// Constructor of base class. /// </summary> public CustomRemoteAttribute(string action, string controller, string areaName) : base(action, controller, areaName) { } /// <summary> /// Overridden IsValid function /// </summary> /// <param name="value"></param> /// <param name="validationContext"></param> /// <returns></returns> protected override ValidationResult IsValid(object value, ValidationContext validationContext) { // Find the controller passed in constructor var controller = GetControllerList().FirstOrDefault(x => x.Name == string.Format("{0}Controller", this.RouteData["controller"])); if (controller == null) { // Default behavior of IsValid when no controller is found. return ValidationResult.Success; } // Find the Method passed in constructor var mi = controller.GetMethod(this.RouteData["action"].ToString()); if (mi == null) { // Default behavior of IsValid when action not found return ValidationResult.Success; } // Create instance of the controller to be able to call non static validation method var instance = Activator.CreateInstance(controller); // invoke the method on the controller with value var result = (JsonResult)mi.Invoke(instance, new object[] { value }); // Return success or the error message string from CustomRemoteAttribute return (bool) result.Data ? ValidationResult.Success : new ValidationResult(base.ErrorMessageString); } } 

Verification Controller Code

 /// <summary> /// Controller for Client and Server validation /// <remarks>disable OutputCache</remarks> /// </summary> [OutputCache(Location = OutputCacheLocation.None, NoStore = true)] public class ValidationController : Controller { /// <summary> /// !!!!!!!!!!!!!!!!!! Needed for instance creation in custom attribute !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! /// </summary> public ValidationController() { } /// <summary> /// IP regex pattern of my choice /// </summary> const string IpPattern = @"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"; /// <summary> /// MAC regex pattern of my choice /// </summary> const string MacPattern = "^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$"; /// <summary> /// Validate IP /// </summary> /// <param name="ip">IP param is only submited on Serverside validation!!!</param> /// <returns>Validation Result</returns> public JsonResult ValidateIP(string ip) { // Check if ip and httpcontext is null to dodge NullReferenceException on Server side validation if (string.IsNullOrEmpty(ip) && HttpContext == null) { return Json(false, JsonRequestBehavior.AllowGet); } /* Use IP on Serverside validation * Use Querystring Param 0 to get IP from Client side vaildation without the need for the correct Id of input control */ string checkip = string.IsNullOrEmpty(ip) ? HttpContext.Request.QueryString[0] : ip; if (string.IsNullOrEmpty(checkip)) { return new JsonResult { Data = true, JsonRequestBehavior = JsonRequestBehavior.AllowGet }; } return new JsonResult { Data = Regex.IsMatch(checkip, IpPattern), JsonRequestBehavior = JsonRequestBehavior.AllowGet }; } } 
+3
source

This is the expected behavior of remote validation. It is impossible to find out what the IsValid implementation is, so it just returns true. If you need server-side validation for the RemoteAttribute attribute, you must override IsValid just like you did.

+1
source

Yes, I know about it and I think that it is lowering. I wrote a fix for it and explained here:

http://www.metaltheater.com/tech/technical/fixing-the-remote-validation-attribute/

I suggested to the ASP.NET team that this could be included as part of MVC4, but they did not agree and said: "It is intended only for verification on the client." I said: "How about a flag so you can at least choose to run it on the server side?" Still not, so you go.

0
source

Remote validator often with extra field. Here's the implementation for this case.

 /// <summary> /// Remote Attribute for Client an Server validation. /// </summary> public class RemoteWithServerSideAttribute : RemoteAttribute { /// <summary> /// List of all Controllers on MVC Application /// </summary> /// <returns></returns> private static IEnumerable<Type> GetControllerList() { return Assembly.GetCallingAssembly().GetTypes().Where( type => type.IsSubclassOf( typeof( Controller ) ) ).ToList(); } /// <summary> /// Constructor of base class. /// </summary> protected RemoteWithServerSideAttribute() {} /// <summary> /// Constructor of base class. /// </summary> public RemoteWithServerSideAttribute( string routeName ) : base( routeName ) {} /// <summary> /// Constructor of base class. /// </summary> public RemoteWithServerSideAttribute( string action, string controller ) : base( action, controller ){} /// <summary> /// Constructor of base class. /// </summary> public RemoteWithServerSideAttribute( string action, string controller, string areaName ) : base( action, controller, areaName ) {} /// <summary> /// Overridden IsValid function /// </summary> /// <param name="value"></param> /// <param name="validationContext"></param> /// <returns></returns> protected override ValidationResult IsValid( object value, ValidationContext validationContext ) { // Find the controller passed in constructor var controller = GetControllerList().FirstOrDefault( x => x.Name == string.Format( "{0}Controller", this.RouteData["controller"] ) ); if ( controller == null ) { // Default behavior of IsValid when no controller is found. return ValidationResult.Success; } // Find the Method passed in constructor var mi = controller.GetMethod( this.RouteData["action"].ToString() ); if ( mi == null ) { // Default behavior of IsValid when action not found return ValidationResult.Success; } // Create instance of the controller to be able to call non static validation method var instance = Activator.CreateInstance( controller ); // invoke the method on the controller with value and "AdditionalFields" JsonResult result; if ( !string.IsNullOrWhiteSpace( AdditionalFields ) ) { var additionalField = validationContext.ObjectType.GetProperty( AdditionalFields ) .GetValue( validationContext.ObjectInstance ); result = (JsonResult) mi.Invoke( instance, new [] { value, additionalField } ); } else result = (JsonResult)mi.Invoke( instance, new [] { value } ); // Return success or the error message string from CustomRemoteAttribute string errorMessaqe = result.Data as string; if (errorMessaqe == null) { bool isValid; try { isValid = (bool) result.Data; } catch (Exception) { isValid = false; } return isValid ? ValidationResult.Success : new ValidationResult( base.ErrorMessageString ); } else return new ValidationResult( errorMessaqe ); } } 
0
source

As already mentioned, this is by design.

I just came across a good article about CodeProject - http://www.codeproject.com/Articles/361113/Extending-the-MVC-RemoteAttribute-to-validate-ser

0
source

Source: https://habr.com/ru/post/1344781/


All Articles