Пользовательский атрибут ValidationAttribute в NancyFX не распознается или не используется

Я указал пользовательский NonEmptyGuidAttribute, который расширяет ValidationAttribute и выглядит следующим образом

public class NonEmptyGuidAttribute:ValidationAttribute
{
    public override bool IsValid(object value)
    {
        Guid parsedValue = Guid.Empty;
        if (value != null && Guid.TryParse(value.ToString(), out parsedValue))
        {
            return true;
        }

        return false;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        Guid parsedValue = Guid.Empty;
        if (value != null && Guid.TryParse(value.ToString(), out parsedValue) && parsedValue != Guid.Empty)
        {
            return ValidationResult.Success;
        }

        return new ValidationResult(
            this.ErrorMessage = string.Format("The value of {0} is not valid", validationContext.MemberName),
            new[] { validationContext.MemberName }
            );
    }
}

Цель этого состоит в том, чтобы убедиться, что если одна из моих моделей имеет свойство Guid, то оно не является пустым и действительным.

Ниже приведен пример использования этого атрибута. Я должен сделать Guid типом, допускающим значение NULL, чтобы уважался атрибут [Required].

public class SomeNancyRequest
{
    [Required]
    [NonEmptyGuid]
    public Guid? Id { get; set; }

    [Required]
    public string Name { get; set; }

    [Required]
    public string Description { get; set; }

    [Required]
    [DataType(DataType.ImageUrl)]
    public string ImagePath { get; set; }

    [Required]
    public bool Enabled {get;set;}
}

Если я попаду в свой API с запросом, подобным следующему, он не использует логику проверки [NonEmptyGuid]. Я знаю это, потому что я разместил в нем точки останова, а также конструктор, чтобы увидеть, был ли атрибут вообще инициализирован.

{
    "id":"Im not a guid",
    "name": "Just a name",
    "description": "Some Description",
    "imagePath": "http://myimage.com",
    "enabled": true
}

Я ожидаю, что это попадет в мой валидатор и потерпит неудачу из-за недопустимого свойства id в запросе выше. Это ДЕЙСТВИТЕЛЬНО терпит неудачу, но поскольку возникает исключение, подобное следующему, когда он пытается преобразовать Guid.

Nancy.RequestExecutionException: Oh noes! ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.FormatException: Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
   at System.Guid.GuidResult.SetFailure(ParseFailureKind failure, String failureMessageID, Object failureMessageFormatArgument, String failureArgumentName, Exception innerException)
   at System.Guid.TryParseGuidWithNoStyle(String guidString, GuidResult& result)
   at System.Guid.TryParseGuid(String g, GuidStyles flags, GuidResult& result)
   at System.Guid..ctor(String g)
   at System.ComponentModel.GuidConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
   at System.ComponentModel.NullableConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
   at System.ComponentModel.TypeConverter.ConvertFromInvariantString(String text)
   at Nancy.Json.JavaScriptSerializer.ConvertToType(Type type, Object obj)
   at Nancy.Json.JavaScriptSerializer.ConvertToObject(IDictionary`2 dict, Type type)
   at Nancy.Json.JavaScriptSerializer.ConvertToType(Type type, Object obj)
   at Nancy.Json.JavaScriptSerializer.ConvertToType[T](Object obj)
   at Nancy.Json.JavaScriptSerializer.Deserialize[T](String input)
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at Nancy.ModelBinding.DefaultBodyDeserializers.JsonBodyDeserializer.Deserialize(String contentType, Stream bodyStream, BindingContext context)
   at Nancy.ModelBinding.DefaultBinder.DeserializeRequestBody(BindingContext context)
   at Nancy.ModelBinding.DefaultBinder.Bind(NancyContext context, Type modelType, Object instance, BindingConfig configuration, String[] blackList)
   at Nancy.ModelBinding.DynamicModelBinderAdapter.TryConvert(ConvertBinder binder, Object& result)
   at CallSite.Target(Closure , CallSite , Object )
   at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
   at Nancy.ModelBinding.ModuleExtensions.Bind[TModel](INancyModule module, String[] blacklistedProperties)
   at Nancy.ModelBinding.ModuleExtensions.BindAndValidate[TModel](INancyModule module)
   at Server.Extensibility.NancyModuleExtensions.d__3a`2.MoveNext() in c:\Users\Me\Source\Repos\my-server\.Server\Extensibility\NancyModuleExtensions.cs:line 121
   --- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Server.Extensibility.NancyModuleExtensions.<>c__DisplayClass25`2.<b__24>d__27.MoveNext() in c:\Users\Me\Source\Repos\my-server\Server\Extensibility\NancyModuleExtensions.cs:line 49
   --- End of inner exception stack trace ---
   at Nancy.NancyEngine.InvokeOnErrorHook(NancyContext context, ErrorPipeline pipeline, Exception ex)

Почему это не работает?


person TheJediCowboy    schedule 13.09.2015    source источник
comment
Подняли вопрос на GitHub github.com/NancyFx/Nancy/issues/2058.   -  person Phill    schedule 15.09.2015
comment
Поскольку это ошибка в реализации сериализатора Mono, который мы используем в Nancy, мы решили не исправлять ее в выпуске 1.#. Решение состоит в том, чтобы использовать другой сериализатор.   -  person Phill    schedule 25.09.2015


Ответы (1)


Проверка происходит после выполнения привязки. Таким образом, похоже, что внутренний сериализатор JSON дает сбой во время преобразования. Так что я бы классифицировал это как ошибку. Однако вы сможете обойти это, используя библиотеку json newtonsoft.

https://www.nuget.org/packages/Nancy.Serialization.JsonNet/

Install-Package Nancy.Serialization.JsonNet

Вам не нужно ничего настраивать, он автоматически начнет использовать его при установке.

person Phill    schedule 15.09.2015