Topshelf的Ioc实现

在前面使用Topshelf的文章里,我们的工作类TownCrier使用的是无参数的构造函数,满足测试的目的。在实际的开发过程中,我们常常需要使用带有参数的构造函数,就不可避免的使用Ioc的技术。在这里我们使用的是Topshelf.Autofac这个开源框架

1.安装Topshelf.Autofac 

install-package Topshelf.Autofac -Version 3.1.0

2.创建带有参数的TownCrier构造函数类

    public class TownCrier
    {
        readonly Timer _timer;
        private AM am;
        public TownCrier(AM parameter)
        {
            am = parameter;
            _timer = new Timer(1000) { AutoReset = true };
            _timer.Elapsed += (sender, eventArgs) => Console.WriteLine("It is {0} and all is well", DateTime.Now);
        }
        public void Start() { _timer.Start(); }
        public void Stop() { _timer.Stop(); }
    }

    public class AM
    {
        public string Name { get; set; }
    }

这里纯粹是为了进行测试,AM类没有任何其他方法,但可以达到测试的目的。

3.配置Ioc

public static void TestIoc()
        {
            // Autofac
            var builder = new ContainerBuilder();
            builder.RegisterType<TownCrier>();
            builder.RegisterType<AM>();
            var container = builder.Build();

            var rc = HostFactory.Run(x =>                                   //1
            {
                x.Service<TownCrier>(s =>                                   //2
                {
                    s.ConstructUsing(() => container.Resolve<TownCrier>());                //3
                    s.WhenStarted(tc => tc.Start());                         //4
                    s.WhenStopped(tc => tc.Stop());                          //5
                });
                x.RunAsLocalSystem();                                       //6

                x.SetDescription("Sample Topshelf Host");                   //7
                x.SetDisplayName("Stuff");                                  //8
                x.SetServiceName("Stuff");                                  //9
            });                                                             //10

            var exitCode = (int)Convert.ChangeType(rc, rc.GetTypeCode());  //11
            Environment.ExitCode = exitCode;
        }

代码中的红色版本是配置的主要地方,简单2点,一是将涉及到的类,通过RegisterType方法注册进来。二是ConstructUsing函数使用函数表达式container.Resolve方法注册我们的工作类TownCrier。

在测试这段代码的时候,遇见的问题是根据官方提供的demo案例是不对的,根本没有对应的方法,可能是不同版本或者github网站代码和nuget安装代码不是同一份的缘故,反正这里是一个坑。以下是官方Demo:

static void Main(string[] args)
{
    // Create your container
    var builder = new ContainerBuilder();
    builder.RegisterType<SampleDependency>().As<ISampleDependency>();
    builder.RegisterType<SampleService>();
    var container = builder.Build();

    HostFactory.Run(c =>
    {
        // Pass it to Topshelf
        c.UseAutofacContainer(container);

        c.Service<SampleService>(s =>
        {
            // Let Topshelf use it
            s.ConstructUsingAutofacContainer();
            s.WhenStarted((service, control) => service.Start());
            s.WhenStopped((service, control) => service.Stop());
        });
    });
}

以上代码测试通过之后,就对Topshelf.Autofac的依赖注入有了基本了解,就可以着手自己实际业务的Ioc处理了。

实际项目中的应用代码案例:

        public static void RunService()
        {
            // IOC Autofac
            var builder = new ContainerBuilder();
            builder.RegisterAssemblyTypes(Assembly.Load("HengShen.Pts.Domain")).Where(i => i.Namespace == "HengShen.Pts.Domain.Services");
            builder.RegisterAssemblyTypes(Assembly.Load("HengShen.Pts.Domain")).Where(i => i.Namespace == "HengShen.Pts.Domain.TopshelfSevice");
            builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
            builder.RegisterType<SqlUowDbContext>().As<ISqlUnitOfWork>();
            var container = builder.Build();
            
            var rc = HostFactory.Run(x =>                                   //1
            {
                try
                {
                    x.Service<WavePlanSyncService>(s =>                                   //2
                    {
                        s.ConstructUsing(() => container.Resolve<WavePlanSyncService>());
                        s.WhenStarted(tc => tc.Start());
                        s.WhenStopped(tc => tc.Stop()); 
                    });
                    x.RunAsLocalSystem();                                       //6

                    x.SetDescription("Sample Topshelf Host");                   //7
                    x.SetDisplayName("Stuff");                                  //8
                    x.SetServiceName("Stuff");                                  //9
                }
                catch(Exception ex)
                {
                    string m = ex.Message;
                }
            });                                                             //10

            var exitCode = (int)Convert.ChangeType(rc, rc.GetTypeCode());  //11
            Environment.ExitCode = exitCode;
        }

考虑到以后还会有新的task加入,这里就不在一个个的去注册Service类,而是通过程序集的方式将所有的Service一起注册进来,而这些Service类又依赖Repository,所以也将对应的泛型形式注册进来,SqlUowDbContext是Repository要使用的,所以也注册进来。在测试的时候,使用了以下方式的代码,程序报错。原因是这里我们使用的是控制台程序,没有网络请求

builder.RegisterType<SqlUowDbContext>().As<ISqlUnitOfWork>().InstancePerRequest();

改正后的代码是

builder.RegisterType<SqlUowDbContext>().As<ISqlUnitOfWork>();

再编译运行,程序不在出错,打印出我们预先设定的内容,IOC依赖注入处理就此完毕。

原文地址:https://www.cnblogs.com/crazyguo/p/8490681.html