Валидатор RemoteAttribute не запускает серверную часть - PullRequest
4 голосов
/ 22 марта 2011

Похоже, что валидатор RemoteAttribute, представленный в ASP.NET MVC 3, не проверяет на стороне сервера, только через JavaScript.Если вы отключите JS в своем браузере, вы обнаружите, что при привязке модели действие контроллера проверки (указанное вами при украшении свойства модели с помощью RemoteAttribute) не будет выполнено.На самом деле, если вы проверите исходный код RemoteAttribute, вы обнаружите, что методы IsValid просто возвращают true во всех случаях.

Это кажется довольно упущением - я думаю, что большинство людей предполагает, что RemoteAttributeработать как все другие встроенные валидаторы и проверять как на стороне клиента, так и на стороне сервера.Вместо этого вы должны вручную вызвать вашу логику удаленной проверки в действии контроллера.

Знают ли люди об этом и пытался ли кто-нибудь обратиться к нему?

Я переклассифицировал RemoteAttribute и переопределил метод IsValid, гдеУ меня есть доступ к RouteData, RouteName и Routes, а также метод GetUrl, который возвращает URL-адрес действия.Я думал об использовании отражения для вызова действия и получения результата, чтобы я мог видеть, является ли он действительным или нет, но есть ли какие-то встроенные методы, которые я могу использовать, не прибегая к отражению?

Ответы [ 4 ]

3 голосов
/ 16 мая 2013

Возможно, это не лучший код.Если у вас есть рекомендации, пожалуйста, дайте мне знать.Developed @ MVC4

Свойство модели с пользовательским атрибутом

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

Subclassed 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);
    }
}

ПроверкаКод контроллера

/// <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
            };
    }
}
1 голос
/ 22 марта 2011

Это предполагаемое поведение удаленной проверки.Нет никакого способа узнать, какой будет реализация IsValid, поэтому он просто возвращает true.Если вам нужна проверка на стороне сервера для RemoteAttribute, вы должны переопределить IsValid, как вы это сделали.

0 голосов
/ 12 августа 2015

Как уже было сказано ранее, это умышленно.

Я только что наткнулся на хорошую статью о CodeProject - http://www.codeproject.com/Articles/361113/Extending-the-MVC-RemoteAttribute-to-validate-ser

0 голосов
/ 24 декабря 2014

Удаленный валидатор часто с дополнительным полем.Вот реализация для этого случая.

/// <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 );    
    }
}
...