I'm trying to use localization with resource files, but it's not working, just for custom required attribute
public class RequiredIntAttribute : RequiredAttribute
{
public override bool IsValid(object value)
{
bool isValid = base.IsValid(value);
if (isValid)
{
isValid = int.Parse(value.ToString()) != 0;
}
return isValid;
}
}
public class SalonForInsertDto
{
public string Name { get; set; }
public string NameEn { get; set; }
[RequiredInt(ErrorMessage = "the userId is required")]
public int UserId { get; set; }
}
In your Configure method add:
//localization & globalization
var locOptions = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
app.UseRequestLocalization(locOptions.Value);
Then in your custom validator class you add:
var _localizationService = (IStringLocalizer<SalonForInsertDto>)validationContext.GetService(typeof(IStringLocalizer<SalonForInsertDto>));
and then you are now able to get the localized string value from the resource file like:
_localizationService["How are you?"]
You can read about IStringLocalizer object and it's working in official docs.
Related
I am validating the content for file import and I have an IsValid property for each line.
public class Header
{
public int LineNumber { get; set; }
public string Property1 { get; set; }
public string Property2 { get; set; }
public bool IsValid { get; set; }
}
public class Detail
{
public int LineNumber { get; set; }
public string Property1 { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
public bool IsValid { get; set; }
}
public class Trailer
{
public int LineNumber { get; set; }
public string Property1 { get; set; }
public bool IsValid { get; set; }
}
public class ImportFile
{
public Header Header { get; set; }
public List<Detail> Details { get; set; }
public Trailer Trailer { get; set; }
}
and my validators look somewhat like:
public class DetailValidator : AbstractValidator<Detail>
{
public DetailValidator()
{
RuleFor(d => d.Property1)
.Cascade(CascadeMode.Stop)
.NotEmpty()
.WithState(d => d.LineNumber)
.Length(3)
.WithState(d => d.LineNumber);
RuleFor(d => d.Property2)
.Cascade(CascadeMode.Stop)
.NotEmpty()
.WithState(d => d.LineNumber)
.MaximumLength(50)
.WithState(d => d.LineNumber);
...
}
}
public class ImportFileValidator : AbstractValidator<ImportFile>
{
public ImportFileValidator()
{
RuleFor(f => f.Header)
.SetValidator(new HeaderValidator());
RuleForEach(f => f.Details)
.SetValidator(new DetailsValidator());
...
}
}
After I call the validation, I wanted to set the IsValid property of each line of the file (be it header, detail or trailer) base from the result of the validation.
What is possible for now is, since I am using WithState to store the LineNumber, I can match the ValidationResult against the ImportFile instance to set each line's validity like below:
ImportFile file = // parsed file content
var result = new ImportFileValidator().Validate(file);
foreach (var detail in file.Details)
{
var error = result.Errors.FirstOrDefault(e =>
Convert.ToInt32(e.CustomState) == detail.LineNumber);
detail.IsValid = error == null;
}
And I have to check for the header and trailer as well.
Is there a way I can do this inside the validators? I am trying to explore the FluentValidation's documentation, but I can't seem to find what I needed there.
As I was exploring the available methods in FluentValidation, I saw OnFailure and OnAnyFailure methods. This methods might be a good help to what I needed to do, but the problem is they're obsolete as of 10.3.0 and will be removed on version 11. They're suggesting to use a custom validator instead.
The Header, Detail and Trailer Abstract Validators remain as is.
I created custom validator extensions for those 3.
Each extension methods creates an instance of the corresponding validator and executes it. I can make them generic for header, detail and trailer since they will do the same thing, set IsValid property to the validation result.
public static IRuleBuilderOptionsConditions<ImportFile, T> IsHeaderValid<T>(this IRuleBuilder<ImportFile, T> ruleBuilder)
where T : Header
{
return builder.Custom((header, context) =>
{
// Create the Header Abstract Validator Instance
var validator = new HeaderValidator();
var result = validator.Validate(Header);
header.IsValid = result.IsValid;
// Pass the errors to the context
result.Errors.ForEach(context.AddFailure);
}
}
I had to change the ImportFileValidator to call the custom validators, instead of using setvalidator.
The ImportFileValidator looks like this:
public class ImportFileValidator : AbstractValidator<ImportFile>
{
public ImportFileValidator()
{
RuleFor(f => f.Header)
.IsHeaderValid();
RuleForEach(f => f.Details)
.IsDetailValid();
...
}
}
This is pretty much how I was able to set the IsValid property without having to do the matching I initially did in the question.
Can anyone help me to solve this problem?
I am using visual studio2010 and its windows phone 7 application
I have created addpet.xaml and mypet.xaml.
Created IsolatedStorageSetting object in mypet.cs file
{
public static IsolatedStorageSettings settings=IsolatedStorageSettings.ApplicationSettings;
}
I have 5 textboxes and I am storing its value in list item.That list stores in IsolatedStorageSetting object.
{
SaveMypet savepet = new SaveMypet();
savepet.Name = txt_name.ToString();
savepet.Birthday = txt_birthday.ToString();
savepet.FavFood = txt_favouritefood.ToString();
savepet.DocNo = txt_doctorsno.ToString();
savepet.VacDate = txt_vacdate.ToString();
savepet.FavToy = txt_favouritetoy.ToString();
// savepet.Image1 = image1.Source;
listMyPet.Add(savepet);
settings.Add("iso_listMyPet", listMyPet);
}
Now I want to access this object in addpet.cs and cast it to list and then want to assign to listbox.
Like this, I have did but does not work
Created list object in addpet.cs
{
static List<pg_addPet> list_listMyPet = null;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
list_listMyPet = (List<pg_addPet>)pg_addPet.settings["iso_mypet_list"];
listbox_mypet.ItemsSource = list_listMyPet;
}
And my SaveMypet class is
public class SaveMypet
{
public string Name { get; set; }
public string Birthday { get; set; }
public string FavFood { get; set; }
public string DocNo { get; set; }
public string VacDate { get; set; }
public string FavToy { get; set; }
// public ImageSource Image1 { get; set; }
}
You've declared the settings property as static. Therefore, you need to use the class name to access it:
list_listMyPet = (List<pg_addPet>)pg_mypet.settings["iso_mypet_list"];
Try the following:
if(!pg_mypet.settings.TryGetValue("iso_mypet_list", out list_listMyPet))
{
list_listMyPet = new List<pg_addPet>();
}
This will try to retrieve the value and if if fails it will create an empty list instead.
I have a model called Foo which has a property called MyProp of type Bar.
When I post this model to the controller I want the model binder to validate MyProp because it has the Required attribute just as it does with a string. I need this to be self-contained within the Bar class or as a separate class. I have tried to use the IValidatableObject on the Bar class but it seems like it's impossible to check if the Foo class has the Required attribute on MyProp? So now I'm out of options and need some help. Below is some sample code for my question.
public class Foo {
[Required]
public Bar MyProp { get; set; }
}
public class Bar {
[ScaffoldColumn(false)]
public int Id { get; set; }
public string Name { get; set; }
}
Here is one solution to my problem where I can use the built in required attribute and still get custom behavior. This is just some proof of concept code.
The model:
public class Page : IPageModel {
[Display(Name = "Page", Prompt = "Specify page name...")]
[Required(ErrorMessage = "You must specify a page name")]
public PageReference PageReference { get; set; }
}
The model binder:
public class PageModelBinder : DefaultModelBinder {
protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext) {
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(bindingContext.ModelType)) {
var attributes = property.Attributes;
if (attributes.Count == 0) continue;
foreach (var attribute in attributes) {
if (attribute.GetType().BaseType == typeof(ValidationAttribute) && property.PropertyType == typeof(PageReference)) {
var pageReference = bindingContext.ModelType.GetProperty(property.Name).GetValue(bindingContext.Model, null) as PageReference;
Type attrType = attribute.GetType();
if (attrType == typeof (RequiredAttribute) && string.IsNullOrEmpty(pageReference.Name)) {
bindingContext.ModelState.AddModelError(property.Name,
((RequiredAttribute) attribute).ErrorMessage);
}
}
}
}
base.OnModelUpdated(controllerContext, bindingContext);
}
}
The model binder provider:
public class InheritanceAwareModelBinderProvider : Dictionary<Type, IModelBinder>, IModelBinderProvider {
public IModelBinder GetBinder(Type modelType) {
var binders = from binder in this
where binder.Key.IsAssignableFrom(modelType)
select binder.Value;
return binders.FirstOrDefault();
}
}
And last the global.asax registration:
var binderProvider = new InheritanceAwareModelBinderProvider {
{
typeof (IPageModel), new PageModelBinder() }
};
ModelBinderProviders.BinderProviders.Add(binderProvider);
The result: http://cl.ly/IjCS
So what do you think about this solution?
The problem is that there is no html field called MyProp and MVC doesn't fire any validation for this property.
One way to achieve your goal is to get rid of Bar and create Bar's properties in Foo. You can use AutoMapper to minimize plumbing code to minimum.
Another solution is to write a custom validation attribute which validates against the null values and use it instead of Required attribute.
Solution 1
Instead of using [Required], try a custom ValidationAttribute
public class Foo {
[RequiredBar]
public Bar MyProp { get; set; }
}
public class Bar {
[ScaffoldColumn(false)]
public int Id { get; set; }
public string Name { get; set; }
}
public class RequiredBar : ValidationAttribute {
public override bool IsValid(object value)
{
Bar bar = (Bar)value;
// validate. For example
if (bar == null)
{
return false;
}
return bar.Name != null;
}
}
Solution Two:
Simply put Required on the corresponding required properties of Bar, For example
public class Foo {
//[RequiredBar]
public Bar MyProp { get; set; }
}
public class Bar {
[ScaffoldColumn(false)]
public int Id { get; set; }
[Required]
public string Name { get; set; }
}
I am reading up on ASP.NET MVC and all of it's fun uses and I just found out about DataTemplates.
In my hurry to test this thing out, I converted one of my simpler models over to using #Html.DisplayForModel() and #Html.EditForModel() and it worked like a lucky charm that it is :)
One thing that I immediately found out though was that I could not easily define a field to show up on display views but not be present at all for editing...
You can make use of IMetadataAware interface an create attribute which will set ShowForEdit and ShowForDislay in Metadata:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class TemplatesVisibilityAttribute : Attribute, IMetadataAware
{
public bool ShowForDisplay { get; set; }
public bool ShowForEdit { get; set; }
public TemplatesVisibilityAttribut()
{
this.ShowForDisplay = true;
this.ShowForEdit = true;
}
public void OnMetadataCreated(ModelMetadata metadata)
{
if (metadata == null)
{
throw new ArgumentNullException("metadata");
}
metadata.ShowForDisplay = this.ShowForDisplay;
metadata.ShowForEdit = this.ShowForEdit;
}
}
Then you can attach it to your property like this:
public class TemplateViewModel
{
[TemplatesVisibility(ShowForEdit = false)]
public string ShowForDisplayProperty { get; set; }
public string ShowAlwaysProperty { get; set; }
}
And this is all you need.
You could write a custom metadata provider and set the ShowForEdit metadata property. So start with a custom attribute:
public class ShowForEditAttribute : Attribute
{
public ShowForEditAttribute(bool show)
{
Show = show;
}
public bool Show { get; private set; }
}
then a custom model metadata provider:
public class MyModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(
IEnumerable<Attribute> attributes,
Type containerType,
Func<object> modelAccessor,
Type modelType,
string propertyName
)
{
var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
var sfea = attributes.OfType<ShowForEditAttribute>().FirstOrDefault();
if (sfea != null)
{
metadata.ShowForEdit = sfea.Show;
}
return metadata;
}
}
then register this provider in Application_Start:
ModelMetadataProviders.Current = new MyModelMetadataProvider();
and finally decorate:
public class MyViewModel
{
[ShowForEdit(false)]
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
Now if in your view you have:
#model MyViewModel
<h2>Editor</h2>
#Html.EditorForModel()
<h2>Display</h2>
#Html.DisplayForModel()
the Prop1 property won't be included in the editor template.
Remark: you could do the same with the ShowForDisplay metadata property.
Can you display each of the fields you want using Html.DisplayTextbox or one of the other options? That way you can also customize the appearance and labels referring to the field.
I am using DataAnnotations for validation (including client side)
I have a form with multiple fields. Basic validation for individual fields work fine. Now there are a couple of fields of which atleast one needs to have a value (if there are 3 fields then either 1st or 2nd or 3rd field should have a value).
I have read quite a few posts on this site and couple of blog entries. But I couldn't find a solution that works in the above mentioned scenario. I might have missed something or doing it incorrectly.
Can you help with this please?
try this
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public sealed class EitherOr : ValidationAttribute
{
private const string _defaultErrorMessage = "'{0}' OR '{1}' OR '{2}' must have a value";
private readonly object _typeId = new object();
public EitherOr(string prop1, string prop2, string prop3)
: base(_defaultErrorMessage)
{
Prop1 = prop1;
Prop2 = prop2;
Prop3 = prop3;
}
public string Prop1 { get; private set; }
public string Prop2 { get; private set; }
public string Prop3 { get; private set; }
public override object TypeId
{
get
{
return _typeId;
}
}
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString, Prop1, Prop2,Prop3);
}
public override bool IsValid(object value)
{
if(string.IsNullOrEmpty(Prop1)&&string.IsNullOrEmpty(Prop2) && string.IsNullOrEmpty(Prop3))
{
return false;
}
return true;
}
then mark your class with the EitherOr attribute:
[EitherOr("Bar","Stool","Hood", ErrorMessage = "please supply one of the properties")]
public class Foo
{
public string Bar{ get; set;}
public string Stool{ get; set;}
public string Hood{ get; set;}
}
Please note that i made use of string properties, if your property is of other type, makle sure to change the IsValid(object value) validation