2012-05-19 60 views
0

我有以下問題,我試圖在Windows Phone中使用FluentValidation來驗證字符串是否是有效的用戶名。Fluent驗證WP7 - 驗證簡單類型​​(字符串)

我遇到的問題是驗證器值的類型爲string需要測試。在所有的例子我能找到它總是被這樣RuleFor(customer => customer.Surname).NotEmpty();

測試當我運行這段代碼,我得到以下錯誤的對象的屬性

代碼:

public class UsernameValidator : AbstractValidator<string> 
{ 
    public UsernameValidator() 
    { 
     RuleFor(username => username).NotNull().NotEmpty().WithMessage("Enter a username"); 
     RuleFor(username => username).Matches("^[a-zA-Z0-9_]*$").WithMessage("Only letters and numbers"); 
     RuleFor(username => username).Length(3, 30).WithMessage("Minimum length is 3"); 
    } 
} 

錯誤:

FluentValidation for WP7 can only be used with expressions that reference public properties, ie x => x.SomeProperty 
    at FluentValidation.Internal.Extensions.CompilePropertyGetterExpression(LambdaExpression expression, Type delegateType) 
    at FluentValidation.Internal.Extensions.Compile[TDelegate](Expression`1 expression) 
    at FluentValidation.Internal.PropertyRule`1.Create[TProperty](Expression`1 expression, Func`1 cascadeModeThunk) 
    at FluentValidation.AbstractValidator`1.RuleFor[TProperty](Expression`1 expression) 
    at WorldChat.ViewModels.Validators.UsernameValidator..ctor() 
    at WorldChat.ViewModels.RegisterViewModel.get_ErrorUsername() 
    at System.Reflection.RuntimeMethodInfo.InternalInvoke(RuntimeMethodInfo rtmi, Object obj, BindingFlags invokeAttr, Binder binder, Object parameters, CultureInfo culture, Boolean isBinderDefault, Assembly caller, Boolean verifyAccess, StackCrawlMark& stackMark) 
    at System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, StackCrawlMark& stackMark) 
    at System.Reflection.RuntimePropertyInfo.InternalGetValue(PropertyInfo thisProperty, Object obj, Object[] index, StackCrawlMark& stackMark) 
    at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index) 
    at System.Windows.CLRPropertyListener.get_Value() 
    at System.Windows.PropertyAccessPathStep.ConnectToPropertyInSource(Boolean isSourceCollectionViewCurrentItem) 
    at System.Windows.PropertyAccessPathStep.ConnectToProperty() 
    at System.Windows.PropertyAccessPathStep.ReConnect(Object newSource) 
    at System.Windows.PropertyPathListener.ReConnect(Object source) 
    at System.Windows.Data.BindingExpression.SourceAcquired() 
    at System.Windows.Data.BindingExpression.System.Windows.IDataContextChangedListener.OnDataContextChanged(Object sender, DataContextChangedEventArgs e) 
    at System.Windows.Data.BindingExpression.DataContextChanged(Object sender, DataContextChangedEventArgs e) 
    at System.Windows.FrameworkElement.OnDataContextChanged(DataContextChangedEventArgs e) 
    at System.Windows.FrameworkElement.OnAncestorDataContextChanged(DataContextChangedEventArgs e) 
    at System.Windows.FrameworkElement.NotifyDataContextChanged(DataContextChangedEventArgs e) 
    at System.Windows.FrameworkElement.OnAncestorDataContextChanged(DataContextChangedEventArgs e) 
    at System.Windows.FrameworkElement.NotifyDataContextChanged(DataContextChangedEventArgs e) 
    at System.Windows.FrameworkElement.OnTreeParentUpdated(DependencyObject newParent, Boolean bIsNewParentAlive) 
    at System.Windows.DependencyObject.UpdateTreeParent(IManagedPeer oldParent, IManagedPeer newParent, Boolean bIsNewParentAlive, Boolean keepReferenceToParent) 
    at MS.Internal.FrameworkCallbacks.ManagedPeerTreeUpdate(IntPtr oldParentElement, IntPtr parentElement, IntPtr childElement, Byte bIsParentAlive, Byte bKeepReferenceToParent, Byte bCanCreateParent) 
    at MS.Internal.XcpImports.MeasureNative(IntPtr element, Single inWidth, Single inHeight) 
    at MS.Internal.XcpImports.UIElement_Measure(UIElement element, Size availableSize) 
    at System.Windows.UIElement.Measure(Size availableSize) 
    at System.Windows.Controls.ScrollViewer.MeasureOverride(Size constraint) 
    at System.Windows.FrameworkElement.MeasureOverride(IntPtr nativeTarget, Double inWidth, Double inHeight, Double& outWidth, Double& outHeight) 
    at MS.Internal.XcpImports.MeasureOverrideNative(IntPtr element, Single inWidth, Single inHeight, Single& outWidth, Single& outHeight) 
    at MS.Internal.XcpImports.FrameworkElement_MeasureOverride(FrameworkElement element, Size availableSize) 
    at System.Windows.FrameworkElement.MeasureOverride(Size availableSize) 
    at System.Windows.FrameworkElement.MeasureOverride(IntPtr nativeTarget, Double inWidth, Double inHeight, Double& outWidth, Double& outHeight) 
    at MS.Internal.XcpImports.MeasureOverrideNative(IntPtr element, Single inWidth, Single inHeight, Single& outWidth, Single& outHeight) 
    at MS.Internal.XcpImports.FrameworkElement_MeasureOverride(FrameworkElement element, Size availableSize) 
    at System.Windows.FrameworkElement.MeasureOverride(Size availableSize) 
    at Microsoft.Phone.Controls.PhoneApplicationFrame.MeasureOverride(Size availableSize) 
    at System.Windows.FrameworkElement.MeasureOverride(IntPtr nativeTarget, Double inWidth, Double inHeight, Double& outWidth, Double& outHeight) 

回答

1

我找到了一個解決方法,它需要你有一個額外的字符串包裝類。

ValidationString.cs

public class ValidationString 
{ 
    public string value { get; set; } 

    public ValidationString(string value) 
    { 
     this.value = value; 
    } 
} 

在用戶名驗證器類添加靜態方法IsUsername

public class UsernameValidator : AbstractValidator<ValidationString> 
{ 
    public UsernameValidator() 
    { 
     RuleFor(username => username.value).NotNull().NotEmpty().WithMessage("Enter a username"); 
     RuleFor(username => username.value).Matches("^[a-zA-Z0-9_]*$").WithMessage("Only letters and numbers"); 
     RuleFor(username => username.value).Length(3, 30).WithMessage("Minimum length is 3"); 
    } 

    internal static bool IsUsername(string value) 
    { 
     return new UsernameValidator().Validate(new ValidationString(value)).IsValid; 
    } 
} 

現在我將是既能夠使用一個字符串這UsernameValidator以及我還可以使用另一個驗證器,例如註冊驗證器

public class RegisterValidator : AbstractValidator<User> 
{ 
    public RegisterValidator() 
    { 
     RuleFor(user => user.Username).Must(UsernameValidator.IsUsername); 
     // some more rules 
    } 
} 

如果您不想在其他驗證類中使用您的UsernameValidator,則可以使用IsUsername方法。

+0

這可能沒有額外的包裝類,請參閱我的答案。 – theDmi

1

如何做一個虛擬的類,其唯一的成員是測試的東西? (嗯,說的每種數據類型的一個成員):

public class ForYourTestsOnly 
{ 
    public string MyString { get; set;} 
    public int MyInt32 { get; set;} 
    //And so on... 
} 

然後:

RuleFor(test => test.MyString) 

(我承認我什麼都不知道FluentValidation,但如果它是唯一的方法有它的工作,我想我會朝那個方向搜索......)

+0

我想出了同樣的想法,但比下一個問題是當我想要用戶例如'RegisterationValidator'中的'UsernameValidator',它想要將'UsernameValidator'應用到一個字符串屬性。 –

-1

的問題

RuleFor(username => username) 

是流利的驗證不能提取屬性的名稱。 Fluent Validation期望驗證屬性,因此它會嘗試從RuleFor()參數中的表達式樹中提取屬性名稱。由於您的表達式沒有提及屬性,因此失敗。

您可以禁止FV通過明確指定屬性來嘗試。即使該屬性不存在,這也可以工作,因爲據我瞭解,FV只需要報告驗證錯誤。

所以下面的工作對我來說,沒有額外ValidationString包裝類:

public class StringNotEmptyValidator : AbstractValidator<string> 
{ 
    public StringNotEmptyValidator() 
    { 
     RuleFor(str => str).NotEmpty().OverridePropertyName("StringValue"); 
    } 
} 

這是例子驗證字符串是不是空的。對於你的用戶名驗證時,驗證看起來類似的東西(我沒有測試這一點,但概念是相同的):

public class UsernameValidator : AbstractValidator<string> 
{ 
    public UsernameValidator() 
    { 
     RuleFor(username => username).NotNull().NotEmpty().WithMessage("Enter a username").OverridePropertyName("UsernameValue"); 
     RuleFor(username => username).Matches("^[a-zA-Z0-9_]*$").WithMessage("Only letters and numbers").OverridePropertyName("UsernameValue"); 
     RuleFor(username => username).Length(3, 30).WithMessage("Minimum length is 3").OverridePropertyName("UsernameValue"); 
    } 
} 
+0

剛剛在這裏做的是確切的問題,FluentValidation與Windows Phone 7的組合不支持'username - > username' Linq,它需要對象的屬性。 –

+0

我明白了,似乎我認爲整個框架上的問題是相同的錯誤。然後我的解決方案解決了我的問題,不是你的,對不起:-) – theDmi