一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

突破短板,傳統(tǒng)桌面程序 使用webapi 擴展迎合web和移動端融合的需求

 WindySky 2016-03-01

標簽:

技術分享

 

傳統(tǒng)桌面程序不能完全被web和移動端替代,但是需要改造。這里要說的是巧用webapi把以前用dll和com組件,ocx等方式做接口,做分布式開發(fā)的方式,改成restful 風格api的方式實現(xiàn)跨平臺,多客戶端(類型).并分享幾則案例.

1、智能儲物柜

項目背景:某智慧城市項目需要用到有智能鎖的儲物柜,用app掃碼控制存取,并和智慧城市后臺交互。智能鎖系統(tǒng)是工業(yè)的塔式控制器,使用modbus ascii協(xié)議控制,端口使用串口。儲物柜配備了工控電腦32寸豎屏,工控電腦控制塔式控制器(單片機),工控機上需要開發(fā)一套桌面程序,對外暴露儲物柜的功能性(存取物品),對用戶來說作為人機交互界面。話寫的有點難懂還是上圖吧:

技術分享

 規(guī)格有幾種,這是不是實物忘記了。總之也沒去過現(xiàn)場。

技術分享

柜機人機界面

說明:

工作區(qū)是底部的1024*1080像素的區(qū)域,關鍵設計是把二維碼的內容設計成了JSON,app掃描后獲取到設備和意圖,智慧城市后臺對云主機上的中間件發(fā)起控制請求,中間件轉發(fā)給柜機程序,柜機程序和塔式控制器通信,塔式控制器控制鎖動作。

技術分享

技術分享

中間件程序界面

說明:中間使用winform+owin宿主webapi,對外暴露api,對柜機程序提供套接字連接。中間件是socket server端,柜機程序作為client。

還是暈了吧,沒看懂么。簡單來說柜機程序是個上位機程序,設備需要把控制鎖的需求封裝成api給外部調用。這里的解決方案是使用中間件,中間件對外暴露api外部發(fā)起控制請求,中間件對內(設備端程序)執(zhí)行控制指令。

為了實現(xiàn)"網(wǎng)頁和移動客戶端控制工控設備"這個核心需求,這也是擠破了腦袋吧.呵呵呵,總算不枉費你進來圍觀了一回...

 

不留下點代碼,算什么分享呢!哼!

 

好的,上代碼:

技術分享

技術分享

這就是傳說中的asp.net mvc webapi啊

winform宿主:

IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 0);
                EndPoint epSender = (EndPoint)ipeSender;
                serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                // 首次探測時間5 秒, 間隔偵測時間2 秒
                byte[] inValue = new byte[] { 1, 0, 0, 0, 0x88, 0x13, 0, 0, 0xd0, 0x07, 0, 0 };
                serverSocket.IOControl(IOControlCode.KeepAliveValues, inValue, null);
                IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(SocketBindingIP), int.Parse(config.AppSettings.Settings["Middleware_PORT"].Value));
                try
                {
                    serverSocket.Bind(ipEndPoint);
                    serverSocket.Listen(1024);
                    backgroundWorker.WorkerSupportsCancellation = true;
                    backgroundWorker.RunWorkerAsync();
                    LogMessage(DateTime.Now + "->Socket啟動成功,監(jiān)聽IP:" + ipEndPoint.Address.ToString() + ":" + config.AppSettings.Settings["Middleware_PORT"].Value);                    
                }
                catch (Exception ex)
                {
                    Com.DataCool.DotNetExpand.LogHelper.Error("服務啟動失敗,原因:" + ex.Message);                    
                }
                btnServiceControl.Tag = 1;
                btnServiceControl.Text = "停止監(jiān)聽";
                btnServiceControl.BackColor = Color.Green;
                pbxServiceStatus.BackgroundImage = Properties.Resources.online_status;
                lbWebApiBaseAddress.Text = SocketBindingIP;
                hostObject = WebApp.Start<RegisterRoutesStartup>("http://" + SocketBindingIP + ":5990");
 public class RegisterRoutesStartup
    {
        public void Configuration(IAppBuilder appBuilder)
        {
            HttpConfiguration config = new HttpConfiguration();
            //自定義路由
            config.Routes.MapHttpRoute(
              name: "CustomApi",
              routeTemplate: "api/{controller}/{action}/{id}",
              defaults: new { id = RouteParameter.Optional }
            );
            //只響應Json請求
            var jsonFormatter = new JsonMediaTypeFormatter();
            config.Services.Replace(typeof(IContentNegotiator), new JsonContentNegotiator(jsonFormatter));
            appBuilder.UseWebApi(config);
        }
    }

就是最后一句了。owin怎么宿主webapi去看看張善友等的文章吧。

 public ApiActionResult BufferBox_API_Request(string StationNo, string CellNo, string Action)
        {
            var result = new ApiActionResult()
            {
                Success = false,
                Result = null,
                Message = "操作失敗。"
            };
            byte[] results = new byte[1024];
            Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                clientSocket.Connect(new IPEndPoint(IPAddress.Parse(conf.AppSettings.Settings["Middleware_IP"].Value), Convert.ToInt32(conf.AppSettings.Settings["Middleware_PORT"].Value)));
                using (var db = new BufferBoxDBEntities())
                {
                    var stationEntity = db.station_signin_session.Where(st => st.SessionDict == StationNo).FirstOrDefault();
                    if (stationEntity == null)
                    {
                        result.Message = "設備不存在或者設備編號有誤!";
                        result.Result = "";
                        return result;
                    }
                    var requestEntity = new API_Request_session
                    {
                        API_Request_IP = Request.GetClientIpAddress(),
                        RequestID = Guid.NewGuid(),
                        RequestData = CellNo + "|" + Action,
                        RequestDataTime = DateTime.Now,
                        ResultData = "",
                        ExecuteFlag = false,
                        StationNo = StationNo
                    };
                    db.API_Request_session.AddObject(requestEntity);
                    db.SaveChanges();
                    clientSocket.Send(Encoding.UTF8.GetBytes("api_request:" + JsonConvert.SerializeObject(requestEntity)));
                    result.Success = true;
                    result.Message = "設備已經(jīng)受理請求。";
                    result.Result = requestEntity.RequestID.ToString();
                }
            }
            catch (Exception ex)
            {
                result.Message = "中間件發(fā)生異常:" + ex.Message;
            }
            return result;
        }

  這可是項目分析的關鍵之處啊。中間件是如何轉發(fā)api請求并通知柜機客戶端執(zhí)行指令的呢。就是webapi里使用socket作為client去連接中間件的socket server的。

問題就是出在這里!webapi不能阻塞socket 直到柜機客戶端響應之后回復了再返回給外部。

 

2、php頁面js開POS觸摸屏電腦外接的錢箱

  這是昨天晚上接的一個小活。新年第一單,正是有了前面項目的經(jīng)驗,給提供了這個解決方案。

項目背景: php做的bs項目打包成桌面項目用內嵌瀏覽器訪問php頁面來代替POS觸摸屏桌面程序。打印使用插件聽說解決了,但是打開錢箱遇到麻煩了。由于發(fā)包方不知道網(wǎng)頁如何控制本地設備,也不想用activex方式,所以提供了這個解決方案:

POS觸摸屏上運行一windows服務程序對外提供api(控制錢箱)和php服務器端的中間件通信,中間件對外部暴露api。

這個項目圖片不高大上,所以只有代碼了:

using System;
using System.Net;
using System.Web.Http;
using System.Net.Sockets;
using System.Configuration;
using System.Text;

namespace MiddlewareServer
{
   /// <summary>
   /// POS觸摸屏收銀機錢箱控制API控制器
   /// </summary>
    public class MoneyBoxApiController : ApiController
    {
        public static readonly Configuration conf = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

        [HttpGet]
        /// <summary>
        /// 打開POS錢箱,IP取發(fā)起請求的客戶端的IP,中間件以此IP為依據(jù)通知該POS機執(zhí)行開錢箱動作
        /// 局域網(wǎng)環(huán)境IP最好是靜態(tài)IP,不要使用DHIP,動態(tài)獲取
        /// </summary>
        /// <returns>{Success,Result=請求發(fā)起機器的IP地址,Message}</returns>

        public ApiActionResult OpenMoneyBox()
        {
            var result = new ApiActionResult()
            {
                Success = false,
                Result = null,
                Message = "操作失敗。"
            };
            byte[] results = new byte[1024];
            Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                clientSocket.Connect(new IPEndPoint(IPAddress.Parse(conf.AppSettings.Settings["Middleware_IP"].Value), Convert.ToInt32(conf.AppSettings.Settings["Middleware_PORT"].Value)));
                string ip = Request.GetClientIpAddress();
                clientSocket.Send(Encoding.UTF8.GetBytes("api_request:" + ip));
                result.Result = ip;
                result.Success = true;
                result.Message = "請求成功。";
            }
            catch (Exception ex)
            {
                result.Message = "中間件發(fā)生異常:" + ex.Message;
            }
            return result;
        }       
    }
}

  

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using System.Runtime.InteropServices;
using System.Configuration;
using Microsoft.Win32.SafeHandles;
using System.IO;
using System.Net.Sockets;
using System.Net;

namespace MoneyBoxSvr
{
    public partial class MoneyBoxService : ServiceBase
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode, int lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, int hTemplateFile);

        private Configuration config;
        /// <summary>
        /// 打印機端口名稱
        /// </summary>
        public string PrintPortName
        {
            get { return config.AppSettings.Settings["PortName"].Value; }
        }

        /// <summary>
        /// 中間件的IP地址
        /// </summary>
        public string RemoteServerIP
        {
            get
            {
                return config.AppSettings.Settings["MiddlewareIP"].Value;
            }
        }

        /// <summary>
        /// 中間件監(jiān)聽的端口
        /// </summary>
        public int MiddlewarePort
        {
            get
            {
                return Convert.ToInt32(config.AppSettings.Settings["MiddlewarePort"].Value);
            }
        }

        protected Socket clientSocket = null;
        /// <summary>
        /// 緩沖區(qū)
        /// </summary>        
        protected byte[] buffers = new byte[1024];

        protected System.Threading.Thread socketThread;

        public MoneyBoxService()
        {
            InitializeComponent();
            config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
        }      
       
        protected override void OnStart(string[] args)
        {
            StartSocketThread();
        }

        protected override void OnStop()
        {
            base.OnStop();
        }

        protected override void OnShutdown()
        {
            base.OnShutdown();
            socketThread.Abort();
            socketThread = null;
        }

        private void StartSocketThread()
        {          
            socketThread = new System.Threading.Thread(ThreadWork);
            socketThread.Start();
        }

        /// <summary>
        /// 異步接收到遠程請求
        /// </summary>
        /// <param name="ar"></param>
        private void OnReceive(IAsyncResult ar)
        {
            try
            {
                IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 0);
                EndPoint epSender = (EndPoint)ipeSender;
                //結束掛起的,從特定終結點進行異步讀取
                if (clientSocket != null)
                {
                    int len = clientSocket.EndReceiveFrom(ar, ref epSender);
                    string requestCommand = System.Text.Encoding.UTF8.GetString(buffers);
                    if (requestCommand.StartsWith("api_request"))
                    {
                        OpenMoneyBox();
                    }
                }
            }
            catch
            { 
            
            }
            finally
            {
                try
                {
                    IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 0);
                    EndPoint epSender = (EndPoint)ipeSender;
                    buffers = new byte[1024];
                    clientSocket.BeginReceiveFrom(buffers, 0, buffers.Length, SocketFlags.None, ref epSender, new AsyncCallback(OnReceive), epSender);
                }
                catch 
                {                    
                }
            }
        }

        private void ThreadWork()
        {
            while (true)
            {
                if (clientSocket == null)
                {
                    #region 建立socket連接
                    IPAddress ip = IPAddress.Parse(RemoteServerIP);
                    clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    try
                    {
                        // 首次探測時間5 秒, 間隔偵測時間2 秒
                        byte[] inValue = new byte[] { 1, 0, 0, 0, 0x88, 0x13, 0, 0, 0xd0, 0x07, 0, 0 };
                        clientSocket.IOControl(IOControlCode.KeepAliveValues, inValue, null);
                        clientSocket.Connect(new IPEndPoint(IPAddress.Parse(RemoteServerIP), MiddlewarePort)); //配置服務器IP與端口  
                        #region 簽到
                        string request = "pos_sign_in:";
                        clientSocket.Send(Encoding.UTF8.GetBytes(request));
                        IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 0);
                        EndPoint epSender = (EndPoint)ipeSender;
                        buffers = new byte[1024];
                        clientSocket.BeginReceiveFrom(buffers, 0, buffers.Length, SocketFlags.None, ref epSender, new AsyncCallback(OnReceive), epSender);
                        #endregion
                    }
                    catch 
                    {
                        if (clientSocket != null)
                        {
                            clientSocket.Close();
                            clientSocket = null;
                        }
                    }
                    #endregion
                }
                if (clientSocket != null )
                {
                    #region 發(fā)0字節(jié)的包探測連接是否可用
                    bool blockingState = clientSocket.Blocking;
                    try
                    {
                        byte[] tmp = new byte[1];
                        clientSocket.Blocking = false;
                        clientSocket.Send(tmp, 0, 0);
                    }
                    catch 
                    {
                        if (clientSocket != null)
                        {
                            clientSocket.Close();
                            clientSocket = null;
                        }                        
                    }
                    finally
                    {
                        if (clientSocket != null)
                        {
                            clientSocket.Blocking = blockingState;
                        }
                    }
                    #endregion
                }
                System.Threading.Thread.Sleep(5000);
            }        
        }
        
        /// <summary>
        /// 開錢箱
        /// </summary>
        public void OpenMoneyBox()
        {
            IntPtr iHandle = CreateFile(PrintPortName, 0x40000000, 0, 0, 3, 0, 0);
            if (iHandle.ToInt32() != -1)
            {
                SafeFileHandle handle = new SafeFileHandle(iHandle, true);
                FileStream fs = new FileStream(handle, FileAccess.ReadWrite);
                StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.Default);
                sw.Write(((char)27).ToString() + "p" + ((char)0).ToString() + ((char)60).ToString() + ((char)255).ToString());
                sw.Close();
                fs.Close();
            }
        }        
    }
}

  好久沒寫博客了。就這樣吧,目的就是分享和總結。還有不說你也知道的,這文章怎么看怎么“軟”。希望大家體諒一下,技術把代碼變成錢本身就是困難的事情。適度廣告一下吧,項目和私活就是這樣找上門的。

 

突破短板,傳統(tǒng)桌面程序 使用webapi 擴展迎合web和移動端融合的需求

標簽:

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    国产精品免费自拍视频| 亚洲最大的中文字幕在线视频| 亚洲中文在线中文字幕91| 清纯少妇被捅到高潮免费观看| 麻豆视频传媒入口在线看| 九九热最新视频免费观看| 色婷婷视频国产一区视频| 国产不卡在线免费观看视频| 成人亚洲国产精品一区不卡 | 一区二区三区四区亚洲专区| 国产成人精品国产成人亚洲| 久热这里只有精品九九| 国产又粗又猛又爽色噜噜 | 亚洲精品中文字幕熟女| 国产日韩欧美一区二区| 久久久精品日韩欧美丰满| 国产欧美高清精品一区| 日韩欧美中文字幕av| 国产精品久久三级精品| 东京不热免费观看日本| 欧美精品一区二区水蜜桃| 国产熟女一区二区不卡| 又黄又硬又爽又色的视频| 欧美成人久久久免费播放| 日韩和欧美的一区二区三区 | 91插插插外国一区二区婷婷| 免费在线播放一区二区| 千仞雪下面好爽好紧好湿全文| 日韩国产精品激情一区 | 人人爽夜夜爽夜夜爽精品视频| 大尺度激情福利视频在线观看| 激情综合五月开心久久| 久久精品国产熟女精品| 亚洲一区精品二人人爽久久| 免费亚洲黄色在线观看| 国产又色又爽又黄又免费| 久草国产精品一区二区| 亚洲熟女熟妇乱色一区| 欧美二区视频在线观看| 99久久精品午夜一区二区| 久久国产人妻一区二区免费|