对依赖注入或控制反转不了解的童鞋请先自行学习一下这一设计,这里直接介绍项目和实现步骤。

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

目录:

一、介绍

二、纯C#使用Grace的Demo

三、ASP.NET Core使用Grace的Demo

四、ASP.NET MVC使用Grace的Demo

五、多个构造方法

结尾

一、介绍

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介绍的更多相关文章

  1. Ninject是一款.Net平台下的开源依赖注入框架

    Ninject是一款.Net平台下的开源依赖注入框架.按照官方说法,它快如闪电.超级轻量,且充分利用了.Net的最新语法,使用Lambda表达式代替Xml文件完成类型绑定.Ninject结构精巧,功能 ...

  2. Spring.NET依赖注入框架学习--简单对象注入

    Spring.NET依赖注入框架学习--简单对象注入 在前面的俩篇中讲解了依赖注入的概念以及Spring.NET框架的核心模块介绍,今天就要看看怎么来使用Spring.NET实现一个简单的对象注入 常 ...

  3. [ASP.NET Core 3框架揭秘] 依赖注入[4]:一个Mini版的依赖注入框架

    在前面的章节中,我们从纯理论的角度对依赖注入进行了深入论述,我们接下来会对.NET Core依赖注入框架进行单独介绍.为了让读者朋友能够更好地理解.NET Core依赖注入框架的设计与实现,我们按照类 ...

  4. ASP.NET MVC IOC依赖注入之Autofac系列(一)- MVC当中应用

    话不多说,直入主题看我们的解决方案结构: 分别对上面的工程进行简单的说明: 1.TianYa.DotNetShare.Model:为demo的实体层 2.TianYa.DotNetShare.Repo ...

  5. Android Dagger依赖注入框架浅析

    今天接触了Dagger这套android的依赖注入框架(DI框架).感觉跟Spring 的IOC差点儿相同吧.这个框架它的优点是它没有採用反射技术(Spring是用反射的),而是用预编译技术.因为基于 ...

  6. 依赖注入及AOP简述(四)——“好莱坞原则”和依赖注入框架简介 .

    3.2.    “好莱坞原则” 看了前面关于依赖注入概念的描述,我们来提炼出依赖注入的核心思想.如果说传统的组件间耦合方式,例如new.工厂模式等,是一种由开发者主动去构建依赖对象的话,那么依赖注入模 ...

  7. Spring 之 控制反转(IoC), 依赖注入(DI)和面向切面(AOP)

    关于依赖注入, 这篇博文写的非常简单易懂. https://github.com/android-cn/blog/tree/master/java/dependency-injection 此外, 博 ...

  8. .net core程序中使用微软的依赖注入框架

    我之前在博文中介绍过Asp.net core下系统自带的依赖注入框架,这个依赖框架在Microsoft.Extensions.DependencyInjection中实现,本身并不是.net core ...

  9. Spring.NET依赖注入框架学习--简介

    Spring.NET依赖注入框架学习--Spring.NET简介 概述 Spring.NET是一个应用程序框架,其目的是协助开发人员创建企业级的.NET应用程序.它提供了很多方面的功能,比如依赖注入. ...

随机推荐

  1. Nagios HTTP WARNING: HTTP/1.1 403 Forbidden

    当我们第一次搭建好nagios后会有Nagios HTTP WARNING: HTTP/1.1 403 Forbidden告警 要解决这个问题, 可以创建一个html文件,然后重启两个服务,等待几分钟 ...

  2. ssh免密钥登陆的两种方式

    ssh 免密钥登陆的两种方式第一种:直接使用命令复制过去ssh-copy-id root@192.168.3.113批量复制for i in {113..140}; do ssh-copy-id ro ...

  3. 五种IO模型

    参考文档 https://www.jianshu.com/p/486b0965c296 概念说明 用户空间和内核空间        现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空 ...

  4. FileInputFormat 的实现之TextInputFormat

    说明 TextInputFormat默认是按行切分记录record,本篇在于理解,对于同一条记录record,如果被切分在不同的split时是怎么处理的.首先getSplits是在逻辑上划分,并没有物 ...

  5. 2019t1_sumdoc_list.txt aa.docx acc baidu v2 sbb.docx Acc jindon v2 sbb.docx assetsList.html Atiitt 日本刑法典读后笔记.docx Atiti 遇到说花心的时候赞美应对.docx Atitit lesson.docx Atitit malye主义、mzd思想和dsp理论的区别和联系.docx Ati

    2019t1_sumdoc_list.txtaa.docxacc baidu v2 sbb.docxAcc jindon v2 sbb.docxassetsList.htmlAtiitt 日本刑法典读 ...

  6. ios 报错 Invalid row height provided by table delegate. Value must be at least 0.0, or UITableViewAutomaticDi......

    Invalid row height provided by table delegate. Value must be at least 0.0, or UITableViewAutomaticDi ...

  7. 人脸识别(基于ArcFace)

    我们先来看看效果 上面是根据图片检测出其中的人脸.每个人脸的年龄还有性别,非常强大 第一步: 登录https://ai.arcsoft.com.cn/,注册开发者账号,身份认证,注册应用,得到APPI ...

  8. EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器启用https服务申请免费证书

    背景分析 目前想在 web 上使用 HTTPS 的话, 你需要获得一个证书文件, 该证书由一个受浏览器信任的公司所签署. 一旦你获得了它, 你就在你的 web 服务器上指定其所在的位置, 以及与你关联 ...

  9. 设计模式php+java版本(1) 基础篇 七大原则

    2019年9月6日11:15:46 关于设计模式,其实就是编程思想的一个体现,有比较完善的编程思想写出的项目代码和没有编程思想的写出的差距巨大,代码的可读性,可维护性,可扩展性天差地别,有些刚接触的编 ...

  10. istio1.0安装

    1. istio1.0安装 创建 istio 目录 [root@centos-110 ~]# mkdir istio [root@centos-110 ~]# cd istio 1.1 获取安装包 链 ...