Asp.net MVC 搭建属于自己的框架(一)
为什么要自己搭框架?
大家伙别急,让我慢慢地告诉你!大家有没有这种感觉,从一家跳槽到另一家公司,公司的框架往往是不相同的,这样你必须就得摒弃原来的,学习新的框架。
问题是你用习惯了一种框架,比如封装的扩展方法、工厂模式、实体映射等等,你用得很爽,但是跳槽到新的公司,又得学习他们公司的框架,往往你在这上面
要花费不少时间。
所以我才有了搭建自己的框架的想法,我的框架用到了EntityFramework6.0+Asp.NET MVC4+Autofac等,下面是我的框架结构:
MyFrame.Domain 实体模型层
MyFrame.DataMapping 数据映射层:映射实体类和数据库表关系,数据库上下文存放在该层
MyFrame.IDao 数据访问接口层
MyFrame.Dao 数据访问层
MyFrame.IService 业务逻辑接口层
MyFrame.Service 业务逻辑层
MyFrame.Common 通用扩展层
MyFrame.Web UI层
层与层之间的引用关系
Domain(最低层)=》每个层调用;IDao=>Dao,Service; IService=>Service ; IDao,IService=>Web
实体基类
MyFrame.Domain.DomainBase:实体基类,实体类都需要继承DomainBase,现在这个类只有两个属性,等之后慢慢扩展完善
1 using System; 2 3 namespace MyFrame.Domain 4 { 5 /// <summary> 6 /// 实体基类 7 /// </summary> 8 public class DomainBase 9 { 10 /// <summary> 11 /// 编号 12 /// </summary> 13 public int Id { get; set; } 14 15 /// <summary> 16 /// 创建时间 17 /// </summary> 18 public DateTime CreateTime { get; set; } 19 } 20 }
数据访问基类接口
MyFrame.IDao.IDaoBase:封装了增删改查方法以及分页等
1 using System.Collections.Generic; 2 using PagedList; 3 4 namespace MyFrame.IDao 5 { 6 /// <summary> 7 /// 数据访问层的基类接口 8 /// </summary> 9 public interface IDaoBase<T> where T:class 10 { 11 /// <summary> 12 /// 增加 13 /// </summary> 14 /// <param name="domain">实体</param> 15 /// <returns></returns> 16 int Insert(T domain); 17 18 /// <summary> 19 /// 通过Id删除 20 /// </summary> 21 /// <param name="id">Id</param> 22 /// <returns></returns> 23 bool Delete(int id); 24 25 /// <summary> 26 /// 删除 27 /// </summary> 28 /// <param name="domain">实体</param> 29 /// <returns></returns> 30 bool Delete(T domain); 31 32 /// <summary> 33 /// 更新操作 34 /// </summary> 35 /// <param name="domain">实体</param> 36 /// <returns></returns> 37 bool Update(T domain); 38 39 /// <summary> 40 /// 通过Id查询 41 /// </summary> 42 /// <param name="id">Id</param> 43 /// <returns></returns> 44 T SelectById(int id); 45 46 /// <summary> 47 /// 查询所有 48 /// </summary> 49 /// <returns></returns> 50 IEnumerable<T> SelectAll(); 51 52 /// <summary> 53 /// 分页查询 54 /// </summary> 55 /// <typeparam name="T"></typeparam> 56 /// <param name="pageIndex"></param> 57 /// <param name="pageSize"></param> 58 /// <returns></returns> 59 IPagedList<T> SelectPageList(int? pageIndex = 1, int? pageSize = 10); 60 } 61 }
数据访问实现基类
MyFrame.Dao.DaoBase:需要继承IDaoBase,IDisposable
1 using System; 2 using System.Collections.Generic; 3 using System.Data.Entity; 4 using System.Linq; 5 using MyFrame.Domain; 6 using MyFrame.IDao; 7 using MyFrame.DataMapping; 8 using PagedList; 9 10 namespace MyFrame.Dao 11 { 12 /// <summary> 13 /// 数据访问层基类 14 /// </summary> 15 public class DaoBase<T> : IDisposable, IDaoBase<T> where T : DomainBase 16 { 17 protected readonly DbContext DbContext; 18 19 public DaoBase() 20 { 21 DbContext = new DataBaseContext(); 22 } 23 24 public int Insert(T t) 25 { 26 t.CreateTime = DateTime.Now; 27 DbContext.Entry<T>(t); 28 DbContext.Set<T>().Add(t); 29 return SaveChanges(); 30 } 31 32 public bool Delete(int id) 33 { 34 T domain = DbContext.Set<T>().FirstOrDefault(s => s.Id == id); 35 if (domain == null) 36 return false; 37 DbContext.Set<T>().Attach(domain); 38 DbContext.Set<T>().Remove(domain); 39 return SaveChanges() > 0; 40 } 41 42 public bool Delete(T t) 43 { 44 DbContext.Set<T>().Attach(t); 45 DbContext.Set<T>().Remove(t); 46 return SaveChanges() > 0; 47 } 48 49 public bool Update(T t) 50 { 51 DbContext.Set<T>().Attach(t); 52 DbContext.Entry(t).State = EntityState.Modified; 53 return SaveChanges() > 0; 54 } 55 56 public T SelectById(int id) 57 { 58 return DbContext.Set<T>().FirstOrDefault(s => s.Id == id); 59 } 60 61 public IEnumerable<T> SelectAll() 62 { 63 return DbContext.Set<T>(); 64 } 65 66 public IPagedList<T> SelectPageList(int? pageIndex, int? pageSize) 67 { 68 IEnumerable<T> list = DbContext.Set<T>().OrderByDescending(s=>s.CreateTime); 69 return list.ToPagedList(pageIndex??1,pageSize??10); 70 } 71 72 /// <summary> 73 /// 提交数据库操作进行异常捕捉 74 /// </summary> 75 /// <returns></returns> 76 private int SaveChanges() 77 { 78 try 79 { 80 int result = DbContext.SaveChanges(); 81 return result; 82 } 83 catch (System.Data.Entity.Infrastructure.DbUpdateException ex) 84 { 85 string message = "error:"; 86 if (ex.InnerException == null) 87 message += ex.Message + ","; 88 else if (ex.InnerException.InnerException == null) 89 message += ex.InnerException.Message + ","; 90 else if (ex.InnerException.InnerException.InnerException == null) 91 message += ex.InnerException.InnerException.Message + ","; 92 throw new Exception(message); 93 } 94 } 95 96 public void Dispose() 97 { 98 DbContext.Dispose(); 99 } 100 } 101 }
数据库访问上下文
MyFrame.DataMapping.DataBaseContext
1 using System.Data.Entity; 2 using MyFrame.DataMapping.Mapping; 3 using MyFrame.Domain; 4 5 namespace MyFrame.DataMapping 6 { 7 /// <summary> 8 /// 数据库访问上下文 9 /// </summary> 10 public class DataBaseContext : DbContext 11 { 12 public DataBaseContext() 13 : base("Name=EhiBus") 14 { 15 Database.SetInitializer<DataBaseContext>(null); 16 } 17 //实体类 18 public DbSet<User> Users { get; set; } 19 public DbSet<Driver> Drivers { get; set; } 20 //将实体映射到数据库表 21 protected override void OnModelCreating(DbModelBuilder modelBuilder) 22 { 23 modelBuilder.Configurations.Add(new UserMap()); 24 modelBuilder.Configurations.Add(new DriverMap()); 25 } 26 27 } 28 }
1 using System.Data.Entity.ModelConfiguration; 2 using MyFrame.Domain; 3 4 namespace MyFrame.DataMapping.Mapping 5 { 6 public class UserMap : EntityTypeConfiguration<User> 7 { 8 public UserMap() 9 { 10 this.HasKey(t => t.Id); 11 this.ToTable("User"); 12 this.Property(t => t.Id).HasColumnName("Id"); 13 this.Property(t => t.CreateTime).HasColumnName("CreateTime"); 14 } 15 } 16 }
扩展帮助类
MyFrame.Common.Helper:封装了一些常用的方法,我自己用起来比较顺手,增加自己的开发效率
1 using System; 2 3 namespace MyFrame.Common 4 { 5 public static class Helper 6 { 7 #region 字符串转换为Int 8 /// <summary> 9 /// 将字符串转换为Int?类型 10 /// </summary> 11 public static int? ToInt32(this string s) 12 { 13 int? num; 14 try 15 { 16 num = Convert.ToInt32(s); 17 } 18 catch (FormatException formatException) 19 { 20 num = null; 21 } 22 catch (OverflowException overflowException) 23 { 24 num = null; 25 } 26 return num; 27 } 28 29 /// <summary> 30 /// 将字符串转换为Int类型 31 /// </summary> 32 public static int ToInt32Req(this string s) 33 { 34 try 35 { 36 int num = Convert.ToInt32(s); 37 return num; 38 } 39 catch (FormatException ex) 40 { 41 throw new Exception(ex.Message); 42 } 43 catch (OverflowException overflowException) 44 { 45 throw new Exception(overflowException.Message); 46 } 47 } 48 #endregion 49 50 #region 字符串转换为Decimal 51 /// <summary> 52 /// 将字符串转换为Decimal?类型 53 /// </summary> 54 public static decimal? ToDecimal(this string s) 55 { 56 decimal? num; 57 try 58 { 59 num = Convert.ToDecimal(s); 60 } 61 catch (Exception formatException) 62 { 63 num = null; 64 } 65 return num; 66 } 67 68 /// <summary> 69 /// 将字符串转换为Decimal类型,无法转换抛出异常 70 /// </summary> 71 public static decimal ToDecimalReq(this string s) 72 { 73 try 74 { 75 decimal num = Convert.ToDecimal(s); 76 return num; 77 } 78 catch (FormatException ex) 79 { 80 throw new Exception(ex.Message); 81 } 82 catch (OverflowException overflowException) 83 { 84 throw new Exception(overflowException.Message); 85 } 86 } 87 #endregion 88 89 #region 字符串转换为DateTime 90 /// <summary> 91 /// 将字符串转换为DateTime?类型 92 /// </summary> 93 public static DateTime? ToDateTime(this string s) 94 { 95 DateTime? num; 96 try 97 { 98 num = Convert.ToDateTime(s); 99 } 100 catch (FormatException formatException) 101 { 102 num = null; 103 } 104 return num; 105 } 106 107 /// <summary> 108 /// 将字符串转换为DateTime类型,无法转换抛出异常 109 /// </summary> 110 public static DateTime ToDateTimeReq(this string s) 111 { 112 try 113 { 114 DateTime num = Convert.ToDateTime(s); 115 return num; 116 } 117 catch (FormatException ex) 118 { 119 throw new Exception(ex.Message); 120 } 121 } 122 #endregion 123 124 #region 字符串转换为bool 125 /// <summary> 126 /// 将字符串转换为bool?类型 127 /// </summary> 128 public static bool? ToBool(this string s) 129 { 130 bool? num; 131 try 132 { 133 num = Convert.ToBoolean(s); 134 } 135 catch (FormatException formatException) 136 { 137 num = null; 138 } 139 return num; 140 } 141 142 /// <summary> 143 /// 将字符串转换为bool类型,无法转换抛出异常 144 /// </summary> 145 public static bool ToBoolReq(this string s) 146 { 147 try 148 { 149 bool num = Convert.ToBoolean(s); 150 return num; 151 } 152 catch (FormatException ex) 153 { 154 throw new Exception(ex.Message); 155 } 156 } 157 #endregion 158 159 #region 根据Text转换为Enum 160 /// <summary> 161 /// 根据Text转换为Enum?类型 162 /// </summary> 163 public static T? ToEnumByText<T>(this string s) where T:struct 164 { 165 T? t; 166 try 167 { 168 t = (T) Enum.Parse(typeof (T), s); 169 } 170 catch (Exception ex) 171 { 172 t = null; 173 } 174 return t; 175 } 176 177 /// <summary> 178 ///根据Text转换为Enum类型,无法转换抛出异常 179 /// </summary> 180 public static T ToEnumReqByText<T>(this string s) where T : struct 181 { 182 183 try 184 { 185 T t= (T)Enum.Parse(typeof (T), s); 186 return t; 187 } 188 catch (ArgumentNullException argumentNullException) 189 { 190 throw new Exception(argumentNullException.Message); 191 } 192 catch (ArgumentException argumentException) 193 { 194 throw new Exception(argumentException.Message); 195 } 196 catch (OverflowException overflowException) 197 { 198 throw new Exception(overflowException.Message); 199 } 200 } 201 #endregion 202 203 #region 根据Value转换为Enum 204 /// <summary> 205 /// 根据Value转换为Enum?类型 206 /// </summary> 207 public static T? ToEnumByValue<T>(this int s) where T : struct 208 { 209 T? t; 210 try 211 { 212 t = (T)Enum.Parse(typeof(T), s.ToString()); 213 } 214 catch (Exception ex) 215 { 216 t = null; 217 } 218 return t; 219 } 220 221 /// <summary> 222 ///根据Value转换为Enum类型,无法转换抛出异常 223 /// </summary> 224 public static T ToEnumByValueReq<T>(this int s) where T : struct 225 { 226 227 try 228 { 229 T t = (T)Enum.Parse(typeof(T), s.ToString()); 230 return t; 231 } 232 catch (ArgumentNullException argumentNullException) 233 { 234 throw new Exception(argumentNullException.Message); 235 } 236 catch (ArgumentException argumentException) 237 { 238 throw new Exception(argumentException.Message); 239 } 240 catch (OverflowException overflowException) 241 { 242 throw new Exception(overflowException.Message); 243 } 244 } 245 #endregion 246 247 248 } 249 }
分页控件
我用得是PagedList,Nuget里搜索安装PagedList.MVC即可,然后自己封装了一下,封装得在DaoBase里SelectPageList()
为了让这个控件扩展性更强,写了一个分部试图_PageList,定义了一个分页Model,
为什么要自己写个而不是用它自己封装好的,因为后期页码可能需要跳转“首页”,”末页“等
1 using PagedList; 2 3 namespace MyFrame.Web.Models 4 { 5 public class PageListModel<T> where T:class 6 { 7 public IPagedList<T> PageList { get; set; } 8 9 public string Action { get; set; } 10 11 public string Controller { get; set; } 12 } 13 }
1 <div class="page-box"> 2 @if (Model.PageList.HasPreviousPage) 3 { 4 <a href="@Url.Action(Model.Action, Model.Controller, new { pageIndex = (Model.PageList.PageNumber - 1) })">上一页</a> 5 } 6 @for (int i = 1; i <= Model.PageList.PageCount; i++) 7 { 8 <a class="@(i == Model.PageList.PageNumber ? "currentpage" : "")" href="@Url.Action(Model.Action, Model.Controller, new { pageIndex = i })">@i</a> 9 } 10 @if (Model.PageList.HasNextPage) 11 { 12 <a href="@Url.Action(Model.Action, Model.Controller, new { pageIndex = (Model.PageList.PageNumber + 1) })">下一页</a> 13 } 14 </div>
分页css
1 /*分页*/ 2 .page-box{ width:770px; height:40px; background:#FFF; padding-top:15px; text-align:right; padding-right:20px;} 3 .page-box a{text-decoration: none; padding:3px 7px; display:inline-block; text-align:center; border:1px solid #CFCFCF; color:#666; font-size:12px;} 4 .page-box a:hover{ background:#A4A4A4; color:#fff;} 5 .page-box .currentpage{ background:#CCC;}
怎么调用呢?跟调用分部试图方法一样,只是需要传进一个PageListModel
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.Mvc; 6 using MyFrame.Common; 7 using MyFrame.Domain; 8 using MyFrame.Dao; 9 using MyFrame.IDao; 10 using PagedList; 11 12 namespace MyFrame.Web.Controllers 13 { 14 public class HomeController : Controller 15 { 16 private readonly IUserDao _userDao; 17 private readonly IDriverDao _driverDao; 18 public HomeController(IUserDao userDao,IDriverDao driverDao) 19 { 20 _userDao = userDao; 21 _driverDao = driverDao; 22 } 23 24 public ActionResult Index(int? pageIndex=1) 25 { 26 IPagedList<Driver> drivers = _driverDao.SelectPageList(pageIndex,2); 27 return View(drivers); 28 } 29 30 } 31 }
1 @using MyFrame.Domain 2 @using MyFrame.Web.Models 3 @model PagedList.IPagedList<MyFrame.Domain.Driver> 4 @{ 5 ViewBag.Title = "Index"; 6 Layout = "~/Views/Shared/_Layout.cshtml"; 7 } 8 9 @foreach (var driver in Model) 10 { 11 <p>@driver.Id</p> 12 <p>@driver.DriverName</p> 13 <p>@driver.Phone</p> 14 15 } 16 17 @Html.Partial("_PageList", new PageListModel<Driver> { PageList = Model, Action = "Index", Controller = "Home" })
Autofac组件
控制反转,类似于Ioc容器的组件,通过配置接口对应具体的实现类
然后调用我们只需要调接口就行了,降低耦合性。
组件Nuget里有自己下载安装就行
在Globl.asax里配置
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Reflection; 5 using System.Web; 6 using System.Web.Http; 7 using System.Web.Mvc; 8 using System.Web.Optimization; 9 using System.Web.Routing; 10 using Autofac; 11 using Autofac.Integration.Mvc; 12 using MyFrame.Common; 13 using MyFrame.Dao; 14 using MyFrame.IDao; 15 using MyFrame.IService; 16 using MyFrame.Service; 17 18 namespace MyFrame.Web 19 { 20 // 注意: 有关启用 IIS6 或 IIS7 经典模式的说明, 21 // 请访问 http://go.microsoft.com/?LinkId=9394801 22 23 public class MvcApplication : System.Web.HttpApplication 24 { 25 26 private void SetupResolveRules(ContainerBuilder builder) 27 { 28 //Components are wired to services using the As() methods on ContainerBuilder 29 builder.RegisterType<UserDao>().As<IUserDao>(); 30 builder.RegisterType<UserService>().As<IUserService>(); 31 builder.RegisterType<DriverDao>().As<IDriverDao>(); 32 } 33 protected void Application_Start() 34 { 35 AreaRegistration.RegisterAllAreas(); 36 37 // 依赖注入 38 var builder = new ContainerBuilder(); 39 SetupResolveRules(builder); 40 builder.RegisterControllers(Assembly.GetExecutingAssembly()); 41 var container = builder.Build(); 42 DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); 43 44 WebApiConfig.Register(GlobalConfiguration.Configuration); 45 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 46 RouteConfig.RegisterRoutes(RouteTable.Routes); 47 BundleConfig.RegisterBundles(BundleTable.Bundles); 48 } 49 } 50 }
通过控制器里的构造方法,调用即可
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.Mvc; 6 using MyFrame.Common; 7 using MyFrame.Domain; 8 using MyFrame.Dao; 9 using MyFrame.IDao; 10 using PagedList; 11 12 namespace MyFrame.Web.Controllers 13 { 14 public class HomeController : Controller 15 { 16 private readonly IUserDao _userDao; 17 private readonly IDriverDao _driverDao; 18 public HomeController(IUserDao userDao,IDriverDao driverDao) 19 { 20 _userDao = userDao; 21 _driverDao = driverDao; 22 } 23 24 public ActionResult Index(int? pageIndex=1) 25 { 26 IPagedList<Driver> drivers = _driverDao.SelectPageList(pageIndex,2); 27 return View(drivers); 28 } 29 30 } 31 }
其实配置接口对应哪个具体实体的关系,应该放到config文件比较好,这个后期再慢慢优化把。
结尾
这是一个初级版本,后期肯定要再好好完善,比如加入Transaction事务管理,排序,条件查询等等。
大家如果有什么好的建议,尽管提,互相促进互相学习。
转载请注明出处,谢谢!
源代码下载地址:http://yun.baidu.com/share/link?shareid=2761504180&uk=2820969304