基于.Net Core3.1 MVC + EF Core的项目(一)框架的初步搭建
项目暂时分为六大块,结构如图所示
代码地址是 https://github.com/hudean/VacantCloud-
里面有许多没有完成,不过一些大致的内容都写的差不多了,权限认证依赖注入,支持多种数据库等等。
Vacant.EntityFrameWorkCore 暂时没有用到
一、Vacant.Entity 顾名思义主要是存放与数据库交互的实体类,这个项目库里面主要有一个Entitys文件夹存放实体类,还有实体类用到的2个抽象类和两个接口
1、首先是Entity类代码如下
1 using System; 2 using System.Collections.Generic; 3 using System.Reflection; 4 using System.Text; 5 6 namespace Vacant.Entitys 7 { 8 ///9 /// A shortcut of for most used primary key type ( ). 10 /// 11 [Serializable] 12 public abstract class Entity : Entity<long>, IEntity 13 { 14 15 } 16 17 18 /// 19 /// Basic implementation of IEntity interface. 20 /// An entity can inherit this class of directly implement to IEntity interface. 21 /// 22 /// Type of the primary key of the entity 23 [Serializable] 24 public abstract class Entity : IEntity 25 { 26 /// 27 /// Unique identifier for this entity. 28 /// 29 public virtual TPrimaryKey Id { get; set; } 30 31 /// 32 /// Checks if this entity is transient (it has not an Id). 33 /// 34 /// True, if this entity is transient 35 public virtual bool IsTransient() 36 { 37 if (EqualityComparer .Default.Equals(Id, default(TPrimaryKey))) 38 { 39 return true; 40 } 41 42 //Workaround for EF Core since it sets int/long to min value when attaching to dbcontext 43 if (typeof(TPrimaryKey) == typeof(int)) 44 { 45 return Convert.ToInt32(Id) <= 0; 46 } 47 48 if (typeof(TPrimaryKey) == typeof(long)) 49 { 50 return Convert.ToInt64(Id) <= 0; 51 } 52 53 return false; 54 } 55 56 /// 57 public virtual bool EntityEquals(object obj) 58 { 59 if (obj == null || !(obj is Entity )) 60 { 61 return false; 62 } 63 64 //Same instances must be considered as equal 65 if (ReferenceEquals(this, obj)) 66 { 67 return true; 68 } 69 70 //Transient objects are not considered as equal 71 var other = (Entity )obj; 72 if (IsTransient() && other.IsTransient()) 73 { 74 return false; 75 } 76 77 //Must have a IS-A relation of types or must be same type 78 var typeOfThis = GetType(); 79 var typeOfOther = other.GetType(); 80 if (!typeOfThis.GetTypeInfo().IsAssignableFrom(typeOfOther) && !typeOfOther.GetTypeInfo().IsAssignableFrom(typeOfThis)) 81 { 82 return false; 83 } 84 85 //if (this is IMayHaveTenant && other is IMayHaveTenant && 86 // this.As ().TenantId != other.As 87 //{ 88 // return false; 89 //} 90 91 //if (this is IMustHaveTenant && other is IMustHaveTenant && 92 // this.As().TenantId) ().TenantId != other.As 93 //{ 94 // return false; 95 //} 96 97 return Id.Equals(other.Id); 98 } 99 100 public override string ToString() 101 { 102 return $"[{GetType().Name} {Id}]"; 103 } 104 } 105 }().TenantId)
2、然后是EntityNotFoundException 类代码如下
1 using System; 2 using System.Collections.Generic; 3 using System.Runtime.Serialization; 4 using System.Text; 5 using Vancant.Comman; 6 7 namespace Vacant.Entitys 8 { 9 ///10 /// This exception is thrown if an entity excepted to be found but not found. 11 /// 12 [Serializable] 13 public class EntityNotFoundException : VacantException 14 { 15 /// 16 /// Type of the entity. 17 /// 18 public Type EntityType { get; set; } 19 20 /// 21 /// Id of the Entity. 22 /// 23 public object Id { get; set; } 24 25 /// 26 /// Creates a new object. 27 /// 28 public EntityNotFoundException() 29 { 30 31 } 32 33 /// 34 /// Creates a new object. 35 /// 36 public EntityNotFoundException(SerializationInfo serializationInfo, StreamingContext context) 37 : base(serializationInfo, context) 38 { 39 40 } 41 42 /// 43 /// Creates a new object. 44 /// 45 public EntityNotFoundException(Type entityType, object id) 46 : this(entityType, id, null) 47 { 48 49 } 50 51 /// 52 /// Creates a new object. 53 /// 54 public EntityNotFoundException(Type entityType, object id, Exception innerException) 55 : base($"There is no such an entity. Entity type: {entityType.FullName}, id: {id}", innerException) 56 { 57 EntityType = entityType; 58 Id = id; 59 } 60 61 /// 62 /// Creates a new object. 63 /// 64 /// Exception message 65 public EntityNotFoundException(string message) 66 : base(message) 67 { 68 69 } 70 71 /// 72 /// Creates a new object. 73 /// 74 /// Exception message 75 /// Inner exception 76 public EntityNotFoundException(string message, Exception innerException) 77 : base(message, innerException) 78 { 79 80 } 81 } 82 }
3、然后是接口 IEntityOfTPrimaryKey 代码如下
1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 5 namespace Vacant.Entitys 6 { 7 ///8 /// Defines interface for base entity type. All entities in the system must implement this interface. 9 /// 10 /// Type of the primary key of the entity 11 public interface IEntity 12 { 13 /// 14 /// Unique identifier for this entity. 15 /// 16 TPrimaryKey Id { get; set; } 17 18 /// 19 /// Checks if this entity is transient (not persisted to database and it has not an ). 20 /// 21 /// True, if this entity is transient 22 bool IsTransient(); 23 } 24 }
4、接口 IEntity 的代码如下
1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 5 namespace Vacant.Entitys 6 { 7 ///8 /// A shortcut of for most used primary key type ( ). 9 /// 10 public interface IEntity : IEntity<long> 11 { 12 13 } 14 }
二 、现在 实体类库大概完成了,现在开始建一个仓储类库,Vacant.Repositorys里面有三个文件夹分别是DbContexts 、IRepositorys、Repositorys
1、DbContexts文件夹是放数据库上下文类,添加引用 nuget安装包 Microsoft.EntityFrameworkCore.Design 、Microsoft.EntityFrameworkCore.SqlServer、Microsoft.EntityFrameworkCore.Tools;建一个类名为MSSqlEFDbContext的数据库上下文类
添加对实体类项目库Entity的引用
代码如下
1 using Microsoft.EntityFrameworkCore; 2 using System; 3 using System.Collections.Generic; 4 using System.Text; 5 6 namespace Vacant.Repositorys.DbContexts 7 { 8 public class MSSqlEFDbContext : DbContext 9 { 10 public MSSqlEFDbContext(DbContextOptionsoptions) : base(options) 11 { 12 13 } 14 15 protected override void OnModelCreating(ModelBuilder modelBuilder) 16 { 17 base.OnModelCreating(modelBuilder); 18 } 19 //protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 20 //{ 21 // base.OnConfiguring(optionsBuilder); 22 // //连接数据库-一般不用 23 // optionsBuilder.UseSqlServer(""); 24 //} 25 } 26 }
2、IRepositorys 是放仓存类的泛型接口,这样我们就不需要写三层里的dal层,代码如下
(1)先建一个接口IRepository
1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 5 namespace Vacant.Repositorys.IRepositorys 6 { 7 ///8 /// 仓储接口 9 /// 10 public interface IRepository 11 { 12 13 } 14 }
(3)再建 接口 IRepositoryOfTEntity
1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using Vacant.Entitys; 5 6 namespace Vacant.Repositorys.IRepositorys 7 { 8 ///9 /// A shortcut of for most used primary key type ( ). 10 /// 11 /// 实体类 12 public interface IRepository : IRepository long> where TEntity : class, IEntity<long> 13 { 14 15 } 16 }
(2)再建接口 IRepositoryOfTEntityAndTPrimaryKey
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Linq.Expressions; 5 using System.Text; 6 using System.Threading.Tasks; 7 using Vacant.Entitys; 8 9 namespace Vacant.Repositorys.IRepositorys 10 { 11 ///12 /// This interface is implemented by all repositories to ensure implementation of fixed methods. 13 /// 14 /// Main Entity type this repository works on 15 /// Primary key type of the entity 16 public interface IRepository : IRepository where TEntity : class, IEntity 17 { 18 #region Select/Get/Query 19 20 /// 21 /// Used to get a IQueryable that is used to retrieve entities from entire table. 22 /// 23 /// IQueryable to be used to select entities from database 24 IQueryable GetAll(); 25 26 /// 27 /// Used to get a IQueryable that is used to retrieve entities from entire table. 28 /// One or more 29 /// 30 /// A list of include expressions. 31 /// IQueryable to be used to select entities from database 32 IQueryable GetAllIncluding(params Expression object>>[] propertySelectors); 33 34 /// 35 /// Used to get all entities. 36 /// 37 /// List of all entities 38 List GetAllList(); 39 40 /// 41 /// Used to get all entities. 42 /// 43 /// List of all entities 44 Task > GetAllListAsync(); 45 46 ///
47 /// Used to get all entities based on given . 48 /// 49 /// A condition to filter entities 50 /// List of all entities 51 List GetAllList(Expression bool>> predicate); 52 53 /// 54 /// Used to get all entities based on given . 55 /// 56 /// A condition to filter entities 57 /// List of all entities 58 Task > GetAllListAsync(Expression
bool>> predicate); 59 60 /// 61 /// Used to run a query over entire entities. 62 /// attribute is not always necessary (as opposite to ) 63 /// if finishes IQueryable with ToList, FirstOrDefault etc.. 64 /// 65 /// Type of return value of this method 66 /// This method is used to query over entities 67 /// Query result 68 T Query (Func , T> queryMethod); 69 70 /// 71 /// Gets an entity with given primary key. 72 /// 73 /// Primary key of the entity to get 74 /// Entity 75 TEntity Get(TPrimaryKey id); 76 77 /// 78 /// Gets an entity with given primary key. 79 /// 80 /// Primary key of the entity to get 81 /// Entity 82 Task GetAsync(TPrimaryKey id); 83 84 /// 85 /// Gets exactly one entity with given predicate. 86 /// Throws exception if no entity or more than one entity. 87 /// 88 /// Entity 89 TEntity Single(Expression bool>> predicate); 90 91 /// 92 /// Gets exactly one entity with given predicate. 93 /// Throws exception if no entity or more than one entity. 94 /// 95 /// Entity 96 Task SingleAsync(Expression bool>> predicate); 97 98 /// 99 /// Gets an entity with given primary key or null if not found. 100 /// 101 /// Primary key of the entity to get 102 /// Entity or null 103 TEntity FirstOrDefault(TPrimaryKey id); 104 105 /// 106 /// Gets an entity with given primary key or null if not found. 107 /// 108 /// Primary key of the entity to get 109 /// Entity or null 110 Task FirstOrDefaultAsync(TPrimaryKey id); 111 112 /// 113 /// Gets an entity with given given predicate or null if not found. 114 /// 115 /// Predicate to filter entities 116 TEntity FirstOrDefault(Expression bool>> predicate); 117 118 /// 119 /// Gets an entity with given given predicate or null if not found. 120 /// 121 /// Predicate to filter entities 122 Task FirstOrDefaultAsync(Expression bool>> predicate); 123 124 /// 125 /// Creates an entity with given primary key without database access. 126 /// 127 /// Primary key of the entity to load 128 /// Entity 129 TEntity Load(TPrimaryKey id); 130 131 #endregion 132 133 #region Insert 134 135 /// 136 /// Inserts a new entity. 137 /// 138 /// Inserted entity 139 TEntity Insert(TEntity entity); 140 141 /// 142 /// Inserts a new entity. 143 /// 144 /// Inserted entity 145 Task InsertAsync(TEntity entity); 146 147 /// 148 /// Inserts a new entity and gets it's Id. 149 /// It may require to save current unit of work 150 /// to be able to retrieve id. 151 /// 152 /// Entity 153 /// Id of the entity 154 TPrimaryKey InsertAndGetId(TEntity entity); 155 156 /// 157 /// Inserts a new entity and gets it's Id. 158 /// It may require to save current unit of work 159 /// to be able to retrieve id. 160 /// 161 /// Entity 162 /// Id of the entity 163 Task InsertAndGetIdAsync(TEntity entity); 164 165 /// 166 /// Inserts or updates given entity depending on Id's value. 167 /// 168 /// Entity 169 TEntity InsertOrUpdate(TEntity entity); 170 171 /// 172 /// Inserts or updates given entity depending on Id's value. 173 /// 174 /// Entity 175 Task InsertOrUpdateAsync(TEntity entity); 176 177 /// 178 /// Inserts or updates given entity depending on Id's value. 179 /// Also returns Id of the entity. 180 /// It may require to save current unit of work 181 /// to be able to retrieve id. 182 /// 183 /// Entity 184 /// Id of the entity 185 TPrimaryKey InsertOrUpdateAndGetId(TEntity entity); 186 187 /// 188 /// Inserts or updates given entity depending on Id's value. 189 /// Also returns Id of the entity. 190 /// It may require to save current unit of work 191 /// to be able to retrieve id. 192 /// 193 /// Entity 194 /// Id of the entity 195 Task InsertOrUpdateAndGetIdAsync(TEntity entity); 196 197 #endregion 198 199 #region Update 200 201 /// 202 /// Updates an existing entity. 203 /// 204 /// Entity 205 TEntity Update(TEntity entity); 206 207 /// 208 /// Updates an existing entity. 209 /// 210 /// Entity 211 Task UpdateAsync(TEntity entity); 212 213 /// 214 /// Updates an existing entity. 215 /// 216 /// Id of the entity 217 /// Action that can be used to change values of the entity 218 /// Updated entity 219 TEntity Update(TPrimaryKey id, Action updateAction); 220 221 /// 222 /// Updates an existing entity. 223 /// 224 /// Id of the entity 225 /// Action that can be used to change values of the entity 226 /// Updated entity 227 Task UpdateAsync(TPrimaryKey id, Func updateAction); 228 229 #endregion 230 231 #region Delete 232 233 /// 234 /// Deletes an entity. 235 /// 236 /// Entity to be deleted 237 void Delete(TEntity entity); 238 239 /// 240 /// Deletes an entity. 241 /// 242 /// Entity to be deleted 243 Task DeleteAsync(TEntity entity); 244 245 /// 246 /// Deletes an entity by primary key. 247 /// 248 /// Primary key of the entity 249 void Delete(TPrimaryKey id); 250 251 /// 252 /// Deletes an entity by primary key. 253 /// 254 /// Primary key of the entity 255 Task DeleteAsync(TPrimaryKey id); 256 257 /// 258 /// Deletes many entities by function. 259 /// Notice that: All entities fits to given predicate are retrieved and deleted. 260 /// This may cause major performance problems if there are too many entities with 261 /// given predicate. 262 /// 263 /// A condition to filter entities 264 void Delete(Expression bool>> predicate); 265 266 /// 267 /// Deletes many entities by function. 268 /// Notice that: All entities fits to given predicate are retrieved and deleted. 269 /// This may cause major performance problems if there are too many entities with 270 /// given predicate. 271 /// 272 /// A condition to filter entities 273 Task DeleteAsync(Expression bool>> predicate); 274 275 #endregion 276 277 #region Aggregates 278 279 /// 280 /// Gets count of all entities in this repository. 281 /// 282 /// Count of entities 283 int Count(); 284 285 /// 286 /// Gets count of all entities in this repository. 287 /// 288 /// Count of entities 289 Task<int> CountAsync(); 290 291 /// 292 /// Gets count of all entities in this repository based on given . 293 /// 294 /// A method to filter count 295 /// Count of entities 296 int Count(Expression bool>> predicate); 297 298 /// 299 /// Gets count of all entities in this repository based on given . 300 /// 301 /// A method to filter count 302 /// Count of entities 303 Task<int> CountAsync(Expression bool>> predicate); 304 305 /// 306 /// Gets count of all entities in this repository (use if expected return value is greather than . 307 /// 308 /// Count of entities 309 long LongCount(); 310 311 /// 312 /// Gets count of all entities in this repository (use if expected return value is greather than . 313 /// 314 /// Count of entities 315 Task<long> LongCountAsync(); 316 317 /// 318 /// Gets count of all entities in this repository based on given 319 /// (use this overload if expected return value is greather than ). 320 /// 321 /// A method to filter count 322 /// Count of entities 323 long LongCount(Expression bool>> predicate); 324 325 /// 326 /// Gets count of all entities in this repository based on given 327 /// (use this overload if expected return value is greather than ). 328 /// 329 /// A method to filter count 330 /// Count of entities 331 Task<long> LongCountAsync(Expression bool>> predicate); 332 333 #endregion 334 } 335 }
3、Repositorys 是放仓存类的泛型类的
(1)建一个 RepositoryBase 抽象父类实现IRepository接口,代码如下
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Linq.Expressions; 5 using System.Text; 6 using System.Threading.Tasks; 7 using Vacant.Entitys; 8 using Vacant.Repositorys.IRepositorys; 9 10 namespace Vacant.Repositorys.Repositorys 11 { 12 ///13 /// 抽象仓储类 14 /// 15 /// 实体类 16 /// 主键 17 public abstract class RepositoryBase : IRepository where TEntity : class, IEntity 18 { 19 public abstract IQueryable GetAll(); 20 21 public virtual IQueryable GetAllIncluding(params Expression object>>[] propertySelectors) 22 { 23 return GetAll(); 24 } 25 26 public virtual List GetAllList() 27 { 28 return GetAll().ToList(); 29 } 30 31 public virtual Task > GetAllListAsync() 32 { 33 return Task.FromResult(GetAllList()); 34 } 35 36 public virtual List
GetAllList(Expression bool>> predicate) 37 { 38 return GetAll().Where(predicate).ToList(); 39 } 40 41 public virtual Task > GetAllListAsync(Expression
bool>> predicate) 42 { 43 return Task.FromResult(GetAllList(predicate)); 44 } 45 46 public virtual T Query (Func , T> queryMethod) 47 { 48 return queryMethod(GetAll()); 49 } 50 51 public virtual TEntity Get(TPrimaryKey id) 52 { 53 var entity = FirstOrDefault(id); 54 if (entity == null) 55 { 56 throw new EntityNotFoundException(typeof(TEntity), id); 57 } 58 59 return entity; 60 } 61 62 public virtual async Task GetAsync(TPrimaryKey id) 63 { 64 var entity = await FirstOrDefaultAsync(id); 65 if (entity == null) 66 { 67 throw new EntityNotFoundException(typeof(TEntity), id); 68 } 69 70 return entity; 71 } 72 73 public virtual TEntity Single(Expression bool>> predicate) 74 { 75 return GetAll().Single(predicate); 76 } 77 78 public virtual Task SingleAsync(Expression bool>> predicate) 79 { 80 return Task.FromResult(Single(predicate)); 81 } 82 83 public virtual TEntity FirstOrDefault(TPrimaryKey id) 84 { 85 return GetAll().FirstOrDefault(CreateEqualityExpressionForId(id)); 86 } 87 88 public virtual Task FirstOrDefaultAsync(TPrimaryKey id) 89 { 90 return Task.FromResult(FirstOrDefault(id)); 91 } 92 93 public virtual TEntity FirstOrDefault(Expression bool>> predicate) 94 { 95 return GetAll().FirstOrDefault(predicate); 96 } 97 98 public virtual Task FirstOrDefaultAsync(Expression bool>> predicate) 99 { 100 return Task.FromResult(FirstOrDefault(predicate)); 101 } 102 103 public virtual TEntity Load(TPrimaryKey id) 104 { 105 return Get(id); 106 } 107 108 public abstract TEntity Insert(TEntity entity); 109 110 public virtual Task InsertAsync(TEntity entity) 111 { 112 return Task.FromResult(Insert(entity)); 113 } 114 115 public virtual TPrimaryKey InsertAndGetId(TEntity entity) 116 { 117 return Insert(entity).Id; 118 } 119 120 public virtual async Task InsertAndGetIdAsync(TEntity entity) 121 { 122 var insertedEntity = await InsertAsync(entity); 123 return insertedEntity.Id; 124 } 125 126 public virtual TEntity InsertOrUpdate(TEntity entity) 127 { 128 return entity.IsTransient() 129 ? Insert(entity) 130 : Update(entity); 131 } 132 133 public virtual async Task InsertOrUpdateAsync(TEntity entity) 134 { 135 return entity.IsTransient() 136 ? await InsertAsync(entity) 137 : await UpdateAsync(entity); 138 } 139 140 public virtual TPrimaryKey InsertOrUpdateAndGetId(TEntity entity) 141 { 142 return InsertOrUpdate(entity).Id; 143 } 144 145 public virtual async Task InsertOrUpdateAndGetIdAsync(TEntity entity) 146 { 147 var insertedEntity = await InsertOrUpdateAsync(entity); 148 return insertedEntity.Id; 149 } 150 151 public abstract TEntity Update(TEntity entity); 152 153 public virtual Task UpdateAsync(TEntity entity) 154 { 155 return Task.FromResult(Update(entity)); 156 } 157 158 public virtual TEntity Update(TPrimaryKey id, Action updateAction) 159 { 160 var entity = Get(id); 161 updateAction(entity); 162 return entity; 163 } 164 165 public virtual async Task UpdateAsync(TPrimaryKey id, Func updateAction) 166 { 167 var entity = await GetAsync(id); 168 await updateAction(entity); 169 return entity; 170 } 171 172 public abstract void Delete(TEntity entity); 173 174 public virtual Task DeleteAsync(TEntity entity) 175 { 176 Delete(entity); 177 return Task.CompletedTask; 178 } 179 180 public abstract void Delete(TPrimaryKey id); 181 182 public virtual Task DeleteAsync(TPrimaryKey id) 183 { 184 Delete(id); 185 return Task.CompletedTask; 186 } 187 188 public virtual void Delete(Expression bool>> predicate) 189 { 190 foreach (var entity in GetAllList(predicate)) 191 { 192 Delete(entity); 193 } 194 } 195 196 public virtual async Task DeleteAsync(Expression bool>> predicate) 197 { 198 var entities = await GetAllListAsync(predicate); 199 200 foreach (var entity in entities) 201 { 202 await DeleteAsync(entity); 203 } 204 } 205 206 public virtual int Count() 207 { 208 return GetAll().Count(); 209 } 210 211 public virtual Task<int> CountAsync() 212 { 213 return Task.FromResult(Count()); 214 } 215 216 public virtual int Count(Expression bool>> predicate) 217 { 218 return GetAll().Count(predicate); 219 } 220 221 public virtual Task<int> CountAsync(Expression bool>> predicate) 222 { 223 return Task.FromResult(Count(predicate)); 224 } 225 226 public virtual long LongCount() 227 { 228 return GetAll().LongCount(); 229 } 230 231 public virtual Task<long> LongCountAsync() 232 { 233 return Task.FromResult(LongCount()); 234 } 235 236 public virtual long LongCount(Expression bool>> predicate) 237 { 238 return GetAll().LongCount(predicate); 239 } 240 241 public virtual Task<long> LongCountAsync(Expression bool>> predicate) 242 { 243 return Task.FromResult(LongCount(predicate)); 244 } 245 246 protected virtual Expression bool>> CreateEqualityExpressionForId(TPrimaryKey id) 247 { 248 var lambdaParam = Expression.Parameter(typeof(TEntity)); 249 250 var leftExpression = Expression.PropertyOrField(lambdaParam, "Id"); 251 252 var idValue = Convert.ChangeType(id, typeof(TPrimaryKey)); 253 254 Expression object>> closure = () => idValue; 255 var rightExpression = Expression.Convert(closure.Body, leftExpression.Type); 256 257 var lambdaBody = Expression.Equal(leftExpression, rightExpression); 258 259 return Expression.Lambda bool>>(lambdaBody, lambdaParam); 260 } 261 } 262 }
(2)建一个 子类EFRepository 继承RepositoryBase 这个类,代码如下
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using Vacant.Entitys; 6 using Vacant.Repositorys.DbContexts; 7 using Vacant.Repositorys.IRepositorys; 8 9 namespace Vacant.Repositorys.Repositorys 10 { 11 ///12 /// 使用Ef的sqlserver版本 13 /// 14 /// 15 public class EFRepository : EFRepository long>, IRepository where TEntity : class, IEntity<long> 16 { 17 public EFRepository(MSSqlEFDbContext dbContext) : base(dbContext) 18 { 19 20 } 21 } 22 23 24 public class EFRepository : RepositoryBase where TEntity : class, IEntity 25 { 26 public readonly MSSqlEFDbContext _dbContext; 27 28 public EFRepository(MSSqlEFDbContext dbContext) 29 { 30 _dbContext = dbContext; 31 } 32 public override void Delete(TEntity entity) 33 { 34 _dbContext.Set ().Remove(entity); 35 _dbContext.SaveChanges(); 36 } 37 38 public override void Delete(TPrimaryKey id) 39 { 40 var entity = _dbContext.Set ().SingleOrDefault(t => t.Id.Equals(id)); 41 Delete(entity); 42 43 } 44 45 public override IQueryable GetAll() 46 { 47 return _dbContext.Set ().AsQueryable(); 48 } 49 50 public override TEntity Insert(TEntity entity) 51 { 52 _dbContext.Set ().Add(entity); 53 _dbContext.SaveChanges(); 54 return entity; 55 } 56 57 public override TEntity Update(TEntity entity) 58 { 59 _dbContext.Set ().Update(entity); 60 _dbContext.SaveChanges(); 61 return entity; 62 } 63 } 64 65 }
三、现在泛型仓储库大致完成了,我们开始建一个Vacant.Services类库、里面有两个文件夹,分别是IServices 和Services ,添加对仓库项目库和实体项目库的引用
四、Vancant.Comman是项目公共帮助类库 ,先建3个类分别是 HttpHelper、VacantException、ValidateCode,上面的类库都要添加对此项目的引用
(1)HttpHelper是发送http请求的帮助类的代码如下
1 using System; 2 using System.Collections.Generic; 3 using System.Net.Http; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace Vancant.Comman 8 { 9 ///10 /// http请求帮助类 11 /// 12 public class HttpHelper 13 { 14 /// 15 /// 发起POST同步请求 16 /// 17 /// 18 /// 19 /// 20 /// application/xml、application/json、application/text、application/x-www-form-urlencoded 21 /// 填充消息头 22 /// 23 public static string HttpPost(string url, string postData = null, string contentType = null, int timeOut = 30, Dictionary<string, string> headers = null) 24 { 25 postData = postData ?? ""; 26 using (HttpClient client = new HttpClient()) 27 { 28 if (headers != null) 29 { 30 foreach (var header in headers) 31 client.DefaultRequestHeaders.Add(header.Key, header.Value); 32 } 33 using (HttpContent httpContent = new StringContent(postData, Encoding.UTF8)) 34 { 35 if (contentType != null) 36 httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType); 37 38 HttpResponseMessage response = client.PostAsync(url, httpContent).Result; 39 return response.Content.ReadAsStringAsync().Result; 40 } 41 } 42 } 43 44 45 /// 46 /// 发起POST异步请求 47 /// 48 /// 49 /// 50 /// application/xml、application/json、application/text、application/x-www-form-urlencoded 51 /// 填充消息头 52 /// 53 public static async Task<string> HttpPostAsync(string url, string postData = null, string contentType = null, int timeOut = 30, Dictionary<string, string> headers = null) 54 { 55 postData = postData ?? ""; 56 using (HttpClient client = new HttpClient()) 57 { 58 client.Timeout = new TimeSpan(0, 0, timeOut); 59 if (headers != null) 60 { 61 foreach (var header in headers) 62 client.DefaultRequestHeaders.Add(header.Key, header.Value); 63 } 64 using (HttpContent httpContent = new StringContent(postData, Encoding.UTF8)) 65 { 66 if (contentType != null) 67 httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType); 68 69 HttpResponseMessage response = await client.PostAsync(url, httpContent); 70 return await response.Content.ReadAsStringAsync(); 71 } 72 } 73 } 74 75 /// 76 /// 发起GET同步请求 77 /// 78 /// 79 /// 80 /// 81 /// 82 public static string HttpGet(string url, Dictionary<string, string> headers = null) 83 { 84 using (HttpClient client = new HttpClient()) 85 { 86 if (headers != null) 87 { 88 foreach (var header in headers) 89 client.DefaultRequestHeaders.Add(header.Key, header.Value); 90 } 91 HttpResponseMessage response = client.GetAsync(url).Result; 92 return response.Content.ReadAsStringAsync().Result; 93 } 94 } 95 96 /// 97 /// 发起GET异步请求 98 /// 99 /// 100 /// 101 /// 102 /// 103 public static async Task<string> HttpGetAsync(string url, Dictionary<string, string> headers = null) 104 { 105 using (HttpClient client = new HttpClient()) 106 { 107 if (headers != null) 108 { 109 foreach (var header in headers) 110 client.DefaultRequestHeaders.Add(header.Key, header.Value); 111 } 112 HttpResponseMessage response = await client.GetAsync(url); 113 return await response.Content.ReadAsStringAsync(); 114 } 115 } 116 } 117 }
(2)VacantException是错误异常
1 using System; 2 using System.Collections.Generic; 3 using System.Runtime.Serialization; 4 using System.Text; 5 6 namespace Vancant.Comman 7 { 8 ///9 /// Base exception type for those are thrown by Abp system for Abp specific exceptions. 10 /// 11 [Serializable] 12 public class VacantException : Exception 13 { 14 /// 15 /// Creates a new object. 16 /// 17 public VacantException() 18 { 19 20 } 21 22 /// 23 /// Creates a new object. 24 /// 25 public VacantException(SerializationInfo serializationInfo, StreamingContext context) 26 : base(serializationInfo, context) 27 { 28 29 } 30 31 /// 32 /// Creates a new object. 33 /// 34 /// Exception message 35 public VacantException(string message) 36 : base(message) 37 { 38 39 } 40 41 /// 42 /// Creates a new object. 43 /// 44 /// Exception message 45 /// Inner exception 46 public VacantException(string message, Exception innerException) 47 : base(message, innerException) 48 { 49 50 } 51 } 52 }
(3)ValidateCode是生成随机的验证码 ,注意 一定添加nuget安装包 System.Drawing.Common
1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using System.Drawing; 5 using System.Drawing.Imaging; 6 using System.IO; 7 8 namespace Vancant.Comman 9 { 10 ///11 /// 验证码 12 /// 13 public class ValidateCode 14 { 15 public byte[] GetVerifyCode(out string code) 16 { 17 code = string.Empty; 18 int codeW = 80; 19 int codeH = 30; 20 int fontSize = 16; 21 string chkCode = string.Empty; 22 Random rnd = new Random(); 23 //颜色列表,用于验证码、噪线、噪点 24 Color[] color = { Color.Black, Color.Red, Color.Blue, Color.Green, Color.Orange, Color.Brown, Color.Brown, Color.DarkBlue }; 25 //字体列表,用于验证码 26 string[] font = { "Times New Roman" }; 27 //验证码的字符集,去掉了一些容易混淆的字符 28 char[] character = { '2', '3', '4', '5', '6', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'h', 'k', 'm', 'n', 'r', 'x', 'y', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W', 'X', 'Y' }; 29 //生成验证码字符串 30 for (int i = 0; i < 4; i++) 31 { 32 chkCode += character[rnd.Next(character.Length)]; 33 } 34 code = chkCode; 35 36 //创建画布 37 Bitmap bmp = new Bitmap(codeW, codeH); 38 Graphics g = Graphics.FromImage(bmp); 39 g.Clear(Color.White); 40 //画噪线 41 for (int i = 0; i < 1; i++) 42 { 43 int x1 = rnd.Next(codeW); 44 int y1 = rnd.Next(codeH); 45 int x2 = rnd.Next(codeW); 46 int y2 = rnd.Next(codeH); 47 Color clr = color[rnd.Next(color.Length)]; 48 g.DrawLine(new Pen(clr), x1, y1, x2, y2); 49 } 50 //画验证码字符串 51 for (int i = 0; i < chkCode.Length; i++) 52 { 53 string fnt = font[rnd.Next(font.Length)]; 54 Font ft = new Font(fnt, fontSize); 55 Color clr = color[rnd.Next(color.Length)]; 56 g.DrawString(chkCode[i].ToString(), ft, new SolidBrush(clr), (float)i * 18, (float)0); 57 } 58 //将验证码图片写入内存流,并将其以 "image/Png" 格式输出 59 MemoryStream ms = new MemoryStream(); 60 try 61 { 62 bmp.Save(ms, ImageFormat.Png); 63 return ms.ToArray(); 64 } 65 catch (Exception) 66 { 67 return null; 68 } 69 finally 70 { 71 g.Dispose(); 72 bmp.Dispose(); 73 } 74 } 75 76 } 77 }
五、现在开始建.net core mvc 3.1 版本的web应用程序 Vacant.Web添加对上面四个项目的引用
statupp类进行配置,里面代码如下,
services.AddScoped(typeof(IRepository<,>), typeof(EFRepository<,>));
services.AddScoped(typeof(IRepository<>), typeof(EFRepository<>)); 是泛型注入
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Reflection; 5 using System.Threading.Tasks; 6 using Microsoft.AspNetCore.Builder; 7 using Microsoft.AspNetCore.Hosting; 8 using Microsoft.AspNetCore.HttpsPolicy; 9 using Microsoft.EntityFrameworkCore; 10 using Microsoft.Extensions.Configuration; 11 using Microsoft.Extensions.DependencyInjection; 12 using Microsoft.Extensions.Hosting; 13 using Vacant.Repositorys.DbContexts; 14 using Vacant.Repositorys.IRepositorys; 15 using Vacant.Repositorys.Repositorys; 16 using Vacant.Services.IServices; 17 18 namespace Vacant.Web 19 { 20 public class Startup 21 { 22 public Startup(IConfiguration configuration) 23 { 24 Configuration = configuration; 25 } 26 27 public IConfiguration Configuration { get; } 28 29 // This method gets called by the runtime. Use this method to add services to the container. 30 public void ConfigureServices(IServiceCollection services) 31 { 32 services.AddControllersWithViews(); 33 //注册服务连接数据库 34 services.AddDbContext(options => 35 { 36 options.UseSqlServer(Configuration.GetConnectionString("Default"));//获取配置的连接字符串 37 //options.UseMySql(Configuration.GetConnectionString("Default")); 38 //options.UseSqlite(Configuration.GetConnectionString("Default")); 39 //options.UseNpgsql(Configuration.GetConnectionString("Default")); 40 }); 41 42 #region 依赖注入仓储 43 44 //重点仓储和服务注入方式要一样 45 //依赖注入仓储 46 services.AddScoped(typeof(IRepository<,>), typeof(EFRepository<,>)); 47 services.AddScoped(typeof(IRepository<>), typeof(EFRepository<>)); 48 49 //services.AddScoped (); 50 //services.AddScoped(); 51 #endregion 52 53 #region 批量注入 54 //加载程序集MyApplication 55 var serviceAsm = Assembly.Load(new AssemblyName("Vacant.Services")); 56 foreach (Type serviceType in serviceAsm.GetTypes().Where(t => typeof(IBaseService).IsAssignableFrom(t) && !t.GetTypeInfo().IsAbstract)) 57 { 58 var interfaceTypes = serviceType.GetInterfaces(); 59 foreach (var interfaceType in interfaceTypes) 60 { 61 services.AddScoped(interfaceType, serviceType); 62 } 63 } 64 65 #endregion 66 services.AddSession(); 67 services.AddMvc(options => 68 { 69 options.Filters.Add(); 70 }); 71 } 72 73 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 74 public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 75 { 76 if (env.IsDevelopment()) 77 { 78 app.UseDeveloperExceptionPage(); 79 } 80 else 81 { 82 app.UseExceptionHandler("/Home/Error"); 83 // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. 84 app.UseHsts(); 85 } 86 app.UseHttpsRedirection(); 87 app.UseStaticFiles(); 88 89 app.UseRouting(); 90 91 app.UseAuthorization(); 92 93 app.UseEndpoints(endpoints => 94 { 95 endpoints.MapControllerRoute( 96 name: "default", 97 pattern: "{controller=Home}/{action=Index}/{id?}"); 98 }); 99 } 100 } 101 }