The good architecture is at the heart of any project. The developer is always looking for great architecture that reduces repetitive code and separates the Data Access and Business Logic. So we will be creating our generic repository using ASP.NET MVC and Entity Framework. If you don’t know about Entity Framework, please click here to get started with Entity Framework. So before getting started with repository pattern, firstly we have to understand what is the repository pattern? and why we want it?
In simple words, repository means, the abstraction between your Data Access and Business Logic layers which will very useful for unit testing or test-driven development (TDD). By using repository, your system will be more loosely coupled.
In programming terms, we have to create one interface for each repository or entity. e.g.
When the controller runs under a unit test class, it receives a repository that works with data stored in a way that you can easily manipulate for testing, such as an in-memory collection. So we can supply fake repository in unit testing.
If you want to see the complete implementation, please refer to the following link:
Each time we have to create Repository for each entity, it results in redundant code.
Now we need only a data access class which accepts any entity and performs required operation, e.g. CRUD. After studying lots of articles, theories and sample code, I got one very good reference of Generic Repository Pattern.
My code is heavily based on the Huy Nguyen’s Blog. Please refer to the following links:
I have changed a bit of code and added to new class library project as well as I added some common function which required to each project. Now I can use this library in any project. Following is the folder structure.
Lets understand briefly each file in Mayur.DAL:
Repository Folder: In this folder, all the Data Access logic is present. There are 4 files, 2 are Interfaces and 2 are classes which inherited from respective Interface.
Now in Mayur.DAL.Core folder, there is one
Now our Generic repository is ready with inbuilt common functions. Now we can see how to use them in controller. Suppose we have
Repository and Unit of Work Pattern
In simple words, repository means, the abstraction between your Data Access and Business Logic layers which will very useful for unit testing or test-driven development (TDD). By using repository, your system will be more loosely coupled.
In programming terms, we have to create one interface for each repository or entity. e.g.
Student
entity has One interface (IStudentInterface
) in which all methods are declared like Insert
, Update
, Delete
, Get
and another is class (StudentRepository
) which is inherited from IStudentInterface
and StudentRepository
will implement all the methods which are declared in Interface. When we instantiate the repository in our controller, we will use the interface so that the controller will accept a reference to any object that implements the repository interface. When the controller runs under a web server, it receives a repository that works with the Entity Framework.When the controller runs under a unit test class, it receives a repository that works with data stored in a way that you can easily manipulate for testing, such as an in-memory collection. So we can supply fake repository in unit testing.
If you want to see the complete implementation, please refer to the following link:
Disadvantage
Each time we have to create Repository for each entity, it results in redundant code.
Using the Code
Now we need only a data access class which accepts any entity and performs required operation, e.g. CRUD. After studying lots of articles, theories and sample code, I got one very good reference of Generic Repository Pattern.
My code is heavily based on the Huy Nguyen’s Blog. Please refer to the following links:
- https://huyrua.wordpress.com/2010/07/13/entity-framework-4-poco-repository-and-specification-pattern/
- https://huyrua.wordpress.com/2012/09/16/entity-framework-poco-repository-and-specification-pattern-upgraded-to-ef-5/
I have changed a bit of code and added to new class library project as well as I added some common function which required to each project. Now I can use this library in any project. Following is the folder structure.
Mayur.DAL
– Class library project with generic repository and common functions.- Core – Folder
- GlobalCommonHelper.cs – An
abstract
class which contents all common function required to each project
- GlobalCommonHelper.cs – An
- Repository – Folder
- IRepository.cs – Interface for generic repository
- Repository.cs – Generic repository class inherited from
IRepository
. All methods are implemented in it. - IUnitOfWork.cs – Interface for unit of work class.
- UnitOfWork.cs – Implemented
SaveChanges()
methods for Entity Framework . The unit of work class is very important when we execute any transitional command to the database likeInsert
,Update
,Delete
the entity framework not commit to database untilSavechanges()
method calls.
Mayur.Web
– MVC project- Controller – Folder
- HomeController.cs – Home controller with
Index
,Create
,Edit
,Delete ActionResult
- HomeController.cs – Home controller with
- Core – Folder
- CommonHelper.cs – Inherited from Mayur.DAL.Core.GlobalCommonHelper.cs which contents all common methods related to MVC project
- Model – Folder
- Student.cs –
Student Model
representingstudnet
table
- Student.cs –
- Views – Folder
- Index.chtml – Display All student html
- Create.chtml – Create new student html
- Edit.cshtml – Update student info html
- Delete.cshtml – Delete student info html
Lets understand briefly each file in Mayur.DAL:
Repository Folder: In this folder, all the Data Access logic is present. There are 4 files, 2 are Interfaces and 2 are classes which inherited from respective Interface.
1. IRepository Interface
public interface IRepository : IDisposable { /// <summary> /// Gets the unit of work. /// </summary> /// <value>The unit of work.</value> IUnitOfWork UnitOfWork { get; } /// <summary> /// Gets entity by key. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="keyValue">The key value.</param> /// <returns></returns> TEntity GetByKey<TEntity>(object keyValue) where TEntity : class; /// <summary> /// Gets the query. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <returns></returns> IQueryable<TEntity> GetQuery<TEntity>() where TEntity : class; /// <summary> /// Gets the query. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="predicate">The predicate.</param> /// <returns></returns> IQueryable<TEntity> GetQuery<TEntity> (Expression<Func<TEntity, bool>> predicate) where TEntity : class; /// <summary> /// Gets all. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <returns></returns> IEnumerable<TEntity> GetAll<TEntity>() where TEntity : class; /// <summary> /// Gets the specified order by. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <typeparam name="TOrderBy">The type of the order by.</typeparam> /// <param name="orderBy">The order by.</param> /// <param name="pageIndex">Index of the page.</param> /// <param name="pageSize">Size of the page.</param> /// <param name="sortOrder">The sort order.</param> /// <returns></returns> IEnumerable<TEntity> Get<TEntity, TOrderBy>(Expression<Func<TEntity, TOrderBy>> orderBy, int pageIndex, int pageSize, SortOrder sortOrder = SortOrder.Ascending) where TEntity : class; /// <summary> /// Gets the specified criteria. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <typeparam name="TOrderBy">The type of the order by.</typeparam> /// <param name="criteria">The criteria.</param> /// <param name="orderBy">The order by.</param> /// <param name="pageIndex">Index of the page.</param> /// <param name="pageSize">Size of the page.</param> /// <param name="sortOrder">The sort order.</param> /// <returns></returns> IEnumerable<TEntity> Get<TEntity, TOrderBy>(Expression<Func<TEntity, bool>> criteria, Expression<Func<TEntity, TOrderBy>> orderBy, int pageIndex, int pageSize, SortOrder sortOrder = SortOrder.Ascending) where TEntity : class; /// <summary> /// Gets one entity based on matching criteria /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="criteria">The criteria.</param> /// <returns></returns> TEntity Single<TEntity>(Expression<Func<TEntity, bool>> criteria) where TEntity : class; /// <summary> /// Firsts the specified predicate. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="predicate">The predicate.</param> /// <returns></returns> TEntity First<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : class; /// <summary> /// Finds entities based on provided criteria. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="criteria">The criteria.</param> /// <returns></returns> IEnumerable<TEntity> Find<TEntity> (Expression<Func<TEntity, bool>> criteria) where TEntity : class; /// <summary> /// Finds one entity based on provided criteria. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="criteria">The criteria.</param> /// <returns></returns> TEntity FindOne<TEntity>(Expression<Func<TEntity, bool>> criteria) where TEntity : class; /// <summary> /// Counts the specified entities. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <returns></returns> int Count<TEntity>() where TEntity : class; /// <summary> /// Counts entities with the specified criteria. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="criteria">The criteria.</param> /// <returns></returns> int Count<TEntity>(Expression<Func<TEntity, bool>> criteria) where TEntity : class; /// <summary> /// Adds the specified entity. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="entity">The entity.</param> void Add<TEntity>(TEntity entity) where TEntity : class; /// <summary> /// Attaches the specified entity. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="entity">The entity.</param> void Attach<TEntity>(TEntity entity) where TEntity : class; /// <summary> /// Updates changes of the existing entity. /// The caller must later call SaveChanges() /// on the repository explicitly to save the entity to database /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="entity">The entity.</param> void Update<TEntity>(TEntity entity) where TEntity : class; /// <summary> /// Deletes the specified entity. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="entity">The entity.</param> void Delete<TEntity>(TEntity entity) where TEntity : class; /// <summary> /// Deletes one or many entities matching the specified criteria /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="criteria">The criteria.</param> void Delete<TEntity>(Expression<Func<TEntity, bool>> criteria) where TEntity : class; /// <summary> /// Deletes entities which satisfy specificatiion /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="criteria">The criteria.</param> //void Delete<TEntity> (ISpecification<TEntity> criteria) where TEntity : class; }
2. Repository Class
/// <summary> /// Generic repository Class /// </summary> public partial class Repository : IRepository, IDisposable { //Private Variables private bool bDisposed; private DbContext context; private IUnitOfWork unitOfWork; #region Contructor Logic /// <summary> /// Initializes a new instance of the /// <see cref="Repository<TEntity>"/> class. /// </summary> public Repository() { } /// <summary> /// Initializes a new instance of the /// <see cref="Repository<TEntity>" /> class. /// </summary> /// <param name="context">The context.</param> public Repository(DbContext contextObj) { if (contextObj == null) throw new ArgumentNullException("context"); this.context = contextObj; } public Repository(ObjectContext contextObj) { if (contextObj == null) throw new ArgumentNullException("context"); context = new DbContext(contextObj, true); } public void Dispose() { Close(); } #endregion #region Properties //DbContext Property protected DbContext DbContext { get { if (context == null) throw new ArgumentNullException("context"); return context; } } //Unit of Work Property public IUnitOfWork UnitOfWork { get { if (unitOfWork == null) { unitOfWork = new UnitOfWork(DbContext); } return unitOfWork; } } #endregion #region Data Display Methods //Helper Method tp create Query [IQuerable] public TEntity GetByKey<TEntity>(object keyValue) where TEntity : class { EntityKey key = GetEntityKey<TEntity>(keyValue); object originalItem; if (((IObjectContextAdapter)DbContext). ObjectContext.TryGetObjectByKey(key, out originalItem)) { return (TEntity)originalItem; } return default(TEntity); } public IQueryable<TEntity> GetQuery<TEntity>() where TEntity : class { string entityName = GetEntityName<TEntity>(); return ((IObjectContextAdapter)DbContext). ObjectContext.CreateQuery<TEntity>(entityName); } public IQueryable<TEntity> GetQuery<TEntity> (Expression<Func<TEntity, bool>> predicate) where TEntity : class { return GetQuery<TEntity>().Where(predicate); } //All Readonly Display or fetch data methods. public IEnumerable<TEntity> GetAll<TEntity>() where TEntity : class { return GetQuery<TEntity>().AsEnumerable(); } public IEnumerable<TEntity> Get<TEntity, TOrderBy> (Expression<Func<TEntity, TOrderBy>> orderBy, int pageIndex, int pageSize, SortOrder sortOrder = SortOrder.Ascending) where TEntity : class { if (sortOrder == SortOrder.Ascending) { return GetQuery<TEntity>() .OrderBy(orderBy) .Skip((pageIndex - 1) * pageSize) .Take(pageSize) .AsEnumerable(); } return GetQuery<TEntity>() .OrderByDescending(orderBy) .Skip((pageIndex - 1) * pageSize) .Take(pageSize) .AsEnumerable(); } public IEnumerable<TEntity> Get<TEntity, TOrderBy>(Expression<Func<TEntity, bool>> criteria, Expression<Func<TEntity, TOrderBy>> orderBy, int pageIndex, int pageSize, SortOrder sortOrder = SortOrder.Ascending) where TEntity : class { if (sortOrder == SortOrder.Ascending) { return GetQuery(criteria). OrderBy(orderBy). Skip((pageIndex - 1) * pageSize). Take(pageSize) .AsEnumerable(); } return GetQuery(criteria) .OrderByDescending(orderBy) .Skip((pageIndex - 1) * pageSize) .Take(pageSize) .AsEnumerable(); } public TEntity Single<TEntity> (Expression<Func<TEntity, bool>> criteria) where TEntity : class { return GetQuery<TEntity>().Single<TEntity>(criteria); } public TEntity First<TEntity> (Expression<Func<TEntity, bool>> predicate) where TEntity : class { return GetQuery<TEntity>().First(predicate); } public IEnumerable<TEntity> Find<TEntity> (Expression<Func<TEntity, bool>> criteria) where TEntity : class { return GetQuery<TEntity>().Where(criteria); } public TEntity FindOne<TEntity> (Expression<Func<TEntity, bool>> criteria) where TEntity : class { return GetQuery<TEntity>().Where(criteria).FirstOrDefault(); } public int Count<TEntity>() where TEntity : class { return GetQuery<TEntity>().Count(); } public int Count<TEntity> (Expression<Func<TEntity, bool>> criteria) where TEntity : class { return GetQuery<TEntity>().Count(criteria); } #endregion #region Data Transactional Methods public void Add<TEntity>(TEntity entity) where TEntity : class { if (entity == null) { throw new ArgumentNullException("entity"); } DbContext.Set<TEntity>().Add(entity); } public void Attach<TEntity>(TEntity entity) where TEntity : class { if (entity == null) { throw new ArgumentNullException("entity"); } DbContext.Set<TEntity>().Attach(entity); } public void Update<TEntity>(TEntity entity) where TEntity : class { string fqen = GetEntityName<TEntity>(); object originalItem; EntityKey key = ((IObjectContextAdapter)DbContext).ObjectContext.CreateEntityKey(fqen, entity); if (((IObjectContextAdapter)DbContext).ObjectContext.TryGetObjectByKey (key, out originalItem)) { ((IObjectContextAdapter)DbContext).ObjectContext.ApplyCurrentValues (key.EntitySetName, entity); } } public void Delete<TEntity>(TEntity entity) where TEntity : class { if (entity == null) { throw new ArgumentNullException("entity"); } DbContext.Set<TEntity>().Remove(entity); } public void Delete<TEntity>(Expression<Func<TEntity, bool>> criteria) where TEntity : class { IEnumerable<TEntity> records = Find(criteria); foreach (TEntity record in records) { Delete(record); } } #endregion #region Internal Processing Private Methods private EntityKey GetEntityKey<TEntity>(object keyValue) where TEntity : class { string entitySetName = GetEntityName<TEntity>(); ObjectSet<TEntity> objectSet = ((IObjectContextAdapter)DbContext).ObjectContext.CreateObjectSet<TEntity>(); string keyPropertyName = objectSet.EntitySet.ElementType.KeyMembers[0].ToString(); var entityKey = new EntityKey (entitySetName, new[] { new EntityKeyMember(keyPropertyName, keyValue) }); return entityKey; } private string GetEntityName<TEntity>() where TEntity : class { // Thanks to Kamyar Paykhan - // http://huyrua.wordpress.com/2011/04/13/ // entity-framework-4-poco-repository-and-specification-pattern-upgraded-to-ef-4-1/ // #comment-688 string entitySetName = ((IObjectContextAdapter)DbContext).ObjectContext .MetadataWorkspace .GetEntityContainer(((IObjectContextAdapter)DbContext). ObjectContext.DefaultContainerName, DataSpace.CSpace) .BaseEntitySets.Where(bes => bes.ElementType.Name == typeof(TEntity).Name).First().Name; return string.Format("{0}.{1}", ((IObjectContextAdapter)DbContext).ObjectContext.DefaultContainerName, entitySetName); } private string RemoveAccent(string txt) { byte[] bytes = System.Text.Encoding.GetEncoding("Cyrillic").GetBytes(txt); return System.Text.Encoding.ASCII.GetString(bytes); } private bool IsValidTag(string tag, string tags) { string[] allowedTags = tags.Split(','); if (tag.IndexOf("javascript") >= 0) return false; if (tag.IndexOf("vbscript") >= 0) return false; if (tag.IndexOf("onclick") >= 0) return false; var endchars = new char[] { ' ', '>', '/', '\t' }; int pos = tag.IndexOfAny(endchars, 1); if (pos > 0) tag = tag.Substring(0, pos); if (tag[0] == '/') tag = tag.Substring(1); foreach (string aTag in allowedTags) { if (tag == aTag) return true; } return false; } #endregion #region Disposing Methods protected void Dispose(bool bDisposing) { if (!bDisposed) { if (bDisposing) { if (null != context) { context.Dispose(); } } bDisposed = true; } } public void Close() { Dispose(true); GC.SuppressFinalize(this); } #endregion } }
3. IUnitOfWork Interface
public interface IUnitOfWork : IDisposable { void SaveChanges(); }
4. UnitOfWork Class
internal class UnitOfWork : IUnitOfWork { private readonly DbContext _dbContext; public UnitOfWork(DbContext context) { _dbContext = context; } public void SaveChanges() { ((IObjectContextAdapter)_dbContext).ObjectContext.SaveChanges(); } #region Implementation of IDisposable private bool _disposed; /// <summary> /// Performs application-defined tasks associated with freeing, /// releasing, or resetting unmanaged resources. /// </summary> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// <summary> /// Disposes off the managed and unmanaged resources used. /// </summary> /// <param name="disposing"></param> private void Dispose(bool disposing) { if (!disposing) return; if (_disposed) return; _disposed = true; } #endregion }
Now in Mayur.DAL.Core folder, there is one
abstract
class with all common functions required for each project. If you have any new functions which we required in each project, please suggest in the comments.5. Mayur.DAL.Core.GlobalCommonHelper.cs Class
abstract public class GlobalCommonHelper { #region General Methods /// <summary> /// Take any string and encrypt it using SHA1 then /// return the encrypted data /// </summary> /// <param name="data">input text you will enterd to encrypt it</param> /// <returns>return the encrypted text as hexadecimal string</returns> public string GetSHA1HashData(string data) { //create new instance of md5 SHA1 sha1 = SHA1.Create(); //convert the input text to array of bytes byte[] hashData = sha1.ComputeHash(Encoding.Default.GetBytes(data)); //create new instance of StringBuilder to save hashed data StringBuilder returnValue = new StringBuilder(); //loop for each byte and add it to StringBuilder for (int i = 0; i < hashData.Length; i++) { returnValue.Append(hashData[i].ToString()); } // return hexadecimal string return returnValue.ToString(); } /// <summary> /// Creates a slug url from string . /// </summary> /// <param name="phrase"></param> /// <returns></returns> public string GetSlugURLFromString(string phrase) { string str = RemoveAccent(phrase).ToLower(); // invalid chars str = Regex.Replace(str, @"[^a-z0-9\s-]", ""); // convert multiple spaces into one space str = Regex.Replace(str, @"\s+", " ").Trim(); // cut and trim str = str.Substring(0, str.Length <= 45 ? str.Length : 45).Trim(); str = Regex.Replace(str, @"\s", "-"); // hyphens return str; } /// <summary> /// Delete file by specified path. /// </summary> /// <param name="path">path of file.</param> public void DeleteTargetFile(string path) { if (File.Exists(path)) { File.SetAttributes(path, FileAttributes.Normal); File.Delete(path); } } /// <summary> /// Sent email to target email address with attachment. /// </summary> /// <param name="toEmail">Email addresses of /// one or multiple receipients semi colon (;) separated values.</param> /// <param name="subject">Email subject</param> /// <param name="body">Email body</param> /// <returns>True | False</returns> public bool SendEmailToTarget(string toEmail, string subject, string body) { bool success = false; try { SmtpClient SmtpServer = new SmtpClient(); MailMessage mail = new MailMessage(); SmtpServer.Credentials = new NetworkCredential( Convert.ToString(ConfigurationManager.AppSettings["fromEmail"]), Convert.ToString(ConfigurationManager.AppSettings["fromPassword"])); SmtpServer.Host = Convert.ToString (ConfigurationManager.AppSettings["hostName"]); SmtpServer.Port = Convert.ToInt32 (ConfigurationManager.AppSettings["portNumber"]); if (Convert.ToBoolean (ConfigurationManager.AppSettings["isEnableSSL"]) == true) SmtpServer.EnableSsl = true; mail.From = new MailAddress(Convert.ToString (ConfigurationManager.AppSettings["senderName"])); string[] multiEmails = toEmail.Split(';'); foreach (string email in multiEmails) { mail.To.Add(email); } mail.Subject = subject; mail.IsBodyHtml = true; mail.Body = body; SmtpServer.Send(mail); mail.Dispose(); success = true; } catch (Exception) { success = false; } return success; } /// <summary> /// Sent email to target email address with attachment. /// </summary> /// <param name="toEmail">Email addresses of /// one or multiple receipients semi colon (;) separated values.</param> /// <param name="subject">Email subject</param> /// <param name="body">Email body</param> /// <param name="body">Email attachment file path</param> /// <returns>True | False</returns> public bool SendEmailToTarget(string toEmail, string subject, string body, string attachmentPath) { bool success = false; try { SmtpClient SmtpServer = new SmtpClient(); MailMessage mail = new MailMessage(); SmtpServer.Credentials = new NetworkCredential( Convert.ToString(ConfigurationManager.AppSettings["fromEmail"]), Convert.ToString(ConfigurationManager.AppSettings["fromPassword"])); SmtpServer.Host = Convert.ToString (ConfigurationManager.AppSettings["hostName"]); SmtpServer.Port = Convert.ToInt32 (ConfigurationManager.AppSettings["portNumber"]); if (Convert.ToBoolean(ConfigurationManager.AppSettings["isEnableSSL"]) == true) SmtpServer.EnableSsl = true; mail.From = new MailAddress(Convert.ToString (ConfigurationManager.AppSettings["senderName"])); string[] multiEmails = toEmail.Split(';'); foreach (string email in multiEmails) { mail.To.Add(email); } Attachment attachment; attachment = new System.Net.Mail.Attachment(attachmentPath); mail.Attachments.Add(attachment); mail.Subject = subject; mail.IsBodyHtml = true; mail.Body = body; SmtpServer.Send(mail); mail.Dispose(); success = true; } catch (Exception) { success = false; } return success; } /// <summary> /// Strips tags /// </summary> /// <param name="text">Text</param> /// <returns>Formatted text</returns> public string RemoveHtmlFromString(string text) { if (String.IsNullOrEmpty(text)) return string.Empty; text = Regex.Replace(text, @"(>)(\r|\n)*(<)", "><"); text = Regex.Replace(text, "(<[^>]*>)([^<]*)", "$2"); text = Regex.Replace(text, "(&#x?[0-9]{2,4};|"|&| |<|>|€|©|®|‰|‡|†|‹| ›|„|”|“|‚|’|‘|—| –||||| | | |˜| ˆ|Ÿ|š|Š)", "@"); return text; } /// <summary> /// Verifies that a string is in valid e-mail format /// </summary> /// <param name="email">Email to verify</param> /// <returns>true if the string is a valid e-mail address and false if it's not</returns> public bool IsValidEmail(string email) { if (String.IsNullOrEmpty(email)) return false; email = email.Trim(); var result = Regex.IsMatch(email, "^(?:[\\w\\!\\#\\$\\%\\&\\ '\\*\\+\\-\\/\\=\\?\\^\\`\\{\\|\\}\\~]+\\.)*[\\w\\!\\#\\$\\%\\&\\ '\\*\\+\\-\\/\\=\\?\\^\\`\\{\\|\\}\\~]+@(?:(?:(?:[a-zA-Z0-9] (?:[a-zA-Z0-9\\-](?!\\.)){0,61}[a-zA-Z0-9]?\\.)+[a-zA-Z0-9] (?:[a-zA-Z0-9\\-](?!$)){0,61}[a-zA-Z0-9]?)|(?:\\[(?:(?:[01]?\\d{1,2}|2[0-4] \\d|25[0-5])\\.){3}(?:[01]?\\d{1,2}|2[0-4]\\d|25[0-5])\\]))$", RegexOptions.IgnoreCase); return result; } /// <summary> /// Returns Allowed HTML only. /// </summary> /// <param name="text">Text</param> /// <returns>Allowed HTML</returns> public string EnsureOnlyAllowedHtml(string text) { if (String.IsNullOrEmpty(text)) return string.Empty; const string allowedTags = "br,hr,b,i,u,a,div,ol,ul,li,blockquote,img,span,p,em," + "strong,font,pre,h1,h2,h3,h4,h5,h6,address,cite"; var m = Regex.Matches(text, "<.*?>", RegexOptions.IgnoreCase); for (int i = m.Count - 1; i >= 0; i--) { string tag = text.Substring(m[i].Index + 1, m[i].Length - 1).Trim().ToLower(); if (!IsValidTag(tag, allowedTags)) { text = text.Remove(m[i].Index, m[i].Length); } } return text; } #endregion #region Internal Processing Private Methods private string RemoveAccent(string txt) { byte[] bytes = System.Text.Encoding.GetEncoding("Cyrillic").GetBytes(txt); return System.Text.Encoding.ASCII.GetString(bytes); } private bool IsValidTag(string tag, string tags) { string[] allowedTags = tags.Split(','); if (tag.IndexOf("javascript") >= 0) return false; if (tag.IndexOf("vbscript") >= 0) return false; if (tag.IndexOf("onclick") >= 0) return false; var endchars = new char[] { ' ', '>', '/', '\t' }; int pos = tag.IndexOfAny(endchars, 1); if (pos > 0) tag = tag.Substring(0, pos); if (tag[0] == '/') tag = tag.Substring(1); foreach (string aTag in allowedTags) { if (tag == aTag) return true; } return false; } #endregion }
Now our Generic repository is ready with inbuilt common functions. Now we can see how to use them in controller. Suppose we have
Students
model in which studentID
, name
, rollNo
columns. Following is the code for HomeController
.- Before we proceed, we are using code first approach and following is our
DbContext
class:
public partial class MyFirstDbContext : DbContext { public MyFirstDbContext() : base("name=MyFirstDbContext") { Database.SetInitializer<MyFirstDbContext>(null); } public virtual DbSet<Students> Students { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { } }
- We have created an
abstract
class in out Data Access Layer which contains Global common function means almost in each project we required that function. The class is anabstract
class so we cannot create an instance of it . So we create new CommonHelper.cs Class in Our Web project which is inherited fromAbstract
class and we can implement project-specific common functions here.
public class CommonHelper : GlobalCommonHelper { public int PageSize = 25; //Some common functions. Only Project-specific. }
- Now we can see how we use repository in our
HomeController
. TheHomeController
is as follows:
//Constructor public HomeController() { IRepository repository = new Repository(new MyFirstDbContex); CommonHelper helper = new CommonHelper(); }
- Index.cshtml represents the view of all
Students
in table format. SoActionResult
is as follows:
public ActionResult Index() { return View(repository.GetAll<Students>()); }
- Create.cshtml creates new
Students
record means it inserts new record in db.
public ActionResult Create() { return View(); } [HttpPost] public ActionResult Create(Students studPost) { if(ModelState.IsValid) { repository.Add<Students>(studPost); repository.UnitOfWork.SaveChanges(); } }
- Edit.cshtml represents the edit view in which we can modify the records.
public ActionResult Edit(int id=0) { if(id==0) return HttpNotFound(); Students stud = repository.FindOne<Students>(x=>x.studentID == id); return View(stud); } [HttpPost] public ActionResult Edit(Students studPost) { if(ModelState.IsValid) { repository.Update<Students>(studPost); repository.UnitOfWork.SaveChanges(); } }
- And the last one is
Delete
as follows:
[HttpPost] public ActionResult Delete(int id=0) { if(id==0) return HttpNotFound(); Students stud = repository.FindOne<Students>(x=>x.studentID == id); if(stud == null) return HttpNotFound(); repository.Delete<Students>(stud); repository.UnitOfWork.SaveChanges(); }
- Index.cshtml represents the view of all
I need more suggestions and improvements from you. Please comment.
Revisions
- 31/05/2015: Article published
- 30/04/2016: Article Updated fixed some constructor error as per the "Irene Troupansky" Suggestions.
Comments
Post a Comment