65.9K
CodeProject 正在变化。 阅读更多。
Home

适用于iPhone的Visual Studio调试控制台

starIconstarIconstarIconstarIconstarIcon

5.00/5 (8投票s)

2012 年 7 月 17 日

CPOL

6分钟阅读

viewsIcon

48766

downloadIcon

534

一个集成移动端和 .Net 应用程序的架构提案


   

引言

本文有两个目的

  • 从架构角度:展示一种通过HTML5 WebSockets将 Windows 应用程序与智能手机和平板电脑应用程序集成的方案。
  • 从软件工程角度:展示一个在 iPhone 上使用 Visual Studio 远程调试控制台的具体且有用的案例,该案例可扩展到 Android 设备。
本文无意提供一个最终且完善的解决方案,提供的源代码和应用程序仅用于演示概念。尽管 .net 应用程序使用了 WPF 库,但也可与任何 UI 库一起使用。

背景

几天前我拿到了一部 iPhone 4。我希望能找到一种方法将其用作 .net 应用程序的调试控制台:但没有成功。于是,我开始研究最简单的解决方案,并遵循以下标准:

  • 避免学习一门全新的语言,例如Objective-C
  • 避免通过Apple 的 AppStore分发应用程序(并省下一百美元!)
  • 使用一种防火墙友好的通信技术
  • 使用一个简单的库,最好只有一个 DLL
研究过程并不长,HTML5 似乎是编写无需 AppStore 流程的应用程序的最佳选择,iOS 对 HTML5 应用程序缓存功能支持良好,而 HTML5 WebSockets 符合防火墙友好的要求,并在 iOS 的 Safari 浏览器中实现了原生支持。

架构 

在 Windows 端,该工具的核心功能是一个 TraceListener 派生类。该类负责捕获 System.Diagnostics.Debug.Write().WriteLine() 调用,并通过HTML5 WebSocket服务器将其发送到远程设备。另一方面,iPhone 实现了一个使用 WebSocket 客户端的 JavaScript 应用程序。高层设计如下所示: 

实现

Windows 端

在 Windows 端,WebSockets 尚未在 .Net 中得到原生支持(但已在 .Net Framework 4.5 中公布)。在评估了半打 C#WebSocket库后,我选择了Alchemy(参见 http://alchemywebsockets.net),因为它简单且是单一 DLL 实现。
Alchemy 的另一个重要特性是支持 WebSocket 协议的多个版本。由于它不是一个成熟的标准,因此有很多版本,具体取决于浏览器品牌、版本和平台。支持的版本包括hixie-76 (hybi00)、hybi-10、hybi-17 和 RFC6455
如前所述,Windows 端的主要类是一个 TraceListener 派生类,名为 WebSocketTraceListener。实现非常简短,如下所示:
namespace System.Diagnostics
{
    public class WebSocketTraceListener : TraceListener
    {
        private Alchemy.WebSocketServer  server = new Alchemy.WebSocketServer();
        private Alchemy.Classes.UserContext connection = null;

        public void Initialize(System.Net.IPAddress ip, int port)
        {
            try
            {
                server.ListenAddress = ip;
                server.Port = port;
                server.OnConnect = OnConnect;
                server.OnDisconnect = OnDisconnect;
                server.Start();

                Debug.WriteLine("WebSocket Trace Listener: An error ocurred when the application tried to start");
                Debug.Listeners.Add(this);
            }
            catch (Exception)
            {
                Debug.WriteLine("WebSocket Trace Listener: Started correctly.");
            }
        }
        public override void Write(string message)
        {
            if (this.connection != null)
                this.connection.Send(message);
        }
        public override void WriteLine(string message)
        {
            if (this.connection != null)
                this.connection.Send(message);
        }

        private void OnConnect(Alchemy.Classes.UserContext context)
        {
            if (this.connection != null)
                this.server.Restart();
            this.connection = context;
        }
        private void OnDisconnect(Alchemy.Classes.UserContext context)
        {
            this.connection = null;
        }
    }
}

此类可以直接嵌入到您的应用程序中;无需将其保存在单独的 DLL 中。但有两个依赖项:Alchemy 库(Alchemy.dll,包含在解决方案中)和 System.Web.dll,这要求项目配置为使用标准的.Net Framework(而不是.Net Framework Client Profile),以便允许您附加该 DLL。最后,可以通过添加几行代码来使用侦听器类: 

            var listener = new WebSocketTraceListener();
            listener.Initialize(IPAddress.Parse("192.168.0.101"), 81);
            ...
            Debug.WriteLine("This is a debug line");

请注意,IP 地址属于运行被调试应用程序的计算机,端口号应该是当前操作系统和硬件防火墙设置未阻止的端口;81 是一个不错的选择。IP 地址通常是本地的,因为预计会从局域网内的移动设备连接。要调试在 Internet 上运行的应用程序,可能需要对路由器进行更多设置。

已创建一个 WPF 应用程序的模拟器,以根据用户交互发送一些调试字符串。

移动设备端

在移动设备端,源代码也很简单,通过使用原生的WebSocket客户端对象,如下模板所示:

var socket;

function Initialize(address) {
    socket = new WebSocket(address);
    socket.onopen = function (event) {
       // Prepare the UI here
    };
    socket.onclose = function(event) {
       // Reset the UI here
    };
    socket.onerror = function (event) {
       // Display the error (event.data)
    };
    socket.onmessage = function (event) {
       // Display the debug message (event.data)
    };
}
function Stop() {
    if (socket !== undefined) {
        socket.close();
    }
}

地址必须指示ws://协议,并且应与 Windows 端指定的 IP 和端口匹配。

关于具体的工具,它有一个极简的用户界面。第一行允许指定套接字地址、启动和停止连接。传入的行将从上到下显示,并且可以像平常一样滚动。

成功连接后,Connect 按钮将变为禁用状态,Stop 按钮将变为启用状态。成功停止后,两个按钮将互换状态。

部署

需要部署的唯一文件是DebugConsole.htm,其中包含所有 HTML、CSS 和 JavaScript 代码。它可以放置在任何服务器上。由于这是一个使用WebSocket的 HTML5 应用程序,因此在通过浏览器加载后,该应用程序将作为独立应用程序运行。为了将此网页转换为缓存应用程序,需要一些技巧和窍门。

准备缓存应用程序的第一步是创建一个清单文件。最低内容应如下所示:

CACHE MANIFEST
CACHE:
DebugConsole.htm

网页通过将清单文件指定到 html 标签中来链接:<html manifest="manifest_file">。这将使页面缓存在本地机器上,直到清单在服务器上更改或用户手动清除本地缓存。

这里的一个重要技巧是,清单必须以MIME类型text/cache-manifest提供。许多作者建议配置服务器以允许该特定文件的此新 MIME 类型,但有时我们无法完全控制。另一种完成相同任务的方法是,在动态创建清单文件时手动操作标头。示例源代码显示了一种使用 PHP 的方法,但也可以使用 ASP 来实现。

<?php ob_start(); header('Content-type: text/cache-manifest'); 
echo 'CACHE MANIFEST
CACHE:
DebugConsole.htm';
ob_end_flush(); ?>

一个最后的技巧可以避免数小时的痛苦:在运行时修改标头时,在标头更改之前输出任何单个字符都极其重要。否则会引发服务器异常。请确保删除脚本文件末尾的任何额外空格。

iPhone 特定

要使其成为真正的 iPhone 应用程序,还需要一些额外的步骤。我们需要几个资源:一个 57x57 的图标和一个 320x460 的启动屏幕。这两个图像文件可以是pngjpeg格式。创建所需的资源文件后,应将其添加到清单中。

<?php ob_start(); header('Content-type: text/cache-manifest'); 
echo 'CACHE MANIFEST
CACHE:
Debug_Icon.png
Debug_Start.png
DebugConsole.htm';
ob_end_flush(); ?>

在 HTML 文件中,需要一些METALINK记录来告知 iOS 如何设置某些行为并处理添加的资源。

    <head>
        <title>VS Debug</title>
        <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
        <meta name="apple-mobile-web-app-capable" content="yes" />
        <meta name="apple-mobile-web-app-status-bar-style" content="black" />

        <link rel="apple-touch-icon" href="Debug_Icon.png"/>
        <link rel="apple-touch-startup-image" href="Debug_Start.png"  media="screen and (min-device-width: 200px) and (max-device-width: 320) and (orientation:portrait)" />

最后一步可以在以下屏幕截图中看到。总而言之,您需要使用Safari浏览到所需的页面,然后将页面添加到主屏幕。iOS 将扫描清单,并为将来使用图标和启动屏幕。

 

就是这样!您现在可以开发更多复杂的 iPhone/HTML5 应用程序,并与其他 Windows 应用程序连接了。

现场演示 

我暂时在地址: http://www.jaimeolivares.com/debug/DebugConsole.htm发布了一个调试应用程序的现场演示,但它可能会随时被移除或迁移。

© . All rights reserved.