游刃于MVC、WCF中的Autofac

时间:2023-03-09 04:23:06
游刃于MVC、WCF中的Autofac

为了程序的健壮性、扩展性、可维护性,依赖抽象而不是具体实现类等等,于是我选择了Autofac依赖注入容器 就是这个工厂来降低耦合。之前买东西是自己去超市,现在呢 我需要什么东西,他们给送过来直接拿到了。

 本例中将会分享

1.Autofac在Mvc的Controller控制器、Filter过滤器的使用

2.WCF中的使用

3.用Autofac来完成Unit Of Work工作单元模式 即同一个界限上下文内可以共享同一个工作单元实例。这样就可以统一提交,起到事务作用、数据统一性。一个http请求只有一个上下文实例也算是性能优化吧, 在这里只用到工作单元的一些皮毛。

Demo全貌如下

游刃于MVC、WCF中的Autofac

  •  Autofac.DataModel 采用database first的实体数据模型
  •  Autofac.Repository 实体泛型的仓储模式 ,也可以简单的理解是数据层
  •  Autofac.CoreService 业务逻辑处理
  •  Autofac.UnitOfWork 工作单元统一提交 
  •  Autofac.Controllers 控制器层是从Web层把所有控制器提取出来,这里用到区域Area
  •  AutoFac.Web 前端采用的是MVVM模式的knockout.js ,还有autofac的配置
  •  Autofac.ViewModel 视图

  其中Repository、UnitOfWork、CoreService几者之间调用接口或对供其他层调用接口。

  从nuget获取必要的Autofac程序包 Autofac、Autofac.Configuration、Autofac.Integration.Mvc、Autofac.Integration.Wcf

各个层依赖的是接口而不是具体实现类,Autofac是个工厂可以通过编译的代码xml配置文件两种方式指定接口、实现类来完成注入实例。

这里用的是xml配置的方式,需要用到Autofac.Configuration程序集。这样做有个明显的好处:文件不需要编译;不会扰乱各层关系。为什么这么说呢?如果用代码来完成,web层就需要其他层的接口和实现类 也就是引用Repository、UnitOfWork、CoreService层,很明显web层只需要引用Autofac.Controllers  就足够了。而通过xml配置文件可以在bin目录下找到具体的程序集如:Autofac.CoreService.dll

Autoface依赖注入在MVC里实现

Global.cs    

protected void Application_Start()
{
//创建IOC容器
AutofacRegistion.BuildMvcContainer();
AutofacRegistion.BuildWcfContainer();
AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
/// <summary>
/// 依赖注入Controller、FilterAtrribute、WCF
/// </summary>
public class AutofacRegistion
{
/// <summary>
/// 创建 MVC容器(包含Filter)
/// </summary>
public static void BuildMvcContainer()
{
var builder = new ContainerBuilder();
//注册Module方法2 在Web.config中配制方式
builder.RegisterModule(new ConfigurationSettingsReader("autofacMvc"));
//加载 *.Controllers 层的控制器,否则无法在其他层控制器构造注入,只能在web层注入
Assembly[] asm = GetAllAssembly("*.Controllers.dll").ToArray();
builder.RegisterAssemblyTypes(asm);
//注册仓储
Assembly[] asmRepository = GetAllAssembly("*.Repository.dll").ToArray();
builder.RegisterAssemblyTypes(asmRepository)
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces();

        //注入逻辑层也可以通过配置实现
        //Assembly[] asmRepositoryService = GetAllAssembly("*.CoreService.dll").ToArray();
        //builder.RegisterAssemblyTypes(asmRepositoryService).AsImplementedInterfaces();

            builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
builder.RegisterModelBinderProvider(); //注册过滤器
builder.RegisterFilterProvider();
builder.RegisterType<OperateAttribute>().PropertiesAutowired();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
/// <summary>
///创建WCF的容器,不存放Controller、Filter
/// </summary>
public static void BuildWcfContainer()
{
var builder = new ContainerBuilder();
builder.RegisterModule(new ConfigurationSettingsReader("autofacWcf"));
builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
builder.RegisterModelBinderProvider();
var container = builder.Build();
//WCF IOC容器
AutofacHostFactory.Container = container;
//DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
} #region 加载程序集
public static List<Assembly> GetAllAssembly(string dllName)
{
List<string> pluginpath = FindPlugin(dllName);
var list = new List<Assembly>();
foreach (string filename in pluginpath)
{
try
{
string asmname = Path.GetFileNameWithoutExtension(filename);
if (asmname != string.Empty)
{
Assembly asm = Assembly.LoadFrom(filename);
list.Add(asm);
}
}
catch (Exception ex)
{
Console.Write(ex.Message);
}
}
return list;
}
//查找所有插件的路径
private static List<string> FindPlugin(string dllName)
{
List<string> pluginpath = new List<string>(); string path = AppDomain.CurrentDomain.BaseDirectory;
string dir = Path.Combine(path, "bin");
string[] dllList = Directory.GetFiles(dir, dllName);
if (dllList.Length > )
{
pluginpath.AddRange(dllList.Select(item => Path.Combine(dir, item.Substring(dir.Length + ))));
}
return pluginpath;
}
#endregion }

说明:

1 web.config还需要配置 globlal代码中对应的【autofacMvc】和【autofacWcf】节点

2 反射*.Controllers.dll获取 Autofac.Controllers程序集,实现注入

3 反射*.Repository.dll获取 Autofac.Repository程序集 以'Repository'结尾的类的实例注入到它所继承的接口,这个就不需要在xml中配置

4 filter的注入和controller的注入方式不一样

5 MVC和WCF注入实例分别存到两个容器中。这就用到Autofac.Integration.Mvc、Autofac.Integration.Wcf两个程序集。WCF注入的容器中不需要Controller、Filter,就可以把相关的反射和注册去掉了。

web.config

<configSections>
<!-- autofac配置-->
<section name="autofacMvc" type="Autofac.Configuration.SectionHandler, Autofac.Configuration" />
<section name="autofacWcf" type="Autofac.Configuration.SectionHandler, Autofac.Configuration" />
</configSections>
<autofacMvc>
<files>
<file name="configs/CoreService.config" section="autofac" />
</files>
</autofacMvc>
<autofacWcf>
<files>
<!--<file name="configs/IocDAL.config" section="autofac" />-->
</files>
</autofacWcf>
<!--↑↑↑↑autofac配置结束↑↑↑↑-->

在上述webconfig中为了统一管理配置,具体指定接口、实现类、和注入实例的生命周期放到了configs/CoreService.config文件中

CoreService.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="autofac" type="Autofac.Configuration.SectionHandler, Autofac.Configuration"/>
</configSections>
<autofac>
<components>
<!--DbContext上下文的生命周期为【per-lifetime-scope】即http请求的生命周期 -->
<component type="Autofac.DataModel.VehicleCheckDBEntities, Autofac.DataModel"
service="System.Data.Entity.DbContext, EntityFramework"
instance-scope="per-lifetime-scope"/>
<component type="Autofac.UnitOfWork.UnitOfWork, Autofac.UnitOfWork" service="Autofac.UnitOfWork.IUnitOfWork, Autofac.UnitOfWork" /> <component type="Autofac.CoreService.Impl.UserManage, Autofac.CoreService" service="Autofac.CoreService.IUserManage, Autofac.CoreService" />
<component type="Autofac.CoreService.Impl.RoleManage, Autofac.CoreService" service="Autofac.CoreService.IRoleManage, Autofac.CoreService" />
</components>
</autofac>
</configuration>

说明:

1 component组件配置中type、service配置的是实现类、程序集名称(不是命名空间)、接口、程序集名称。

2 instance-scope 配置的是实例的生命周期。本例中用到两种:一是默认的调用一次创建一次;二是一个http请求会共享一个实例,期间会多次用到,但只有一个实例。这个就是工作单元的核心了。instance-scope="per-lifetime-scope"类型共享DbContext的上下文实例。

参考官网 http://docs.autofac.org/en/latest/configuration/xml.html#additional-config-files

注入方式

MVC、WCF下是通过构造方法注入,Filter过滤器是通过访问器get set注入,下面有具体区别。

Controller和其他层的构造注入

public class HomeController : Controller
{
private readonly IUserManage _userManage;
private IRoleManage _roleManage;
public HomeController(IUserManage userManage, IRoleManage roleManage)
{
_userManage = userManage;
_roleManage = roleManage;
}
}

Filter过滤器的注入取得实例

public class OperateAttribute : ActionFilterAttribute
{
public IUserManage UserManage { get; set; }
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
//Do Something...
var user =UserManage.LoadUser();
if (user == null)
{
filterContext.Result = new JsonResult
{
Data=new{message="不合法操作,未能进入"},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
}

WCF注入

<!-- wcf服务文件 -->
<%@ ServiceHost
Language="C#"
Debug="true"
Service="CypApp.VehicleWeb.Services.IAutofacService,CypApp.VehicleWeb"
Factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf"
%>
//契约的实现类服务
/// <summary>
/// Autofac wcf注入
/// </summary>
public class AutofacService : IAutofacService
{
private readonly IInspectorBc _functionBc;
//构造函数依赖注入
public AutofacService(IInspectorBc functionBc)
{
_functionBc = functionBc;
}
public void DoWork()
{
_functionBc.GetCompanyIdByInspectorId();
}
}
}
/// <summary>
/// EntityFramework仓储操作基类
/// </summary>
/// <typeparam name="TEntity">动态实体类型</typeparam>
public class EFRepositoryBase<TEntity> : IRepository<TEntity> where TEntity : class,new()
{
public EFRepositoryBase(DbContext context)
{
Context = context;
}
public DbContext Context { get; set; } public void Dispose()
{
if (Context==null)return;
Context.Dispose();
Context = null;
GC.SuppressFinalize(this);
}
public IQueryable<TEntity> Entities()
{
return Context.Set<TEntity>().AsQueryable();
}
//Delete、Update等等
}
public sealed class UnitOfWork : IUnitOfWork
{
/// <summary>
/// The DbContext
/// </summary>
private DbContext _dbContext; /// <summary>
/// Initializes a new instance of the UnitOfWork class.
/// </summary>
/// <param name="context">The object context</param>
public UnitOfWork(DbContext context)
{ _dbContext = context;
} /// <summary>
/// Saves all pending changes
/// </summary>
/// <returns>The number of objects in an Added, Modified, or Deleted state</returns>
public int Commit()
{
// Save changes with the default options
return _dbContext.SaveChanges();
} /// <summary>
/// Disposes the current object
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
} /// <summary>
/// Disposes all external resources.
/// </summary>
/// <param name="disposing">The dispose indicator.</param>
private void Dispose(bool disposing)
{
if (disposing)
{
if (_dbContext != null)
{
_dbContext.Dispose();
_dbContext = null;
}
}
}
}
//业务逻辑处理
public class UserManage : IUserManage
{
private readonly IUserRepository _userRepository;
private readonly IUserRoleRepository _userRoleRepository;
private IUnitOfWork _unitOfWork;
public UserManage(IUserRepository userRepository, IUserRoleRepository userRoleRepository,IUnitOfWork unitOfWork)
{
_userRepository = userRepository;
_userRoleRepository = userRoleRepository;
_unitOfWork = unitOfWork;
}
/// <summary>
/// 添加、修改 User
/// </summary>
/// <param name="userModel"></param>
/// <param name="message"></param>
/// <returns></returns>
public bool SaveUser(UserModel userModel , out string message)
{
message = null; var userEntity = new Sys_User
{
UserName = userModel.UserName,
Password = userModel.Password,
UserTrueName = userModel.UserTrueName,
CreateDate = DateTime.Now, };
//添加用户
if (userModel.Id < )
{
_userRepository.Insert(userEntity);
_unitOfWork.Commit();
if (userEntity.Id < )
{
message = "添加用户失败";
return false;
}
}
//修改操作
else
{
//删除用户角色关系
var userRoleIdArray = _userRoleRepository.Entities()
.Where(m => m.UserId == userModel.Id)
.Select(s => s.Id).ToList();
foreach (var roleId in userRoleIdArray)
{
_userRoleRepository.Delete(new Sys_User_Roles {Id = roleId});
}
}
var userRoles = new List<Sys_User_Roles>();
foreach (var roleId in userModel.Role)
{
userRoles.Add(new Sys_User_Roles { UserId = userModel.Id, RoleId = roleId });
}
//添加用户角色关系
_userRoleRepository.Insert(userRoles);
return _unitOfWork.Commit() > ;
}

批量删除、批量添加操作只是映射,并未提交,只有Commit后才会保存数据。各个类拿到的DbContext是同一个实例,因此统一提交整个上下文状态才起到了作用。

仓储和工作单元都有销毁方法, 每次调用仓储类和工作单元类, 都会从IOC容器取到共享实例Dbcontext,当处理完业务后会把这些拿到的Dbcontext实例销毁掉。

共享Demo

AutoFac.7z

作者:HsutonWang

出处:http://www.cnblogs.com/AntonWang/p/4192119.html/

本文版权归作者和博客园共有,欢迎转载