首页 > 代码库 > C#编写Windows服务程序 (服务端),客户端使用 消息队列 实现淘宝 订单全链路效果

C#编写Windows服务程序 (服务端),客户端使用 消息队列 实现淘宝 订单全链路效果

需求: 针对 淘宝提出的 订单全链路 产品接入 .http://open.taobao.com/doc/detail.htm?id=102423&qq-pf-to=pcqq.group

         oms(订单管理系统) 实现  , 完成后 效果:在千牛工作台 --订单全链路  可看到效果如下图

 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

目标: 客户端 使用消息队列 将订单信息保存, 服务端使用  Windows服务 ,将消息队列中的订单信息 通过淘宝api 上传到淘宝.


一、创建一个Windows Service

 1)创建Windows Service项目

 


2)对Service重命名

将Service1重命名为你服务名称,这里我们命名为TradeTraceService。

二、创建服务安装程序

1)添加安装程序


之后我们可以看到上图,自动为我们创建了ProjectInstaller.cs以及2个安装的组件。

2)修改安装服务名

右键serviceInsraller1,选择属性,将ServiceName的值改为TradeTraceService。

  

  • 补充:

1.Service启动属性:

        Manual      服务安装后,必须手动启动。

        Automatic    每次计算机重新启动时,服务都会自动启动。

        Disabled     服务无法启动。

3)修改安装权限

右键serviceProcessInsraller1,选择属性,将Account的值改为LocalSystem。

  三、创建 类库 封装方法(用于:将消息队列中数据 通过淘宝api上传到淘宝 ),写入服务代码

1) 创建类库 


2) 创建接口 和对应实现 


3) 代码展示 

   ITradeTraceService.cs 

   

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

namespace TradeTrace.Service
{
    [ServiceContract]
    public interface ITradeTraceService
    {
        /// <summary>
        /// 把订单信息插入到队列里
        /// </summary>
        /// <param name="orderSource"></param>
        /// <param name="orderNum"></param>
        /// <param name="status"></param>
        /// <param name="createtime"></param>
        [OperationContract(IsOneWay = true)]
        void Insert(int orderSource, string orderNum, int status, DateTime createtime );
    }
}
   TradeTraceService.cs

using ECERP.FrameWork.Log;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;

namespace TradeTrace.Service
{
    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single)]
    public class TradeTraceService : ITradeTraceService
    {
        public void Insert(int orderSource, string orderNum, int status, DateTime createtime)
        {
            Logger.Info(string.Format("[淘宝订单 全链路]读取店铺:{0},订单:{1},状态:{2}", orderSource, orderNum, status));
            DateTime dt = DateTime.Now;
            if (string.IsNullOrEmpty(orderNum) || orderNum == "0" ||orderSource==0)
            {
                Logger.Info(string.Format("[淘宝订单 全链路]发布消息 时读取到 异常单号:{0},店铺:{1},时间:{2}", orderNum, orderSource, dt));
                return;
            }
            try
            {
                var list = ECERP.AddIn.ShopService.ShopList;
                var shop = list.FirstOrDefault(c => c.ID == orderSource);
                //var shop = ECERP.Service.ShopService.Instance.GetShopByID(orderSource);
                if (shop != null)
                {
                    ECERP.AddIn.TaoBao.Service.TradeTraceService trace = new ECERP.AddIn.TaoBao.Service.TradeTraceService(shop);
                    trace.TradeTraceMessageProduce(orderNum, status, createtime);

                    Logger.Info("OrderNum:" + orderNum + "  createtime:" + createtime + " OrderSource:" + orderSource + "耗时:" + (DateTime.Now - dt));
                }
                else
                {
                    Logger.Info("shop is null" + orderSource);
                }
            }
            catch (Exception ex)
            {
                Logger.Error("淘宝订单 全链路 (正向交易状态跟踪消息) 异常", ex);
            }
        }
    }
}

4) 写入服务代码:打开TradeTraceService代码

右键TradeTraceService.cs,选择查看代码。

    TradeTraceService.cs

using ECERP.FrameWork.Log;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Messaging;
using System.ServiceModel;
using System.ServiceProcess;
using System.Text;

namespace TradeTrace.Host
{
    public partial class TradeTraceService : ServiceBase
    {
        ServiceHost host = new ServiceHost(typeof(TradeTrace.Service.TradeTraceService));
        public TradeTraceService()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            if (!MessageQueue.Exists(@".\private$\tradetracelist"))
            {
                Logger.Info("不存在队列创建");
                var mq = MessageQueue.Create(@".\private$\tradetracelist", true);
                //可以根据实际情况自己设置
                mq.SetPermissions("Everyone", MessageQueueAccessRights.FullControl);
            }
            else
            {
                Logger.Info("已经存在队列");
            }
            try
            {
                host.Open();
                Logger.Info("服务开始启动了");
            }
            catch (Exception ex)
            {
                Logger.Error("err", ex);
            }
        }

        protected override void OnStop()
        {
            try
            {
                host.Close();
                Logger.Info("服务关闭了");
            }
            catch (Exception ex)
            {
                host.Abort();
                Logger.Error("err",ex);
            }
        }
    }
}
 
  应用程序入口  Program.cs

using ECERP.FrameWork.Log;
using System;
using System.Collections.Generic;
using System.Configuration.Install;
using System.Linq;
using System.ServiceProcess;
using System.Text;

namespace TradeTrace.Host
{
    static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        static void Main(string[] args)
        {
            string f = AppDomain.CurrentDomain.BaseDirectory + "Log.config";
            log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo(f));

            Logger.Info("start...");

            try
            {
                // 运行服务
                if (args.Length == 0)
                {
                    try
                    {
                        ServiceBase[] ServicesToRun = new ServiceBase[] { new TradeTraceService() };
                        ServiceBase.Run(ServicesToRun);
                    }
                    catch (Exception ex)
                    {
                        Logger.Error("err", ex);
                    }
                }
                // 安装服务
                else if (args[0].ToLower() == "/i" || args[0].ToLower() == "-i")
                {
                    try
                    {
                        string[] cmdline = { };
                        string serviceFileName = System.Reflection.Assembly.GetExecutingAssembly().Location;

                        TransactedInstaller transactedInstaller = new TransactedInstaller();
                        AssemblyInstaller assemblyInstaller = new AssemblyInstaller(serviceFileName, cmdline);
                        transactedInstaller.Installers.Add(assemblyInstaller);
                        transactedInstaller.Install(new System.Collections.Hashtable());
                    }
                    catch (Exception ex)
                    {
                        Logger.Error("err", ex);
                        //string msg = ex.Message;
                    }
                }
                // 删除服务
                else if (args[0].ToLower() == "/u" || args[0].ToLower() == "-u")
                {
                    try
                    {
                        string[] cmdline = { };
                        string serviceFileName = System.Reflection.Assembly.GetExecutingAssembly().Location;

                        TransactedInstaller transactedInstaller = new TransactedInstaller();
                        AssemblyInstaller assemblyInstaller = new AssemblyInstaller(serviceFileName, cmdline);
                        transactedInstaller.Installers.Add(assemblyInstaller);
                        transactedInstaller.Uninstall(null);
                    }
                    catch (Exception ex)
                    {
                        Logger.Error("err", ex);
                    }
                }
            }
            catch (Exception ex)
            { 
                Logger.Error("err", ex);
            }
          
        }
    }
}

  5) log.config 日志文件 和app.config 数据库配置 文件

   log.config  基本 没啥大变化  不做展示 

   app.config 

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<connectionStrings>
		<add name="local" connectionString="server=.;database=Aozzo0808;uid=sa;Pwd=" providerName="sql2005"/>
	</connectionStrings>

	<system.serviceModel>
		<services>
   <service name="TradeTrace.Service.TradeTraceService">
    <endpoint address="net.msmq://localhost/private/tradetracelist" binding="netMsmqBinding"
     bindingConfiguration="msmq" contract="TradeTrace.Service.ITradeTraceService" />
   </service>
  </services>

		<bindings>
			<netMsmqBinding>
				<binding name="msmq" exactlyOnce="true">
					<security mode="None" />
				</binding>
			</netMsmqBinding>
		</bindings>

	</system.serviceModel>
	<startup>
		<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
	</startup>
</configuration>
需注意的 是 消息队列 服务地址配置

   6) 项目整体 展示

 

         四、安装 服务

用.net framework工具INSTALLUTIL安装服务程序即可。

用项目的输出作为参数,从命令行运行 InstallUtil.exe。在命令行中输入下列代码: 

installutil yourproject.exe

     

五、卸载 服务

用项目的输出作为参数,从命令行运行 InstallUtil.exe。

installutil /u yourproject.exe



六 . 客户端 代码 

 公共方法 : 在你任务 需要的 地方 自己调用

 

  /// <summary>
        /// 把订单信息保存到msmq里
        /// </summary>
        /// <param name="list"></param>
        private void SaveTradeTraceToMsmq(List<SalesOrder> list)
        {
            ChannelFactory<TradeTrace.Service.ITradeTraceService> channelFactory = new ChannelFactory<TradeTrace.Service.ITradeTraceService>("TradeTraceServiceClient");
            TradeTrace.Service.ITradeTraceService calculate = channelFactory.CreateChannel();
            int i = 0;
            DateTime beginTime = DateTime.Now;
            foreach (var order in list)
            {
                calculate.Insert(order.OrderSource.GetValueOrDefault(0), order.OrderNum, order.Status.GetValueOrDefault(0),DateTime.Now);
                Logger.Info(string.Format("orderNum:{0} createtime:{1} shop:{2} no:{3}", order.OrderNum, order.ModifyTime, shop.Name, ++i));
            }

            Logger.Info(string.Format("{0}保存进队列{1}/{2}条 time:{3} 耗时:{4}", shop.Name, i, list.Count, DateTime.Now, DateTime.Now.Subtract(beginTime)));
        }
   客户端配置文件 截图



总结:  Windows服务 和消息队列的 结合使用 会提高 你的  效率  

C#编写Windows服务程序 (服务端),客户端使用 消息队列 实现淘宝 订单全链路效果