C#下IOC/依赖注入框架Grace介绍
对依赖注入或控制反转不了解的童鞋请先自行学习一下这一设计,这里直接介绍项目和实现步骤。
Grace是一个开源、轻巧、易用同时特性丰富、性能优秀的依赖注入容器框架。从这篇IOC容器评测文章找到的Grace,评测显示这款开源轻巧的框架性能挺成熟优秀的,但是中文资料几乎找不到,作者文档也不多,Get Started在各种项目中的案例也没有。这里贴一下介绍和纯后台以及ASP.NET Core的使用Demo,部分翻译自项目,更多内容可以直接看项目的Readme和Tests——Tests作者分类很好,可以作为需求切入点了解。
作者:Ian Johnson
主项目Nuget:https://www.nuget.org/packages/Grace/
主项目Github:https://github.com/ipjohnson/Grace
ASP.Net Core Nuget: https://www.nuget.org/packages/Grace.AspNetCore.MVC
ASP.Net Core Github:https://github.com/ipjohnson/Grace.DependencyInjection.Extensions
目录:
一、介绍
Grace有如下特性:
- 配置提供允许最大限度扩展的流式(Fluent)接口/属性
- 支持子容器和轻量级生命周期作用域
- 支持绑定上下文化(类似NInject)
- 容器创建的IDisposable对象将被跟踪和释放,除非另有配置
- 性能特点使它成为最快的容器之一
- 支持特殊类型
- IEnumerable<T> - 支持将集合解析为IEnumerable<T>,包括其他如List<T>,ReadOnlyCollection<T>,T[]和其他实现ICollection<T>的集合。具体可以查看这里,可以实现批量自动注册绑定。
- Func<T> - 支持自动解析Func<T>
- Lazy<T> - 当解析一个Lazy<T>对象时,其将在自己创建的生命周期内创建和解析对象T
- Owned<T> - 在一个Owned<T>对象内解析时,其将有与自己Owned<T>相关联的生命周期(与Autofac类似)
- Meta<T> - 在一个Meta<T>内解析时,其元数据也会跟着解析
- 自定义委托 - 任何返回一个类型的委托都能被自动解析
- 用Grace.Factory自定义接口
- 支持多种生命周期,包括单例、作用域内单例、请求内单例(MVC4, MVC5 和 WCF 扩展包中)、对象图内单例、基类上单例和弱单例。如果以上都没有符合需求的,可以使用ICompiledLifeStyle接口实现
- 内置支持装饰器设计
- 支持自定义包装(Func<T>和Meta<T>是内置包装的举例)
- ASP.Net Core支持(测试似乎只支持.Net Standard 1.0,DotNetCore 2.0Linux下不行)
- ASP.Net MVC 4 & 5支持
二、纯C#使用Grace的Demo
假设我们有Repository和Service模式,有用户(User)和账户(Account)这两个DAO对象,分别如下定义好接口和类,此部分在附件的“IOCFramework.Dao”工程中。
public interface IAccountRepository
{
string Get();
} public class AccountRepository : IAccountRepository
{
public string Get()
{
return "[Account]简单注册调用[Repo]";
}
} public interface IAccountService
{
string Get();
} public class AccountService : IAccountService
{
IAccountRepository _accountRepository;
public AccountService(IAccountRepository accountRepository)
{
_accountRepository = accountRepository;
} public string Get()
{
return _accountRepository.Get() + "[Service]";
}
} public interface IUserRepository
{
string Get();
} public class UserRepositoryA : IUserRepository
{
public string Get()
{
return "[User]键值注册调用A[Repo]";
}
} public class UserRepositoryB : IUserRepository
{
public UserRepositoryB(string param1, string param2)
{
Console.WriteLine($"Ctor param1:{param1}");
} public string Get()
{
return "[User]键值注册调用B[Repo]";
}
} public interface IUserService
{
string Get();
} public class UserService : IUserService
{ IUserRepository _userRepository; public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
} public string Get()
{
return _userRepository.Get() + "[Service]";
}
}
接下来可以使用源码也可以添加Nuget的方式添加Grace。下面的代码实现了纯C#的容器的注册和实现,过程简单,看注释即可,不在赘述,此部分在附件的“IOCFramework.Demo”工程中。
public static void Exec()
{
//容器
var container = new DependencyInjectionContainer(); container.Configure(m =>
{
//这里演示如何简单注册同一个接口对应其实现
m.Export<AccountRepository>().As<IAccountRepository>();
m.Export<AccountService>().As<IAccountService>(); //这里演示如何使用键值注册同一个接口的多个实现
m.Export<UserRepositoryA>().AsKeyed<IUserRepository>("A");
//这里同时演示使用带参数构造器来键值注册
m.Export<UserRepositoryB>().AsKeyed<IUserRepository>("B").WithCtorParam<string>(() => { return "kkkkk"; }); //这里演示依赖倒置而使用构造器带键值注入
m.Export<UserService>().As<IUserService>().WithCtorParam<IUserRepository>().LocateWithKey("B");
}); //获取简单注册实例
var accountRepo = container.Locate<IAccountRepository>();
Console.WriteLine(accountRepo.Get());//输出:[Account]简单注册调用[Repo]
var accountSvc = container.Locate<IAccountService>();
Console.WriteLine(accountSvc.Get());//输出:[Account]简单注册调用[Repo][Service] Console.WriteLine(); //获取指定键值的实例
var userRepo = container.Locate<IUserRepository>(withKey: "A");
Console.WriteLine(userRepo.Get());//输出:[User]键值注册调用A[Repo] var userSvc = container.Locate<IUserService>();//输出:Ctor param1:kkkkk
Console.WriteLine(userSvc.Get());//输出:[User]键值注册调用B[Repo][Service]
}
三、ASP.NET Core使用Grace的Demo
此部分Demo在附件的“WebCoreApplicationUseGrace”工程中。
1. 先在项目中添加Grace.AspNetCore.Hosting包。依赖项有Grace包和Grace.DependencyInjection.Extensions包,也可以使用这里的源码:https://github.com/ipjohnson/Grace.DependencyInjection.Extensions。
2. 然后在Program.cs添加Grace组件:
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseKestrel()
.UseIISIntegration()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseGrace() //添加Grace
.UseStartup<Startup>()
.Build();
3. 在Startup.cs中添加方法ConfigureContainer方法,然后在IInjectionScope里面注册接口和类型,具体看下面代码。这里可以将Startup.cs修改为部分类而单独将ConfigureContainer方法放于新建的Startup.cs部分类中,方便以后添加配置
public partial class Startup
{
// 添加此方法
public void ConfigureContainer(IInjectionScope scope)
{
scope.Configure(m =>
{
//这里演示如何简单注册同一个接口对应其实现
m.Export<AccountRepository>().As<IAccountRepository>();
m.Export<AccountService>().As<IAccountService>(); //这里演示如何使用键值注册同一个接口的多个实现
m.Export<UserRepositoryA>().AsKeyed<IUserRepository>("A");
//这里同时演示使用带参数构造器来键值注册
m.Export<UserRepositoryB>().AsKeyed<IUserRepository>("B").WithCtorParam<string>(() => { return "kkkkk"; }); //这里演示依赖倒置而使用构造器带键值注入
m.Export<UserService>().As<IUserService>().WithCtorParam<IUserRepository>().LocateWithKey("B");
}); scope.SetupMvc();//这一句需先添加Grace.AspNetCore.MVC
}
}
4. Grace提供了自定义控制器和视图激活器,用一些自定义特性提供了更好的性能。这里添加Grace.AspNetCore.MVC Nuget包/源码项目,然后在上一步方法中添加scope.SetupMvc(),至此配置完毕。
5. 在控制器中使用方法如下。一般的可以使用构造器参数方式赋值实例,有特殊注入的(如下面带键值的注入)可以先实例IExportLocatorScope出来,再用其Locate来获得实例。
public class HomeController : Controller
{
//IExportLocatorScope可以获取从InjectionScope和LifeTimeScope注入的类型实例
IExportLocatorScope locator; IAccountRepository accountRepo;
IAccountService accountSvc;
IUserRepository userRepo;
IUserService userSvc; public HomeController(IExportLocatorScope locator, IAccountRepository accountRepo, IAccountService accountSvc, IUserService userSvc)
{
this.locator = locator;
//获取简单注册实例
this.accountRepo = accountRepo;
this.accountSvc = accountSvc;
//获取指定键值的实例
this.userRepo = this.locator.Locate<IUserRepository>(withKey: "A");
this.userSvc = userSvc; } public IActionResult Index()
{
return Json(new
{
accountRepoGet = accountRepo.Get(),
accountSvcGet = accountSvc.Get(),
userRepoGet = userRepo.Get(),
userSvcGet = userSvc.Get(),
});
} }
以上代码输出如下:
{
"accountRepoGet": "[Account]简单注册调用[Repo]",
"accountSvcGet": "[Account]简单注册调用[Repo][Service]",
"userRepoGet": "[User]键值注册调用A[Repo]",
"userSvcGet": "[User]键值注册调用B,Ctor param1:kkkkk[Repo][Service]"
}
四、ASP.NET MVC使用Grace的Demo
Grace支持ASP.NET MVC4和MVC5,这里以MVC5为例,此部分Demo在附件的“WebCoreApplicationUseGrace”工程中。
1. 先在项目中添加Grace.MVC5包,依赖项有Grace包。也可以使用这里的源码:https://github.com/ipjohnson/Grace.MVC。
2. 新建一个类,用于配置注册接口及其实现
public class DependencyInjectionScope
{
public static DependencyInjectionContainer GetContainer()
{
//容器
var container = new DependencyInjectionContainer();
container.Configure(m =>
{
//这里演示如何简单注册同一个接口对应其实现
m.Export<AccountRepository>().As<IAccountRepository>();
m.Export<AccountService>().As<IAccountService>(); //这里演示如何使用键值注册同一个接口的多个实现
m.Export<UserRepositoryA>().AsKeyed<IUserRepository>("A");
//这里同时演示使用带参数构造器来键值注册
m.Export<UserRepositoryB>().AsKeyed<IUserRepository>("B").WithCtorParam<string>(() => { return "kkkkk"; }); //这里演示依赖倒置而使用构造器带键值注入
m.Export<UserService>().As<IUserService>().WithCtorParam<IUserRepository>().LocateWithKey("B");
}); return container;
}
}
3. 在Global.asax.cs中MvcApplication类的Application_Start方法指定MVC的控制器实例工厂为Grace的DisposalScopeControllerActivator,至此配置完毕。
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles); //获取注册容器
var graceIocContainer = DependencyInjectionScope.GetContainer();
//MVC指定Grace的工厂为控制器实例工厂
ControllerBuilder.Current.SetControllerFactory(new DisposalScopeControllerActivator(graceIocContainer));
}
}
4. 在控制器中使用方法如下。一般的可以使用构造器参数方式赋值实例,有特殊注入的(如下面带键值的注入)可以先实例IExportLocatorScope出来,再用其Locate来获得实例。
public class HomeController : Controller
{
//IExportLocatorScope可以获取从InjectionScope和LifeTimeScope注入的类型实例
IExportLocatorScope locator; IAccountRepository accountRepo;
IAccountService accountSvc;
IUserRepository userRepo;
IUserService userSvc; public HomeController(IExportLocatorScope locator, IAccountRepository accountRepo, IAccountService accountSvc, IUserService userSvc)
{
this.locator = locator;
//获取简单注册实例
this.accountRepo = accountRepo;
this.accountSvc = accountSvc;
//获取指定键值的实例
this.userRepo = this.locator.Locate<IUserRepository>(withKey: "A");
this.userSvc = userSvc; } public ActionResult Index()
{
return Json(new
{
accountRepoGet = accountRepo.Get(),
accountSvcGet = accountSvc.Get(),
userRepoGet = userRepo.Get(),
userSvcGet = userSvc.Get(),
}, JsonRequestBehavior.AllowGet);
}
}
以上代码输出如下:
{
"accountRepoGet": "[Account]简单注册调用[Repo]",
"accountSvcGet": "[Account]简单注册调用[Repo][Service]",
"userRepoGet": "[User]键值注册调用A[Repo]",
"userSvcGet": "[User]键值注册调用B,Ctor param1:kkkkk[Repo][Service]"
}
五、多个构造方法
Grace支持多个构造函数,当然是单一构造函数注入的,有相关Tests可以参考:https://github.com/ipjohnson/Grace/blob/master/tests/Grace.Tests/Classes/Simple/MultipleConstructorImport.cs
在以下代码中有两个构造方法,Grace选了最多参数的构造方法进行Import,这里构造方法的继承语句(: this(userSvc))是无关的,用不用都可以。
public class MultipleConstructorImportService : IMultipleConstructorImportService
{
IUserService userSvc;
IAccountService accountSvc;
public MultipleConstructorImportService(IUserService userSvc)
{
this.userSvc = userSvc; Console.WriteLine($"构造函数1:userSvc:{this.userSvc != null}, accountSvc: {this.accountSvc != null}");
//输出:构造函数1:userSvc:True, accountSvc: False
} public MultipleConstructorImportService(IAccountService accountSvc, IUserService userSvc)
: this(userSvc)
{
//this.userSvc = userSvc;
this.accountSvc = accountSvc; Console.WriteLine($"构造函数2:userSvc:{this.userSvc != null}, accountSvc: {this.accountSvc != null}");
//输出:构造函数2:userSvc:True, accountSvc: True
} }
结尾:
Grace的其他特性用法可以参看项目的Tests例子和项目里面的Wiki,后面有时间再慢慢贴上来咯。这里给大家附上文章的源码Demo或者查看GitHub项目
C#下IOC/依赖注入框架Grace介绍的更多相关文章
- Ninject是一款.Net平台下的开源依赖注入框架
Ninject是一款.Net平台下的开源依赖注入框架.按照官方说法,它快如闪电.超级轻量,且充分利用了.Net的最新语法,使用Lambda表达式代替Xml文件完成类型绑定.Ninject结构精巧,功能 ...
- Spring.NET依赖注入框架学习--简单对象注入
Spring.NET依赖注入框架学习--简单对象注入 在前面的俩篇中讲解了依赖注入的概念以及Spring.NET框架的核心模块介绍,今天就要看看怎么来使用Spring.NET实现一个简单的对象注入 常 ...
- [ASP.NET Core 3框架揭秘] 依赖注入[4]:一个Mini版的依赖注入框架
在前面的章节中,我们从纯理论的角度对依赖注入进行了深入论述,我们接下来会对.NET Core依赖注入框架进行单独介绍.为了让读者朋友能够更好地理解.NET Core依赖注入框架的设计与实现,我们按照类 ...
- ASP.NET MVC IOC依赖注入之Autofac系列(一)- MVC当中应用
话不多说,直入主题看我们的解决方案结构: 分别对上面的工程进行简单的说明: 1.TianYa.DotNetShare.Model:为demo的实体层 2.TianYa.DotNetShare.Repo ...
- Android Dagger依赖注入框架浅析
今天接触了Dagger这套android的依赖注入框架(DI框架).感觉跟Spring 的IOC差点儿相同吧.这个框架它的优点是它没有採用反射技术(Spring是用反射的),而是用预编译技术.因为基于 ...
- 依赖注入及AOP简述(四)——“好莱坞原则”和依赖注入框架简介 .
3.2. “好莱坞原则” 看了前面关于依赖注入概念的描述,我们来提炼出依赖注入的核心思想.如果说传统的组件间耦合方式,例如new.工厂模式等,是一种由开发者主动去构建依赖对象的话,那么依赖注入模 ...
- Spring 之 控制反转(IoC), 依赖注入(DI)和面向切面(AOP)
关于依赖注入, 这篇博文写的非常简单易懂. https://github.com/android-cn/blog/tree/master/java/dependency-injection 此外, 博 ...
- .net core程序中使用微软的依赖注入框架
我之前在博文中介绍过Asp.net core下系统自带的依赖注入框架,这个依赖框架在Microsoft.Extensions.DependencyInjection中实现,本身并不是.net core ...
- Spring.NET依赖注入框架学习--简介
Spring.NET依赖注入框架学习--Spring.NET简介 概述 Spring.NET是一个应用程序框架,其目的是协助开发人员创建企业级的.NET应用程序.它提供了很多方面的功能,比如依赖注入. ...
随机推荐
- 【cf比赛记录】Codeforces Round #600 (Div. 2)
Codeforces Round #600 (Div. 2) ---- 比赛传送门 昨晚成绩还好,AC A,B题,还能上分(到底有多菜) 补了C.D题,因为昨晚对C.D题已经有想法了,所以补起题来也快 ...
- Honk's pool[STL multiset]
目录 题目地址 题干 代码和解释 题目地址 Honk's pool(The Preliminary Contest for ICPC Asia Shenyang 2019 ) 题干 代码和解释 本题使 ...
- mlocate比find快很多的查找命令
mlocate比find快很多的查找命令 使用linux操作系统的人,一般都用过文件查找命令find,在文件数量非常庞大的时候,比如在高通的android工程项目中,目录大小有十几个G,文件数量非常多 ...
- Netty 4 实现一个 NettyClient
本文章为作者原创,有问题的地方请提出指正. 1.类继承Diagram 2.定义EndPoint类 目前仅仅定义了2个方法,分别用来获取本地或远程服务器的地址. package netty; impor ...
- 使用 atom 将 makedown 编辑并转换成 pdf
链接: https://www.cnblogs.com/fanzhidongyzby/p/6637084.html
- javafx这些学会后,开发就不难了,往tablecloumn列中添加按钮,修改javafx中tableview中tablecell中的值,修改完回车表示保存到内存中
javafx开发过程中遇见难题,往tablecloumn列中添加按钮 想了很久的方法,也配有办法判断每行中有数据的地方添加按钮set bank_caozuo.setCellFactory((col)- ...
- 【翻译】FlinkCEP-Flink的复杂事件处理
本文翻译自官网:FlinkCEP - Complex event processing for Flink FlinkCEP是在Flink之上实现的复杂事件处理(CEP)库. 它使您可以检测无穷无尽的 ...
- 元素高度变化使用动画transition
高度变化,使用transition,没有效果,可以使用max-height替换. 思路: 初始元素max-height:0; 不显示,父元素hover时,重新设置元素的max-height的值, 可以 ...
- Android File Transfer Mac: 如何在 macOS 和 Android 系统之间移动数据
三大 Mac OS X 系统 Android 文件传输软件 谷歌出品的 Android File Transfer 如何在 Mac 系统上使用 Android File Transfer Androi ...
- (转) 解决django项目部署到nginx+uwsgi服务器后 admin页面样式消失的问题
原贴地址:https://blog.csdn.net/qq_42571805/article/details/80862455 摘要 uwsgi为主要服务器,nginx为反向代理服务器部署完成之后发现 ...