You are on page 1of 41

User

Tutorial : EF Code First- Design Pattern

Part 0 Introduction:
Our main goal is to develop a MVC website for a hypermarket using .NET framework and
following this architecture:

DataBase

Front-Office
Back-Office

Part 1 - Setting up a solution:


Create these projects in one solution named MyFinance

MyFinance.Domain, MyFinance.Service, MyFinance.Data ( 3 Class


Library Project)
MyFinance.Web (ASP.NET Web Application (mvc))

Add the references following this schemas.


MyFinance.Service

MyFinance.Web

Reference

MyFinance.Data

MyFinance.Domainn

W
(MyF

BLL : Busi
(MyFinanc

DAL : Da
(MyFinan

To add a reference follow these steps:


1. Right click on project that needs the reference
2. Click Add
3. Click Reference

4. In the Reference Manager Message box, check referenced projects

5. Click OK

Part 2 Entities and Context Implementation:


Step 1 :
In the MyFinance.Domain, you should create a new folder named Entities
that includes all the classes of the following classes diagram, dont forget
navigation properties.

The following code expose the different entities:


public class Category
{
public int CategoryId { get; set; }
public string Name { get; set; }
//navigation properties
virtual public ICollection<Product> Products { get; set; }
}
public class Provider
{
public int Id { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
public string Email { get; set; }
public bool IsApproved { get; set; }
public DateTime? DateCreated { get; set; } // ? nullable
//navigation properties
virtual public ICollection<Product> Products { get; set; }
}
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public double Price { get; set; }
public int Quantity { get; set; }
public DateTime DateProd { get; set; }
//foreign Key properties

public int? CategoryId { get; set; }


//navigation properties
public virtual Category Category { get; set; }
public virtual ICollection<Provider> Providers { get; set; }

public class Biological : Product


{
public string Herbs { get; set; }
}
public class Chemical : Product
{
public string LabName { get; set; }
public string City { get; set; }
public string StreetAddress { get; set; }
}

We've made the navigation properties virtual so that we get lazy loading.
DateTime? Type is the nullable DateTime
We used ICollection interface so we can use later any collection implementation.

Step 2 : Entity Framework Installation


Now, lets move to MyFinance.Data project and add a reference to the Entity-Framework.
So lets open Manage NuGet package.
We need this reference so we can implement the context.
Do the same for MyFinance.Web project. Because entity framework wont be deployed
unless its referenced by the web project

We install the Entity Framework package

Step 3 : Context Implmentation


A Context is a class inherits DbContext, and manage entities and database.
Add a new Context by following these steps:
1. Create a class MyFinanceContext in MyFinance.Data project
2. Add an inheritance from DbContext
3. Add a default constructor that calls the parent one, and give it the named connection
string DefaultConnection that exists in the web.Config file in MyFinance.web
project
4. Add sets (Collection for entities management)
5. Add necessary using.
using MyFinance.Domain.Entities;
using System.Data.Entity;
public class MyFinanceContext : DbContext
{
public MyFinanceContext()
: base("Name=DefaultConnection")
{
}

Web.config

public DbSet<Category> Categories { get; set; }


public DbSet<Provider> Providers { get; set; }
public DbSet<Product> Products { get; set; }

Step 4 : Scaffold a Controller


1.
2.
3.
4.
5.
6.
7.

In MyFinance.Web Project add a reference to MyFinance.Data project (Context)


Build the solution
Right click on Controllers folder in the MyFinance.Web Project
click Add
click controller
in the message box choose : MVC5 Controller with views, using entity framework
Fill the message box like this :

8. Click Add
9. Explore the generated Controller and Views
Step 5 : Run and enjoy
Follow these steps:
1. Right click the MyFinance.Web project
2. Click Set as start-up project

3. Click the button


4. Add /products to the url and visit the page Ex : http://localhost:{your
port}/products
5. Insert some data

Step 6 explore database


Select App_Data folder in
MyFinance.Web and click on show all
files icon
Open App_Data folder and double click on
the mdf File

By default, Entity framework code first


uses Table Per Hierarchy (TPH) method to
handle inheritance when creating tables
from entities. in TPH, All Data in the
hierarchy will be saved in a single database
table and it uses a Discriminator column to
identify which record belongs to which sub
type. The value of this column will be the
name of the subtype.

Part 3 Update the model:


Step 1 (Optional):-Lets try to add a property public string Image { get; set; }
to the entity Product.
1. Run the application. Try to list products. What happen?
The application throws this exception:

-That exception is thrown because


the model changed and the the
Entity Framework Code First doesnt
know how it will behave. Therefore
we have to tell the framework how
it must behave.

2. Lets add another class MyFinanceContextInitialize in the same file of


This class inherit from
DropCreateDatabaseIfModelChanges<MyFinanceContext>, which give
the Entity Framework the strategy of initializing the application. In other
word, this class informs the Entity Framework to drop and create the database
if the model changes. We can replace this class by
DropCreateDatabaseAlways or CreateDatabaseIfNotExists.
the Context.
3. Override the Seed method inherited from the base class.
This method serves to seed the database in case on dropping and creating the
database, so we can seed some data for test instead of adding data manually in
the database each time the database is created.
public class MyFinanceContextInitializer :
DropCreateDatabaseIfModelChanges<MyFinanceContext>
{
protected override void Seed(MyFinanceContext context)
{
var listCategories = new List<Category>{
new Category{Name="Medicament" },
new Category{Name="Vetement" },
new Category{Name="Meuble" },
};
context.Categories.AddRange(listCategories);
context.SaveChanges();
}

4. In order to set the initializer we have to add this code to the


constructor of the class MyFinanceContext.
Database.SetInitializer<MyFinanceContext>(new MyFinanceContextInitializer());

5. In MyFinance.Web project, delete the controller ProductsController and


the Products folder under the Views Folder and scaffold
ProductsController. (same steps as Part2, Step4) to refresh the views
with the new added property
6. Go to the server explorer panel, right click on your database and close
connection.
This Step is necessary to close all connection to the database, you delete
the database in the SQL Server Object Explorer or Restart the visual studio
7. Run the application another time and check the database

Step 2 : Assuming that we are using a production environment and we have important
data. Then we are not allowed to lose this data. In this case the initialisation
strategy doesn't seem to be a good choice. So lets try something else,
Migration !!!! Lets do it.
1. The first step: we have to enable the Migration: Open the Package
Manager Console the choose the project MyFinance.Data which
contains the class Context. Then execute this command EnableMigrations

Entity Framework Code First generate a new folder Migration which contains
two classes xxx_InitialCreate and Configuration.
-The first class contains an Up () method that contains instructions to create the
table with its original definition, and another method Down () to delete the table.
-The second class define the behavior of the migration for DbContext used. This is
where you can specify the data to insert, enter the providers of other databases

2. The second step: we will change the name of the property public string
Image { get; set; } to public string ImageName { get; set; }.
3. Execute the command Add-Migration ModifyNameImage in the
Package Manager Console.
4. The Add-migration command checks for changes since your last
migration and scaffold a new migration with any changes found. We can
give a name for our migration, in this case, we call migration
"ModifyNameImage".

5. Go to the Configuration class in Migrations folder and add the following


code in the seed method of the migration :
context.Categories.AddOrUpdate(
p => p.Name, //Uniqueness property
new Category { Name = "Medicament" },
new Category { Name = "Vetement" },
new Category { Name = "Meuble" }
);
context.SaveChanges();

6. Execute the command Update-Database


-TargetMigration:"ModifyNameImage"
in the Package Manager Console. This command will apply any pending
migration to the database and then check the database.

Part 4 Complex Type:


Step 1 : Lets add a Complex Type Address in entities folder in
MyFinance.Domain project
public class Address {
public string StreetAddress { get; set; }
public string City { get; set; }
}

To create a new Complex Type we have to follow those rules otherwise we have to
configure a complex type using either the data annotations or the fluent API.

Step 2 : Lets update Chemical entity with the complex type as the following :
public class Chemical : Product
{
public string LabName { get; set; }
public Address LabAddress { get; set; }
}

Part 5 Configuration using annotations:


Step 1 : Add a reference to System.ComponentModel.DataAnnotions
assembly to the MyFinance.Model project

Step 2 : Now , we will add different data annotations to configure those entities.

In class Product : properties should be configured as the following :


the property Name should be
required
The user input string have the length 25 (max)
The property have length 50 (max)
An error message will be displayed if the rules are not
respected.
The property Description should be
Multiline
The property Price should be
Currency
The property Quantity should be
Positive integer
The property DateProd should be
Displayed as Production Date
Valid Date
The property CategoryId should be
The foreign Key property to the Category entity.
public class Product
{
public int ProductId { get; set; }
[DataType(DataType.MultilineText)]
public string Description { get; set; }
[Required(ErrorMessage = "Name Required")]
[StringLength(25, ErrorMessage = "Must be less than 25 characters")]
[MaxLength(50)]
public string Name { get; set; }
[Range(0,double.MaxValue)]

[DataType(DataType.Currency)]
public double Price { get; set; }
[Range(0, int.MaxValue)]
public int Quantity { get; set; }
[DataType(DataType.ImageUrl),Display(Name = "Image")]
public string ImageName { get; set; }
[Display(Name = "Production Date")]
[DataType(DataType.DateTime)]
public DateTime DateProd { get; set; }
//foreign Key properties
public int? CategoryId { get; set; }
//navigation properties
[ForeignKey("CategoryId ")]
//useless in this case
public virtual Category Category { get; set; }
public virtual ICollection<Provider> Providers { get; set; }
}

MaxLength is used for the Entity Framework to decide how large to make a string
value field when it creates the database.
StringLength is a data annotation that will be used for validation of user input.
DataType : is used to specify a specific type : email, currency, card number
Display is used to change the displayed name of the property
Range is used to limit valid inputs between min and max values.
Foreignkey : To configure the foreign key

In class Provider : properties should be configured as the following :


the property Id should be
Key (Id is already a primary key By Convention)
The property Password should be
Password (hidden characters in the input)
Minimum length 8 characters
Required
The property ConfirmPassword should be
Required
Not mapped in the database
Password
Same value as Password property
The property Email should be
Email
Required

public class Provider


{
[Key] // optional !
public int Id { get; set; }
public string UserName { get; set; }
[Required(ErrorMessage = "Password is required")]
[DataType(DataType.Password)]
[MinLength(8)]

public string Password { get; set; }


[NotMapped]
[Required(ErrorMessage = "Confirm Password is required")]
[DataType(DataType.Password)]
[Compare("Password")]
public string ConfirmPassword { get; set; }
[Required,EmailAddress]
public string Email { get; set; }
public bool IsApproved { get; set; }
public DateTime? DateCreated { get; set; }
virtual public List<Product> Products { get; set; }
}

Key Define the Key column in the database..


NotMapped : no column would be generated in the database
Comapre : compare two properties
MinLength the opposite of MaxLength

Step 3 : Lets Test


1.
2.
3.
4.
5.

Update the database using migration


Delete ProductsController and products folder under Views folder
scaffold a new ProductsController
scaffold ProvidersController
Run and test

Part 6 Configuration using fluent API:


Note that the data annotations and the fluent API configuration could
coexist.

Step 1 : Create new Folder named Configurations in MyFinance.Data


project

Step 2 : Add CategoryConfiguration classes in the Configurations folder


public class CategoryConfiguration : EntityTypeConfiguration<Category>
{
public CategoryConfiguration()
{
ToTable("MyCategories");
HasKey(c => c.CategoryId);
Property(c => c.Name).HasMaxLength(50).IsRequired();
}
}

-This class inherit from the generic class EntityTypeConfiguration , defined in


System.Data.Entity.ModelConfiguration , then we pass the type that we want to
configure
-In fact, Following the convention Entity Framework names the table created in
the database with the name of the entity in plural. In this case the table
generated will be named Categories. Therefore, when we want to change the
name of the table we use the method ToTable(MyCategories).
-We will apply some rules on the Name and the Description proprieties

Step 3 : Add ProductConfiguration classes in the Configurations folder : This


step contains 3 main parts. The first part refers to the many-to-many
association between products and providers, the second part configure the
inheritance, the third part configure the one-to-many association between the
Product and the Category.
public class ProductConfiguration : EntityTypeConfiguration<Product>
{
public ProductConfiguration()
{
//properties configuration
Property(e => e.Description).HasMaxLength(200).IsOptional();
//Many to Many configuration
HasMany(p => p.Providers)
.WithMany(v => v.Products)
.Map(m =>
{
m.ToTable("Providings"); //Table d'association
m.MapLeftKey("Product");
m.MapRightKey("Provider");
});
//Inheritance
Map<Biological>(c =>
{
c.Requires("IsBiological").HasValue(1); //isBiological is the descreminator
});
Map<Chemical>(c =>
{
c.Requires("IsBiological").HasValue(0);
});
//One To Many
HasOptional(p => p.Category) // 0,1..* //if you need 1..* use HasRequired()
.WithMany(c => c.Products)
.HasForeignKey(p => p.CategoryId)
.WillCascadeOnDelete(false);
} }

The Many to many part configure the association between the Product class and
The Provider class

Those classes have a many to many association. Entity Framework uses


the convention to create an association table following this pattern. The
name of the table will be the name of the first entity concatenated with the
name of the second one. This table will contain two columns, those names

will follow the next pattern:


[The_name_of_the_navigation_propriety]
[The_name_of_the_primary_Key]. This example
explains better.
In this case we want to alter the name of the
association table as well as the names of the
columns.
The inheritance part customizes the TPH inheritance:

Indeed Entity Framework create a flag column named


Discriminator, so we want to change the name of
the column to IsBiological. This column will contain
the value 1 in the case of adding a Biological object.
Otherwise it will contain the value 0.

The final part customizes the one-to-many association


between the Product class and the Category class.

The Product can belong to a Category, which explains the optional


relationship. In the HasOptional method, we pass the navigation
propriety Category of the Product Class. The method WithMany
specifies that the Category contains many Products. As well as the other
method, we pass the navigation navigation property Products of the
Category class.
We also want to disable the Cascade On Delete to conserve products after
deleting an associated category. For this aim the foreign key CategoryId
should be nullable

Step 4 :Finally we configure the complex type Address by creating this class:
public class AddressConfiguration : ComplexTypeConfiguration<Address>
{
public AddressConfiguration()
{
Property(p => p.City).IsRequired();
Property(p => p.StreetAddress).HasMaxLength(50)
.IsOptional();
}
}

Step 5 : Update the Context to apply these configurations so, in the


MyFinanceContext class override the OnModelCreating method like this :
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//If you want to remove all Convetions and work only with configuration :
// modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
modelBuilder.Configurations.Add(new CategoryConfiguration());
modelBuilder.Configurations.Add(new ProductConfiguration());
modelBuilder.Configurations.Add(new AddressConfiguration());
}

Step 6 : Update the database by migration and explore it to see what the
configurations have done.

Part 7 Design Patterns:


Step 1 : Add a new folder in MyFinance.Data project called Infrastructure
Step 2 : We will implement the Disposable pattern, but first we should
understand why we will use this pattern.

In fact there are two types of resources in the Framework .Net:


o Managed resources are resources that the garbage collector can be
dispose when there the reference is broken in the memory.
o Unmanaged resources that are all that the garbage collector can not
handle, example: open files, database connections ...

How can we free up memory if any unmanaged resources remain? Solution:


Dispose pattern
This is a design pattern that is used to clean unmanaged resources.

To provide explicit control, implement the Dispose method provided by


the IDisposable interface. The consumer of the object should call this
method when it has finished using the object.
Note that you must provide implicit cleanup using the Finalize () method,
even when you provide explicit control with Dispose. Finalize () provides a
backup to prevent a definitive resource drain if the programmer does not
call Dispose.

Add a class Disposable which inherit from the IDisposable interface in the
Infrastructure folder.
public class Disposable : IDisposable
{
// Track whether Dispose has been called.
private bool isDisposed;
// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~Disposable()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
public void Dispose()
{
Dispose(true);

// This object will be cleaned up by the Dispose method.


// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged
resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!isDisposed && disposing)
{
DisposeCore();
}
isDisposed = true;
}
protected virtual void DisposeCore()
{
}
}

Step 3 : Then we will add an interface IDatabaseFactory which inherit from


the interface IDisposable in the Infrastructure folder.
public interface IDatabaseFactory : IDisposable
{
MyFinanceContext DataContext { get; }
}

- Next, we add a DatabaseFactory class which inherit from the class:


Disposable and implement the interface IDatabaseFactory.
public class DatabaseFactory : Disposable, IDatabaseFactory
{
private MyFinanceContext dataContext;
public MyFinanceContext DataContext { get { return dataContext; } }
public DatabaseFactory()
{
dataContext = new MyFinanceContext();
}
protected override void DisposeCore()
{
if (DataContext != null)
DataContext.Dispose();
}
}

-This class implement the design pattern Factory, in fact before talking about
this design pattern, lets see two great principals that stands on the base of many
design and architecture decisions.

Separation of Concerns (SoC) is the process of breaking a computer


program into distinct features that overlap in functionality as little as
possible. A concern is any piece of interest or focus in a program. Typically,
concerns are synonymous with features or behaviors.
Single Responsibility Principle (SRP) every object should have a
single responsibility, and that all its services should be narrowly aligned
with that responsibility. On some level Cohesion is considered as synonym
for SRP.

The separation allows:

To allow people to work on individual pieces of the system in isolation;


To facilitate reusability;
To ensure the maintainability of a system;
To add new features easily;
To enable everyone to better understand the system;
-Therefore we choose the Factory pattern which will be responsible for the
instantiation of our Context and will act as a factory that create the Context
object and yield it to the other classes. So, as we can see this class is divided into
two parts.
1. The first part instantiate the MyFinanceContext in the first call
2. The second part dispose the current object.

Step 4 :-Lets move now to the implementation of CRUD methods. No , we wont


use the DAO classes. Why?
-In fact, the pattern DAO is an anti-pattern rather than a design pattern.
Supposing that we have 100 pocos, then we have to create 100 DAO classes
where we will replicate the same code 100 times.
-Moreover , when we want to modify the behavior of an update method for
example , then we have to do the same thing 100 times.
-Therefore , we will use the Repository pattern. The repository pattern is an
abstraction layer which provides a well-organised approach to maintaining a
separation between an application's data access and business logic layers. This
gives us the important advantages of making code more maintainable and
readable and improving the testability of our code. It also works great with
dependency injection!
-Lets add first an interface IRepository.
public interface IRepository<T> where T : class
{
void Add(T entity);
void Update(T entity);
void Delete(T entity);
void Delete(Expression<Func<T, bool>> where);
T GetById(long Id);
T GetById(string Id);

T Get(Expression<Func<T, bool>> where);


IEnumerable<T> GetAll();
IEnumerable<T> GetMany(Expression<Func<T, bool>> where);
}

-Then we will add an RepositoryBase class. In the first hand, we create this
abstract class is a generic class which contain generics CRUD methods. In the
second hand , well add the different repositories which inherit from this base
Repository.
-As we see in this class, we pass a DatabaseFactory object through the
constructor and we create a generic Set since this Set will be used by the
different entities.
-After getting the Context object created by the DatabaseFactory we add some
generics methods.
-Note that in somes methods like public virtual void
Delete(Expression<Func<T, bool>> where)

we can pass a lambda expression to add a criteria instead of creating


several methods to delete by criteria.
public abstract class RepositoryBase<T> : IRepository<T> where T : class
{
private MyFinanceContext dataContext;
private IDbSet<T> dbset;
IDatabaseFactory databaseFactory;
protected RepositoryBase(IDatabaseFactory dbFactory)
{
this.databaseFactory = dbFactory;
dbset = DataContext.Set<T>();
}
protected MyFinanceContext DataContext
{
get { return dataContext = databaseFactory.DataContext; }
}
public virtual void Add(T entity)
{
dbset.Add(entity);
}
public virtual void Update(T entity)
{
dbset.Attach(entity);
dataContext.Entry(entity).State = EntityState.Modified;
}
public virtual void Delete(T entity)
{
dbset.Remove(entity);
}
public virtual void Delete(Expression<Func<T, bool>> where)
{
IEnumerable<T> objects = dbset.Where<T>(where).AsEnumerable();
foreach (T obj in objects)
dbset.Remove(obj);
}
public virtual T GetById(long id)
{
return dbset.Find(id);

}
public virtual T GetById(string id)
{
return dbset.Find(id);
}
public virtual IEnumerable<T> GetAll()
{
return dbset.ToList();
}
public virtual IEnumerable<T> GetMany(Expression<Func<T, bool>> where)
{
return dbset.Where(where).ToList();
}
public T Get(Expression<Func<T, bool>> where)
{
return dbset.Where(where).FirstOrDefault<T>();
}
}

Now , we create a Repositories Folder to add the different repositories. Then


we add the following repositories CategoryRepository, ProviderRepository,
ProductRepository. Those classes inherit from the BaseRepository ,
thus we don't need to replicate CRUD methods , we can just add some specific
methods in those repositories.
public class CategoryRepository : RepositoryBase<Category>, ICategoryRepository
{
public CategoryRepository(IDatabaseFactory dbFactory)
: base(dbFactory)
{
}
}
public interface ICategoryRepository : IRepository<Category> { }

public class ProviderRepository : RepositoryBase<Provider>, IProviderRepository


{
public ProviderRepository(IDatabaseFactory dbFactory)
: base(dbFactory)
{
}
}
public interface IProviderRepository : IRepository<Provider> { }

public class ProductRepository : RepositoryBase<Product>, IProductRepository


{
public ProductRepository(IDatabaseFactory dbFactory)
: base(dbFactory)
{
}
}
public interface IProductRepository : IRepository<Product> { }

Step 10 :-Now we will see the last design pattern in our project The Unit Of
Work.

-The idea is that we can use the Unit of Work to group a set of related operations
the Unit of Work keeps track of the changes that we are interested in until we
are ready to save them to the database.
-The pattern Unit Of Work consists in making one or more transactions database
committed or rolled back together.
-The pattern "Unit of work" is used to:

-Group several "repositories" so they share a context of unique database


(DbContext).
-Apply the SaveChanges () method on the instance of the context defined and
ensure that any changes connected to each other will be made in a coordinated
manner.
-Lets add the next interface IUnitOfWork in the Infrastructure folder:
public interface IUnitOfWork : IDisposable
{
void Commit();
IProviderRepository ProviderRepository { get; }
ICategoryRepository CategoryRepository { get; }
IProductRepository ProductRepository { get; }
}

-Then add The UnitOfWork class:


public class UnitOfWork : IUnitOfWork
{
private MyFinanceContext dataContext;
IDatabaseFactory dbFactory;
public UnitOfWork(IDatabaseFactory dbFactory)
{
this.dbFactory = dbFactory;
}
private IProviderRepository providerRepository;
public IProviderRepository ProviderRepository
{
get { return providerRepository = new ProviderRepository(dbFactory); }
}
private ICategoryRepository categoryRepository;
public ICategoryRepository CategoryRepository
{
get { return categoryRepository = new CategoryRepository(dbFactory); }
}
private IProductRepository productRepository;
public IProductRepository ProductRepository

get { return productRepository = new ProductRepository(dbFactory); }


}
protected MyFinanceContext DataContext
{
get
{
return dataContext = dbFactory.DataContext;
}
}
public void Commit()
{
DataContext.SaveChanges();
}
public void Dispose()
{
dbFactory.Dispose();
}

Part 8 Business Layer


Step 1 :-We move to the business layer (MyFinance.Service), Lets add a service
to encapsulate the methods implemented in the data layer:
public interface IEBuyService: IDisposable
{
void CreateProduct(Product p);
Biological GetBiologicol(int id);
IEnumerable<Category> GetCategories();
Chemical GetChemical(int id);
IEnumerable<Chemical> GetChemicals();
Product GetProduct(int id);
IEnumerable<Product> GetProducts();
IEnumerable<Product> GetProductsByCategory(string categoryName);
void UpdateProduct(Product p);
}
public class EBuyService : IEBuyService
{
DatabaseFactory dbFactory = null;
IUnitOfWork utOfWork = null;
public EBuyService()
{
dbFactory = new DatabaseFactory();
utOfWork = new UnitOfWork(dbFactory);
}
public IEnumerable<Category> GetCategories()
{
var categories = utOfWork.CategoryRepository.GetAll();
return categories;
}
IEnumerable<Biological> GetBiologicols()
{
var Biologicals = utOfWork.ProductRepository.GetAll().OfType<Biological>();
return Biologicals;
}
public IEnumerable<Product> GetProducts()
{
var Products = utOfWork.ProductRepository.GetAll();

return Products;
}
public IEnumerable<Chemical> GetChemicals()
{
var Chemicals = utOfWork.ProductRepository.GetAll().OfType<Chemical>();
return Chemicals;
}
public Biological GetBiologicol(int id)
{
var Biological = utOfWork.ProductRepository.GetById(id) as Biological;
return Biological;
}
public Chemical GetChemical(int id)
{
var Chemical = utOfWork.ProductRepository.GetById(id) as Chemical;
return Chemical;
}
public void CreateProduct(Product p)
{
utOfWork.ProductRepository.Add(p);
utOfWork.Commit();
}
public Product GetProduct(int id)
{
var Product = utOfWork.ProductRepository.GetById(id);
return Product;
}
public void UpdateProduct(Product p)
{
utOfWork.ProductRepository.Update(p);
utOfWork.Commit();
}
public IEnumerable<Product> GetProductsByCategory(string categoryName)
{
return utOfWork.ProductRepository.GetMany(x => x.Category.Name ==
categoryName);
}
public void Dispose()
{
utOfWork.Dispose();
}
}

Part 9 Product Insertion


Step 1 : Controller preparation
1. Delete the old ProductsController class and the Products folder under
the views folder
2. Create a new Controller with empty actions

3. Instanciate the EBuyService class in the default constructor of the


controller
IEBuyService service = null;
public ProductsController()
{
service = new EBuyService();
}

4. Implement the disposibal pattern in the controller by overrinding the


Dispose methode
protected override void Dispose(bool disposing)
{
if (disposing)
{
service.Dispose();
}
base.Dispose(disposing);
}

Step 2 : CreateBiological get action Coding


1. Add the CreateBiological Action
public ActionResult CreateBiological()
{
var categories = service.GetCategories();
ViewBag.Category = new SelectList(categories, "CategoryId", "Name");
return View();
}

Step 3 : CreateBiological view Coding


1. Right click on the action name and choose add View

2. Generate a form for the product insertion.

3. Explore the generated view under the Products folder, and change the
Html.BeginForm() method to the folowing
Html.BeginForm("CreateBiological", "Products", FormMethod.Post, new { enctype =
"multipart/form-data" })

Now, you have a multi-part form and so you can upload files with your data.
4. Change the editor for the image name from a simple text box to a file
upload input
@Html.Editor("file", new { htmlAttributes = new { @class = "form-control", type = "file" } })

5. Change the CategoryId editor to enable the category selection by a drop


down list.
@Html.DropDownListFor(model => model.CategoryId, (SelectList)ViewData["Category"], new
{ htmlAttributes = new { @class = "form-control" } })

6. Add a checkbox under the drop down list to check if the inserted product is
a new One !

<div class="form-group">
@Html.Label("New ?", htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.CheckBox("isNew", new { htmlAttributes = new { @class = "form-control" } })
</div>
</div>

This is a hole code of the CreateBiological.cshtml view :


@model MyFinance.Domain.Entities.Biological
@{
ViewBag.Title = "CreateBiological";
}
<h2>CreateBiological</h2>
@*first change*@
@using (Html.BeginForm("CreateBiological", "Products", FormMethod.Post, new { enctype =
"multipart/form-data" }))
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Product Info :</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label
col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class =
"form-control" } })
@Html.ValidationMessageFor(model => model.Name, "", new { @class = "textdanger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Description, htmlAttributes: new { @class =
"control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Description, new { htmlAttributes = new { @class
= "form-control" } })
@Html.ValidationMessageFor(model => model.Description, "", new { @class =
"text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Price, htmlAttributes: new { @class = "control-label
col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Price, new { htmlAttributes = new { @class =
"form-control" } })
@Html.ValidationMessageFor(model => model.Price, "", new { @class = "textdanger" })
</div>
</div>
<div class="form-group">

@Html.LabelFor(model => model.Quantity, htmlAttributes: new { @class = "controllabel col-md-2" })


<div class="col-md-10">
@Html.EditorFor(model => model.Quantity, new { htmlAttributes = new { @class =
"form-control" } })
@Html.ValidationMessageFor(model => model.Quantity, "", new { @class = "textdanger" })
</div>
</div>
@*second change*@
<div class="form-group">
@Html.LabelFor(model => model.ImageName, htmlAttributes: new { @class =
"control-label col-md-2" })
<div class="col-md-10">
@Html.Editor("file", new { htmlAttributes = new { @class = "form-control", type =
"file" } })
@Html.ValidationMessageFor(model => model.ImageName, "", new { @class =
"text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.DateProd, htmlAttributes: new { @class = "controllabel col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.DateProd, new { htmlAttributes = new { @class
= "form-control" } })
@Html.ValidationMessageFor(model => model.DateProd, "", new { @class = "textdanger" })
</div>
</div>
@*modif 3*@
<div class="form-group">
@Html.LabelFor(model => model.CategoryId, htmlAttributes: new { @class = "controllabel col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(model => model.CategoryId,
(SelectList)ViewData["Category"], new { htmlAttributes = new { @class = "form-control" } })
</div>
</div>
@*modif 4*@
<div class="form-group">
@Html.Label("New ?", htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.CheckBox("isNew", new { htmlAttributes = new { @class = "formcontrol" } })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Herbs, htmlAttributes: new { @class = "control-label
col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Herbs, new { htmlAttributes = new { @class =
"form-control" } })
@Html.ValidationMessageFor(model => model.Herbs, "", new { @class = "textdanger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" />

</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}

Step 4 : CreateBiological post action Coding


Lets add a post action so the server can handel the product, file and the
checkbox data.
First, we will validate these data, and save it in Session or TempData type and
finally we will redirect the user the another view for validation before insertion.
public ActionResult CreateBiological(Biological bio, HttpPostedFileBase file, bool? isNew)
{
if (!ModelState.IsValid || file.ContentLength == 0 || isNew == null)
{
return CreateBiological();
}
bio.ImageName = file.FileName;
Session["Product"] = bio;
TempData["isNew"] = isNew;
TempData["Image"] = file;
return RedirectToAction("ValidateBiological");
}

Step 5 : ValidateBiological get action Coding


1. Now we add another get action called ValidateBiological that do two
things based on a Boolean value :
Display the product details view, so the client can check data before
validation
Insert the product in the data base and save the file on the server.
public ActionResult ValidateBiological (bool? insertion)
{
Product p = Session["Product"] as Product;
if (insertion == true)
{
HttpPostedFileBase file = TempData["Image"] as HttpPostedFileBase;
if (file.ContentLength > 0)
{
service.CreateProduct(p);
var path = Path.Combine(Server.MapPath("~/Content/Upload"), p.ImageName);
file.SaveAs(path);
}
return RedirectToAction("Index");
}

else
{
return View(p);
}

2. Add a new folder named Upload under the Content Folder


3. Change the following configuration <httpRuntime targetFramework="4.5" /> in
the Web.config file to increase the maximum upload file size from 80KB to
10MB
<httpRuntime targetFramework="4.5" executionTimeout="3600"
maxRequestLength="102400"
appRequestQueueLimit="100" requestValidationMode="2.0"
requestLengthDiskThreshold="10024000"/>

Step 6 : ValidateBiological view Coding


1. Right click on the ValidateBiological action name and choose add
View

2. Generate a view for the product details.

3.

Modify the generated view as the folowing :


Get the isNew boolean value from the TempData Dictionary
Display a big title if its a new product or a small one
Add a validation action link and a cancel action link

@model MyFinance.Domain.Entities.Biological
@{
ViewBag.Title = "ValidateBiological";
bool? isNew = Convert.ToBoolean(TempData["isNew"]);

}
<h2>Validate Biological</h2>
<div>
@if (isNew == true)
{
<h1>New Biological Product !!</h1>
}
else
{
<h4>Biological Product !!</h4>
}
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.Description)
</dt>
<dd>
@Html.DisplayFor(model => model.Description)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Name)
</dt>
<dd>
@Html.DisplayFor(model => model.Name)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Price)
</dt>
<dd>
@Html.DisplayFor(model => model.Price)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Quantity)
</dt>
<dd>
@Html.DisplayFor(model => model.Quantity)
</dd>
<dt>
@Html.DisplayNameFor(model => model.ImageName)
</dt>
<dd>
@Html.DisplayFor(model => model.ImageName)
</dd>
<dt>
@Html.DisplayNameFor(model => model.DateProd)
</dt>
<dd>
@Html.DisplayFor(model => model.DateProd)
</dd>

<dt>
@Html.DisplayNameFor(model => model.CategoryId)
</dt>
<dd>
@Html.DisplayFor(model => model.CategoryId)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Herbs)
</dt>
<dd>
@Html.DisplayFor(model => model.Herbs)
</dd>
</dl>
</div>
<p>
@Html.ActionLink("Confirmation", "ValidateBiological", new { insertion = true }) |
@Html.ActionLink("Cancel", "Index")
</p>

Step 7 : Run and Test


Run the application, insert some products and check the database.

Step 8 : Chemical product insertion


Repete the same steps for chemical product insertion.

Part 10 Product Index


Step 1 : Index action coding
1- Implement the ProductController Index action to return a View with the list
of products.
public ActionResult Index()
{
var products = service.GetProducts();
return View(products);

Step 2 -

Creating the Index View


In this task, you will create the Index View template to display the list of products returned by
the Product Controller.
1.

Right-click inside the Index action method and select Add View. This will bring up
the Add View dialog.

Step 3 - Customizing the scaffold of the Index View


In this task, you will adjust the simple View template created with ASP.NET MVC scaffolding
feature to have it display the fields you want.
Note: The scaffolding support within ASP.NET MVC generates a simple View template
which lists all fields in the Product model. Scaffolding provides a quick way to get started on
a strongly typed view: rather than having to write the View template manually, scaffolding
quickly generates a default template and then you can modify the generated code.

1.

Review the code created. The generated list of fields will be part of the following
HTML table that Scaffolding is using for displaying tabular data.

2.

Replace the code under the title <h2>Index</h2> by the next code

@model IEnumerable<MyFinance.Domain.Entities.Product>
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
@using (Html.BeginForm())
{
<table>
<tr>
<td>
<div>
Search by category: @Html.TextBox("categoryName")
</div>
</td>
<td>
<input type="submit" value="Search" id="submit" />
</td>
<td>
@ViewBag.Message
</td>
</tr>
</table>
}
<div id="divExpenseList">
<p>
@Html.ActionLink("Create New", "CreateBiological")
</p>
</div>

-We use
the Razor
View
Engine
and
HTML
helpers
to
generate
HTM
tags. For
example
the
@Html.Te
xtBox("ca
tegoryNam
e ")

Helper
will
generate
the next
tag:
<input
id='categ
oryName'

name='categoryName' />
-Note: To understand Razor, you can view this blog
http://weblogs.asp.net/scottgu/archive/2010/07/02/introducing-razor.aspx.
And this blog for HTML Helper
http://www.mikesdotnetting.com/Article/184/HTML-Helpers-For-Forms-In-RazorWeb-Pages

-Back to the code this view, the Html.BeginForm() Helper will generate a form
which will send the data by default to the current action Index located in the
ProductController.

-The Form contain the buttom <input type="submit" value="Search" id="submit"


/> which send the data extracted from the TextBox to the action Index.

-In fact when a form send data to the controller, we need another version of the
current action. In our case the Index action. To make the difference between the
two actions named Index, the second version which retrieve data from the view

will be decorated by the attribute [HttpPost], the first action will use by default
the Get mode.

[HttpPost]

-Before

public ActionResult Index(string categoryName)


{
}

implementing this action, we will continue with our View. The next Helper
@Html.ActionLink("Create New", "CreateBiological") will generate an
Hyperlink.It should redirect to The CreateBiological action.
-Before moving to the controller, we notice that this view lacks the display part,
where we display the list of products retrieved from the database.
- Step 4 Working with Partial View
- A partial view is used when you have some view component that is used in
more than one place, or is better separated in to a separate file (for readability,
for example).
-In our case, instead of displaying the list of products in this view, we will create a
partial view where we will display the description, the price and the image of a
product. Then,in the Index view we will display this partial view as well as we
have products.
-Lets add our partial view, Right click on the Product folder located in Views
folder, then Add View:

Lets add the next code:


@{string path = "~/Content/Upload/" + @Model.ImageName;}
<div style="float:left; margin:5px;">
<p>@Model.Name</p>
<img alt="Produit" src="@Url.Content(path)" width="50" height="50" />
<p>@Model.Description</p>
<p>@Model.Price</p>
<p>@Html.ActionLink("Details", "Details", new { id = Model.ProductId })</p>
<p>@Html.ActionLink("Edit", "Edit", new { id = Model.ProductId })</p>
</div>

-This partial view is strongly typed. First we create a string field where we store
the hole path of the image. Then we display the imge using
@Url.Content(path) Helper which converts a virtual (relative) path to an
application absolute path

-The Model object contain the Product object passed from the Controller.
-The >@Html.ActionLink("Details", "Details",new { id = Model.ProductId }) will
generate an HyperLink which redirect to the Details action. This tag will send
the value of the ProductId of the current product object to the Details action.
Lets adding a custom Helper.
- Step 5 Adding an HTML Helper
-

The Desription properties can be long. In this step you will learn how to
add a custom HTML helper to truncate that text.

In this task, you will add a new method Truncate to the HTML object
exposed within ASP.NET MVC Views. To do this, you will implement an
extension method to the built-in System.Web.Mvc.HtmlHelper class
provided by ASP.NET MVC.
Add the following code below the @model directive to define
the Truncate helper method.

@helper Truncate(string input, int length)


{
if (input.Length <= length)
{
@input
}
else
{
@input.Substring(0, length)<text>...</text>
}
}

Replace the lines that show the Product Description .


<p>@Model.Description</p> by the following line

<p>@Truncate(Model.Description, 25)</p>

- Step 6 Calling the partial view


-Backing to the Index View. Now we will call the partial view to show the list
of products from the database.
-Add the next code to the Index View.
<div style="display:block;">
@if (Model != null)
{
foreach (var item in Model)
{
@Html.Partial("_DisplayProduct", item)
}
}
</div>

-After finishing the Index View, we move to the ProductController to


implement the second version of the Index action.

Step 7 Implementing the HTTP-POST Index action method


-After implementing the HTTP-GET Index Action Method, we will implement now the HTTPPOST version.
-Add the next code in the ProductController.

public ActionResult Index(string categoryName)


{
try
{
var products = service.GetProductsByCategory(categoryName);
return View(products);
}
catch (Exception)
{
ViewBag.Message = "The category doesn't exist";
return View();
}

-This action
retrieve a
string which
present the
category
chosen by the
user from the
view. Then
retrieve the
list of
products by
category, and

return the lists of products to the view.


-In case of exception, we use the ViewBag which present a dynamic property
and can store data and pass it from controller to view.

Step 8 : Run and Test

Part 11 Product Update


Step 1 Get Edit Action
Modify the Get edit Action as the following:
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Biological p = service.GetBiologicol(id.Value);
if (p == null)
{
return HttpNotFound();
}
return View(p);
}

Step 2 Scaffold the view


Right click on the Edit action name and add a view with Edit Template for a biological product :

Step 3 Post edit Action


Modify the Post edit Action as the following:
[HttpPost]
public ActionResult Edit(Biological bio)
{
if (ModelState.IsValid)
{
service.UpdateProduct(bio);
return RedirectToAction("Index");
}
return View(bio);
}

Step 7 : Run and Test

Part 12 Dependecy Injection


DI is a software design pattern that allow us to develop loosely coupled code. DI is a great
way to reduce tight coupling between software components. DI also enables us to better
manage future changes and other complexity in our software. The purpose of DI is to make
code maintainable.
The Dependency Injection pattern uses a builder object to initialize objects and provide
the required dependencies to the object means it allows you to "inject" a dependency from
outside the class.
-Dependency Injection means that objects do not create other objects on which they rely to
do their work. Instead, they get the objects that they need from an outside source

-At a high level, the goal of Dependency Injection is that a client class (e.g. the golfer) needs
something that satisfies an interface (e.g. IClub). It doesn't care what the concrete type is
(e.g. WoodClub, IronClub, WedgeClub or PutterClub), it wants someone else to handle that
(e.g. a goodcaddy). The Dependency Resolver in ASP.NET MVC can allow you to register
your dependency logic somewhere else (e.g. a container or a bag of clubs).

The advantages of using Dependency Injection pattern and Inversion of Control


are the following:

Reduces class coupling

Increases code reusing

Improves code maintainability

Improves application testing

What is DI Container
A DI Container is a framework to create dependencies and inject them automatically
when required. It automatically creates objects based on request and inject them when
required. DI Container helps us to manage dependencies with in the application in a simple
and easy way.

We can also manage an application dependencies without a DI Container, but it will be like
as POOR MANS DI and we have to do more work, to make it configured and
manageable.

List of popular DI Container for .Net


Today, there are a lot of excellent DI Containers that are available for .NET. Here, the list of
most useful DI Container for .Net framework.
-Castle Windsor
-Spring.NET
-Autofac
-StructureMap
-Unity
-Ninject

-We will use Unity, the Dependency Injection of Microsft.

Step 1: Injecting a Constructor


-Abore all projects in our solution we use constructor to inject abstract
objects, for example in the ProductController we pass the ProductService and
the CategoryService in constructor. So we are not obliged to instanciate classes
existing in other projet which can make ours projects high coupleds.
IEBuyService service = null;
public ProductsController(IEBuyService service)
{
this.service = service;
}

Step 2: Including Unity into MvcFinance Solution


In this task, you will include Unity bootstrapper for ASP.NET MVC NuGet
Package to the solution.
Note: Unity is a lightweight, extensible dependency injection container with
optional support for instance and type interception. It is a general-purpose
container for use in any type of .NET application. It provides all the
common features found in dependency injection mechanisms including:
object creation, abstraction of requirements by specifying dependencies at
runtime and flexibility, by deferring the component configuration to the
container.

-Install Unity bootstrapper for ASP.NET MVC NuGet Package in


the MyFinance.Web project. Righ Click on the projet -> Manage NuGet
Packages:

Step 3 - Registering Types in Unity container


Open the Unityconfig class in the App-Start folder in the MyFinance.Web
Project and add this code in the RegisterTypes method.
container.RegisterType<IEBuyService, EBuyService>( new PerRequestLifetimeManager());
container.RegisterType<IUnitOfWork, UnitOfWork>( new PerRequestLifetimeManager());
container.RegisterType<ICategoryRepository, CategoryRepository>( new
PerRequestLifetimeManager());
container.RegisterType<IProviderRepository, ProviderRepository>( new
PerRequestLifetimeManager());
container.RegisterType<IProductRepository, ProductRepository>( new
PerRequestLifetimeManager());
container.RegisterType<IDatabaseFactory, DatabaseFactory>( new
PerRequestLifetimeManager());

Step 4 - Running the Application


In this task, you will run the application to verify that it can now be loaded after including
Unity

You might also like