Validating and modifying a variable from MetaData Class - asp.net-mvc-3

I’m using ASP.NET MVC 3 for a project I have.
The problem is that I would like to save a value to the database, which should before saving into the database be "cleaned" (say removing trailing and ending spaces, and also validate).
I use a MetaData Class to validate the models before I save it to the database with data annotations, using the following code to validate:
if (ModelState.IsValid) {
My MetaData Class looks like this:
public class OrganizationMD {
[Required(ErrorMessage = "*This field is required.")]
[CustomValidationRule(ErrorMessage = "*Another error message")]
public string OrganizationNumber;
}
My first idea was to give the OrganizationNumber string a getter and setter, and there let the value become “fixed”.
For example if someone tries to save a company with "19860415-4785" as organizationnumber, it should automatically remove the trailing "19" and the dash in the string before validating and saving that new value into the database.
I can’t give the model a getter and setter because we’re developing using Model-First, otherwise I think that should work.
Does anyone have any idea how to solve this?

You could create a view model to pass the the data to/from the view and controller instead of using your domain (entity framework) model directly.
Put your data annotations on the view model's property.
public class OrganizationMDViewModel
{
[Required(ErrorMessage = "*This field is required.")]
[CustomValidationRule(ErrorMessage = "*Another error message")]
public string OrganizationNumber {get; set;}
}
Then you can do whatever you think will work in the getter and setter before mapping back to the domain model for persisting.
For readability and easier debugging, you could do your 'cleaning' in the controller instead of in the getter and setter, but that's up to you.
[HttpPost]
public ActionResult SaveData (OrganizationMDViewModel viewModel)
{
if (ModelState.IsValid) {
viewModel.OrganizationNumber...//clean up the value here
OrganizationMD = new OrganizationMD{OrganizationNumber = viewModel.OrganizationNumber}
//...and save
}
}

Related

Validating view data before its set into the model

My model object superficially is quite simple I don't think its worth describing my model, but a good analogy would be a SQL connection string, its just a string, but the rules for constructing it are quite complex, requiring a number of conditional UI elements depending on the DB, and other options.
Some of the data I have in the view can not be written to back to the Model if its invalid (imagine the database name is a quoted string, if a quote character is entered by the user, this can’t be written into the connection string without making the connection string unreadable).
The blazor validation API requires a model object to work from, so how do I create a validator for my blazor control that reports the errors against the invalid view fields. In this case the model is just the ConnectionString string field, and although I could write a custom validator for that, the data in it may not represent the data in the view, as the view can't always be written to the model.
UPDATED With Code
The following code shows the concept, I can't find a way for the validation rules in ConnectionStringViewModel to be run within the DatabaseInfoEditor.
class DatabaseInfoModel
{
[MaxLength(10)]
public string Name {get;set;}
[ValidateComplexType] // used to cause validation of child objects - but there is no child object to validate, what we want to validate is the ConnectionStringViewModel
public string ConnectionString {get;set;}
}
DatabaseInfoEditor.razor
<EditForm Model="MyDatabaseInfoModel">
<ObjectGraphDataAnnotationsValidator />
Name:<TextEditor #bind-Text="MyDatabaseInfoModel.Name"/>
<ConnectionStringEditor ConnectionString="MyDatabaseInfoModel.ConnectionString "/>
</EditForm>
ConnectionStringEditor.razor
Database:<TextEditor #bind-Text="MyConnectionStringViewModel.Database"/>
Username:<TextEditor #bind-Text="MyConnectionStringViewModel.Username"/>
#code
{
[Parameter]
public string ConnectionString {get;set;}
ConnectionStringViewModel MyConnectionStringViewModel;
override OnParameterSet()
{
base.OnParameterSet();
MyConnectionStringViewModel = PickApartConnectionString(ConnectionString);
}
class ConnectionStringViewModel
{
[MaxLength(10)]
public string Database {get;set;}
[MaxLength(10)]
public string Username {get;set;}
}
}

Web API parameters binding

I have this action in Web Api controller:
public Data GetData(ComplexModel model)
and model is
class ComplexModel
{
Guid Guid1 { get; set;}
Guid Guid2 { get; set;}
string String1 { get; set;}
}
i would like to specify custom binder for Guid type such as empty string or null would bind to empty guid and would like not use nullable type. Was trying to register model binder like this:
var pb = configuration.ParameterBindingRules;
pb.Insert(0, typeof(Guid), param => param.BindWithModelBinding(new GuidBinder()));
but it is not called and I am getting invalid model state with error message that empty string cant be converted to type Guid.
Remember, ParameterBindingRules checks the controller action parameter itself (ComplexModel in your case), not the contents of the parameter. You'd need to register a parameter binding against ComplexModel and do any processing with the custom binder to validate the model instance. Seems like you're better off making the Guid properties nullable despite your reluctance to do so.

Giving error while creating partial class

I am developing MVC application in which , I am trying to create the partial class of class generated by MVC application lets say Location class.
Now I want to create the partial class of Location class in new class file.
The below class code is auto genrated by MVC of Location code.
namespace CRM
{
public partial class Location
{
public int Id { get; set; }
public string Name { get; set; }
public string Remark { get; set; }
}
}
I have added new class file which contain the partial class of above file
namespace CRMEntities.Partial_Class
{
public interface ILocation
{
[StringLength(50, ErrorMessage = "Region can accept maximum 50 characters.")]
string Region { get; set; }
[Key]
int Id { get; set; }
[Required]
string Name { get; set; }
string Remark { get; set; }
}
public partial class Location : ILocation
{
}
}
Its giving the below error...
CRMEntities.Partial_Class.Location' does not implement interface member 'CRMEntities.Partial_Class.ILocation.Name
First, you don't need to do this, what I understand is you are trying to do validation right? Think about, the object generated by EF is not ViewModel, they are domain model. Data annotation should be in View Model, not domain model.
Most of cases, often mis-use is to use domain model as view model, but it is not correct much. Because sometime, view models need more than one domain model to provide data for your UI.
So for separation of concerns, you need to define your View Model different with domain model.
Example: you have Location class, you need to add LocationViewModel class and put data annotation in here.
You can map manually or use AutoMapper for mapping bettween View Model and Domain Model.
Another solution is you can use Fluent Validation, with this way, needless to have more partial class just for validation.
You don't show the definition of ILocation in your question, but the error says that the Location.Name property is declared differently than the ILocation.Name member.
Edit: Your two partial classes appear to be in two different namespaces, hence they are actually two entirely different classes, not two parts of the same class. That would explain the compiler error.
Having said that, I do agree with the other answer (+1!) that you should do your UI validation on a view model instead.

Failing to get unobtrusive client validation

I figured out that property i want to be validated has to have [Required] attribute in C#
(am i right?)
If so -my model is linq generated class - how to add this attribute?
You can do it a couple of ways:
If it's possible, make the field non-nullable in the database. This will make the field required at the data layer.
Create a partial class that adds a property to your model class. Use this property instead of the database-generated property.
For example:
public partial class YourEntity
{
[Required]
public string YourNewProperty
{
get { return this.TheRealProperty; }
set { this.TheRealProperty = value; }
}
}
Hopefully this helps
well, you could always make a new class, as a part of a Data access layer, with the same attributes, just put [required] where you want.
I believe your LINQ classes are partials. With MVC, you can use the "MetatDataTypeAttribute"
Like so
[MetadataType(typeof(UserMetadataSource))]
public partial class User {
}
class UserMetadataSource {
[HiddenInput(DisplayValue = false)]
public int UserId { get; set; }
}

mvc3 validation when using buddy classes

I am working on an mvc3 application and having some problems with getting validation to work as I want.
The application is using buddy classes for the models. (This is something I haven't used in the past and I am a little confused why they are used...anyway)
I want to add required fields to ensure data been submitted is correct. I have tried adding the required field to the buddy class.
When I submit the form no client-side validation takes place and the debugger steps into the entity frameworks generated code. Here is complains that the fields that contain null values are causing are invalid. If I step through all of those it finally gets to the controller where my if (ModelState.IsValid) is showing false.
I have client-side validation switched on.
Am I meant to be applying the data validation at the buddy class level or at the view model?
One other question is why use buddy classes? to me they seem to over complicate things.
Updated added an example of the buddy class
[MetadataType(typeof (CustomerMetaData))]
public partial class Customer
{
public string Priorty
{
get
{
var desc = (Priority) Priority;
return desc.ToString().Replace('_', ' ');
}
}
internal class CustomerMetaData
{
[Required]
[DisplayName("Priorty")]
public string Priorty { get; set; }
Buddy classes are metadata classes to put data annotation attributes when you are not in control of the original class i.e. can't edit it. Typical situation is when the class is generated by an ORM like Entity Framework.
//Can't edit this class
public partial class YourClass{
public string SomeField {get; set;}
}
//Add a partial class
[MetadataType(typeof(YourClassMetadata))]
public partial class YourClass{
}
//And a metadata class
public class YourClassMetadata
{
[Required(ErrorMessage = "Some Field is required")]
public string SomeField {get; set;}
}
are you sure that you have [MetadataType(typeof(YourClassMetadata))]?
More about buddy classes here and here
You would typically use a buddy class when it isn't possible to add meta data to an entity class such as when a model is automatically generated by an ORM tool. In this case any meta data you had applied would be lost.
Therefore, your original (automatically generated) class would be defined as a partial class:
public partial class Customer
{
public string Priority { get; set; }
}
And then you would generate your buddy classes to add the meta data.
[MetadataType(typeof(CustomerMetaData))]
public partial class Customer
{
}
internal class CustomerMetaData
{
[Required]
public string Priority { get; set; }
}
You would then pass the Customer class to the view where the Priority would be set.
In your case i'm not sure if you only have one partial class or two (as the other is not shown but please provide if there is). I'm interested to know how you obtain the priority information from the customer as i'm wondering if this is an issue with how you use ModelState.IsValid? The reason I ask is that no set accessor is declared on the Priority property so i'm wondering how this is set from the view in order to report that it is not valid?
You would also use a buddy class when it isn't possible to add meta data to an entity class such as when a model is automatically generated by an WCF Data Contract.

Resources