I have just started working on an MVC project and things are going ok but it looks like I am creating alot of spaghetti code with just too many objects. Can anyone see how I can simplify this solution before the whole projects gets out of hand?
ok, here's my set up:
DAL - has Entity framework connections and methods to obtain data then convert the data to my model objects in the model layer
BLL - sends the data back up to the UI
Model - this contains all the model objects that are used throughout the site, anything coming from the DAL is converted into these objects by creating a new object then populating the variables.
UI - my MVC solution
The DAL,BLL and Model are also used by other solutions.
Now with MVC, I am trying to use the validation annotations ([Required], etc) which means I have to re-create the model objects with the annotations. This is fine but if I want to save the data back into the database I need to convert the classes which is just messy.
Can anyone see how I can use my current model class library with MVC model objects that use the validation annotations?
If I have not explained myself clearly please let me know and I will provide more details.
Thanks
Ideally there needs to be a separation from the domain models on one hand and MVC models (they are really ViewModels) on the other hand. This separation is really crucial and strongly advised.
These will look a lot similar in most cases although ViewModel can contain extra stuff. Then you can use AutoMapper to convert from one to the other.
For example:
public class User // in entity DLL
{
[Required]
public string Name {get; set;}
}
public class UserViewModel : User // in MVC DLL
{
public string LastVisitedPage {get; set;} // which only MVC needs to know
}
Mapper.Map<User, UserViewModel>();
Mapper.Map<UserViewModel, User>();
you can put the metadata in metadata objects without recreating the model objects. Here is a very simple way of doing it, however it does require that the model objects themselves are marked as partial. I hope that is OK if not this solution will not work for you.
[MetadataType(typeof(PreviousResultsMetaData))]
public partial class PreviousResults
{
public class PreviousResultsMetaData
{
[DisplayName("Class Ranking Score")]
[Required]
[Range(0.0, 100.0)]
public object ClassRankingScore { get; set; }
}
}
in the example above there is a data model object called PreviousResults that is created elsewhere by some scaffolding code. It defines the POCO object that is sent to and from database using LINQ. The MetadataType attribute indicates the class that will be used to hold the metadata. Then you simply create plain objects that match the names of your real data members and annotate them.
I hope this helps.
You can use FluentValidation framework for validation. Look here
http://fluentvalidation.codeplex.com/
You can perfectly add attributes to your BLL (the business entities). Just add a reference and add a using statement for System.ComponentModel.DataAnnotations. Apart from that, you can implement the IValidatableObject interface (which is pretty easy, see below).
For the mapping, you can use for example AutoMapper, so you don't have to write to much of mapping logic yourself (if you can take advantage of the name mapping magic).
Validate example:
ICollection<ValidationResult> validationErrors = new List<ValidationResult>();
var validationContext = new ValidationContext(this, null, null);
Validator.TryValidateObject(this, validationContext, ValidationErrors, true);
return validationErrors;
Related
I'm using entity framework. It auto generated an Answer class. But I cannot modify this class as it will be overwritten if code is regenerated.
Is there a way/technique to add data annotations using this class?
The reason I ask is that I have a Create Answer view that uses the Answer class. Hence, I want to add data annotations such as Required, etc.
If I cannot add data annotations to the Answer class, then I have to create an "AnswerDuplicate" class, pass that into the view, and also use that in my Create() method. However, I then have to map all the values from AnswerDuplicate to an instance of Answer, since Answer is what I "add" to the entity.
Seems like extra work since Answer is autocreated (class and the binding in Create() method). Would be nice if I can just add data annotations.
If this is not possible, then is my only option to create an "AnswerDuplicate" class and use that in place of the Answer class?
My suggestion is: Use ViewModels.
I always consider creating a ViewModel when editing/viewing data - rather than passing the model object directly down to the view.
How Will This Help?
The logic to display it in the view (with Required, DataType and validation such like) can be left down to the ViewModel; while your Model is just left as a normal all-intents-and-purposes class (in your case, a generated one).
As an example, you could have an AnswerViewModel, which contains all of your display/validation logic, to then use in your corresponding View.
How Do I Save Time Mapping Properties?
You can use AutoMapper (or other similar auto-mapping packages) to then automatically map the properties between your model and the view model, for easy updating of entities etc.
This then saves you time having to write lines-upon-lines of code to update entities - which may essentially need to change over time - this can be a big problem (and a huge PITA) if refactoring/adding extra properties across different classes.
How Does This Help Going Forward?
Well, because you are not leaving the logic up to your class:
Let's say you have 3 different views for different purposes (Add, Edit, Delete)
If (for some reason) you need to show/display something differently in only one particular view, you are able to just apply/change the logic in the relevant ViewModel; rather than worrying about updating the Model and having breaking changes affect everything else.
Here is a handy tutorial on How To Use ViewModels In MVC: http://rachelappel.com/use-viewmodels-to-manage-data-amp-organize-code-in-asp-net-mvc-applications/
I do hope this helps, somewhat :)
If you need me to provide any examples - just let me know.
I think the best solution is to use ViewModels as #Geoff James said, but if you don't like to add different classed you can write a partial class and add the MetadataType attribute to it and the add the attributes you want like Required to its properties.
public partial class Answer // this is auto-generated
{
public long AnswerID {set; get;}
}
[MetadataType(typeof(Answer ))]
public partial class Answer // this is what you can write
{
[Required]
public long AnswerID {set; get;}
}
remember that both class must have a same namespace.
And other solution to your problem is the you can switch to Code First
I am new to MVC. According to MVC tutorial, Model are the classes which contains business logic. But in all the example which i referred, Model contains only the declaration (using interface). Why the Model cannot contain definition of business logic. Since i compared with MVVM model, where Model contains definition.
Why model look like this?
public interface IDBModel
{
void addRecord();
void deleteRecord();
}
Instead of like below.,
public Class DBModel
{
void addRecord()
{
// Insert logic
}
void deleteRecord()
{
// Delete logic
}
}
Kindly help me to understand the "Model" purpose in MVC and MVVM with some real time examples.
A model is meant to encapsulate data, making it easier to transfer from different logical areas of your application. The first example you give is incorrect, in that you're defining an interface with methods. You're more likely to see a model that looks like this:
public class Person {
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName() {
return string.Format("{0} {1}", FirstName, LastName);
}
}
Notice that I'm using properties as a way to transfer data, but have a method that performs lightweight logic (this could have also been done as a read only property). 90% of the time this is what your models will look like.
I would treat the M in MVC more like a view model. It contains all properties and formatting logic needed for the view to display itself. No need to have interfaces for it.
The controller is responsible for building that view model based on the models it receives from the services.
I think you misunderstood about the Model.
Worng: Model are the classes which contains business logic (not the business logic).
Models: Model objects are the parts of the application that implement the logic for the application's data domain. Often, model objects retrieve and store model state in a database. For example, a Product object might retrieve information from a database, operate on it, and then write updated information back to a Products table in SQL Server.
Take a look at official ASP.NET MVC Site.
Why model look like this?
Your application may follow certain different patters. other than MVVM.
Real Time Examples / Basic Understandings : Click Here
I'm using ASP .NET MVC (C#) and EntityFramework (database first) for a project.
Let's say I'm on a "Movie detail" page which shows the detail of one movie of my database. I can click on each movie and edit each one.
Therefore, I have a Movie class, and a Database.Movie class generated with EF.
My index action looks like :
public ActionResult MovieDetail(int id)
{
Movie movie = Movie.GetInstance(id);
return View("MovieDetail", movie);
}
GetInstance method is supposed to return an instance of Movie class which looks like this for the moment :
public static Movie GetInstance(int dbId)
{
using (var db = new MoviesEntities())
{
Database.Movie dbObject = db.Movies.SingleOrDefault(r => r.Id == dbId);
if (dbObject != null)
{
Movie m = new Movie(dbObject.Id, dbObject.Name, dbObject.Description);
return m;
}
return null;
}
}
It works fine but is this a good way to implement it? Is there an other cleaner way to get my instance of Movie class ?
Thanks
is this a good way to implement it?
That's a very subjective question. It's valid, and there's nothing technically wrong with this implementation. For my small-size home projects, I've used similar things.
But for business applications, it's better to keep your entities unrelated to your MVC application. This means that your data context + EF + generated entities should be kept in a separate project (let's call it the 'Data' project), and the actual data is passed in the form of a DTO.
So if your entity resembles this:
public class Person {
public int Id { get; set; }
public string Name { get; set; }
}
You'd expect there to be an equivalent DTO class that is able to pass that data:
public class PersonDTO {
public int Id { get; set; }
public string Name { get; set; }
}
This means that your 'Data' project only replies with DTO classes, not entities.
public static MovieDTO GetInstance(int dbId)
{
...
}
It makes the most sense that your DTOs are also in a separate project. The reason for all this abstraction is that when you have to change your datacontext (e.g. the application will start using a different data source), you only need to make sure that the new data project also communicates with the same DTOs. How it works internally, and which entities it uses, is only relevant inside the project. From the outside (e.g. from your MVC application), it doesn't matter how you get the data, only that you pass it in a form that your MVC projects already understand (the DTO classes).
All your MVC controller logic will not have to change, because the DTO objects haven't changed. This could save you hours. If you link the entity to your Controller AND View, you'll have to rewrite both if you suddenly decide to change the entity.
If you're worried about the amount of code you'll have to write for converting entities to DTOs and vice versa, you can look into tools like Automapper.
The main question: Is this needed?
That, again, is a very subjective question. It's relative to the scope of the project, but also the expected lifetime of the application. If it's supposed to be used for a long time, it might be worth it to keep everything interchangeable. If this is a small scale, short lifetime project, the added time to implement this might not be worth it.
I can't give you a definitive answer on this. Evaluate how well you want the application to adapt to changes, but also how likely it is that the applicaiton will change in the future.
Disclaimer: This is how we do it at the company where I work. This is not the only solution to this type of problem, but it's the one I'm familiar with. Personally, I don't like making abstractions unless there's a functional reason for it.
A few things:
The naming you're using is a little awkward and confusing. Generally, you don't ever want to have two classes in your project named the same, even if they're in different namespaces. There's nothing technically wrong with it, but it creates confusion. Which Movie do I need here? And if I'm dealing with a Movie instance, is it Movie or Database.Movie? If you stick to names like Movie and MovieDTO or Movie and MovieViewModel, the class names clearly indicate the purpose (lack of suffix indicates a database-backed entity).
Especially if you're coming from another MVC framework like Rails or Django, ASP.NET's particular flavor of MVC can be a little disorienting. Most other MVC frameworks have a true Model, a single class that functions as the container for all the business logic and also acts as a repository (which could be considered business logic, in a sense). ASP.NET MVC doesn't work that way. Your entities (classes that represent database tables) are and should be dumb. They're just a place for Entity Framework to stuff data it pulls from the database. Your Model (the M in MVC) is really more a combination of your view models and your service/DAL layer. Your Movie class (not to be confused with Database.Movie... see why that naming bit is important) on the other hand is trying to do triple duty, acting as the entity, view model and repository. That's simply too much. Your classes should do one thing and do it well.
Again, if you have a class that's going to act as a service or repository, it should be an actual service or repository, with everything those patterns imply. Even then, you should not instantiate your context in a method. The easiest correct way to handle it is to simply have your context be a class instance variable. Something like:
public class MovieRepository
{
private readonly MovieEntities context;
public MovieRepository()
{
this.context = new MovieEntities();
}
}
Even better, though is to use inversion of control and pass in the context:
public class MovieRepository
{
private readonly MovieEntities context;
public MovieRepository(MovieEntities context)
{
this.context = context;
}
}
Then, you can employ a dependency injection framework, like Ninject or Unity to satisfy the dependency for you (preferably with a request-scoped object) whenever you need an instance of MovieRepository. That's a bit high-level if you're just starting out, though, so it's understandable if you hold off on going the whole mile for now. However, you should still design your classes with this in mind. The point of inversion of control is to abstract dependencies (things like the context for a class that needs to pull entities from the database), so that you can switch out these dependencies if the need should arise (say perhaps if there comes a time when you're going to retrieve the entities from an Web API instead of through Entity Framework, or even if you just decide to switch to a different ORM, such as NHibernate). In your code's current iteration, you would have to touch every method (and make changes to your class in general, violating open-closed).
entity-model never should act as view-model. Offering data to the views is an essential role of the view-model. view-model can easily be recognized because it doesn’t have any other role or responsibility other than holding data and business rules that act solely upon that data. It thus has all the advantages of any other pure model such as unit-testability.
A good explanation of this can be found in Dino Esposito’s The Three Models of ASP.NET MVC Apps.
You can use AutoMapper
What is AutoMapper?
AutoMapper is a simple little library built to solve a deceptively complex problem - getting rid of code that mapped one object to another. This type of code is rather dreary and boring to write, so why not invent a tool to do it for us?
How do I get started?
Check out the getting started guide.
Where can I get it?
First, install NuGet. Then, install AutoMapper from the package manager console:
PM> Install-Package AutoMapper
Supposing I had, by way of demonstration, a controller that looked like this:
public class ProjectController : Controller
{
private IProjectRepository projectRepository;
public ProjectController()
{
DBContext context = new DBContext();
this.projectRepository = new ProjectRepository(context);
}
public ActionResult Create(Project project)
{
if (ModelState.IsValid)
{
// do whatever
}
else
{
return View(project);
}
}
}
And suppose that this was the controller for a model that looked like this:
public class Project : IValidatableObject
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// this is where I would like to add code
}
}
My question is: is there really no way in the validation code to reference the projectRepository object on the controller? Yes, I could technically add quasi-validation to the Create() function on the controller, do the check there, and add errors directly - but in the real case, there are a number of actions that would all perform the same validation, which is really tied to the model you're trying to create (or edit, or copy, or whatever else). But it's tied to the model and to other existing instances of the same model, which only the controller knows how to query for. Is there any way to get around that?
(The goal is to check that the current model object under validation isn't the same as one that exists already; I'm open to other suggestions of how to do that as well, it just seemed like it clearly should be a job for standard validation code, either using IValidatableObject or using a ValidationAttribute. But I am not an expert in .net MVC validation, or for that matter, .net MVC at all.)
Thanks!
IValidatableObject belongs to the DataAnnotations namespace. To my mind, Data Annotations are great for input validation. Where they start to fall down is when you start applying complex business rules where your domain model's validity depends on the state of other domain models.
When that happens, introduce a service layer. Put all your business rules in there, and allow the service to mediate the conversation between your models. At the end of the day, a service is supposed to be the interface with which you communicate with your model.
This is where I usually say to myself, "Hey, your app has now reached the 'medium-complexity' stage"! :)
An older but still relevant tutorial can be found here: http://www.asp.net/mvc/tutorials/older-versions/models-(data)/validating-with-a-service-layer-cs
IMO, there is a bit of a convention issue at play. The model that the controller returns to the client is a ViewModel, not an entity. This comes into play when thinking about which objects have knowledge of dependent objects.
The repository deals with models (entities), and the controller deals with ViewModels. ViewModels are really just a bunch of data and formatting, so set-level validations don't make sense on a ViewModel.
And really want the business-layer or repository to perform set-level validation, not the model itself. You could set a reference to the repository on the model when it is created and have the model call the repository for set-level validation. But this becomes problematic when you want to clone or deserialize the entity.
By the way, EntityFramework solves these problems by allowing you to Attach a disconnected entity. You might want to use EF instead of the repository pattern.
But for you immediate issue, I would not try to perform set-level validation from within the entity or viewmodel.
You might be better of putting your validation in the service layer
The online scaffolding tool CamoteQ generate its model validation code this way, which is a good reference for self-study.
I have a project, with a classic 3 tier structure: DataStore, BusinessLogic, Web-Frontend
In the DataStore I have a Model (simplified) e.g. ConfigModel.cs:
public class ConfigModel
{
[DataType(DataType.EmailAddress)]
public string DefaultSenderEmail { get; set; }
public IPAddress FallbackDNS { get; set; }
}
Here comes the question:
What's an elegant way to programmatically add Validators according to either the actual DataType, or the DataType Attribute?
A few answers that I have considered myself so far, but did not find them satisfactory:
Add an [EmailAddress] validation attribute to the parameter: I don't want duplication and I don't want any reference to MVC specific code in my DataStore Layer.
Make separate ViewModels and use AutoMapper: Since some of my models are a lot more complex than that, I'd hate to make specific ViewModels.
Thanks!
I would also consider using AutoMapper, but not as an answer to this solution.
Maybe you can consider this: http://weblogs.asp.net/srkirkland/archive/2011/02/15/adding-client-validation-to-dataannotations-datatype-attribute.aspx
That is not duplication. DataType is used for different purposes, and validation is different thing. Although they may sound the same (specifically for EmailAddress), you should not consider using both as duplication. Moreover, validation is automatically controlled for non nullable types - they are marked as Required. Datetimes are also checked for valid format automatically.
What you will definitely hate is controlling what properties of your domain model can be edited by users using BindAttribute and controlling different validations on same model, when using different views. So go for using ViewModels! Decorate them with all the attributes needed for your web application and map back to domain models using AutoMapper
You also may also want to check out FluentValidation