Using DataAnnotations on Windows Forms project - c#

I recently used ASP.Net MVC with DataAnnotations and was thinking of using the same approach for a Forms project but I'm not sure how to go about it.
I have set my attributes but they do not seem to get checked when I click Save.
UPDATE: I have used Steve Sanderson's approach which will check for attributes on my class and return a collection of errors like so:
try
{
Business b = new Business();
b.Name = "feds";
b.Description = "DFdsS";
b.CategoryID = 1;
b.CountryID = 2;
b.EMail = "SSDF";
var errors = DataAnnotationsValidationRunner.GetErrors(b);
if (errors.Any())
throw new RulesException(errors);
b.Save();
}
catch(Exception ex)
{
}
What do you think of this approach?

Here's a simple example. suppose you have an object like the following
using System.ComponentModel.DataAnnotations;
public class Contact
{
[Required(AllowEmptyStrings = false, ErrorMessage = "First name is required")]
[StringLength(20, MinimumLength = 5, ErrorMessage = "First name must be between 5 and 20 characters")]
public string FirstName { get; set; }
public string LastName { get; set; }
[DataType(DataType.DateTime)]
public DateTime Birthday { get; set; }
}
And suppose we have a method that creates an instance of this class and tries to validate its properties, as listed below
private void DoSomething()
{
Contact contact = new Contact { FirstName = "Armin", LastName = "Zia", Birthday = new DateTime(1988, 04, 20) };
ValidationContext context = new ValidationContext(contact, null, null);
IList<ValidationResult> errors = new List<ValidationResult>();
if (!Validator.TryValidateObject(contact, context, errors,true))
{
foreach (ValidationResult result in errors)
MessageBox.Show(result.ErrorMessage);
}
else
MessageBox.Show("Validated");
}
The DataAnnotations namespace is not tied to the MVC framework so you can use it in different types of applications. the code snippet above returns true, try to update the property values to get validation errors.
And make sure to checkout the reference on MSDN: DataAnnotations Namespace

Steve's example is a bit dated (though still good). The DataAnnotationsValidationRunner that he has can be replaced by the System.ComponentModel.DataAnnotations.Validator class now, it has static methods for validating properties and objects which have been decorated with DataAnnotations attributes.

I found a decent example of using DataAnnotations with WinForms using the Validator class, including tying into the IDataErrorInfo interface so ErrorProvider can display the results.
Here is the link.
DataAnnotations Validation Attributes in Windows Forms

If you use newest versions of Entity Framework you can use this cmd to get a list of your errors if existing:
YourDbContext.Entity(YourEntity).GetValidationResult();

Related

How to avoid multiple ifelse statements when validating user input? [Web Forms]

I have a very basic sign up page that has textbox fields like 'email','password','username'.
Although I have already used client-side validators (such as asp:RegularExpressionValidator) I also want to have a strong server-side validation. But so far I got this just for a single text field:
if(username.Contains(" ") || string.IsNullOrEmpty(password))
{
//error: invalid username
}
else if (username.length<8)
{
//error: username cannot be shorter than 8 characters
}
else if (username.length>30)
{
//error: username cannot be longer than 30 characters
}
else if (IsUsernameTaken(username))
{
//error: this username has already been taken by someone else
}
else if (something)
{
//some error
}
//etc etc
Is there a better (and more efficient) way to validate my controls without using the above code?
Edit: I am using Asp.net Web Forms
I don't know if you're using MVC, but yes, there is. You don't really want to validate your 'controls', you want to validate the model / viewmodel. When the user submits the form, you should be deserializing the submitted data into your own model/viewmodel class. In your declaration of the class that makes that viewmodel, you can use DataAnnotations to tell the framework the requirements for each field. Something like this:
using System.ComponentModel.DataAnnotations;
using ExpressiveAnnotations.Attributes; // this is a non-standard library
namespace MyProject.Models.ViewModels.Workorder
{
public class CreateBillableUnbillableProjectViewModels
{
public class CreateBillableUnbillableProject : IValidatableObject
{
[Required]
public string Title { get; set; }
[Display(Name = "Proposed Budget")]
[AssertThat("ProposedBudget > 0", ErrorMessage = "You must enter a value greater than 0")]
[Required]
[UIHint("String")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = Settings.DataFormatStringCurrency)]
public decimal ProposedBudget { get; set; }
}
}
}
Note the markup in square brackets. These are DataAnnotations. Additionally, the model/viewmodel as a whole can be given rules that must be valid. For example, if PropertyA must be greater than PropertyB. This is why the class above implements IValidatableObject. Something like this:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
//TODO: any other validation before changing and saving this record?
if (PropertyA <= PropertyB)
yield return new ValidationResult($"PropertyA must be greater than PropertyB", new[] { "PropertyA" });
var db = new MyProjectEntities();
if (db.WorkOrders.Any(i => i.Title == Title))
yield return new ValidationResult($"A WorkOrder with the same title already exists.", new[] { "Title" });
}
All of the above (property-level validation and model-level validation) is triggered when you do a if (ModelState.IsValid) in your controller action.
See:
https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-6.0

Is it possible to use IValidatableObject with Winforms?

I am working on WinForms with EF 6.2.
I am trying to implement custom validation logic for my entities with Entity Framework.
At first, I succeeded to override the DbEntityValidationResult ValidateEntity method in my DbContext and it's working fine.
But now I have a lot of entities, it becomes very messy and I would like to implement the custom validation directly in my entities classes.
So I tried to implement the IValidatableObject interface.
Here is a simple example of an entity :
public class Inspection : IValidatableObject
{
public int Id { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "You must enter a description")]
[StringLength(maximumLength: 15, ErrorMessage = "The description cannot exceed 15 characters")]
public string Description { get; set; }
public DateTime? ActualDate { get; set; }
public DateTime? ValidityDate { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (ActualDate > ValidityDate)
{
ValidationResult result = new ValidationResult("Actual Date connot be > to ValidityDate");
yield return result;
}
}
}
Now I read a lot of things but cannot figure where do I have to call the Validate method of my entities, and what value I have to pass in ValidationContext parameter.
Every tutorial I've seen targets MVC scenarios so I wonder if it is possible to use it with Winforms.
I maybe have missed something, or maybe it is not the correct approach for validation in Winforms/EF.
Please can you give me some piece of advice ?
Finally I found the solution (and my error) thanks to the MSDN article :
http://msdn.microsoft.com/en-us/data/gg193959.aspx
When I read it the first time, I missed a part while implementing the interface.
I forgot to define the memberNames parameter of the ValidationResult class.
So I just changed :
ValidationResult result = new ValidationResult("Actual Date connot be > to ValidityDate");
to
ValidationResult result = new ValidationResult("Actual Date connot be > to ValidityDate",
new[] { nameof(ActualDate), nameof(ValidityDate) });
And it worked as expected.
I am still wondering what value to pass in ValidationContext parameter if the Validate method of the interface is called manually, but it is another question.
So to answer my own question : Yes, it is possible to use IValidatableObject with Winforms.

DevForce Validation returning Ok for navigation properties that have not been set

I have been working on validatin for our entities in DevForce and I have managed to get everything I need working aside from validating Navigation Properties.
I have tried placing a RequiredValueVerifier attribute on the property and that does show the validation error on the UI but as soon as I use Manager.VerifierEngine.Execute({entitytovalidate}) the result comes back as Ok.
I know DevForce creates nullos and we can modify what the properties have in said nullos but I would like a way that the VeirifierEngine would return not Ok when we have not updated the value from the nullo.
My current work-around is to have a secondary Int32RangeVerifier on the Id that is used for the FKey but I am not to happy with that as a work-around.
Trying to do this without having to create Verifier Providers just for these properties.
If anyone has a solution to this I would be greatly appreciative if you could share.
Here is a sample of the current work-around:
namespace BearPaw.Models.Main
{
[MetadataType(typeof(TechnicianNoteMetadata))]
public partial class TechnicianNote {
public static TechnicianNote Create(int byUserId, DateTimeZone clientZone, DateTime userUtc)
{
var newItem = new TechnicianNote()
{
CreatedById = byUserId,
CreatedDate = userUtc,
CreatedDateTz = clientZone.Id,
ModifiedById = byUserId,
ModifiedDate = userUtc,
ModifiedDateTz = clientZone.Id
};
return newItem;
}
}
public class TechnicianNoteMetadata
{
[Int32RangeVerifier(ErrorMessage = "Note Category is required", MinValue = 1)]
public static int NoteCategoryId;
[RequiredValueVerifier(DisplayName = "Note Category")]
public static NoteCategory NoteCategory;
[RequiredValueVerifier(DisplayName = "Note Detail")]
public static string NoteDetail;
}
}
Many thanks in advance
You can create a custom verifier to handle navigation property validation, and add it directly to the VerifierEngine with the AddVerifier method if you don't want to use an IVerifierProvider.
For example:
public class NullEntityVerifier : PropertyValueVerifier
{
public NullEntityVerifier(
Type entityType,
string propertyName,
string displayName = null)
: base(new PropertyValueVerifierArgs(entityType, propertyName, true, displayName)) { }
public NullEntityVerifier(PropertyValueVerifierArgs verifierArgs)
: base(verifierArgs) { }
protected override VerifierResult VerifyValue(object itemToVerify, object valueToVerify, TriggerContext triggerContext, VerifierContext verifierContext)
{
var entity = valueToVerify as Entity;
var msg = $"{this.ApplicableType.Name}.{this.DisplayName} is required.";
return new VerifierResult(entity != null && !entity.EntityAspect.IsNullEntity, msg);
}
}
To add to the engine:
var verifier = new NullEntityVerifier(typeof(TechnicianNote), "NoteCategory");
_em1.VerifierEngine.AddVerifier(verifier);
If you want to stick with attributed verifiers you can create a custom attribute for your verifier. See the DevForce Resource Center for more information.

Prevent Azure TableEntity property from being serialized in MVC 4 WebAPI

So I have a Model Subscription which inherits from Azure's TableEntity class for use in a WebApi Get method as follows:
[HttpGet]
public IEnumerable<Subscription> Subscribers()
In this method, I do a Select query on my subscribers table to find all subscribers, but I only want to return a few of the columns (properties) as follows:
var query = new TableQuery<Subscription>().Select(new string[] {
"PartitionKey",
"RowKey",
"Description",
"Verified"
});
The definition for the model is below:
public class Subscription : TableEntity
{
[Required]
[RegularExpression(#"[\w]+",
ErrorMessage = #"Only alphanumeric characters and underscore (_) are allowed.")]
[Display(Name = "Application Name")]
public string ApplicationName
{
get
{
return this.PartitionKey;
}
set
{
this.PartitionKey = value;
}
}
[Required]
[RegularExpression(#"[\w]+",
ErrorMessage = #"Only alphanumeric characters and underscore (_) are allowed.")]
[Display(Name = "Log Name")]
public string LogName
{
get
{
return this.RowKey;
}
set
{
this.RowKey = value;
}
}
[Required]
[EmailAddressAttribute]
[Display(Name = "Email Address")]
public string EmailAddress { get; set; }
public string Description { get; set; }
public string SubscriberGUID { get; set; }
public bool? Verified { get; set; }
}
The following is the XML response of the API query:
<ArrayOfSubscription>
<Subscription>
<ETag>W/"datetime'2013-03-18T08%3A54%3A32.483Z'"</ETag>
<PartitionKey>AppName1</PartitionKey><RowKey>Log1</RowKey>
<Timestamp>
<d3p1:DateTime>2013-03-18T08:54:32.483Z</d3p1:DateTime>
<d3p1:OffsetMinutes>0</d3p1:OffsetMinutes>
</Timestamp>
<ApplicationName>AppName1</ApplicationName>
<Description>Desc</Description>
<EmailAddress i:nil="true"/>
<LogName>Log1</LogName>
<SubscriberGUID i:nil="true"/>
<Verified>false</Verified>
</Subscription>
</ArrayOfSubscription>
As you can see, the model not only has a few additional properties such as SubscriberGUID which I do not want to be serialized in the response (and since they are not in the select query, they are null anyway), but TableEntity itself has fields such as PartitionKey, RowKey, Etag, and Timestamp which are also being serialized.
How do I continue to use Azure tables but avoid serializing in the response these undesired fields I do not want the user to see.
Not disagreeing with the answer of using a specific DTO, but the Microsoft.WindowsAzure.Storage assembly now provides an attribute, the IgnorePropertyAttribute, that you can decorate your public property with to avoid serialization.
I haven't actually tried it yet but there is a method on TableEntity called ShouldSkipProperty() that checks a number of things before returning false (i.e. don't skip):
Is the Property Name one of "PartitionKey", "RowKey", "Timestamp" or "ETag" -> skip
Are EITHER of the getter and setter non-public -> skip
Is it static -> skip
Does the property have the attribute IgnorePropertyAttribute -> skip
Looks like it'll do the trick.
I would suggest using DTO (data transfer objects) to solve this type of issues. DTO's might mean more code (more classes) but would benefit you in the long term. You have much better control as to what would be put on the wire. They are better from a security standpoint too rather than using some serializer specific attributes to control what is being put on the wire.
Refer to this asp.net web API tutorial for more.
The use of the DTO is the way to go, IMHO, but to clarify, since it wasn't as obvious from the posts is where to implement to the DTO. I was hoping I could have just used it as part of the query, which I could not. Instead, I had to do this:
query.SelectColumns = new List<string> { "QuoteId", "RateId", "Date" };
var results = await MyCloudTable.ExecuteQuerySegmentedAsync(query, null);
return results.Select(d => new MyDto { QuoteId = d.QuoteId, RateId = d.RateId, Date = d.Date }).ToList();
You have to return your TableEntity derived object from your TableQuery, but since all the properties are null (from explicitly selecting the columns you want) there is no additional data on the wire. You then project into your DTO so you can return exactly the object you need.
You do not need to inherit from TableEntity class. You can use TableEntity.Flatten method to create a DynamicTableEntity from your Subscription class and write to table storage. And you can use TableEntity.ConvertBack method to recompose your subscription object when you read the DynamicTableEntity back from azure table storage. These static helper methods are available in Azure Table Storage SDK version >= 8.0.0
TableEntity.Flatten: https://msdn.microsoft.com/en-us/library/azure/mt775434.aspx
TableEntity.ConvertBack: https://msdn.microsoft.com/en-us/library/azure/mt775432.aspx
Eliminating the need for you to further write up converter classes between DTO s and Business Data Models

Validate This EF4 Validation Approach?

I'm very new to EF4. I've posted a couple of times I think regarding inheritance, validation but my overall aim is to reduce the amount of code I write as much as possible. I'm not interested (yet) in POCOs, masses of ObjectContext fiddling: I want the benefit of EF and minimum of coding.
So, the thorny issue of validation. Take a look at this simplified example and (aside from DRY Buddies and dodgy usings aliases), is this looking like a half-decent approach?
namespace Model
{
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;
using DataAnnotations = System.ComponentModel.DataAnnotations;
using Validation = Microsoft.Practices.EnterpriseLibrary.Validation;
[HasSelfValidation]
[DataAnnotations.MetadataType(typeof(PersonValidator))]
public partial class Person
{
[SelfValidation]
public Validation.ValidationResults Validate()
{
var validationResults = Validation.Validation.Validate(this);
if (string.IsNullOrEmpty(this.LastName) || this.LastName.Length > 4)
{
validationResults.AddResult(new Validation.ValidationResult("This is a test error message for a custom validation error.", this, null, null, null));
}
return validationResults;
}
}
[HasSelfValidation]
public class PersonValidator
{
[NotNullValidator(MessageTemplate = "First Name must be supplied.")]
[ContainsCharactersValidator("Rcd", ContainsCharacters.All, MessageTemplate = "{1} must contains characters \"{3}\" ({4}).")]
[StringLengthValidator(5, 50, MessageTemplate = "{1} (\"{0}\") must be between {3} ({4}) and {5} ({6}) characters in length.")]
public string FirstName { get; set; }
[NotNullValidator(MessageTemplate = "Last Name must be supplied.")]
[ContainsCharactersValidator("Wes", ContainsCharacters.All, MessageTemplate = "{1} must contains characters \"{3}\" ({4}).")]
[StringLengthValidator(5, 50, MessageTemplate = "{1} (\"{0}\") must be between {3} ({4}) and {5} ({6}) characters in length.")]
public string LastName { get; set; }
}
}
There's something rather cool about this. I can call the above like this:
var validationResults = person.Validate();
BUT, if I just want some basic checking, I can strip out Validate(), the [SelfValidation] stuff, keep the attributes and then just call:
var validationResults = Validation.Validate(person);
I only need to include as much validation as I need and there's ZERO configuration in web.config.
How's the cut of my jib? :)
Richard
I'm personally not a fan of calling validation directly in code, and especially not directly on a entity itself. There will be a lot of places were you will call Validate and it is easy to forget to call Validate. Instead, let the ObjectContext invoke the underlying validation framework automatically for ALL entities that have changed, and throw a special exception (that can be caught in the presentation layer) when validation errors occur.
You can do this by hooking onto the ObjectContext.SavingChanges event and trigger validation there. You can write your partial ObjectContext as follows:
public partial class ModelContainer
{
partial void OnContextCreated()
{
this.SavingChanges +=
(sender, e) => Validate(this.GetChangedEntities());
}
private IEnumerable<object> GetChangedEntities()
{
const EntityState AddedAndModified =
EntityState.Added | EntityState.Modified;
var entries = this.ObjectStateManager
.GetObjectStateEntries(AddedAndModified);
return entries.Where(e => e != null);
}
private static void Validate(IEnumerable<object> entities)
{
ValidationResults[] invalidResults = (
from entity in entities
let type = entity.GetType()
let validator = ValidationFactory.CreateValidator(type)
let results = validator.Validate(entity)
where !results.IsValid
select results).ToArray();
if (invalidResults.Length > 0)
throw new ValidationException(invalidResults);
}
}
You can read more about it here.

Categories