基本:服务定位器和依赖注入使用了微软的MircroSoft.Practices.Unity框架.
目的:配合asp.net mvc 3实现一套框架,封装变化,松耦合,依赖注入但不使用配置文件.
思想:使用MircroSoft.Practices.Unity容器注册接口与实例的关系.对外,仅能访问接口,而实例通过容器/注入获得.
基本代码原型:
1.声明一个对外接口
public interface ILogin { bool IsLogin(); }
internal class LoginAdapter : ILogin { public bool IsLogin() { //实现 } }注意: public与internal,把变化封装在LoginAdapter中,外部仅能访问到ILogin.
3.注册LoginAdapter到容器
IUnityContainer unityContainer = new UnityContainer(); unityContainer.RegisterType<ILogin>(new ContainerControlledLifetimeManager());
var instance = unityContainer.Resolve<ILogin>();
至此便是服务定位器的基本使用原型,下面加入依赖注入.
5.使用依赖注入
public class TestUnity { [Dependency] public ILogin Login { get; set; } }
Dependency标签为Login属性注入一个实例,实现此注入的前提是该属性所在类必须是由容器解析的,不然空有Dependency标签,却不能有LoginAdpater的实例. 5.解析TestUnityTestUnity tu = unityContainer.Resolve<TestUnity>();这样TestUnity的属性Login便有了一个LoginAdapter的实例.
接下来是我已经实现的整套框架,框架内采用反射的方式自动注册接口与实例的关系而不需要配置文件.
1.创建一个单例接口
public interface ISingletonRegister { }
2.创建一个弱引用接口public interface IWeakReferenceRegister { }以上两个接口是用来识别是否需要注册某对象的实例.3.创建一个容器的单例
public static class MyUnityContainer { private static IUnityContainer _current; private static readonly object Locker = new object(); public static IUnityContainer Current { get { if (_current == null) { lock (Locker) { if (_current == null) { _current = new UnityContainer(); } } } return _current; } } } 在整个应用程序中,我创建了一个唯一的容器实例,保证所有对像实例都存在此容器中,便于解析.4.创建注册工厂public static class MyDependencyFactory { private static readonly ILog Logger = LogManager.GetLogger(typeof(MyDependencyFactory)); /// <summary> /// auto register all instance for unitycontainer /// created by lihui 20110322 /// </summary> public static void RegisterDependency() { //所有DLL路径 var dllPaths = Directory.GetFiles(HttpContext.Current.Server.MapPath("/bin"), "*.dll"); //所有类型 var typeList = dllPaths.Select(path => { try { return Assembly.LoadFrom(path); } catch (Exception exp) { #if DEBUG throw exp; #endif Logger.Error(string.Format("IOC注册时,加载程序集[{0}]出错!", path), exp); return (Assembly)null; } } ).Where(a => a != null).Select(a => { try { return a.GetTypes(); } catch (Exception exp) { //#if DEBUG // throw exp; //#endif Logger.Error(string.Format("IOC注册时,获取程序集[{0}]内所有类型时出错!", a.GetName().Name), exp); return new Type[] { }; } }).SelectMany(ts => ts).Where( t => t.IsInterface == false); //所有ISingletonRegister类型 var iSingletonRegisterTypeList = typeList.Where( t => t.FindInterfaces((tt, o) => o.Equals(tt), typeof(ISingletonRegister)).Length > 0); //所有IWeakReferenceRegister类型 var iWeakReferenceRegisterTypeList = typeList.Where( t => t.FindInterfaces((tt, o) => o.Equals(tt), typeof(IWeakReferenceRegister)).Length > 0); //注册ISingletonRegister类型 foreach (var t in iSingletonRegisterTypeList) { var implementInterfaceList = t.FindInterfaces((tt, o) => !o.Equals(tt), typeof(ISingletonRegister)); foreach (var iType in implementInterfaceList) { MyUnityContainer.Current.RegisterType(iType, t, new ContainerControlledLifetimeManager());//使用频繁,单例 #region =DebugChecker created by lihui 2010707= if (t.BaseType != typeof(BaseDebugChecker)) continue; var checker = (BaseDebugChecker)MyUnityContainer.Current.Resolve(iType); checker.IsDebug(); #endregion } } //注册IWeakReferenceRegister类型 foreach (var t in iWeakReferenceRegisterTypeList) { var implementInterfaceList = t.FindInterfaces((tt, o) => !o.Equals(tt), typeof(IWeakReferenceRegister)); foreach (var iType in implementInterfaceList) { MyUnityContainer.Current.RegisterType(iType, t, new ExternallyControlledLifetimeManager());//不经常使用的,弱引用 #region =DebugChecker created by lihui 2010707= if (t.BaseType != typeof(BaseDebugChecker)) continue; var checker = (BaseDebugChecker)MyUnityContainer.Current.Resolve(iType); checker.IsDebug(); #endregion } } } } 此工厂会把所有实现ISingletonRegister和IWeakReferenceRegister的类注册到容器.工厂中有个DebugChecker,是用来检测DLL是否是DEBUG编译的,如果是则抛出异常.详细DebugChecker的详细代码稍后贴出.5.创建一个新的MVC的ControllerFactory,用于替换MVC默认ControllerFactory.
public class MyDependencyMvcControllerFactory : DefaultControllerFactory { protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType) { if (controllerType == null) { throw new HttpException(404, String.Format( CultureInfo.CurrentUICulture, "没有找到路由{0}", requestContext.HttpContext.Request.Path)); } if (!typeof(IController).IsAssignableFrom(controllerType)) { throw new ArgumentException( String.Format( CultureInfo.CurrentUICulture, "{0}该类型没有继承ControllerBase", controllerType), "controllerType"); } try { return (IController)MyUnityContainer.Current.Resolve(controllerType); } catch (Exception ex) { throw new InvalidOperationException( String.Format( CultureInfo.CurrentUICulture, "{0}创建该controller失败!", controllerType), ex); } } }
此工厂中将所有mvc中Controller的创建通过容器来解析,便于dependency的注入.6.最后在global中配置整个应用程序,将所有组件串联起来实现框架.
protected void Application_Start() { MktDependencyFactory.RegisterDependency(); ControllerBuilder.Current.SetControllerFactory(new MyDependencyMvcControllerFactory()); }RegisterDependency就是注册接口与实例的关系.setCongrollerFactory则是用MyDependencyMvcControllerFactory替代默认Controller工厂
到此为止,整个框架配置完毕,下面将基本代码原型改成新的框架:
1.声明一个对外接口
public interface ILogin { bool IsLogin(); }2.声明一个实现ILogin的内部类internal class LoginAdapter : ILogin,ISingletonRegister { public bool IsLogin() { //实现 } }3.在asp.net mvc中的Controller中使用public class HomeController:Controller { [Dependency] public ILogin Login { get; set; } public ActionResult Index() { var b = Login.IsLogin(); } }
配置简单:对于想要注册的类,只需要让它实现ISingletonRegister或IWeakReferenceRegister,便会自动注册.使用简单:只需要加一个Dependency标签,便把LoginAdapter的实便注入到了属性Login中.
在此Controller中也仅能访问ILogin接口,对于LoginAdapter的实现则看不到,这样既封装了变化,又降低了耦合度.此框架不仅仅用于asp.net MVC中,任何软件程序都可以使用.