Asp.net MVC 搭建属于自己的框架(一)

为什么要自己搭框架?

  大家伙别急,让我慢慢地告诉你!大家有没有这种感觉,从一家跳槽到另一家公司,公司的框架往往是不相同的,这样你必须就得摒弃原来的,学习新的框架。

问题是你用习惯了一种框架,比如封装的扩展方法、工厂模式、实体映射等等,你用得很爽,但是跳槽到新的公司,又得学习他们公司的框架,往往你在这上面

要花费不少时间。

所以我才有了搭建自己的框架的想法,我的框架用到了EntityFramework6.0+Asp.NET MVC4+Autofac等,下面是我的框架结构:

Asp.net  MVC 搭建属于自己的框架(一)

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,现在这个类只有两个属性,等之后慢慢扩展完善  

 using System;

 namespace MyFrame.Domain
{
/// <summary>
/// 实体基类
/// </summary>
public class DomainBase
{
/// <summary>
/// 编号
/// </summary>
public int Id { get; set; } /// <summary>
/// 创建时间
/// </summary>
public DateTime CreateTime { get; set; }
}
}

DomainBase

数据访问基类接口 

MyFrame.IDao.IDaoBase:封装了增删改查方法以及分页等

 using System.Collections.Generic;
using PagedList; namespace MyFrame.IDao
{
/// <summary>
/// 数据访问层的基类接口
/// </summary>
public interface IDaoBase<T> where T:class
{
/// <summary>
/// 增加
/// </summary>
/// <param name="domain">实体</param>
/// <returns></returns>
int Insert(T domain); /// <summary>
/// 通过Id删除
/// </summary>
/// <param name="id">Id</param>
/// <returns></returns>
bool Delete(int id); /// <summary>
/// 删除
/// </summary>
/// <param name="domain">实体</param>
/// <returns></returns>
bool Delete(T domain); /// <summary>
/// 更新操作
/// </summary>
/// <param name="domain">实体</param>
/// <returns></returns>
bool Update(T domain); /// <summary>
/// 通过Id查询
/// </summary>
/// <param name="id">Id</param>
/// <returns></returns>
T SelectById(int id); /// <summary>
/// 查询所有
/// </summary>
/// <returns></returns>
IEnumerable<T> SelectAll(); /// <summary>
/// 分页查询
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <returns></returns>
IPagedList<T> SelectPageList(int? pageIndex = , int? pageSize = );
}
}

IDaoBase

数据访问实现基类

MyFrame.Dao.DaoBase:需要继承IDaoBase,IDisposable

 using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using MyFrame.Domain;
using MyFrame.IDao;
using MyFrame.DataMapping;
using PagedList; namespace MyFrame.Dao
{
/// <summary>
/// 数据访问层基类
/// </summary>
public class DaoBase<T> : IDisposable, IDaoBase<T> where T : DomainBase
{
protected readonly DbContext DbContext; public DaoBase()
{
DbContext = new DataBaseContext();
} public int Insert(T t)
{
t.CreateTime = DateTime.Now;
DbContext.Entry<T>(t);
DbContext.Set<T>().Add(t);
return SaveChanges();
} public bool Delete(int id)
{
T domain = DbContext.Set<T>().FirstOrDefault(s => s.Id == id);
if (domain == null)
return false;
DbContext.Set<T>().Attach(domain);
DbContext.Set<T>().Remove(domain);
return SaveChanges() > ;
} public bool Delete(T t)
{
DbContext.Set<T>().Attach(t);
DbContext.Set<T>().Remove(t);
return SaveChanges() > ;
} public bool Update(T t)
{
DbContext.Set<T>().Attach(t);
DbContext.Entry(t).State = EntityState.Modified;
return SaveChanges() > ;
} public T SelectById(int id)
{
return DbContext.Set<T>().FirstOrDefault(s => s.Id == id);
} public IEnumerable<T> SelectAll()
{
return DbContext.Set<T>();
} public IPagedList<T> SelectPageList(int? pageIndex, int? pageSize)
{
IEnumerable<T> list = DbContext.Set<T>().OrderByDescending(s=>s.CreateTime);
return list.ToPagedList(pageIndex??,pageSize??);
} /// <summary>
/// 提交数据库操作进行异常捕捉
/// </summary>
/// <returns></returns>
private int SaveChanges()
{
try
{
int result = DbContext.SaveChanges();
return result;
}
catch (System.Data.Entity.Infrastructure.DbUpdateException ex)
{
string message = "error:";
if (ex.InnerException == null)
message += ex.Message + ",";
else if (ex.InnerException.InnerException == null)
message += ex.InnerException.Message + ",";
else if (ex.InnerException.InnerException.InnerException == null)
message += ex.InnerException.InnerException.Message + ",";
throw new Exception(message);
}
} public void Dispose()
{
DbContext.Dispose();
}
}
}

DaoBase

数据库访问上下文

MyFrame.DataMapping.DataBaseContext

 using System.Data.Entity;
using MyFrame.DataMapping.Mapping;
using MyFrame.Domain; namespace MyFrame.DataMapping
{
/// <summary>
/// 数据库访问上下文
/// </summary>
public class DataBaseContext : DbContext
{
public DataBaseContext()
: base("Name=EhiBus")
{
Database.SetInitializer<DataBaseContext>(null);
}
//实体类
public DbSet<User> Users { get; set; }
public DbSet<Driver> Drivers { get; set; }
//将实体映射到数据库表
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new UserMap());
modelBuilder.Configurations.Add(new DriverMap());
} }
}

DataBaseContext

 using System.Data.Entity.ModelConfiguration;
using MyFrame.Domain; namespace MyFrame.DataMapping.Mapping
{
public class UserMap : EntityTypeConfiguration<User>
{
public UserMap()
{
this.HasKey(t => t.Id);
this.ToTable("User");
this.Property(t => t.Id).HasColumnName("Id");
this.Property(t => t.CreateTime).HasColumnName("CreateTime");
}
}
}

UserMap

扩展帮助类

MyFrame.Common.Helper:封装了一些常用的方法,我自己用起来比较顺手,增加自己的开发效率

 using System;

 namespace MyFrame.Common
{
public static class Helper
{
#region 字符串转换为Int
/// <summary>
/// 将字符串转换为Int?类型
/// </summary>
public static int? ToInt32(this string s)
{
int? num;
try
{
num = Convert.ToInt32(s);
}
catch (FormatException formatException)
{
num = null;
}
catch (OverflowException overflowException)
{
num = null;
}
return num;
} /// <summary>
/// 将字符串转换为Int类型
/// </summary>
public static int ToInt32Req(this string s)
{
try
{
int num = Convert.ToInt32(s);
return num;
}
catch (FormatException ex)
{
throw new Exception(ex.Message);
}
catch (OverflowException overflowException)
{
throw new Exception(overflowException.Message);
}
}
#endregion #region 字符串转换为Decimal
/// <summary>
/// 将字符串转换为Decimal?类型
/// </summary>
public static decimal? ToDecimal(this string s)
{
decimal? num;
try
{
num = Convert.ToDecimal(s);
}
catch (Exception formatException)
{
num = null;
}
return num;
} /// <summary>
/// 将字符串转换为Decimal类型,无法转换抛出异常
/// </summary>
public static decimal ToDecimalReq(this string s)
{
try
{
decimal num = Convert.ToDecimal(s);
return num;
}
catch (FormatException ex)
{
throw new Exception(ex.Message);
}
catch (OverflowException overflowException)
{
throw new Exception(overflowException.Message);
}
}
#endregion #region 字符串转换为DateTime
/// <summary>
/// 将字符串转换为DateTime?类型
/// </summary>
public static DateTime? ToDateTime(this string s)
{
DateTime? num;
try
{
num = Convert.ToDateTime(s);
}
catch (FormatException formatException)
{
num = null;
}
return num;
} /// <summary>
/// 将字符串转换为DateTime类型,无法转换抛出异常
/// </summary>
public static DateTime ToDateTimeReq(this string s)
{
try
{
DateTime num = Convert.ToDateTime(s);
return num;
}
catch (FormatException ex)
{
throw new Exception(ex.Message);
}
}
#endregion #region 字符串转换为bool
/// <summary>
/// 将字符串转换为bool?类型
/// </summary>
public static bool? ToBool(this string s)
{
bool? num;
try
{
num = Convert.ToBoolean(s);
}
catch (FormatException formatException)
{
num = null;
}
return num;
} /// <summary>
/// 将字符串转换为bool类型,无法转换抛出异常
/// </summary>
public static bool ToBoolReq(this string s)
{
try
{
bool num = Convert.ToBoolean(s);
return num;
}
catch (FormatException ex)
{
throw new Exception(ex.Message);
}
}
#endregion #region 根据Text转换为Enum
/// <summary>
/// 根据Text转换为Enum?类型
/// </summary>
public static T? ToEnumByText<T>(this string s) where T:struct
{
T? t;
try
{
t = (T) Enum.Parse(typeof (T), s);
}
catch (Exception ex)
{
t = null;
}
return t;
} /// <summary>
///根据Text转换为Enum类型,无法转换抛出异常
/// </summary>
public static T ToEnumReqByText<T>(this string s) where T : struct
{ try
{
T t= (T)Enum.Parse(typeof (T), s);
return t;
}
catch (ArgumentNullException argumentNullException)
{
throw new Exception(argumentNullException.Message);
}
catch (ArgumentException argumentException)
{
throw new Exception(argumentException.Message);
}
catch (OverflowException overflowException)
{
throw new Exception(overflowException.Message);
}
}
#endregion #region 根据Value转换为Enum
/// <summary>
/// 根据Value转换为Enum?类型
/// </summary>
public static T? ToEnumByValue<T>(this int s) where T : struct
{
T? t;
try
{
t = (T)Enum.Parse(typeof(T), s.ToString());
}
catch (Exception ex)
{
t = null;
}
return t;
} /// <summary>
///根据Value转换为Enum类型,无法转换抛出异常
/// </summary>
public static T ToEnumByValueReq<T>(this int s) where T : struct
{ try
{
T t = (T)Enum.Parse(typeof(T), s.ToString());
return t;
}
catch (ArgumentNullException argumentNullException)
{
throw new Exception(argumentNullException.Message);
}
catch (ArgumentException argumentException)
{
throw new Exception(argumentException.Message);
}
catch (OverflowException overflowException)
{
throw new Exception(overflowException.Message);
}
}
#endregion }
}

Helper

分页控件

我用得是PagedList,Nuget里搜索安装PagedList.MVC即可,然后自己封装了一下,封装得在DaoBase里SelectPageList()

为了让这个控件扩展性更强,写了一个分部试图_PageList,定义了一个分页Model,

为什么要自己写个而不是用它自己封装好的,因为后期页码可能需要跳转“首页”,”末页“等

 using PagedList;

 namespace MyFrame.Web.Models
{
public class PageListModel<T> where T:class
{
public IPagedList<T> PageList { get; set; } public string Action { get; set; } public string Controller { get; set; }
}
}

PageListModel

 <div class="page-box">
@if (Model.PageList.HasPreviousPage)
{
<a href="@Url.Action(Model.Action, Model.Controller, new { pageIndex = (Model.PageList.PageNumber - 1) })">上一页</a>
}
@for (int i = ; i <= Model.PageList.PageCount; i++)
{
<a class="@(i == Model.PageList.PageNumber ? "currentpage" : "")" href="@Url.Action(Model.Action, Model.Controller, new { pageIndex = i })">@i</a>
}
@if (Model.PageList.HasNextPage)
{
<a href="@Url.Action(Model.Action, Model.Controller, new { pageIndex = (Model.PageList.PageNumber + 1) })">下一页</a>
}
</div>

_PageList

分页css

 /*分页*/
.page-box{ width:770px; height:40px; background:#FFF; padding-top:15px; text-align:right; padding-right:20px;}
.page-box a{text-decoration: none; padding:3px 7px; display:inline-block; text-align:center; border:1px solid #CFCFCF; color:#666; font-size:12px;}
.page-box a:hover{ background:#A4A4A4; color:#fff;}
.page-box .currentpage{ background:#CCC;}

PageList

怎么调用呢?跟调用分部试图方法一样,只是需要传进一个PageListModel

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MyFrame.Common;
using MyFrame.Domain;
using MyFrame.Dao;
using MyFrame.IDao;
using PagedList; namespace MyFrame.Web.Controllers
{
public class HomeController : Controller
{
private readonly IUserDao _userDao;
private readonly IDriverDao _driverDao;
public HomeController(IUserDao userDao,IDriverDao driverDao)
{
_userDao = userDao;
_driverDao = driverDao;
} public ActionResult Index(int? pageIndex=)
{
IPagedList<Driver> drivers = _driverDao.SelectPageList(pageIndex,);
return View(drivers);
} }
}

Controller

 @using MyFrame.Domain
@using MyFrame.Web.Models
@model PagedList.IPagedList<MyFrame.Domain.Driver>
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
} @foreach (var driver in Model)
{
<p>@driver.Id</p>
<p>@driver.DriverName</p>
<p>@driver.Phone</p> } @Html.Partial("_PageList", new PageListModel<Driver> { PageList = Model, Action = "Index", Controller = "Home" })

Index

Autofac组件

控制反转,类似于Ioc容器的组件,通过配置接口对应具体的实现类

然后调用我们只需要调接口就行了,降低耦合性。

组件Nuget里有自己下载安装就行

在Globl.asax里配置

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using Autofac;
using Autofac.Integration.Mvc;
using MyFrame.Common;
using MyFrame.Dao;
using MyFrame.IDao;
using MyFrame.IService;
using MyFrame.Service; namespace MyFrame.Web
{
// 注意: 有关启用 IIS6 或 IIS7 经典模式的说明,
// 请访问 http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication
{ private void SetupResolveRules(ContainerBuilder builder)
{
//Components are wired to services using the As() methods on ContainerBuilder
builder.RegisterType<UserDao>().As<IUserDao>();
builder.RegisterType<UserService>().As<IUserService>();
builder.RegisterType<DriverDao>().As<IDriverDao>();
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas(); // 依赖注入
var builder = new ContainerBuilder();
SetupResolveRules(builder);
builder.RegisterControllers(Assembly.GetExecutingAssembly());
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
}

通过控制器里的构造方法,调用即可

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MyFrame.Common;
using MyFrame.Domain;
using MyFrame.Dao;
using MyFrame.IDao;
using PagedList; namespace MyFrame.Web.Controllers
{
public class HomeController : Controller
{
private readonly IUserDao _userDao;
private readonly IDriverDao _driverDao;
public HomeController(IUserDao userDao,IDriverDao driverDao)
{
_userDao = userDao;
_driverDao = driverDao;
} public ActionResult Index(int? pageIndex=)
{
IPagedList<Driver> drivers = _driverDao.SelectPageList(pageIndex,);
return View(drivers);
} }
}

其实配置接口对应哪个具体实体的关系,应该放到config文件比较好,这个后期再慢慢优化把。

结尾

这是一个初级版本,后期肯定要再好好完善,比如加入Transaction事务管理,排序,条件查询等等。

大家如果有什么好的建议,尽管提,互相促进互相学习。

转载请注明出处,谢谢!

源代码下载地址:http://yun.baidu.com/share/link?shareid=2761504180&uk=2820969304

上一篇:新浪微博客户端(63)-使用block进行链式编程


下一篇:.NET对象的创建、垃圾回收、非托管资源的手动处理