简介
Ninject是一个轻量级的基于.Net平台的依赖注入框架,用来解决程序中组件的耦合问题,它的目的在于做到最少配置。其他的的IOC工具过于依赖配置文件,导致配置文件过于复杂,容易出现错误 。但,Ninject不能进行热插拔。
使用
使用Ninject都需要引入Ninject.dll服务,Ninject框架官网。
下面用一个多个数据库之间切换的Demo讲解Ninject。
Ninject(无配置文件使用)
数据访问层代码:一个IDalUser接口,两个类(调用SqlServer数据库的类和调用Mysql数据库的类)继承此接口
<span style="font-family:KaiTi_GB2312;font-size:18px;"> public interface IDalUser
{
void AddUser();
}</span>
<span style="font-family:KaiTi_GB2312;font-size:18px;"> public class MysqlUserDal:IDalUser
{
public void AddUser()
{
Console.WriteLine("你好,我是Mysql数据库!");
}
}</span>
<span style="font-family:KaiTi_GB2312;font-size:18px;"> public class SqlServerUserDal:IDalUser
{
public void AddUser() {
Console.WriteLine("你好,我是SqlServer数据库!");
}
}</span>
最重要的部分,使用ninject绑定接口和实现。
<span style="font-family:KaiTi_GB2312;font-size:18px;">public class DataResolver
{
//得到对应的D层方法
private static DataResolver _Instance;
public static DataResolver Instance
{
get
{
if (_Instance == null)
{
_Instance = new DataResolver();
}
return _Instance;
}
}
IKernel ninjectKernel;
private DataResolver()
{
ninjectKernel = new StandardKernel();
//将接口和实现类绑定
</span><p> //Named:表示具有指定名称的绑定。名称不一定是唯一的;对于给定的服务的多个绑定可以以相同的名称注册。
ninjectKernel.Bind<IDalUser>().To<MysqlUserDal>().Named(DataBaseOptions.Mysql.ToString());
ninjectKernel.Bind<IDalUser>().To<SqlServerUserDal>().Named(DataBaseOptions.SqlServer.ToString());
}
public T Resolve<T>(string sql) where T : class
{</p><p> //得到某个接口的实例
return ninjectKernel.Get<T>(sql);
}
}</p>
客户端只需要得到用户想要使用的数据库,就可以调用相应的方法了。
<span style="font-family:KaiTi_GB2312;font-size:18px;">static void Main(string[] args)
{
//调用接口,无需知道具体的类,就可以调用D层的方法了
var dalUser = DataResolver.Instance.Resolve<IDalUser>(DataBaseOptions.SqlServer.ToString());
dalUser.AddUser();
Console.Read();
}</span>
输出结果:Ninject(使用配置文件)
Ninject使用配置文件是它的一个扩展功能,需要引用扩展组件(Ninject.Extensions.Xml)。使用配置文件的方法数据访问层代码和不使用配置文件的一样。
配置文件,此处的配置文件要将其属性“复制到输出目录”设置成“始终复制”或者“如果较新则复制”:
<span style="font-family:KaiTi_GB2312;font-size:18px;"><?xml version="1.0"?>
<!--下面的名称必须配置-->
<configuration name="ServiceModule">
<!--使用Mysql数据库-->
<!--<bind name="IDalUser" service="DAL.IDalUser,DAL" to="DAL.MysqlUserDal,DAL"/>-->
<!--使用SqlServer数据库-->
<bind name="IDalUser" service="DAL.IDalUser,DAL" to="DAL.SqlServerUserDal,DAL"/>
</configuration></span>
读取配置文件的类:
<span style="font-family:KaiTi_GB2312;font-size:18px;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ninject;
using Ninject.Extensions.Xml;
using Ninject.Extensions.Xml.Handlers;
using System.Xml.Linq;
namespace ConsoleConfigNinject
{
public class DataResolver
{
protected readonly IDictionary<string, IXmlElementHandler> elementHandlers;
protected readonly XmlModule module = null;
private static DataResolver _Instance;
public static DataResolver Instance
{
get
{
if (_Instance == null)
{
_Instance = new DataResolver();
}
return _Instance;
}
}
IKernel kernel;
public DataResolver()
{
kernel = new StandardKernel();
//读取配置文件
elementHandlers = new Dictionary<string, IXmlElementHandler> { { "bind", new BindElementHandler(kernel) } };
//配置文件的名称
var document = XDocument.Load("app.config");
module = new XmlModule(document.Element("configuration"), elementHandlers);
module.OnLoad(kernel);
}
public static IKernel GetKernel()
{
return Instance.kernel;
}
}
}</span>
客户端调用:
<span style="font-family:KaiTi_GB2312;font-size:18px;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DAL;
using Ninject;
namespace ConsoleConfigNinject
{
class Program
{
static void Main(string[] args)
{
var kernel = DataResolver.GetKernel();
//得到IDalUser接口的实例
var iUser = kernel.Get<IDalUser>();
iUser.AddUser();
Console.Read();
}
}
}
</span>
拓展:抽象工厂+反射
这种使用配置文件切换数据库的方法和抽象工厂+反射很类似。
配置文件:
<span style="font-family:KaiTi_GB2312;font-size:18px;"><?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings >
<!--使用Sqlserver数据库-->
<add key="DB" value="Sqlserver"/>
<!--使用Mysql数据库-->
<!--<add key="DB" value="Mysql"/>-->
</appSettings>
</configuration></span>
中间类:读取配置文件
<span style="font-family:KaiTi_GB2312;font-size:18px;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using System.Configuration; //引入反射的语句
namespace 抽象工厂模式
{
class DataAccess
{
private static readonly string db = ConfigurationManager.AppSettings["DB"]; //表示读配置文件
private static readonly string AssemblyName = "抽象工厂模式";
public static IUser CreateUser()
{
string className = AssemblyName + "." + db + "User";
return (IUser)Assembly.Load(AssemblyName).CreateInstance(className);
}
}
}</span>
客户端:
<span style="font-family:KaiTi_GB2312;font-size:18px;"> static void Main(string[] args)
{
//直接得到实际的数据库访问实例,而不存在任何依赖
IUser iu = DataAccess.CreateUser();
iu.AddUser();
Console.Read();
}</span>
总结
无论是ninject的两种方法,还是抽象工厂+反射的方法,都是通过中间类和配置文件得到需要的类名,让客户端可以访问业务逻辑层或者数据访问层的方法,都达到了解耦和的目的。无配置文件,需要从客户端或者其他地方设置参数,用来选择数据库;有配置文件,通过配置文件配置,选择数据库。Ninject不使用配置文件的操作过程:
Ninject使用配置文件和抽象工厂+反射的操作过程:
其实,Ninject做的事情很简单,说白了就是为我们选择一个想要的类来处理事务。Ninject不仅可以绑定同一个接口的多个实现,或同一个类的多个派生类,并在不同条件下绑定不同的类。还可以用一个类来触发另一个类的操作和添加属性等功能。
Ninject常用方法属性简介
1.Bind<T1>().To<T2>()
接口IKernel的方法,把某个类绑定到某个接口或抽象类,T1代表的就是接口或者抽象类,而T2代表的就是其实现类
2.Get<ISomeInterface>()
得到某个接口的实例
3.Bind<T1>() .To<T2>(). WithPropertyValue('SomeProprity',value);
在绑定接口的实例时,同时给实例的属性赋值
4.ninjectKernel.Bind<T1>().To<T2>(). WithConstructorArgument('someParam',value);
为实例的构造方法所用的参数赋值
5.Bind<T1>().ToConstant()
绑定到某个已经存在的常量
6.Bind<T1>().ToSelf()
绑定到自身,但是这个绑定的对象只能是具体类,不能是抽象类。绑定到自身的目的是为了能够利用Ninject解析对象本身。
7.Bind<T1>().To<T2>().WhenInjectedInto<instance>()
条件绑定,只有当注入的对象是某个对象的实例时才会将绑定的接口进行实例化