Fork me on GitHub
企业应用微型Windows服务架构

企业应用微型Windows服务架构

 

背景:质量检测集团企业内部有N多系统,这些系统之间有关联性并相互协作,很多业务需要Windows服务大显身手

举例:客户通过网站下定单 > 企业内部收到客户快递的样品在实验室系统登记 > 实验室系统检测 > 实验室系统出具检测报告 > 客户通过浏览器查看报告

运用Windows服务进行:

  • 报告文件同步
  • 对客户的短信、邮件通知
  • 对内部工作人员进行短信、邮件通知
  • 进行分公司内网与公共服务器数据同步

  ……

以上只是一个例子,实际情况要复杂的多,很多个服务放在一起运行、维护很不方便,混乱不堪,如何通过一种巧妙的方式进行管理、部署、监控,让管理人员可操作性更强呢?博主写了一个小程序来达到上面的要求,请大家指点一二。

技术点:

  • XML读写
  • 多线程
  • 反射
  • Windows服务安装卸载脚本

思路:

  1. windows服务项目是一个装载服务的容器,它负责配置并调用功能组件
  2. 提供一个统一的编程接口,使后续所有的功能组件都需要实现这个接口方便服务容器去调用
  3. 植入功能组件:实现以上接口并单独做自己的事情,与其他功能组件互不相干
  4. 放到Windows服务容器,配置组件信息(执行间隔,程序集名称,类名等)

以上模式有点像一个多媒体播放器程序,自身提供了解析mp3,mp4,wma,rmvb等格式的功能

播放器就是一个装载容器,解析媒体文件格式的组件就相当于插件

当有一种新的媒体格式比如(flv)诞生后,开发者们可以实现播放器提供的接口并解析这种(flv)媒体文件,然后通过配置文件添加到播放器目录即可

当播放器要播放flv的文件,就会去加载解析flv的组件

每一种对媒体格式的解析组件互不影响,这符合松耦合、工厂模式的设计思想

废话说到这里,贴代码:

接口:

1 public interface IRun
2     {
3         void Run();
4     }

 

配置文件Config.xml,配置程序集的执行时间间隔,程序集名称,类名

复制代码
 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <Configuration>
 3   <!--
 4   assembly:程序集名称
 5   class:类名
 6   method:固定Run(),默认为Run,对应类需要实现接口IRun并实现Run()
 7   -->
 8   <AssemblyConfig>
 9       <Assembly Interval="30000" Assembly="FCL.Monitor" Class="Monitor" />
10       <Assembly Interval="30000" Assembly="FCL.Monitor" Class="Monitor_Vancl" />
11       <Assembly Interval="30000" Assembly="FCL.Monitor" Class="CreateNotify" />
12       <Assembly Interval="30000" Assembly="FCL.Monitor" Class="CreateNotify_Vancl" />
13       <Assembly Interval="1000" Assembly="FCL.Email" Class="SendEmail" />
14   </AssemblyConfig>
15 </Configuration>
复制代码

容器加载后需要构造的实体类

复制代码
 1     public class AssemblyInfo
 2     {
 3         /// <summary>
 4         /// 执行间隔
 5         /// </summary>
 6         public int Interval { get; set; }
 7 
 8         /// <summary>
 9         /// 程序集名称
10         /// </summary>
11         public string AssemblyName { get; set; }
12         /// <summary>
13         /// 类名
14         /// </summary>
15         public string ClassName { get; set; }
16         /// <summary>
17         /// 方法名
18         /// </summary>
19         public readonly string MethodName = "Run";
20     }
复制代码

服务启动需要加载已经配置的程序集

复制代码
 1         /// <summary>
 2         /// 服务启动
 3         /// </summary>
 4         /// <param name="args"></param>
 5         protected override void OnStart(string[] args)
 6         {
 7             Log.log.Info(DateTime.Now + " 服务启动");
 8 
 9             //读取xml配置
10             DataSet ds = new DataSet();
11             ds.ReadXml(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.xml"));
12             DataTable dt = ds.Tables[1];
13             List<AssemblyInfo> assemblyInfoList = new List<AssemblyInfo>();
14             AssemblyInfo assemblyInfo;
15             foreach (DataRow row in dt.Rows)
16             {
17                 assemblyInfo = new AssemblyInfo();
18                 assemblyInfo.AssemblyName = row["Assembly"].ToString();
19                 assemblyInfo.ClassName = row["Class"].ToString();
20                 assemblyInfo.Interval = Convert.ToInt32(row["Interval"]);
21                 assemblyInfoList.Add(assemblyInfo);
22 
23                 Log.log.Info(DateTime.Now
24                        + " 程序集名称:" + assemblyInfo.AssemblyName
25                        + ",类名:" + assemblyInfo.ClassName
26                        + ",执行间隔:" + assemblyInfo.Interval);
27             }
28 
29             //加载XML程序集配置
30             ExcuteAssembly.ExcuteListAssembly(assemblyInfoList);
31         }
复制代码


以及相关用线程、反射执行程序集

复制代码
    public class ExcuteAssembly
    {
        /// <summary>
        /// 执行批量程序集
        /// </summary>
        /// <param name="assemblyList">程序集集合</param>
        public static void ExcuteListAssembly(List<AssemblyInfo> assemblyList)
        {
            try
            {
                Thread thread;
                foreach (AssemblyInfo item in assemblyList)
                {
                    thread = new Thread(new ParameterizedThreadStart(ExcuteSingleAssembly));
                    thread.IsBackground = true;
                    thread.Start(item);
                }
            }
            catch (Exception ex)
            {
                Log.log.Error(DateTime.Now + " 创建多个线程时: " + ex.Message);
            }
        }

        /// <summary>
        /// 执行单个程序集
        /// </summary>
        /// <param name="obj">程序集</param>
        public static void ExcuteSingleAssembly(object obj)
        {
            while (true)
            {
                try
                {
                    AssemblyInfo assembly = obj as AssemblyInfo;
                    Thread.Sleep(assembly.Interval);

                    Log.log.Debug("ExcuteSingleAssembly:" + (assembly as AssemblyInfo).AssemblyName);
                    if (assembly != null && assembly is AssemblyInfo)
                    {
                        Assembly a = Assembly.Load(assembly.AssemblyName);
                        //Type规则:命名空间名称=程序集名
                        Type type = a.GetType(assembly.AssemblyName + "." + assembly.ClassName);
                        Log.log.Debug("Type:" + type.ToString());
                        IRun run = (IRun)Activator.CreateInstance(type);
                        MethodInfo method = type.GetMethod(assembly.MethodName);
                        Log.log.Debug("MethodInfo:" + method.ToString());
                        BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
                        method.Invoke(run, flags, Type.DefaultBinder, null, null);
                    }
                }
                catch (Exception ex)
                {
                    Log.log.Error(DateTime.Now + " 执行程序集时出错: " + ex.Message);
                }
            }
        }
    }
复制代码

以上就是服务容器的核心代码,下面贴一个组件代码

复制代码
 1     /// <summary>
 2     /// 监测ERP数据库的单据状态,并生成消息日志
 3     /// </summary>
 4     public class Monitor : IRun
 5     {
 6         public void Run()
 7         {
 8             new DAL.Sys_ApplyFormNotifyLog().CreateNotify();
 9         }
10     }
复制代码

关于服务的安装运行卸载也写了批处理

安装:

echo 清理原有服务项. . .
%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\installutil /U FCL.WinService.exe
echo 清理完毕,开始安装后台服务. . .
%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\installutil FCL.WinService.exe
echo 服务安装完毕
pause

启动:

echo 启动服务. . .
net start FCLService
pause

停止:

echo 停止服务. . .
net stop FCLService
pause

到此结束,程序里有很多需要改进之处,使程序更加灵活、稳定、强壮,请大家多多指点。

 

 
 
 
posted on 2013-05-16 21:21  HackerVirus  阅读(279)  评论(0编辑  收藏  举报