asp.net MVC3 Custom Validation - asp.net

I am new to MVC so this question may be naive
I know you can add validation attributes to model properties and the framework will provide appropriate server side and client side validation.However I am forced to use a legacy database structure where one of the properties in the model is either "int" or "string"
and the other property(Value) data type is determined by the first property.This means that I cannot use Annotations for validation. But is there any simple way of programatically "annotating" the properties after values are fetched from the database and the model class is constructed.If this can be done then it will do effective (client Side) validation without much hassle.
thanks

This answer shows one way to inject attributes at runtime. Another answer shows how to use validations that are only checked sometimes.
In your case it would be pretty easy to do model-based validation.
For server-side validation:
public class MyModel: IValidatableObject
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public IEnumerable<ValidationResult>
Validate(ValidationContext validationContext)
{
var relevantFields = new [] {"Prop2"};
if (Prop1 == "Int" && NotValidInt(Prop2))
yield return new ValidationResult("Prop2 must be convertable to int", relevantFields);
else if (prop1 == "String" && NotValidString(Prop2))
yield return new ValidationResult("Prop2 must be convertible to string", relevantFields);
}
}
For client-side validation, it's a bit more involved but details are available here:
MSDN article on adding support for clientside validation
A Good StackOverflow answer on the topic
See the custom validation section of the free Pluralsight training on validation for more information on server-side validation.

You are falling into the normal newbie error of thinking of your database as the M in MVC. Any non-trivial app is going to require that you seperate your database model from your view model. So apply your attributes to a view model, then use business logic to copy the values to your database model when your view is properly validated.
MVC is a User Interface pattern, and databases do not belong in it... I know, every sample application under the sun passes your data objects to the view, but that's just not the way it should be done.

Related

Where should Stored Proc business logic be placed in MVC?

I'm looking for a bit of experience and explanation here, given that different sources give different recommendations. I am totally new to MVC. I know this question has been asked before, but I am not (currently) using EF or Linq.
I have a SQL database with many stored procedures. Previously when used with webforms, there was a business layer that contained helper methods for calling the procedures and returning DataSets to the pages. The important part is that the procedures often interrogated about 20 tables; the pages do not simply reflect the database structure exactly (as I see in the majority of MVC tutorials):
SQL database <--> stored procedures <--> business layer <--> web forms
I want to take the best approach here to start on the right footing and learn properly but appreciate there may not be a correct answer. Therefore if you post, could you please offer some explanation as to "why"?
Should stored procedure logic (SQLCommand/business methods etc) go within Model or
Controller?
One post advises neither, but retain the business layer. Another expert advises that
[Models/Entities] should not have any addon methods outside of what's
coming back from the database
If the business layer is retained, where are the methods called from (e.g. Model or Controller)?
If the above answer is "Neither", does that mean the Model part will go unused?
That almost feels that things aren't being done properly, however in this tutorial that appears to be what happens.
Should I plug in the Entity Framework into the Model layer to call the business layer?
That feels like overkill, adding all that additional logic.
Your controllers should gather the information required to build the page the user is currently viewing. That's it.
Controllers should reference classes in your business logic layer.
For example here's your controller. All it does is translate the http request and call the business logic.
public class MyController : Controller
{
private IMyBusinessLogic _businessLogic;
public MyController(IMyBusinessLogic businessLogic)
{
_businessLogic = businessLogic;
}
[HttpPost]
public ActionResult UpdateAllRecords()
{
_businessLogic.UpdateAllRecords();
return Json(new Success());
}
}
And your business logic class
public class MyBusinessLogic : IMyBusinessLogic
{
public void UpdateAllRecords()
{
// call SP here
using(SqlConnection conn = new...
}
}
There are a number of advantages to this:
Your business logic is completely separated from your UI, there's no database code in your presentation layer. This means your controller can focus on it's job and code doesn't get polluted.
You can test your controller and see what happens when your business logic succeeds, throws exceptions etc.
For extra bonus points you should look into creating a data access layer.
public void DataAccess : IDataAccess
{
public void RunStoredProcedure(string spName)
{
}
}
Now you can test that your BLL is calling and processing your SP results correctly!
Expanded following the comment questioning the models:
Ideally your model should have no logic in it at all. It should simply represent the data required to build the page. Your object which you're loading represents the entity in the system, the model represents the data which is displayed on the page. This is often substantially lighter and may contain extra information (such as their address) which aren't present on the main entity but are displayed on the page.
For example
public class Person
{
public int PersonID {get;set;}
public string Firstname {get;set;}
public string Lastname {get;set;}
public Address Address {get;set;}
}
The model only contains the information you want to display:
public class PersonSummaryModel
{
public int PersonID {get;set;}
public string FullName {get;set;}
}
You then pass your model to your view to display it (perhaps in a list of FullNames in this case). Lots of people us a mapper class to convert between these two, some do it in the controller.
For example
public class PersonMapper
{
public PersonSummaryModel Map(Person person)
{
return new PersonSummaryModel
{
PersonID = person.PersonID,
FullName = string.Concat(person.Firstname, " ", person.Lastname)
};
}
}
You can also use some automatic solutions such at AutoMapper to do this step for you.
Your controller should really only be involved with orchestrating view construction. Create a separate class library, called "Data Access Layer" or something less generic, and create a class that handles calling your stored procs, creating objects from the results, etc. There are many opinions on how this should be handled, but perhaps the most
View
|
Controller
|
Business Logic
|
Data Access Layer
|--- SQL (Stored procs)
-Tables
-Views
-etc.
|--- Alternate data sources
-Web services
-Text/XML files
-and son on.
if you feel like learning tiers and best way
MSDN have great article on this link
MSDN

ASP.NET MVC - How to handle a string in a model that does not allow nulls?

So I'm a bit new to ASP.NET and MVC. I've got an ASP.NET MVC5 application, using Entity Framework 6. I've generated my models from a SQL Server database, and am so far just using the vanilla index/create/details/edit constructs.
In my models, various fields are marked as "Allow Nulls" and others aren't. While creating a new entry, any type that is, say, an int that is left as null is handled nicely by the ModelState.IsValid check and the #Html.ValidationMessageFor messages.
On one entry test, however, I received a DbEntityValidationException. I used the try/catch from this question to find out that it was one of the string (VARCHAR) fields that was left blank.
I am assuming this is because the string class allows nulls, where as int does not (unless declared as Nullable<type> in the model) thus the controller/model doesn't flag it as invalid.
What would be the easiest way to handle this? Is there a way to decorate the string property in the model so it gets checked as well? Or do I need to go as far as attempting to save, catching the exception, and manually handling the validation messages?
Thanks
It is possible to decorate your property with a Required-attribute. Mvc wil show an error message when the user is posting a form while this property is empty.
public class TestClassModel
{
[Required]
public string RequiredString { get; set; }
}

Best Way to Write an Asp.Net Web Service To Play Well In the Wild

I am writing an API for my ASP.NET application that other developers will use. The API will basically return a list of people with their first name, last name, and id. There are lots of ways to write web services in ASP.NET, the easiest probably being create a web service function (asmx) that returns a DataTable. This is simple enough for other .NET developers to deal with, but I am not convinced that this is the best way to write a web service for general platform and language independence.
What is the currently accepted standard to write a web service like this that plays well in the wild today?
Some ideas that come to mind from experience:
Use WCF, not .asmx. WCF does all the same things that ASMX files do, and is generally the replacement for ASMX services (see here and here).
Write methods using simple POCO data types, like List<Person> rather than DataTable. Basic types serialize more easily and will make more sense in other programming environments since you want your service to be language independent.
Provide generic CRUD methods for managing data. Depending on how your service will be consumed, if the user needs to modify data, a simple method is to provide getBlah(), updateBlah(obj newObj), deleteBlah(obj objToDelete), etc. that use the same data types.
Hide the details that the service consumer doesn't need to know, rather than just blindly exposing all of your data types, structures, and field names as-is. This will make your service more robust for handling internal changes, and you can simplify and control what the end-users see. For instance, if you have a Person class with 30 properties, and only 5 are relevant to the end-user, provide a class that interfaces between Person and a PersonSimple class which is exposed. Without this layer, your end-users will have to modify your code every time you change your data structure, and you will be locked down by this tight coupling.
If security is important
Execute your service over SSL. This protects data transfered over the wire from being sniffed.
Use authentication, either with a Login method and session, or SOAP headers. Services by default are anonymous unless there is some sort of authentication scheme. Even if you think nobody will find your service because you only provide the URL to your users, it will get out somehow, somewhere, and people will try to misuse the service when it does. Plus, you can control who can do what by different logins and authorization schemes.
I am currently working on a similar issue: A web api service in .NET that receives data tables as input parameters, apply some operations on them (using Table Valued Functions), and return some output data tables.
In your case, you don't need to use a complex class like DataTable; you could use an array (List<>) of a simple class with fields like first name, last name and id. Using Web Api of ASP.NET you could do something like the following:
1) Create a new WebApi project in Visual Studio: For example (in VS 2012) C# > Web > ASP.NET MVC 4 Web Application > select "Wep Api" as project template
You will see a VS project with lots of folders, including one named Models
For help see: http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api
2) Create a new model code file Person.cs with a class like the following:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string[] Friends { get; set; }
}
3) Create e new controller code file PersonController.cs with methods for getting, inserting and updating records of the database. All the necessary serialization/deserialization (JSON and XML) and data binding is done automatically by the Web Api environment set by the project template.
// Get all the records of persons
public IList<Person> Get()
{
// read database into a list of persons (List<Person>)
// return List<Person>
}
Return record of a selected person:
public Person Get(int id)
{
// read database for a selected person
}
Parameter binding (reading a JSON/XML content sent by http POST into an object, or into a list objects) is also done automatically, as easy as the following:
// parameter binding: Create a Person object with content from XML/JSON
public void ReadPerson(Person p)
{
Trace.WriteLine(Person.Id);
}
public void ReadPersonList(List<Person> plist)
{
Trace.WriteLine(plist.Count);
}

Binding Model properties directly in View

I've found this text in Prism documentation. I'm starting on MVVM and I'm at lost. Can (should) I bind model properties in the view or I must create a viewmodel with a proxy property for every property in the model?
The model classes typically provide
property and collection change
notification events through the
INotifyPropertyChanged and
INotifyCollectionChanged interfaces.
This allows them to be easily data
bound in the view. Model classes that
represent collections of objects
typically derive from the
ObservableCollection class.
EDIT: Here is some extra info to help. I'm building a personal project from the ground up (so I'm designing the models too), this is the first time that I use MVVM and I want to learn properly.
My model is very hieraquical, having classes with list of more class with more list inside, building a complex tree of information. I was trying the "standard" MVVM approach, build the model with POCO and no notifications, and using List. Then building the ViewModel with proper notifications and using ObservableCollections.
The problem is, the way it is going, I'm almost reconstructing my whole model as a ViewModel AND having to keep the data synched between the to (the ObservableCollection to the List). Then I read that on the Prism docs and wondered if I should have all that trouble or just create a root ViewModel for logic and bind all the rest to the model itself.
It depends really, if your model already implements INotifyPropertyChanged and/or IError info you might want to bind right to the model property. However if you want to do special validation and other stuff that the model knows nothing about you add the property wrappers in your view model.
This article gives a good example of a hybrid: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
Often my MV properties look like this and thats quite normal:
public string Symbol
{
get { return Model.Symbol; }
set { Model.Symbol = value; this.NotifyOfPropertyChange(() => this.Symbol); }
}
I often do NOT implement INotifyPropertyChanged in the model and thus often I have to write the wrappers.
EDIT: In response to your additional information: It can be a bit tricky to to keep the collections and lists in sync. In your case what I would do is to create a view model for each model class, but NOT wrap all the properties just access them like this: {Bindng Customer.Name}. But of course you have to create a wrapper for the collections which contain view models. The Prism documentation is, as they say themselves, just guidance, if your scenario needs a different approach then this is fine.
Take a look at this code. I only wrap the collections and the properties I will access through the model. This gives you the best of both worlds. Then IF you need a special property that does not belong into you model you can add it to the view model (see the CustomerViewModel), or if you need special notification for a certain properties.
class CompanyViewModel{
public CopanyViewModel(Company c){
foreach(var customer in c.Customers)
Customers.Add(new CustomerViewModel(customer);
}
public Company Company {get;set;}
public ObservableCollection<CustomerViewModel> Customers {get;set;}
}
class CustomerViewModel{
public CustomerViewModel(Customer c){
Customer = c;
}
public Customer Customer {get;set;}
public Brush CustomerBackground{
get{
if(Customer.Active)
return Brush.Greeen;
else
return Brush.Red;
}
}
}
(This code might not work, I just typed it in here.)
Now, if you need changed notification for all models and all properties you have to either implement it in you model or in wrap all properties in a view model.

Object property validation in MVC (using web service)

I have an ASP.Net MVC site, which connects to a web service.
The site's view model contains objects for each group of required service data AccountDetails (containing AccountId, AccountType, etc.), ContactDetails (containing Name, Address, etc.) and so on.
The service has a 'CreateUser()' method that accepts these objects as parameters, and it then performs all the validation itself - handing back an Object which has an array of any errors that have been found, including the name of the specific property/field.
I would like to know if there is a way of passing this returned error data into either DataAnnotations or something else.
I specifically can't write the conditions in the model itself, because the validation conditions within the web service are open to change at any moment - and we want this to dictate what fails and what succeeds.
== FURTHER INFO FOR MAKE IT A BIT CLEARER ==
Imagine I were locally (within the View Model) creating the ContactDetails class, I could very simply do this
public class ContactDetails
{
[IsRequired()]
[CustomAttributeofSomekind]
public string FirstName { get; set; }
public string LastName { get; set; }
}
However in this scenario - if we wanted to change the validation critera for whatever reason we would have to change it in both the web service AND in all the client websites that access the service.
We don't want to have to do this - instead I if (in the above) scenario ContactDetails.LastName is suddenly required and must be no more than 10 characters - this should only need updating in the web service.
I think you have two options:
Create a User class to wrap the CreateUser() method and add the DataAnnotations to that (this is what I would do, it allows you to go strongly-typed.)
Call the CreateUser() method directly from the controller Action and use server-side validation. Add each validation error in the CreateUser() result to the ModelState.Errors collection when any validation rules are violated.

Resources