Проверка Guid - PullRequest
       35

Проверка Guid

9 голосов
/ 25 августа 2011

У меня строго типизированное представление с атрибутом DropDownListFor.

Каждый элемент в раскрывающемся списке представлен GUID.

Что мне нужно, так это способ проверить, выбирает ли пользователь элемент из выпадающего списка. В настоящее время я не вижу никакого способа сделать это с помощью аннотаций данных.

Есть ли способ достичь этого с помощью аннотаций данных, чтобы проверка на стороне клиента и на сервере работала.

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

Ответы [ 4 ]

21 голосов
/ 03 декабря 2012

На самом деле, вы не можете использовать атрибут Required с GUID (без метода, который я упомянул ниже), потому что они наследуются от struct, и поэтому их значение по умолчанию фактически является экземпляром Guid.Empty, который будет удовлетворятьтребования атрибута Required.Теперь, как говорится, можно получить то, что вы хотите, просто сделав вашу собственность обнуляемой, возьмем это, например ...

public class Person
{
    [Required] //Only works because the Guid is nullable
    public Guid? PersonId { get; set;}
    public string FirstName { get; set;}
    public string LastName { get; set;}
}

Отметив GUID обнуляемым (используя? Или Nullable)если вы предпочитаете длинный путь), вы оставляете его пустым при привязке к тому, что отправил браузер.В вашем случае просто убедитесь, что значение параметра по умолчанию раскрывающегося списка использует пустую строку в качестве значения.

РЕДАКТИРОВАТЬ: Единственное предостережение для этого метода - в конечном итоге вам придетсявезде используйте что-то вроде Person.GetValueOfDefault() и, возможно, тестируйте Guid.Empty.Я устал от этого и закончил тем, что создал свой собственный атрибут проверки, чтобы помочь упростить проверку Guids (и любые другие типы, которые имеют значения по умолчанию, которые я хочу считать недействительными, такие как int, DateTime и т. Д.). Однако у меня пока нет подтверждения на стороне клиента, поэтому проверка происходит только на сервере. Это можно комбинировать с [Required] (предназначенным для того, чтобы не дублировать функциональность [Required]), еслиВы в порядке с использованием обнуляемых типов.Это означает, что вам все равно придется использовать GetValueOrDefault(), но, по крайней мере, вам больше не нужно проверять Guid.Empty.Ссылка Gist содержит несколько XMLDocs с примерами, я оставил их здесь для краткости.В настоящее время я использую его с ASP.NET Core.

РЕДАКТИРОВАТЬ: Обновлен, чтобы исправить ошибку с Nullable <>, а также с обработкой null как недействительным.Добавлены вспомогательные классы для обработки проверки на стороне клиента.Полный список см. В Gist.

Gist: RequireNonDefaultAttribute

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
public class RequireNonDefaultAttribute : ValidationAttribute
{
    public RequireNonDefaultAttribute()
        : base("The {0} field requires a non-default value.")
    {
    }

    public override bool IsValid(object value)
    {
        if (value is null)
            return true; //You can flip this if you want. I wanted leave the responsability of null to RequiredAttribute
        var type = value.GetType();
        return !Equals(value, Activator.CreateInstance(Nullable.GetUnderlyingType(type) ?? type));
    }
}
10 голосов
/ 25 августа 2011

Отредактированный ответ

После перечитывания вашего вопроса звучит так, будто вы просто хотите узнать, выбрано ли значение. Если это так, тогда просто примените RequiredAttribute к свойству Guid и сделайте его обнуляемым для модели

public class GuidModel
{
    [Required]
    public Guid? Guid { get; set; }

    public IEnumerable<Guid> Guids { get; set; }
}

затем в строго типизированном представлении (с @model GuidModel)

@Html.ValidationMessageFor(m => m.Guid)
@Html.DropDownListFor(
    m => m.Guid,
    Model.Guids.Select(g => new SelectListItem {Text = g.ToString(), Value = g.ToString()}),
    "-- Select Guid --")

Добавить ссылки на JavaScript-скрипт проверки клиента для проверки на стороне клиента.

Контроллер выглядит как

public class GuidsController : Controller
{
    public GuidRepository GuidRepo { get; private set; }

    public GuidsController(GuidRepository guidRepo)
    {
        GuidRepo = guidRepo;
    }

    [HttpGet]
    public ActionResult Edit(int id)
    {
        var guid = GuidRepo.GetForId(id);
        var guids - GuidRepo.All();

        return View(new GuidModel { Guid = guid, Guids = guids });
    }

    [HttpPost]
    public ActionResult Edit(GuidModel model)
    {
        if (!ModelState.IsValid)
        {
            model.Guids = GuidRepo.All();
            return View(model);
        }

        /* update db */

        return RedirectToAction("Edit");
    }
}

Это гарантирует, что свойство Guid требуется для привязки к модели GuidModel.

Оригинальный ответ

Я не верю, что есть готовый атрибут проверки аннотации данных, способный сделать это. Я написал в блоге об одном способе достижения этой цели ; пост использует контейнер IoC, но вы можете использовать жестко закодированную зависимость, если хотите, чтобы что-то работало.

что-то вроде

public class ValidGuidAttribute : ValidationAttribute
{
    private const string DefaultErrorMessage = "'{0}' does not contain a valid guid";

    public ValidGuidAttribute() : base(DefaultErrorMessage)
    {
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var input = Convert.ToString(value, CultureInfo.CurrentCulture);

        // let the Required attribute take care of this validation
        if (string.IsNullOrWhiteSpace(input))
        {
            return null;
        }

        // get all of your guids (assume a repo is being used)
        var guids = new GuidRepository().AllGuids();

        Guid guid;
        if (!Guid.TryParse(input, out guid))
        {
            // not a validstring representation of a guid
            return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
        }

        // is the passed guid one we know about?
        return guids.Any(g => g == guid) ?
            new ValidationResult(FormatErrorMessage(validationContext.DisplayName)) : null;
    }
}

и затем на модели, которую вы отправляете в действие контроллера

public class GuidModel
{
    [ValidGuid]
    public Guid guid { get; set; }
}

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

3 голосов
/ 16 ноября 2016

Я знаю, что это старый вопрос сейчас, но если кому-то еще интересно, мне удалось обойти это, создав аннотацию [IsNotEmpty] (в моем случае сделать Guul обнуляемым не было возможным).

Это использует рефлексию, чтобы выяснить, есть ли реализация свойства Empty в свойстве, и если это так, сравнивает ее.

public class IsNotEmptyAttribute : ValidationAttribute
{

    public override bool IsValid(object value)
    {

        if (value == null) return false;

        var valueType = value.GetType();
        var emptyField = valueType.GetField("Empty");

        if (emptyField == null) return true;

        var emptyValue = emptyField.GetValue(null);

        return !value.Equals(emptyValue);

    }
}
0 голосов
/ 26 мая 2019

Если для пользовательской проверки не требуется многократное использование в вашей системе (т. Е. Без необходимости настраиваемого атрибута проверки), есть другой способ добавить настраиваемую проверку в модель данных ViewModel / Posted, а именно с помощью IValidatableObject .

Каждая ошибка может быть связана с одним или несколькими свойствами модели, поэтому этот подход по-прежнему работает, например, с ненавязчивой проверкой в ​​MVC Razor.

Вот как проверить Guid по умолчанию(C # 7.1):

public class MyModel : IValidatableObject // Implement IValidatableObject
{
    [Required]
    public string Name {get; set;}
    public Guid SomeGuid {get; set;}
    ... other properties here

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (SomeGuid == default)
        {
            yield return new ValidationResult(
                "SomeGuid must be provided",
                new[] { nameof(SomeGuid) });
        }
    }
 }

Подробнее о IValidatableObject здесь

...