Something To Code

All about programming and information security

Generic Repository Pattern MVC

The good Architecture is heart of any project. The developer 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?

Repository and Unit of work pattern
In simple word 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 term 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 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 complete implementation please refer following link
http://www.asp.net/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

Disadvantage:
Each time we have to create Repository for each entity so results in redundant code.

Using the code

Now we need only on data access class which accepts any entity and perform 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 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 change bit of code and added to new class library project as well as I added some common function which required to each project. Now this library I can use it to 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
— 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 like Insert, Update, Delete the entity framework not commit to database until Savechanges() method calls.

Mayur.Web – MVC project
— Controller – Folder
—— HomeController.cs – Home controller with Index, Create, Edit, Delete ActionResult
— 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 representing studnet table
— 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

1. 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 satify 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  Mayur.DAL.Core Folder there is one abstract class with all common function required for each project. If you have any new functions which we required in each project please suggest in the comment.

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 secolon (;) seperated 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 secolon (;) seperated values.</param>
        /// <param name="subject">Email subject</param>
        /// <param name="body">Email body</param>
        /// <param name="body">Email attachement 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.

1. 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)
    {
 
    }
}

2. We have created abstract class in out Data Access Layer which contains Global common function means almost in each project we required that functions. The class is abstract class so we can not create instance of it . So we create new CommonHelper.cs Class in Our Web project which is inherited from Abstract class and we can implement project-specific common functions here.

public class CommonHelper : GlobalCommonHelper
{
     public int PageSize = 25;
     //Some common functions. Only Project-specific.     
}

3. Now we can see how we use repository in our HomeController. The HomeController as follows

//Constructor
public HomeController()
{
      IRepository repository = new Repository(new MyFirstDbContex);
      CommonHelper helper = new CommonHelper();
}

3.1 Index.cshtml represent the view of all Students in table format. So ActionResult as follows.

public ActionResult Index()
{
      return View(repository.GetAll<Students>());
}

3.2 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();
     }
}

3.3 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 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();
}

I need More suggestion and improvement from you guys. Please comment.

Revisions:

31/05/2015  : Article published.

30/04/2016: Article Updated fixed some constructor error as per the "Irene Troupansky" Suggestions.
Link: http://www.codeproject.com/Articles/1095323/Generic-Repository-Pattern-MVC?msg=5239754#xx5239754xx

About Author

Author Mayur Lohite
Mayur Lohite

My name is Mayur Lohite. I am Programmer and Web Developer also I am Interested in Web Application Security and penetration testing. I have more than 4+ Years of experience in Microsoft Technologies such as C#, ASP.NET Webforms, ASP.NET MVC, Visual Basic, Entity Framework, SQL SERVER.

Loading