Передача настраиваемых параметров в ValidationAttribute

Я построил настраиваемый атрибут ValidationAttribute, чтобы я мог проверять уникальные адреса электронной почты в своей системе. Тем не менее, я хотел бы каким-то образом передать пользовательский параметр, чтобы добавить к моей проверке еще больше логики.

public class UniqueEmailAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        //I need the original value here so I won't validate if it hasn't changed.
        return value != null && Validation.IsEmailUnique(value.ToString());
    }
}

Ответ 1

Как это?

public class StringLengthValidatorNullable : ValidationAttribute
{
    public int MinStringLength { get; set; }
    public int MaxStringLength { get; set; }

    public override bool IsValid(object value)
    {
        if (value == null)
        {
            return false;
        }
        var length = value.ToString().Length;

        if (length < MinStringLength || length >= MaxStringLength)
        {
            return false;
        }
        return true;
    }
}

Использование:

[StringLengthValidatorNullable(MinStringLength = 1, MaxStringLength = 16)]
public string Name {get; set;}

Ответ 2

Имел аналогичное требование, когда мне приходилось передавать значение в пользовательский атрибут.

Проблема здесь в том, что атрибуты атрибутов не позволяют переменные. Вы получаете ошибку времени компиляции:

Ссылка на объект требуется для нестатического поля, метода или Свойство

Вот как я смог это сделать:

В контроллере

[FineGrainAuthorization]
public class SomeABCController : Controller
{
    public int SomeId { get { return 1; } }
}

В атрибуте

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class FineGrainAuthorizationAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);
        ControllerBase callingController = filterContext.Controller;
        var someIdProperty = callingController.GetType().GetProperties().Where(t => t.Name.Equals("SomeId")).First();
        int someId = (int) someIdProperty.GetValue(callingController, null);
    }
}

Помните, что строка внутри .Name.Equals("SomeId") должна совпадать с объявлением public int SomeId

Ответ 3

Вы также можете передать параметры, которые являются другими свойствами в той же модели.

Создайте собственный атрибут проверки:

public class SomeValidationAttribute : ValidationAttribute
{
    //A property to hold the name of the one you're going to use.
    public string OtherProperty { get; set; }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        //Get the value of the property using reflection.
        var otherProperty = validationContext.ObjectType.GetProperty(OtherProperty);
        var otherPropertyValue = (bool)otherProperty.GetValue(validationContext.ObjectInstance, null);

        if (value != null && otherPropertyValue)
        {
            return ValidationResult.Success;
        }

        return new ValidationResult("Invalid property message.");
    }
}

Затем передайте имя свойства, которое вы собираетесь использовать.

    public class RequestModel 
    {
        public bool SomeProperty { get; set; }

        [SomeValidation(OtherProperty = "SomeProperty")]
        public DateTime? StartDate { get; set; }
    }

Ответ 4

Я бы предложил что-то вроде @Oliver (что бы я сделал, во всяком случае), но потом я заметил, что вы не хотите передавать константы.

Как насчет чего-то подобного?

public static class MyConfig
{
    public static int MinStringLength { get; set; }
    public static int MaxStringLength { get; set; }
    public static SomeObject otherConfigObject { get; set; }
}

А затем доступ MyConfig.MinStringLength к проверке? Я соглашусь, что это не слишком красиво.