zoukankan      html  css  js  c++  java
  • C#编写Windows服务程序 (服务端),client使用 消息队列 实现淘宝 订单全链路效果

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

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

     

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

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

    ---(截图上传了 4次 才看到效果 ,最后从简  见谅)

    一、创建一个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$	radetracelist"))
                {
                    Logger.Info("不存在队列创建");
                    var mq = MessageQueue.Create(@".private$	radetracelist", 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=txttt0808;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



    六 . client 代码 

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

     

      /// <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)));
            }
       client配置文件 截图



    总结:  Windows服务 和消息队列的 结合使用 会让你的 程序 焕然一新,更加灵活 . 消息队列的 相关知识 请自寻资料了解.

     小小心得 不正确的地方 请多多不吝赐教 .

  • 相关阅读:
    伺服电机常见故障分析汇总
    PLC常见四大故障及其处理方法
    Qt QString的arg()方法的使用
    Qt 线程池QThreadPool类、QRunnable类
    C++线程池的实现
    C++ List的用法
    C++语言堆栈的详细讲解
    QT中的QQueue类、C++中的queue类
    Qt platform plugin 'windows' 问题的解决方法
    电气接地的相关介绍
  • 原文地址:https://www.cnblogs.com/yxysuanfa/p/6731532.html
Copyright © 2011-2022 走看看