65.9K
CodeProject 正在变化。 阅读更多。
Home

通用仓库模式 MVC

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.79/5 (11投票s)

2016年4月23日

CPOL

4分钟阅读

viewsIcon

52291

通用仓库模式 MVC

良好的架构是任何项目的核心。开发人员一直在寻找能够减少重复代码并分离数据访问和业务逻辑的优秀架构。因此,我们将使用 ASP.NET MVC 和 Entity Framework 来创建我们的通用存储库。如果您不了解 Entity Framework,请 点击此处 了解 Entity Framework。因此,在开始存储库模式之前,我们首先需要了解什么是存储库模式?为什么我们需要它?

存储库和单元工作模式

简单来说,存储库意味着您的数据访问和业务逻辑层之间的抽象,这对于单元测试或测试驱动开发 (TDD) 将非常有用。通过使用存储库,您的系统将更加松耦合。

在编程术语中,我们需要为每个存储库或实体创建一个接口。例如,Student 实体有一个接口 (IStudentInterface),其中声明了所有方法,如 InsertUpdateDeleteGet,另一个是继承自 IStudentInterface 的类 (StudentRepository),StudentRepository 将实现接口中声明的所有方法。当我们在控制器中实例化存储库时,我们将使用接口,这样控制器就可以接受实现存储库接口的任何对象的引用。当控制器在 Web 服务器下运行时,它会接收一个与 Entity Framework 一起工作的存储库。

当控制器在单元测试类下运行时,它会接收一个与存储在易于操作以进行测试的数据(例如内存集合)一起工作的存储库。因此,我们可以在单元测试中提供一个模拟存储库。

如果您想查看完整的实现,请参考以下链接

缺点

每次我们都要为每个实体创建存储库,这会导致代码冗余。

Using the Code

现在我们只需要一个数据访问类,它可以接受任何实体并执行所需的操作,例如 CRUD。在研究了大量文章、理论和示例代码后,我发现了一个非常好的通用存储库模式的参考。

我的代码很大程度上基于Huy Nguyen的博客。请参考以下链接

我更改了一些代码,并将其添加到新的类库项目中,同时添加了一些每个项目所需的通用函数。现在我可以在任何项目中使用这个库。以下是文件夹结构。

Mayur.DAL – 包含通用存储库和通用函数的类库项目。

  • Core – 文件夹
    • GlobalCommonHelper.cs – 一个abstract类,其中包含每个项目所需的所有通用函数
  • Repository – 文件夹
    • IRepository.cs – 通用存储库的接口
    • Repository.cs – 继承自IRepository的通用存储库类。所有方法都在其中实现。
    • IUnitOfWork.cs – 单元工作类的接口。
    • UnitOfWork.cs – 为 Entity Framework 实现SaveChanges()方法。当执行任何事务性数据库命令(如InsertUpdateDelete)时,单元工作类非常重要,在调用Savechanges()方法之前,实体框架不会提交到数据库。

Mayur.Web – MVC 项目

  • Controller – 文件夹
    • HomeController.cs – Home控制器,包含IndexCreateEditDelete ActionResult
  • Core – 文件夹
    • CommonHelper.cs – 继承自Mayur.DAL.Core.GlobalCommonHelper.cs,包含所有与 MVC 项目相关的通用方法
  • Model – 文件夹
    • Student.csStudent Model,代表student
  • Views – 文件夹
    • Index.chtml – 显示所有学生信息的 HTML
    • Create.chtml – 创建新学生信息的 HTML
    • Edit.cshtml – 更新学生信息的 HTML
    • Delete.cshtml – 删除学生信息的 HTML

让我们简要了解一下Mayur.DAL中的每个文件

Repository 文件夹:此文件夹包含所有数据访问逻辑。有 4 个文件,2 个是接口,2 个是继承自相应接口的类。

1. IRepository 接口
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 类
   /// <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 接口
public interface IUnitOfWork : IDisposable
{
    void SaveChanges();
}
4. UnitOfWork 类
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        
    }

现在,在Mayur.DAL.Core文件夹中,有一个abstract类,其中包含每个项目所需的**所有**通用函数。如果您有任何需要在每个项目中都需要的**新**函数,请在评论中提出。

5. Mayur.DAL.Core.GlobalCommonHelper.cs 类
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
 
    }

现在我们的通用存储库已准备好,并内置了通用函数。现在我们可以看到如何在控制器中使用它们。假设我们有一个Students模型,其中包含studentIDnamerollNo列。以下是HomeController的代码。

  1. 在我们继续之前,我们正在使用 code-first 方法,以下是我们的DbContext
    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. 我们在数据访问层中创建了一个abstract类,其中包含全局通用函数,意味着几乎每个项目都需要该函数。该类是abstract类,因此我们无法创建其实例。所以我们在 Web 项目中创建了新的CommonHelper.cs类,它继承自Abstract类,我们可以在这里实现项目特定的通用函数。
    public class CommonHelper : GlobalCommonHelper
    {
         public int PageSize = 25;
         //Some common functions. Only Project-specific.     
    }
  3. 现在我们可以看到如何在HomeController中使用存储库。HomeController如下
    //Constructor
    public HomeController()
    {
          IRepository repository = new Repository(new MyFirstDbContex);
          CommonHelper helper = new CommonHelper();
    }
    1. Index.cshtml 以表格形式显示所有Students。所以 ActionResult 如下
      public ActionResult Index()
      {
            return View(repository.GetAll<Students>());
      }
    2. Create.cshtml 创建新的Students记录,这意味着它在数据库中插入新记录。
      public ActionResult Create()
      {
            return View();
      }
       
      [HttpPost]
      public ActionResult Create(Students studPost)
      {
           if(ModelState.IsValid)
           {
                repository.Add<Students>(studPost);
                repository.UnitOfWork.SaveChanges();
           }
      }
    3. Edit.cshtml 表示编辑视图,我们可以在其中修改记录。
      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();
           }
      }
    4. 最后一个是Delete,如下
      [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();
      }

我需要您更多的建议和改进。请评论。

修订

  • 31/05/2015:文章发布
  • 30/04/2016:根据 "Irene Troupansky" 的建议,更新了文章,修复了一些构造函数错误。

© . All rights reserved.