当前位置:网站首页 / C#人爱学不学 / 正文

AY的Castle.Windsor研究笔记

时间:2019年04月04日 | 作者 : aaronyang | 分类 : C#人爱学不学 | 浏览: 1867次 | 评论 0

先研究使用Castle.Windsor5.0

新建控制台4.5Framework的

新建1个类库,放2个接口和2个实现 和一个Main方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ClassLibrary1
{
   
    public interface IDependency1
    {
        object SomeObject { get; set; }
    }
    public interface IDependency2
    {
        object SomeOtherObject { get; set; }
    }
    public class Dependency1 : IDependency1
    {
        public object SomeObject { get; set; }
    }
    public class Dependency2 : IDependency2
    {
        public object SomeOtherObject { get; set; }
    }
    public class Main
    {
        private IDependency1 object1;
        private IDependency2 object2;

        public Main(IDependency1 dependency1, IDependency2 dependency2)
        {
            object1 = dependency1;
            object2 = dependency2;
        }

        public void DoSomething()
        {
            object1.SomeObject = "Hello World";
            object2.SomeOtherObject = "Hello Mars";
        }
    }
}

请注意,构造函数需要两个参数,与接口相同。 这里我们注入依赖项而不是创建每个依赖项的实例。 除非我们还提供两个依赖项,否则我们无法从主类创建对象。

控制台通过nuget 搜索安装Castle.Windsor

 
            var container = new WindsorContainer();
            container.Register(Castle.MicroKernel.Registration.Component.For<ClassLibrary1.Main>());
            container.Register(Castle.MicroKernel.Registration.Component.For<ClassLibrary1.IDependency1>().ImplementedBy<ClassLibrary1.Dependency1>());
            container.Register(Castle.MicroKernel.Registration.Component.For<ClassLibrary1.IDependency2>().ImplementedBy<ClassLibrary1.Dependency2>());

            // CREATE THE MAIN OBJECT AND INVOKE ITS METHOD(S) AS DESIRED.
            var mainThing = container.Resolve<ClassLibrary1.Main>();
            mainThing.DoSomething();

image.png

打上断点,开始调试

image.png

我们通过构造函数注入方式,把两个接口 都赋值上了对应的实现。


我们把这种行为叫做 IOC,不要记什么依赖注入了。

这种,要在客户端,使用 注册 这种行为(接口和实现对应绑定上),都是老套路,比如 配置文件方式绑定,或者硬代码 绑定。 注入:构造函数,属性,方法参数。然后就是绑定时候指定生命周期,或者名称。


DEMO1  默认生命周期,在Resolve一下,还是上次的实例

image.png

结论1: 

 可以直接注册一个单例类 container.Register(Castle.MicroKernel.Registration.Component.For<一个类>());


结论2:

注册接口和实现 container.Register(Castle.MicroKernel.Registration.Component.For<接口1>().ImplementedBy<接口1的实现>());

image.png

默认也是单例


结论3:

可以指定生命周期方式,常用:Transient和Singleton,Transient是每次请求都创建一个新实例,Singleton是单例,他们都是LifeStyle的属性


image.png

测试

image.png


结论4: 同接口多个实现 可以取 name获得不同的示例

image.png


上面是一些1对1 自己知道类型和实现的 注册,那么默认 已某种规则注册呢,比如 知道接口类型,不知道有多少个实现


DEMO2

   var cTypes =
                from t in Assembly.GetExecutingAssembly().GetTypes()
                where typeof(ClassLibrary1.IDependency1).IsAssignableFrom(t)
                select t;
            foreach (var t in cTypes)
                container.Register(Component.For(t).LifeStyle.Transient);

从当前程序集找到 实现IDependency1接口的所有子类,然后注册


当然 我们的接口在另一个类库,也就是另一个程序集了。

Assembly.GetExecutingAssembly()是获取当前运行的程序集

加载其他程序集

     var _clpath = System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), "ClassLibrary1.dll");

            Assembly ass = Assembly.LoadFrom(_clpath);


正常我们都是通过IWindsorInstaller方法Install统一注册,初始化castle的windsor相关的方法

where指定了同命名空间下的

  public class AyCastleWindsorInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            var _clpath = System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), "ClassLibrary1.dll");
            Assembly ass = Assembly.LoadFrom(_clpath);
            container.Register(Classes.FromAssembly(ass)
                               .Where(Component.IsInSameNamespaceAs<ClassLibrary1.IDependency1>())
                               .WithService.DefaultInterfaces()
                               .LifestyleTransient());
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "AY windsor研究学习";
            var container = new WindsorContainer();
            container.Install(FromAssembly.This());
            var d2_1 = container.Resolve<ClassLibrary1.IDependency1>();
            var d2_2 = container.Resolve<ClassLibrary1.IDependency1>();
            if (d2_1.GetHashCode() == d2_2.GetHashCode())
            {
                Console.WriteLine("单例");
            }
            else
            {
                Console.WriteLine("不是单例");
            }
                     Console.ReadKey();
    }
    
    }

指定 命名空间:InNamespace("ClassLibrary1")


image.png

你也可以在install方法里面单独 一个一个的注册

这里过滤条件是: 和IDependency1一个命名空间下的类型,然后进行自动注册的。然后声明周期是Transient,所以 每次请求都是一个新对象。

所以这里不是单例。

换成 LifestyleSingleton就是单例了。

image.png

竟然能注册,你当然可以写成配置文件方式了,自己映射。

打断点查看,一目了然了。

image.png

如上我测试了Dispose方法,发现调用完了,还是没释放container的,下面还是可以resolve拿到对象的。不管了。



与按照规则批量注册类似,差别在于每个程序集内部自己实现一个IWindsorInstaller接口来定义注册规则。也就是将注册规则下放到程序集。

首先,需要指定对哪些程序集进行安装注册(只指定对程序集的搜索规则):

container.Install(FromAssembly.InDirectory(new AssemblyFilter("Extensions")));//Extensions目录下的所有程序集。



时间 2019-4-4 10:58

关于Install方法的FromAssembly类型,F12进去,有很多方法,感兴趣自己折腾下。

image.png


当然,也支持配置,

image.png

那么配置文件怎么写?

新建app.config(如果你没有的话)

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler,Castle.Windsor" />
  </configSections>
  <castle>
    <components>
      <component id="ide1" service="ClassLibrary1.IDependency1,ClassLibrary1" type="ClassLibrary1.Dependency1,ClassLibrary1">
      </component>
    </components>
  </castle>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
  </startup>
</configuration>

测试

image.png

接下来修改实现,增加默认值

image.png

修改配置

image.png

然后运行,

image.pngimage.png

这是根据配置文件中的name来拿到的对象,那么声明周期怎么指定呢?默认是单例

      <component id="ide11" service="ClassLibrary1.IDependency1,ClassLibrary1" type="ClassLibrary1.Dependency11,ClassLibrary1" lifestyle="Transient">
      </component>

image.png

lifestyle="singleton|thread|transient|pooled|custom" 

当然还可以指定参数,然后给实例的属性赋值

首先我们修改Main方法

  public class Main
    {
        private IDependency1 object1;
        private IDependency2 object2;

        public int Haha { get; set; }
        public void WriteHaha()
        {
            Console.WriteLine(Haha);
        }
        public Main(IDependency1 dependency1, IDependency2 dependency2)
        {
            object1 = dependency1;
            object2 = dependency2;
        }

        public void DoSomething()
        {
            object1.SomeObject = "Hello World";
            object2.SomeOtherObject = "Hello Mars";
        }

    }

image.png

由于上面依赖了 IDependency2,所以必须给这个服务也注册进去。我们添加了Haha参数

修改客户端app.config

 <components>
      <component id="ide1" service="ClassLibrary1.IDependency1,ClassLibrary1" type="ClassLibrary1.Dependency1,ClassLibrary1">
      </component>
      <component id="ide11" service="ClassLibrary1.IDependency1,ClassLibrary1" type="ClassLibrary1.Dependency11,ClassLibrary1" lifestyle="Transient">
      </component>
      <component id="ide2" service="ClassLibrary1.IDependency2,ClassLibrary1" type="ClassLibrary1.Dependency2,ClassLibrary1">
      </component>
      <component id="aymain" type="ClassLibrary1.Main,ClassLibrary1">
        <parameters>
          <Haha>2019</Haha>
        </parameters>
      </component>
    </components>

我们默认实例给了Haha这个属性,一个2019的值

image.png

我们已经自动实例了Main对象,这里2019通过配置方式赋值上去的,由于单例,任意地方都是这个对象的。

image.png


IWindsorContainer container = new WindsorContainer("a.config");

或通过Install方法

container.Install(

    Configuration.FromXmlFile("a.config"));


其实写到这里,已经过去了很久,自己百度加上 F12看源码,或者下载Castle.Core源码溯源,或者看单元测试用例。才写出上面这点内容。AY继续


Windsor很强大的,源码阅读难度对我来说很大了,很难搞懂。


随着慢慢发现,Facility这个知识点也很多,官方源码提供了

image.png

举个网上能找到的例子,比如Logging


我AY编译了Tests项目,在bin文件夹下

image.png

找到了常用的2种日志方式,一个是log4net的,一个nlog

image.png

这里用log4net测试,拷贝,这2个dll到项目,并且引用他

image.png

image.png

项目通过nuget引用log4net类库

然后新建一个log4net.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!--日志配置部分-->
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
  </configSections>
  <log4net>
    <root>
      <priority value="All" />
      <appender-ref ref="FileAppender" />
      <appender-ref ref="InfoLoging" />
    </root>
    <appender name="FileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="log\\log.txt" />
      <appendToFile value="true" />
      <maxSizeRollBackups value="10" />
      <maximumFileSize value="10000KB" />
      <rollingStyle value="Size" />
      <staticLogFileName value="true" />
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="ERROR" />
        <levelMax value="ERROR" />
      </filter>
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
      </layout>
    </appender>
    <appender name="InfoLoging" type="log4net.Appender.RollingFileAppender">
      <file value="log\\logData.txt" />
      <appendToFile value="true" />
      <maxSizeRollBackups value="10" />
      <maximumFileSize value="10000KB" />
      <rollingStyle value="Size" />
      <staticLogFileName value="true" />
      <filter type="log4net.Filter.LevelRangeFilter">
        <levelMin value="INFO" />
        <levelMax value="INFO" />
      </filter>
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
      </layout>
    </appender>
  </log4net>
</configuration>

然后增加AddFacility 添加到容器中

container.AddFacility<LoggingFacility>(f => f.LogUsing<Castle.Services.Logging.Log4netIntegration.Log4netFactory>()
            .WithConfig("log4net.config"));

我是通过它的单元测试看到的,Nlog方式的自己看

image.png

拷贝过来,使用运行时候,Logging会报错的,引用的Castle.Windsor的版本有问题,它要0.0.0.0的,实际上我们是5.0

我只能把它源码拷贝过来,也就3个文件

image.png


然后新建一个类,顶部放上一个ILogger

image.png

    public class SimpleLoggingComponent
    {
        private ILogger logger;

        public SimpleLoggingComponent(ILogger logger)
        {
            this.logger = logger;
        }

        public void TestLog()
        {
            Logger.Error("Ay测试日志Error");
            Logger.Debug("Ay测试日志Debug的");
        }

        public ILogger Logger
        {
            get { return logger; }
        }
    }

image.png

测试使用代码如下:

     var container = new WindsorContainer();
            //container.Install(FromAssembly.This());
            container.Install(Configuration.FromAppConfig());

            container.AddFacility<LoggingFacility>(f => f.LogUsing<Castle.Services.Logging.Log4netIntegration.ExtendedLog4netFactory>()
            .WithConfig("log4net.config"));

            container.Register(Component.For(typeof(SimpleLoggingComponent)).Named("component"));
            var test = container.Resolve<SimpleLoggingComponent>("component");
            test.TestLog();

运行demo后,会输出日志了,至于日志的 控制,自己学习log4net怎么用的就行了。

image.png

由于这里我只对Error和Info输出的,所以自己能理解的。

image.png

关于Windsor就讲研究到这里了,当然这东西和 Asp.Net MVC还有Wcf配合 DEMO都是有的,自己折腾下就差不多了。


它目前Core也支持了,老项目了,很值得学习。

AY先这样了。

====================www.ayjs.net       杨洋    wpfui.com        ayui      ay  aaronyang=======请不要转载谢谢了。=========




自己的其他文章:写给自己的Castle.NET 4.0笔记[1]






推荐您阅读更多有关于“C#IOC,”的文章

猜你喜欢

额 本文暂时没人评论 来添加一个吧

发表评论

必填

选填

选填

必填

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

  查看权限

抖音:wpfui 工作wpf,目前主maui

招聘合肥一枚WPF工程师,跟我一个开发组,10-15K,欢迎打扰

目前在合肥市企迈科技就职

AYUI8全源码 Github地址:前往获取

杨洋(AaronYang简称AY,安徽六安人)AY唯一QQ:875556003和AY交流

高中学历,2010年开始web开发,2015年1月17日开始学习WPF

声明:AYUI7个人与商用免费,源码可购买。部分DEMO不免费

不是从我处购买的ayui7源码,我不提供任何技术服务,如果你举报从哪里买的,我可以帮你转正为我的客户,并送demo

查看捐赠

AYUI7.X MVC教程 更新如下:

第一课 第二课 程序加密教程

标签列表