(译文)MVC通用仓储类

Generic Repository Pattern MVC

Generic Repository Pattern MVC

原文链接:http://www.codeproject.com/Articles/1095323/Generic-Repository-Pattern-MVC

良好的架构师任何项目的核心,开发人员一直在寻找一个牛X的架构,它能减少重复代码,分离数据访问与业务逻辑。因此,我们需要在MVC中使用EF创建一个泛型仓储类。如果不了解EF,去这里学习。在开始之前,我们需要了解什么是仓储模式,为什么使用仓储模式。

仓储模式和工作单元

简言之,仓储模式意味着,数据访问层与业务逻辑层之间的抽象,这是非常有利于单元测试或TDD。通过使用仓储模式,你的系统会更加松散耦合。

在开发过程中,我们通常为每个仓储或实体创建一个接口。例如,我们为Student这个实体创建一个接口约束(IStudentInterface),定义所有的CRUD操作,同时创建另一个类(StudentRepository)实现接口中所定义的所有方法。当我们在控制器中实例化仓储类的时候,我们将使用实现了对应接口的类的引用。当控制器在运行的时候,它将调用在EF基础上工作的仓储类。

当对控制器进行单元测试的时候,我们可以操作仓储类的具体数据实现,例如内存数据集。这样我们可以使用伪数据进行单元测试。

如果你想了解详细的实现,可以参照如下链接:

getting started with ef 5 using mvc 4 / implementing the repository and unit of work patterns in an asp.net mvc application

不利因素

每次我们都需要为实体创建仓储类,导致代码冗余

代码实现

现在我们仅仅需要一个数据访问类,介绍一些实体和执行必要的操作,例如CRUD.在学习了很多文章、理论和示例代码后,我获得了一个很好的通用的仓储模式的实现。

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

entity-framework-4-poco-repository-and-specification-pattern

entity-framework-poco-repository-and-specification-pattern-upgraded-to-ef-5

我修改了很多实现代码同时添加了一些在项目中常用的代码实现。现在我能使用这个类库在任何项目。下面是文件结构:

Mayur.DAL – 通用仓储和公共方法类库

 

  • Core – 文件夹

    • GlobalCommonHelper.cs – 一个为每个项目提供大部分公共方法的抽象类
  • Repository – 文件夹

    • IRepository.cs – 通用仓储接口
    • Repository.cs – 通用仓储实现类,继承与仓储接口
    • IUnitOfWork.cs – 工作单元接口.
    • UnitOfWork.cs – 实现了EF的SaveChanges()方法。工作单元类保证我们在对数据库执行事务性的插入、更新、删除操作时,直到我们执行Savechanges()方法以后EF才会提交所做的修改。

 

Mayur.Web – MVC Web项目

 

  • Controller – 文件夹

    • HomeController.cs – 包含CRUD动作的控制器
  • Core – 文件夹

    • CommonHelper.cs – 继承于 Mayur.DAL.Core.GlobalCommonHelper.cs which 包含MVC项目中相关的公共方法。
  • Model – 文件夹

    • Student.cs – 实体类
  • Views – Folder

    • Index.chtml – 不用说了吧都
    • Create.chtml – Create new student html
    • Edit.cshtml – Update student info html
    • Delete.cshtml – Delete student info html

 

让我们简单了解下DAL中每个文件的作用:

Repository 文件夹: 在这个文件夹,包含所有的数据访问逻辑。有4个文件, 2个接口文件,两个接口的实现类

 

1. IRepository 接口

2. Repository Class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
/// <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

1
2
3
4
public interface IUnitOfWork : IDisposable
{
    void SaveChanges();
}

4. UnitOfWork Class

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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文件夹中,还有一个抽象类,包含了一些项目中常用到的公共方法,如果你也有一些新的方法函数是我们在项目中需要的,请在评论中提出建议(原文这么说的,在我这评论我也不介意)。

5. Mayur.DAL.Core.GlobalCommonHelper.cs Class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
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
  
    }

现在通用仓储已经具备了公共的方法,现在来看下我们怎么在控制器中使用它。假设我们有一个Student实体,包含studentID, name, rollNo 等列,下面是控制器中的代码

1. 在继续之前,我们需要先完善数据上下文信息,以生成数据库和数据表 ,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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. 我在数据访问层创建了一个抽象的包含了每个项目中都要使用的公共方法的类。因为是一个抽象类,这意味着我们为它创建实例。所以我们需要创建一个新的类在Web项目中,这个类继承于GlobalCommonHelper类,命名为CommonHelper,我们可以在这个类中实现一些项目独有的公共方法。

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

3. 现在我们可以看下如何在我们的控制器中使用仓储类,看控制器中的代码:

1
2
3
4
5
6
//Constructor
public HomeController()
{
      IRepository repository = new Repository(new MyFirstDbContex);
      CommonHelper helper = new CommonHelper();
}

  

   1:  public class BooksController : Controller
   2:      {
   3:          private IRepository repository;
   4:          private CommonHelper helper;
   5:   
   6:          public BooksController()
   7:          {
   8:              repository=new Repository(new MyFirstDbContext());
   9:              helper=new CommonHelper();
  10:          }
  11:   
  12:          // GET: Books
  13:          public ActionResult Index()
  14:          {
  15:              var list = repository.GetAll<Book>();
  16:              return View(list);
  17:          }
  18:   
  19:          // GET: Books/Details/5
  20:          public ActionResult Details(int id=0)
  21:          {
  22:              if (id == 0)
  23:              {
  24:                  return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
  25:              }
  26:   
  27:              Book book = repository.FindOne<Book>(b => b.Id == id);
  28:              if (book == null)
  29:              {
  30:                  return HttpNotFound();
  31:              }
  32:              return View(book);
  33:          }
  34:   
  35:          // GET: Books/Create
  36:          public ActionResult Create()
  37:          {
  38:              return View();
  39:          }
  40:   
  41:          // POST: Books/Create
  42:          // 为了防止“过多发布”攻击,请启用要绑定到的特定属性,有关 
  43:          // 详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkId=317598。
  44:          [HttpPost]
  45:          [ValidateAntiForgeryToken]
  46:          public ActionResult Create([Bind(Include = "Id,Cover,BookName,Author,TranslatedName,Translator,Publisher,WordCount,Pages,ISBN,Price,SalePrice,PublicationDate,Introduction,AboutTheAuthors,Link")] Book book)
  47:          {
  48:              if (ModelState.IsValid)
  49:              {
  50:                  repository.Add(book);
  51:                  repository.UnitOfWork.SaveChanges();
  52:                  
  53:                  return RedirectToAction("Index");
  54:              }
  55:   
  56:              return View(book);
  57:          }
  58:   
  59:          // GET: Books/Edit/5
  60:          public ActionResult Edit(int id=0)
  61:          {
  62:              if (id == 0)
  63:              {
  64:                  return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
  65:              }
  66:              Book book = repository.FindOne<Book>(x => x.Id == id);
  67:              if (book == null)
  68:              {
  69:                  return HttpNotFound();
  70:              }
  71:              return View(book);
  72:          }
  73:   
  74:          // POST: Books/Edit/5
  75:          // 为了防止“过多发布”攻击,请启用要绑定到的特定属性,有关 
  76:          // 详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkId=317598。
  77:          [HttpPost]
  78:          [ValidateAntiForgeryToken]
  79:          public ActionResult Edit([Bind(Include = "Id,Cover,BookName,Author,TranslatedName,Translator,Publisher,WordCount,Pages,ISBN,Price,SalePrice,PublicationDate,Introduction,AboutTheAuthors,Link")] Book book)
  80:          {
  81:              if (ModelState.IsValid)
  82:              {
  83:                  repository.Update<Book>(book);
  84:                  repository.UnitOfWork.SaveChanges();
  85:                  //db.Entry(book).State = EntityState.Modified;
  86:                  //db.SaveChanges();
  87:                  return RedirectToAction("Index");
  88:              }
  89:              return View(book);
  90:          }
  91:   
  92:          // GET: Books/Delete/5
  93:          public ActionResult Delete(int id=0)
  94:          {
  95:              if (id == 0)
  96:              {
  97:                  return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
  98:              }
  99:              Book book = repository.FindOne<Book>(b => b.Id == id);
 100:              if (book == null)
 101:              {
 102:                  return HttpNotFound();
 103:              }
 104:              return View(book);
 105:          }
 106:   
 107:          // POST: Books/Delete/5
 108:          [HttpPost, ActionName("Delete")]
 109:          [ValidateAntiForgeryToken]
 110:          public ActionResult DeleteConfirmed(int id)
 111:          {
 112:              Book book = repository.FindOne<Book>(b => b.Id == id);
 113:              if (book == null)
 114:              {
 115:                  return HttpNotFound();
 116:              }
 117:              repository.Delete<Book>(book);
 118:              repository.UnitOfWork.SaveChanges();
 119:              //db.Books.Remove(book);
 120:              //db.SaveChanges();
 121:              return RedirectToAction("Index");
 122:          }
 123:        
 124:      }

我需要更多来自你的建议和改进,请提给我吧。(原作)

译注

正好在学习仓储模式和工作单元,想整理一个通用的仓储类,作者的做参考。

英语不好有些翻译很生硬,还有的直接表意,省掉了作者一些话(他们写文章都很认真,像教小学生一样敦敦教诲)

版本

•31/05/2015: Article published

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

转载自:http://www.cnblogs.com/wit13142/p/5435368.html

posted @   青葱老王  阅读(1197)  评论(1编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
点击右上角即可分享
微信分享提示