zoukankan      html  css  js  c++  java
  • [NET] 如何从 Winform 移植到 Webform [自己搞定HTTP协议]

    Winform 如何移植到 WebForm。

    这个问题其实也就是要找一个好的方案,最大程度的复用现有的资源。

    同时,WebForm的话,不一定要走ASPNET这条路,可以自己搞定HTTP协议的。

        下图是Winform版

        

        下图是Web版本

        

    1。如何自己搞定HTTP协议

         WebForm,可以重头老老实实的用ASPNET来做,不过,现在Oracle,MongoDB这样的数据库都支持本地的浏览器方式管理了,这样的应用,不用安装ASP,PHP这样的服务器,完全自己实现一个简单的HTTP服务器。

          OK,我们也实现一个吧,侦听13000(这里随便什么都可以的,不过推荐使用10000以上的端口号)端口,开启多线程,做HTTP服务吧。

     

            public void Start()
            {
                TcpListener server = null;
                try
                {
                    // Set the TcpListener on port 13000.
                    Int32 port = 13000;
                    IPAddress localAddr = IPAddress.Parse("127.0.0.1");

                    // TcpListener server = new TcpListener(port);
                    server = new TcpListener(localAddr, port);

                    // Start listening for client requests.
                    server.Start();

                    // Enter the listening loop.
                    while (true)
                    {
                        ///对于每个请求创建一个线程,线程的参数是TcpClient对象
                        TcpClient client = server.AcceptTcpClient();
                        OutputLog("[Init]" + DateTime.Now + "Connected!"0);
                        ParameterizedThreadStart ParStart = new ParameterizedThreadStart(ProcessFun);
                        Thread t = new Thread(ParStart);
                        t.Start(client);
                    }
                }
                catch (SocketException e)
                {
                    OutputLog("SocketException: " + e, 0);
                }
                finally
                {
                    // Stop listening for new clients.
                    server.Stop();
                    server = null;
                }

            }

    这里就是不停的启动ProcessFun来响应客户端(写客户端),同时用一个无限循环来侦听请求。

     private void ProcessFun(object clientObj)
            {
                TcpClient client = clientObj as TcpClient;
                // Buffer for reading data
                Byte[] bytes = new Byte[512];

                OutputLog("[Init]Waiting for a connection... "0);

                // Get a stream object for reading and writing
                NetworkStream stream = client.GetStream();
                int i;
                // Loop to receive all the data sent by the client.
                while ((client.Available != 0) && (i = stream.Read(bytes, 0, bytes.Length)) != 0)
                {
                    // Translate data bytes to a ASCII string.
                    String data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
                    //OutputLog("Received:" + data);

                    string[] OrgRequest = data.Split(Environment.NewLine.ToCharArray());
                    if (OrgRequest[0].StartsWith("GET"))
                    {
                        String[] Request = OrgRequest[0].Split(" ".ToCharArray());
                        String RequestItem = HttpUtility.UrlDecode(Request[1], System.Text.Encoding.UTF8);
                        OutputLog("[RequestItem]Received : " + RequestItem, 0);
                        String[] RequestPath = RequestItem.Split("?".ToCharArray());
                        switch (RequestPath[0])
                        {
                            case "/":
                                //根节点 
                                GETPage(stream, GetPage.ConnectionList());
                                break;
                            case "/Connection":
                                GETPage(stream, GetPage.Connection(RequestPath[1]));
                                break;
                            default:
                                GETFile(stream, RequestItem.Replace("/""\\"));
                                break;
                        }
                    }
                    else
                    {
                        if (OrgRequest[0].StartsWith("POST"))
                        {

                        }
                    }
                }

                // Shutdown and end connection
                client.Close();
            }

     这里响应请求,我只写完了GET,POST还没有开始动手呢。这里我们通过Stream.Read来获取请求,然后根据请求内容来寻找资源,将资源返还给客户端。

            /// <summary>
            
    /// 
            
    /// </summary>
            
    /// <param name="stream"></param>
            
    /// <param name="FileName"></param>
            private void GETFile(NetworkStream stream, String FileName)
            {
                byte[] msg = null;
                byte[] bFile = new byte[0];
                String data = String.Empty;
                Boolean IsFound = false;
                if (File.Exists(ServerPath + FileName))
                {
                    IsFound = true;
                    bFile = ReadFile(ServerPath + FileName);
                }
                else
                {
                    //资源文件里面获得
                    if (FileName.StartsWith("\\MainTreeImage"))
                    {
                        //MainTreeImage00.png -- 从MainTreeImage 里面获得
                        int MainTreeImageIndex = Convert.ToInt32(FileName.Substring("\\MainTreeImage".Length, 2));
                        Image img = GetSystemIcon.MainTreeImage.Images[MainTreeImageIndex];
                        bFile = GetSystemIcon.imageToByteArray(img,ImageFormat.Png);
                        IsFound = true;
                    }
                }

                if (IsFound)
                {
                    // Process the data sent by the client.
                    data = "HTTP/1.1 200 OK" + Environment.NewLine;
                    //if content-type is wrong,FF can;t render it,but IE can
                    string filetype = String.Empty;
                    switch (new FileInfo(FileName).Extension)
                    {
                        case ".css":
                            filetype = "text/css";
                            break;
                        case ".js":
                            filetype = "text/javascript";
                            break;
                        case ".png":
                            filetype = "image";
                            break;
                        default:
                            break;
                    }
                    data += "Content-Type: @filetype; charset=utf-8".Replace("@filetype", filetype) + Environment.NewLine;
                    data += "Content-Length: ";
                    data += (bFile.Length).ToString();
                    data += Environment.NewLine + Environment.NewLine;
                    msg = System.Text.Encoding.ASCII.GetBytes(data);
                    // Send back a response.
                    stream.Write(msg, 0, msg.Length);
                    stream.Write(bFile, 0, bFile.Length);
                    OutputLog("[System]Sent HTML OK"0);

                }
                else
                {
                    data = "HTTP/1.1 404 Not Found" + Environment.NewLine;
                    msg = System.Text.Encoding.ASCII.GetBytes(data);
                    // Send back a response.
                    stream.Write(msg, 0, msg.Length);
                    OutputLog("[System]FileName Not Found:" + FileName, 0);
                }
                stream.Flush();

            }
        }

     将资源(文件)给客户端,就是将资源转换为Bytes字节流,然后写入NetStream里面去。

     当然,为了“欺骗”浏览器,我们还要在成功找到资源的时候,给个200 OK的标记,如果没有资源的话,给个404的标记。

     以后,还要考虑 缓存的问题,已经请求过的资源,就给个3XX的,不用再重复取得资源了。

     对于有些资源内容,这里干脆不从实体文件里面取了,直接从资源里面取了。客户才不知道这个文件到底怎么来的。  

    2。最大程度的复用代码

        为了展示这个树形结构,原来的Windows代码非常的冗长(不是冗余)。

        如何将这个树形Winform转为WebForm?如果最大程度的复用代码,这是必须要考虑的。树形展示,我使用了zTree这个Jquery插件。只要能够给他一个JSON的节点信息,就可以帮你自动完成树形了。

        原来的代码的目标是生成一个Treeview,现在的目标是做个JSON。当然,可以将原来的代码里面的TreeNode的构成逻辑化为BsonDocument(MongoDB的概念,类似JSON)。不过,最最正确的做法是,直接将Treeview的结果转换为JSON。不用修改任何原来的代码,最大限度的使用原来的代码。

    #region"展示数据库结构 WebForm"
            /// <summary>
            
    /// 
            
    /// </summary>
            
    /// <param name="ConnectionName"></param>
            
    /// <returns></returns>
            public static String FillConnectionToJSON(String ConnectionName)
            {
                String strJSON = String.Empty;
                TreeView tree = new TreeView();
                FillConnectionToTreeView(tree);
                //Transform Treeview To JSON
                
    //必须这样做,防止二重管理的问题。如果这里的逻辑有两套的话,维护起来比较麻烦。
                
    //一套逻辑,来控制树的内容。然后将TreeView的内容转换为JSON。
                
    //递归GetSubTreeNode
                strJSON = GetSubTreeNode(tree.Nodes[0]).ToJson(SystemManager.JsonWriterSettings);
                return strJSON;
            }
            /// <summary>
            
    /// 
            
    /// </summary>
            
    /// <param name="SubNode"></param>
            
    /// <returns></returns>
            private static BsonDocument GetSubTreeNode(TreeNode SubNode)
            {
                if (SubNode.Nodes.Count == 0)
                {
                    BsonDocument SingleNode = new BsonDocument();
                    SingleNode.Add("name", SubNode.Text);
                    SingleNode.Add("icon""MainTreeImage" + String.Format("{0:00}",SubNode.ImageIndex) + ".png");
                    return SingleNode;
                }
                else
                {
                    BsonDocument MultiNode = new BsonDocument();
                    MultiNode.Add("name", SubNode.Text);
                    BsonArray ChildrenList = new BsonArray();
                    foreach (TreeNode item in SubNode.Nodes)
                    {
                        ChildrenList.Add(GetSubTreeNode(item));
                    }
                    MultiNode.Add("children", ChildrenList);
                    MultiNode.Add("icon""MainTreeImage" + String.Format("{0:00}", SubNode.ImageIndex) + ".png");
                    return MultiNode;
                }
            }
            #endregion

         原来的FillConnectionToTreeView(tree);是一个很庞大的方法,用来构建一个Treeview,里面存放着数据库的完整结构。

         这里我们将这个Treeview ,通过GetSubTreeNode 这个方法转换为了BsonDocument,然后直接使用内置方法转为JSON,一切搞定了。10来行代码,非常优雅。

        通过这个例子,我想说,作为程序员,一定要时刻注意,不要出现同样的代码,不要双重管理代码,不要改了一个地方,另一个地方也必须改动。

        明天去 埃森哲 入职,上海埃森哲的朋友,多多关照阿。。。。

  • 相关阅读:
    Java多线程
    JVM的结构
    CURL POST 请求
    网页504超时 apache php
    Web服务器超时处理
    apache自带压力测试工具ab详解
    好用的日期组件My97DatePicker
    CI源码阅读
    apache rewrite规则详解
    安装mysqli 扩展
  • 原文地址:https://www.cnblogs.com/TextEditor/p/2433568.html
Copyright © 2011-2022 走看看