遗忘海岸

江湖程序员 -Feiph(LM战士)

导航

使用WCF的一些问题

 一个扫描出库程序,采用单实例、单线程模型,主要防止同个号多台电脑同时扫描出库(因为支持手动批量出库)

View Code
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.ComponentModel;
  6 using System.ServiceModel;
  7 using System.Threading;
  8 using DotNetHalfGoodsHouse.EFModel;
  9 using System.Data.SqlClient;
 10 namespace DotNetHalfGoodsHouse.Services
 11 {
 12     #region 接口定义
 13     [ServiceContract]
 14     public interface IOutScanService
 15     {
 16         [OperationContract]
 17         OutScanResponse PostScan(OutScanRequest request);
 18         [OperationContract]
 19         string GetMaxOrderId();
 20 
 21     }
 22     #endregion
 23 
 24     #region 服务实现
 25     [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
 26     public class OutScanService : IOutScanService, IDisposable
 27     {
 28 
 29 
 30         public OutScanResponse PostScan(OutScanRequest request)
 31         {
 32           
 33             Console.WriteLine(string.Format("PN:{0},被调用了!:ThreadId:{1}", request.PN, Thread.CurrentThread.ManagedThreadId));
 34 
 35             var response = new OutScanResponse() 
 36             { 
 37                Code=2,
 38                ErrMsg="错误",
 39                Amount=0
 40             };
 41 
 42             try
 43             {
 44                 #region 扫描出库
 45                 using (JL_MFGEntities dbx = new JL_MFGEntities(ModelSetting.ModelConnString))
 46                 {
 47                     var rmBreakEnt = dbx.RMBreak.FirstOrDefault(ent => ent.PFIFOID == request.PN);
 48 
 49                     //记录是否存在
 50                     if (rmBreakEnt == null) throw new ScanException("该PN不存在!", 401);
 51 
 52                     //PN相关信息
 53                     response.Batno = rmBreakEnt.batno.ToString().Trim();
 54                     response.CarType = rmBreakEnt.p_yw.Trim();
 55                     response.Output = rmBreakEnt.Poutput.Value;
 56                     response.PlanId = rmBreakEnt.PlanID;
 57                     response.MPartNo = rmBreakEnt.partno.Trim();
 58                     response.MPartName = rmBreakEnt.p_partnoName.Trim();
 59                     response.Amount = rmBreakEnt.partnototalqty.Value;
 60 
 61                     //检测状态
 62                     if (rmBreakEnt.IsOut.Trim() != "") throw new ScanException("已发状态为'是',该记录已经被扫描出库!", 402);
 63                     //检测发料记录
 64                     var findItem = dbx.ExecuteStoreQuery<int?>("Select count(*) from storage_fixbin Where fifoid=@PN", new SqlParameter("@PN", request.PN)).FirstOrDefault();
 65                      if (findItem.HasValue && findItem.Value > 0) throw new ScanException("已存在发料记录,该记录已经被其他用户扫描",403);
 66 
 67                     //更改发料状态
 68                     rmBreakEnt.IsOut = "";
 69                     rmBreakEnt.OutDate = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
 70                     rmBreakEnt.OutOperator = request.Username;
 71 
 72                     //添加发料记录
 73                     var fixbin = new Storage_Fixbin()
 74                     {
 75                         #region
 76                         PlanID = rmBreakEnt.PlanID,
 77                         FGpartno = rmBreakEnt.FGpartno,
 78                         p_yw = rmBreakEnt.p_yw,
 79                         p_FGName = rmBreakEnt.p_FGName,
 80                         Batno = rmBreakEnt.batno,
 81                         Poutput = rmBreakEnt.Poutput,
 82                         FIFOID = rmBreakEnt.PFIFOID,
 83                         Barcode = request.EmpCard,
 84                         partno = rmBreakEnt.partno,
 85                         partname = rmBreakEnt.p_partnoName,
 86                         supplier = rmBreakEnt.p_supplier,
 87                         unit = rmBreakEnt.UM,
 88                         OutticketID = request.OrderId,//出库单号
 89                         OutSubID = request.OrderItemId,//子单号
 90                         OutQty = rmBreakEnt.partnototalqty,
 91                         OutDate = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"),
 92                         OutOperator = request.Username,
 93                         Shift = request.EmpGroup,
 94                         ShiftMonitor = request.EmpName,
 95                         TicketStatus = "生产性领料",
 96                         Ptype = "发料",
 97                         Machine = request.Machine,
 98                         Reason = "正常发送"
 99                         #endregion
100 
101                     };
102                     dbx.Storage_Fixbin.AddObject(fixbin);
103                     //更新预定量
104                     var rmReserveEnt = dbx.RMHoldQty.FirstOrDefault(ent => ent.partno == fixbin.partno);
105                     if (rmReserveEnt != null)
106                     {
107 
108                         rmReserveEnt.holdqty -= rmBreakEnt.partnototalqty.Value;
109                     }
110 
111                     #region 处理端子预定量
112                     if (rmBreakEnt.Stock.Trim() == "端子")
113                     {
114                         var rmHandTEnt = dbx.HandTerminal.FirstOrDefault(ent => ent.partno == rmBreakEnt.partno && ent.Barcode == request.EmpCard);
115                         if (rmHandTEnt == null) //执行添加
116                         {
117                             rmHandTEnt = new HandTerminal()
118                             {
119                                 Barcode = request.EmpCard,
120                                 Name = request.EmpName,
121                                 Machine = request.Machine,
122                                 partno = rmBreakEnt.partno,
123                                 partname = rmBreakEnt.p_partnoName,
124                                 p_brand = rmBreakEnt.p_brand,
125                                 supplier = rmBreakEnt.p_supplier,
126                                 unit = rmBreakEnt.UM,
127                                 InQty = rmBreakEnt.partnototalqty,
128                                 Updatedate = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")
129 
130 
131                             };
132                             dbx.HandTerminal.AddObject(rmHandTEnt);
133                         }
134                         else //执行更新
135                         {
136                             if (!rmHandTEnt.InQty.HasValue) rmHandTEnt.InQty = 0;
137                             rmHandTEnt.InQty += rmBreakEnt.partnototalqty;
138 
139                         }
140                     }
141 
142                     #endregion
143 
144                     dbx.SaveChanges();
145 
146                 }
147                 #endregion
148                 response.Msg = "成功";
149                 response.ErrMsg = "";
150                 response.Code = 1;
151             }
152             catch (ScanException ex)
153             {
154 
155 
156                 response.ErrMsg = ex.Message;
157                 response.Code = ex.Code;
158             }
159             catch (Exception ex)
160             {
161                 response.Code = 400;
162 
163                 response.ErrMsg = ex.Message;
164                 if (ex.InnerException != null)
165                     response.ErrMsg += string.Format("\r\n========Inner Exception=========\r\n{0}", ex.InnerException.Message);
166             }
167 
168 
169             return response;
170         }
171 
172         
173         public void Dispose()
174         {
175             
176         }
177 
178 
179         public string GetMaxOrderId()
180         {
181             using (JL_MFGEntities dbx = new JL_MFGEntities(ModelSetting.ModelConnString))
182             {
183                 var list = dbx.ExecuteStoreQuery<string>("Select Max(OutTicketiD) from Storage_Fixbin").ToList();
184                 if (list.Count > 0)
185                 {
186                     var orderId = list[0].Trim();
187                     var newId=long.Parse(orderId) +1;
188                     orderId="0000000000" + newId;
189                     return orderId.Substring(orderId.Length - 10, 10);
190 
191                 }
192 
193             }
194             return "0000000001";
195         }
196     }
197     #endregion
198 
199     #region 请求结构
200 
201     public class OutScanRequest
202     {
203         public string EmpName { get; set; }
204         public string EmpCard { get; set; }
205         public string EmpGroup { get; set; }
206         public string Username { get; set; }
207         public string PN { get; set; }
208         public string Machine { get; set; }
209         public string OrderId { get; set; }
210         public int OrderItemId { get; set; }
211     }
212     public class OutScanResponse
213     {
214         /// <summary>
215         /// 1成功,2失败
216         /// </summary>
217         public int Code { get; set; }
218         public string ErrMsg { get; set; }
219         public string Msg { get; set; }
220         public string PlanId { get; set; }
221         public string CarType { get; set; }
222         public decimal Output { get; set; }
223         public string Batno { get; set; }
224         public string MPartNo { get; set; }
225         public string MPartName { get; set; }
226         public decimal Amount { get; set; }
227     }
228     [Serializable]
229     public class ScanException : Exception
230     {
231         public int Code { get; set; }
232         public ScanException(string msg,int code)
233             : base(msg)
234         {
235             this.Code = code;
236         }
237     }
238     #endregion
239 }

WCF采用TCP方式,并且多个请求使用同个TCP连接(在完成调用请求后使用proxy.close()关闭TCP链接)

View Code
        private IOutScanService _proxy;
        private IOutScanService ScanService
        {
            get
            {
                if (_proxy == null)
                {
                    TryOpenChannel();

                }
                else
                {
                    var cObj = _proxy as ICommunicationObject;
                    if (cObj.State == CommunicationState.Faulted
                        || cObj.State == CommunicationState.Closed
                        || cObj.State == CommunicationState.Closing

                        )
                    {
                        TryOpenChannel();
                    }
                }
                return _proxy;
            }

        }
        private void TryOpenChannel()
        {
            try
            {
                _proxy = WCFHelper.Factory.CreateChannel();
                (_proxy as ICommunicationObject).Open();
            }
            catch (Exception)
            {
                _proxy = null;
                throw;
            }
        }

在局域网使用不对绑定使用加密,需要注意的是该配置要在Server端与Client端同时设置。

View Code
    #region WCF帮助类
   
    public class WCFHelper
    {

        private static ChannelFactory<IOutScanService> _channelFac;

        public static ChannelFactory<IOutScanService>  Factory
        {
            get
            {
                if (_channelFac == null)
                {
                    _channelFac =
                        new ChannelFactory<IOutScanService>(new NetTcpBinding(SecurityMode.None),
                        EndpointStr);

                }
                return _channelFac;
            }
        }

        private static string EndpointStr
        {
            get
            {
                return DotNetHalfGoodsHouse.EFModel.ModelSetting.GetSetting("ServiceEndpoint",
                    "net.tcp://192.168.1.31:8888/OutScanService");
            }
        }
    }

 采用匿名异步委托调用,防止界面卡死

View Code
        private void txtPN_KeyDown(object sender, KeyEventArgs e)
        
        {
            if (e.KeyCode == Keys.Enter)
            {
                try
                {
                    SetEnabled(false);

                    Post();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                finally
                {
                    SetEnabled(true);
                    txtPN.Text = "";
                    txtPN.Focus();
                }
            }
        }
        #endregion
        private void SetEnabled(bool v)
        {
            if (v)
            {

                this.Cursor = Cursors.Arrow;

            }
            else
            {
                this.Cursor = Cursors.WaitCursor;

            }
            dgvScnList.Cursor = this.Cursor;

            txtPN.Enabled = v;
            btnOut.Enabled = v;
            cbxMaterialType.Enabled = v;
            cbxIncharge.Enabled = v;
            cbxEmpGroup.Enabled = v;
        }


        


        private OutScanRequest PreRequest(string pn)
        {
            var request = new OutScanRequest();


            if (string.IsNullOrWhiteSpace(pn)) throw new DataInputException("请输入PN码!");
            if (!pn.StartsWith("P"))
            {
                pn = "0000000000" + pn;
                pn = "P" + pn.Substring(pn.Length - 9);
            }
            request.PN = pn;
            request.EmpCard = txtEmpCard.Text.Trim();
            if (string.IsNullOrWhiteSpace(request.EmpCard)) throw new DataInputException("请提员工身份识别卡!");

            request.EmpGroup = cbxEmpGroup.Text.Trim();

            request.EmpName = txtName.Text.Trim();
            if (string.IsNullOrWhiteSpace(request.EmpName)) throw new DataInputException("请提供员工姓名!");

            request.Machine = txtStation.Text.Trim();

            request.Username = UserSetting.UserName.Trim();

            return request;
        }
        private void Post()
        {

            #region 
            string pn=txtPN.Text.Trim();
            var request = PreRequest(pn);

            Post(request);

            
            #endregion

        }
        
        private void Post(OutScanRequest request)
        {

            //获取定单号
            if (string.IsNullOrWhiteSpace(OrderId))
            {
                GetOrderId();
            }
            request.OrderId = OrderId;
            request.OrderItemId = OrderItemId;
            OrderItemId++;

            //异步处理
            var fun = new Func<OutScanResponse>(() => { return ScanService.PostScan(request);});
            var ar=fun.BeginInvoke(null,null);
            while (!ar.IsCompleted)
            {
                Application.DoEvents();
                Thread.Sleep(50);
            }
            var response = fun.EndInvoke(ar);

            //不是同一批次
            if (!string.IsNullOrWhiteSpace(response.PlanId) && string.Compare(response.PlanId.Trim(), PlanId, true) != 0)
            {
                PlanId = response.PlanId.Trim();

                var action = new Action(() => { LoadData(); });
                var loadDataAR = action.BeginInvoke(null, null);
                while (!loadDataAR.IsCompleted)
                {
                    Application.DoEvents();
                    Thread.Sleep(50);
                }
                
                BindData();
            }


            if (lsvOut.Items.Count >= 1000)
            {
                lsvOut.Items.RemoveAt(0);
            }

            if (response.Code == 1)
            {

                lsvOut.Items.Add(new ListViewItem(new string[] { request.PN, response.MPartNo, response.MPartName, response.Amount.ToString("0.00"), "成功", "成功发送!", DateTime.Now.ToString("yy-MM-dd HH:mm:ss") }));
                SuccessCount++;

                lblSuccesTips.Text = SuccessCount.ToString();


            }
            else
            {
                var item = lsvOut.Items.Add(new ListViewItem(new string[] { request.PN, response.MPartNo, response.MPartName, response.Amount.ToString("0.00"), "失败", response.ErrMsg, DateTime.Now.ToString("yy-MM-dd HH:mm:ss") }));
                item.BackColor = Color.Red;
                item.Tag = request;
                ErrCount++;
                lblErrTips.Text = ErrCount.ToString();

            }



            RemoveFromList(request.PN);


            lsvOut.EnsureVisible(lsvOut.Items.Count - 1);

           
        }
        private void GetOrderId()
        {
            var fun = new Func<string>(() => { return ScanService.GetMaxOrderId(); });
            var ar = fun.BeginInvoke(null, null);
            while (!ar.IsCompleted)
            {
                Thread.Sleep(50);
                Application.DoEvents();

            }
            OrderId = fun.EndInvoke(ar);
            OrderItemId = 1;
        }
        /// <summary>
        /// 将扫描过的记录从列表移除
        /// </summary>
        /// <param name="pn"></param>
        private void RemoveFromList(string pn)
        {
            if (ScanData == null) return;


            var row = ScanData.Table.Select(string.Format(" pfifoid='{0}'", pn)).FirstOrDefault();
            if (row != null)
            {
                ScanData.Table.Rows.Remove(row);
            }


        }

//==========发布配置部分============
1.使用TopShelf方式托管WCF,结果在XPsp3的系统上老是安装不了,不过放到win2003上就正常了

View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Topshelf;
using System.IO;
namespace OutScanServer
{
    using DotNetHalfGoodsHouse;
    using DotNetHalfGoodsHouse.Services;

    class Program
    {
        private static string EndpointStr
        {
            get
            {
                return DotNetHalfGoodsHouse.EFModel.ModelSetting.GetSetting("ServiceEndpoint",
                    "net.tcp://192.168.1.31:8888/OutScanService");
            }
        }
        static void Main(string[] args)
        {
           

            var wsHost = HostFactory.New(x => {
                x.Service<ServiceHost>(s =>
                {
                    s.SetServiceName("配料扫描出库");
                    s.ConstructUsing(name=> new ServiceHost(typeof(OutScanService)));
                    s.WhenStarted(tc => {
                        
                        tc.AddServiceEndpoint(typeof(IOutScanService), new NetTcpBinding(SecurityMode.None), EndpointStr);
                        tc.Opened += (sObj, e) =>
                        {
                            Console.WriteLine("服务启动!");
                        };
                        tc.Open();
                    });

                    s.WhenStopped(tc => {
                        tc.Close();
                    });
                });


                x.RunAsLocalSystem();

                x.StartAutomatically();
                x.DependsOnMsSql();
                x.SetDescription("配料扫描出库服务端!");
                x.SetDisplayName("HaoDaOutScanService");
                x.SetServiceName("HaoDaOutScanService");
             
            });

            wsHost.Run();
  
        }
    }
}

2.采用VS自带的Windows Service项目也不比TopShelf麻烦多少,而且XP上也可以装,就是安装时使用installuntil 注意要使用对应.net framework版本,不然会提示程序集找不到一类的错误。

View Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.ServiceModel;
namespace OutScanWinSvr
{
    using DotNetHalfGoodsHouse;
    using DotNetHalfGoodsHouse.Services;

    public partial class OutScanWinSvr : ServiceBase
    {
        private ServiceHost _Host;
        public OutScanWinSvr()
        {
            InitializeComponent();

            #region  初始华服务
            _Host = new ServiceHost(typeof(OutScanService));
            _Host.AddServiceEndpoint(typeof(IOutScanService), new NetTcpBinding(),
                                     DotNetHalfGoodsHouse.EFModel.ModelSetting.GetSetting("ServiceEndpoint","")
                                     );

      

            
            #endregion

        }

        protected override void OnStart(string[] args)
        {
            _Host.Open();
        }

        protected override void OnStop()
        {
            _Host.Close();
        }
    }
}

 

 

 

 WCF客户端使用BasicHttpBinding时默认开启2条TCP,要开更多需要设置

 System.Net.ServicePointManager.DefaultConnectionLimit = 512;

posted on 2012-07-31 08:49  遗忘海岸  阅读(898)  评论(3编辑  收藏  举报