用命令行参数启动自动部署应用程序

http://www.microsoft.com/china/msdn/archives/library/dnforms/html/winforms05152003.asp

用命令行参数启动自动部署应用程序

Chris Sells
Microsoft Corporation

2003 年 5 月 23 日

摘要:Chris Sells 共享某些自定义代码,您可以将其用在客户端和服务器端中以创建自动部署 Windows 窗体应用程序。(本文还包含英文链接。请注意,在示例文件中,程序员的注释使用的是英文,本文中将其译为中文是为了便于读者理解。)

下载 winforms05152003.exe 示例文件

我最容易被问及的问题之一是在人们开始使用“自动部署 (NTD) 应用程序”时,即可以用 URL 启动的 Windows 窗体应用程序,如何将命令行参数传递给这些程序。很明显,用户想要在其 Web 页面上提供不同启动选项的链接,或者想要基于当前用户的会话,用命令行参数动态生成 URL。有关后者的示例,请仔细查看图 1。


图 1. 带有指向 NTD 应用程序的链接的 Web 页面

图 1 显示了一个 Web 页面,它明显地针对访问的用户进行了个性化。在 Web 页面上的链接指向一个 NTD 应用程序,该应用程序在第一次运行时类似于图 2。

图 2. NTD 应用程序登录窗体

注意,此应用程序启动时预填充了用户名和 ID。我执行此操作的方法是使用如下格式的 URL 传递参数:
http://localhost/vacaplan/vacaplan.exe?uid=csells&uname=Chris%20Sells

从本地硬盘驱动器中启动被管理的应用程序时,命令行参数可以从传递到 Main 的字符串数组中获得:

static   void  Main( string [] args)  {
  
// 获得命令行参数
  string uid = "";
  
string uname = "";
  
foreachstring arg in args ) {
    
string[] pair = arg.Split('=');
    
switch( pair[0].ToLower() ) {
      
case "uid":
        uid 
= pair[1];
        
break;

      
case "uname":
        uname 
= pair[1];
        
break;
    }

  }

  
}

遗憾的是,支持从启动 URL 拖出命令行参数对于 Microsoft .NET Framework 1.1 来说是全新的并且几乎没有说明。而且,因为启动 URL 被用来创建指向 .config 文件的路径,所以对命令行参数的完全支持还需要在服务器端上运行某些代码。

注意:在 NET 1.0 中可以使用一种替代方法将命令行参数拖出启动 URL,本文稍后将对其进行介绍。

NTD 参数的客户端支持

要将参数拖出启动 URL,首先需要从 NTD 应用程序内部访问启动 URL。为此,.NET 1.1 提供了来自应用程序域的 APP_LAUNCH_URL 数据变量:

//  仅可用于 .NET 1.1+
AppDomain domain  =  AppDomain.CurrentDomain;
object  obj  =  domain.GetData( " APP_LAUNCH_URL " );
string  appLaunchUrl  =  (obj  !=   null   ?  obj.ToString() :  "" );
MessageBox.Show(appLaunchUrl);

从 APP_LAUNCH_URL 中可以提供完整的用来启动 NTD 应用程序(包括参数)的 URL。遗憾的是,APP_LAUNCH_URL 在 .NET 1.0 中不可用。但是,因为指向 NTD 应用程序的 .config 文件的路径就是将“.config”加在最后的 URL(包括参数),因此您可以在 .NET 1.0 中拖出与 APP_LAUNCH_URL 等效的参数。例如,从以下位置启动应用程序:

http://foo/foo.exe?foo=bar@quux

将产生以下 .config 文件路径:

http://foo/foo.exe?foo=bar@quux.config

因为应用程序域提供对 .config 文件路径的访问权限,所以对于 .NET 1.0 和 .NET 1.1 来说,您都可以使用此权限和少量字符串操纵获得对 NTD 启动 URL 的访问:

//  仅可用于 .NET 1.1+
AppDomain domain  =  AppDomain.CurrentDomain;
object  obj  =  domain.GetData( " APP_LAUNCH_URL " );
string  appLaunchUrl  =  (obj  !=   null   ?  obj.ToString() :  "" );

//  回到 .NET 1.0
if ( appLaunchUrl  ==   string .Empty )  {
  
const string ext = ".config";
  
string configFile = domain.SetupInformation.ConfigurationFile;
  appLaunchUrl 
=
    configFile.Substring(
0, configFile.Length - ext.Length);
}


无论哪种方法,针对 .NET 1.x 的默认 Intranet 和 Internet访问权限都允许从被部分信任的客户端访问命令行参数信息。一旦您获得了完整的 URL,就可以用它来对参数进行解码和分析参数。

安全性考虑

在了解如何获得参数之前,我必须简要说明有关在 NTD 应用程序中处理命令行参数的安全性含义。当参数被传递到已经安装在计算机中的 EXE 时,此操作通过 shell 或命令行控制台完成,因此您可以信任此操作。但是,在 Web 上,用户随时会受骗打开电子邮件附件或在浏览器中单击对其不利的链接。例如,将 HotMail 设想为允许下列参数的 NTD:

http://hotmail.com/edit.exe?uid=csells&forward=doctor@evil.com&ui=no

在这种情况下,没有任何确认 UI,我们就将指定转发电子邮件意图的参数传递给了其他人。如果此链接被嵌入到 Web 页面中并标为“Free Chocolate!”,老实说您能不受诱惑自己不去单击此链接?在将参数发送到不受控制的、混乱的 Web 世界之前,请确保已仔细考虑命令行参数组合暴露的可能性并提防那些居心不良的人。

对 URL 进行编码和分析

可以控制安全性以后,您将需要分析 URL 本身的参数。有时您需要将特殊字符编码到传送这些字符的 URL 中,就象您将这些字符传递到服务器端的一段代码一样。例如,要对 uname 参数中的空格进行编码,需要用 %dd 语法对空格字符的 ASCII 值进行编码:

http://localhost/vacaplan/vacaplan.exe?uid=csells&uname=Chris%20Sells

在服务器端,System.Web 不是提供一个,而是提供两个用于对 URL 进行解码的类(HttpServerUtilityHttpUtility)。遗憾的是,Intranet 或 Internet 区域中的 NTD 客户端都不允许使用任何一类中的 UrlDecode 方法。幸运的是,对 .NET Framework 类库进行稍有创意的反向工程可以产生一个您可以使用的 UrlDecode(已随本文的源代码一起提供)。对 URL 进行解码后可将类似 %20 等字符还原为实际字符:

http://localhost/vacaplan/vacaplan.exe?uid=csells&uname=Chris Sells

一旦将 URL 解码,您就可以拖出实际参数,并使用问号作为 URL 参数部分的标记,& 作为参数之间的标记。遗憾的是,尽管 System.Web 提供了一个类以执行此操作 (HttpValueCollection),该类只能在内部使用以实现查询字符串分析,其本身并不可单独使用。幸运的是,对此字符串分析功能进行反向工程以使用此功能(即将参数拆分成关键字/值对)以供使用并不难,示例也此提供了该操作的代码。

抽取命令行参数

在示例中,URL 解码和查询字符串分析都被一起捆绑在 WebCommandLineHelper 类中:

static   void  Main( string [] argsFromMain)  {
  
// 获得命令行参数(从 Main 或从启动 URL)
  string uid = "";
  
string uname = "";
  
string[]
    args 
= WebCommandLineHelper.GetCommandLineArgs(argsFromMain);
  
foreachstring arg in args ) {}
  
}


WebCommandLineHelper 类的 GetCommandLineArgs 静态方法将从 Main 中检索到的参数作为输入参数。在 GetCommandLineArgs 方法内,首先检查应用程序是否从 URL 启动:

static   public   bool  LaunchedFromUrl  {
  
get {
    
try {
      
// 查看是否有站点
      string  url = (string)AppDomain.CurrentDomain.GetData("APPBASE");
      System.Security.Policy.Site.CreateFromUrl(url);
      
return true;
    }

    
catch( ArgumentException ) {
      
return false;
    }

  }

}


NET 程序集的 appbase 是其来自的位置;例如,硬盘驱动器中的某个位置或某个 URL。如果可以从 appbase 提取站点,则应用程序从 URL 启动。如果不是从 URL 启动应用程序,则 GetCommandLineArgs 只返回来自 Main 的传递到其本身的参数。

static public string[] GetCommandLineArgs(string[] argsFromMain) {
  if( !LaunchedFromUrl ) return argsFromMain;
  ... // 解码和分析参数的 URL
}

通过这种方法,应用程序并不真正关心参数所来自何处。重要的是参数本身。为方便起见,WebCommandLineHelper 将合并参数的两个源。

对 NTD 参数的服务器端支持

遗憾的是,客户端不是简单的为 NTD 应用程序拖出和处理命令行参数。因为 URL(包括参数)用来生成指向 .config 文件的路径,所以如果您要为 .config 文件提供服务,您需要某些服务器端代码来为 .config 文件转译请求,格式如下:

http://foo/foo.exe?foo=bar@quux.config

在类此的请求中,参数已除去:

 
http://foo/foo.exe.config

IIS 查看 foo.exe.blah.config 时,它将此映射为对 .exe 文件的请求,而不是 .config 文件。这意味着查找 .config 文件的 .NET 的各部分(例如程序集解析进程、自定义配置读取器和 Web 服务),请求 .config 位时将都被传递 .exe 位。尽管前两个堆栈将无提示地失败,就好像缺少 .config 文件一样,.NET Web 服务堆栈在其获得 .exe 位时将会引发异常,即使最初并没有要服务的 .config 文件。很明显,这不是我们所要的。

让 ASP.NET 处理 .EXE 文件

在存在 URL 参数的情况下服务相应的 .config 文件是一个多步骤过程。步骤一是将对 .exe 文件的请求转交给 ASP.NET,以便您可以阻止某些自定义代码对 .exe 文件的请求。默认情况下,所有 Web 应用程序都配置为直接分发 .exe 文件。要将 .exe 扩展名映射到 ASP.NET,请使用 IIS 配置工具调整您的 Web 应用程序的配置,如图 3 所示。


图 3. 将 .exe 文件映射到 IIS 中的 ASP.NET

处理 .EXE 文件

一旦 ASP.NET 处理 .exe 文件,您就可以添加一个 HTTP 处理程序,它关于 ASP.NET 如何允许您写入自定义代码以处理请求。一个处理程序只是 IHttpHandler 的一个实现:

 

public   class  ConfigFileHandler : IHttpHandler  {
    
// 只是文件系统的 .exe 部分
    string path = context.Request.PhysicalPath;

    
// 整个请求 URL,包括参数和配置
    string url = context.Request.RawUrl;

    
// 如果有人请求配置,则提取参数
    string ext = ".config";
    
if( url.ToLower().EndsWith(ext) ) {
      context.Response.WriteFile(path 
+ ext);
    }

    
// 如果有人请求配置,则 .exe,则发送 .exe
    else {
      context.Response.ContentType 
= "application/octet-stream";
      context.Response.WriteFile(path);
    }

  }


  
public   bool  IsReusable  {
    
get return true; }
  }

}

IHttpHandler 接口只有一个有趣的方法 - ProcessRequest。此 ProcessRequest 方法使用某些处理程序获得的上下文(例如指向客户端请求文件的物理路径和同一请求的原始 URL)并检查 URL 是否以“.config”结尾。如果符合这些情况,我们构建被请求的 .exe 文件的物理路径(请记住,IIS 和 ASP.NET 将 .exe 文件,而不是 .config 文件,看作被请求的文件),将“.config.”加在最后并生成相应的 .config 文件。

因为我们已经更改了 .exe 文件到 ASP.NET 的映射,此处理程序将负责分发 .exe 文件和 .exe.blah.config 文件。如果某人正在请求 .exe 文件,则我们设置相应的 MIME 类型并生成此文件。

不论何种情况,如果缺少被请求的文件,则会生成一个 404 错误,.NET 可以处理此错误。

将 .EXE 文件映射到处理程序

将 .EXE 文件映射到 ASP.NET,并实现了一个 .NET 处理程序以生成 .exe 和 .exe.blah.config 文件以后,您仍旧需要让 ASP.NET 知道哪个处理程序要用于 .exe 文件。您在 web.config 文件中为您的 ASP.NET 应用程序执行此操作:

 

< configuration >
  
< system .web >
    
< httpHandlers >
      
<!--  map .exe and .exe?blah.config files to our handler  -->
      
< add  verb ="*"  path ="*.exe"
           type
="Genghis.Web.ConfigFileHandler, ConfigHandler"   />
    
</ httpHandlers >
 
</ system.web >
</ configuration >

当 ASP.NET 查看到 <httpHandlers> 部分中的此 <add> 元素时,它将所有路径以 .exe 结尾的 HTTP 映射到 ConfigHandler 程序集以及 Genghis.Web.ConfigFileHandler 类(先前显示的 IHttpHandler 实现)。ASP.NET 将在 Web 应用程序的根中查找 web.config 文件并在 Web 应用程序根处的 bin 目录中查找程序集,因此确保将文件放在正确的位置。

允许 IIS 和 ASP.NET 分发 .config 文件

将对 .exe 文件请求从 IIS 路由到 ASP.NET 后,除了写入处理程序以传递回 .config 文件、将对 .exe 文件的 ASP.NET 请求路由到该处理程序,还有另外两个配置步骤。第一是因为 IIS 不允许将 .config 文件发出(除非启用匿名访问)。您将需要在您的 IIS Web 应用程序的 “目录安全性”的“验证方法”对话框中检查“匿名访问”,如图 4 所示。


图 4. 在 IIS 中启用对 Web 应用程序的匿名访问以允许使用 .config 文件

并且,在 ASP.NET 正确地允许分发 .exe 文件和 .exe.args.config 文件时,默认情况下,不允许分发 .config 文件。换句话说,我们用当前配置仅可以分发以下四种 URL 类型中的前三种:

1. http://foo/foo.exe?foo=bar@quux
2. http://foo/foo.exe?foo=bar@quux.config
3. http://foo/foo.exe
4. http://foo/foo.exe.config

前三种 URL 类型显示在我们的处理程序中。如果您无需任何 URL 参数,但是仍需要 .config 文件来启动您的 NTD 应用程序,则第四种 URL 类型很重要。默认情况下,ASP.NET 不分发 *.config 文件的原因是因为您可能将各种敏感信息保存在您的 web.config 文件中。要启用 *.config 文件以分发该文件,但是仍保持 web.config 文件受到保护,请添加下列项:

 

< configuration >
  
< system .web >
    
< httpHandlers >
      
<!--  map .exe and .exe?blah.config files to our handler  -->
      
< add  verb ="*"  path ="*.exe"
           type
="Genghis.Web.ConfigFileHandler, ConfigHandler"   />
      
      
<!--  allow .config files but disable web.config files  -->
      
< remove  verb ="*"  path ="*.config"   />
      
< add  verb ="*"  path ="web.config"
           type
="System.Web.HttpForbiddenHandler" />
    
</ httpHandlers >
 
</ system.web >
</ configuration >

在这种情况下,ASP.NET 将 .config 文件映射到 HttpForbiddenHandler 中,这确保不会将它们分发回客户端。我们将删除该处理程序的映射,以便允许 .config 文件,然后再次将其添加回 web.config 文件,以使那些剩下的文件仍旧受保护。

我们所处的位置

现在可能非常清楚了,尽管 .NET Framework 1.1 提供对 NTD 应用程序的启动 URL 的访问,并无内建的真正支持以在启动 NTD 应用程序时处理 URL 参数。但是,使用某些创意的编码,您仍旧可以做到:

  • 在客户端上,使用 APP_LAUNCH_URL 或 ConfigurationFile 以获得启动 URL,根据需要对其进行解码和分析。
  • 如果服务器中使用的是 ASP.NET,请:
    1. 配置 IIS 以将对 .exe 文件的请求路由到 ASP.NET。
    2. 实现一个处理程序以生成 .exe 和 .exe?blah.config 文件。
    3. 将处理程序映射到用于您的 ASP.NET 应用程序的 .exe 文件。
    4. 配置 IIS 匿名访问以允许使用 .config 文件。
    5. 删除禁止所有 .config 文件的 ASP.NET 处理程序映射。
    6. 添加 ASP.NET 处理程序以禁止 web.config 文件。

因此,尽管并非如我们希望的那样完全支持参数,.NET 仍足够灵活,并在客户端和服务器端具备某些智能,您完全可以将参数传递到 NTD 应用程序中。

参考

注意:本材料的某些内容改写自 Addison-Wesley 即将出版的标题为 Windows Forms Programming in C# 一书,作者 Chris Sells (0321116208)。

Chris Sells 是 MSDN Online 的内容战略家,当前专注于 Longhorn(Microsoft 的下一个操作系统)。他已撰写了若干著作,包括 Mastering Visual Studio .NETWindows Forms for C# Programmers。在业余时间内,Chris 主持各种会议,指导 Genghis 可用源项目,和 Rotor 玩,通常会在 blogsphere 中捣捣乱。有关 Chris 及其各种项目的详细信息,可从站点 http://www.sellsbrothers.com/ 获得。

Linux 多tomcat服务 统一安装 统一部署 工具 shell编写 1 引言 基于JAVA开发项目,随着服务的越来越多,配置文件更是眼花缭乱,每次不知道因为配置问题浪费多少时间,更不知道因为配置问题出过多少问题。多台服务器来回切换,如果服务需要依赖,启动更是问题。 1.1 目的 一次修改,统一安装;操作简单,实用高效。 1.2 范围 本项目使用范围包括: * 基于JAVA开发项目 * 项目相关服务繁多 * 服务启动有依赖关系 1.3 读者 本需求规格说明书的阅读者或其他文档干系人有平台总监、产品经理、项目总监、项目经理、开发人员、测试人员、用户体验设计人员等。 2 项目总体描述 2.1 系统总体功能框架 2.2 系统功能列表 Exec 建立信任、初始命令 初始 Tools 提供服务与服务列表 扫描提供服务列表,获取配置信息 Conf 自动获取需要修改配置 自动生成 Bin 执行脚本 提供总执行与单一执行脚本 New 存放修改后配置文件 与bak保留文件成反比 Bak 存放原始配置文件 便于问题分析 Temp 存放临时文件 临时文件将及时删除无任何冗积 Workapp 存放war包 上传war包 3 功能描述 3.1 获取配置文件 通过本系统获取配置文件非常简单,只需用户提供服务列表,其他无需操作。服务列表如下: name ip serve 服务名称 192.168.0.1 /home/tomcat_服务名称 服务名称 192.168.1.2 /home/tomcat_服务名称 服务名称 192.168.1.2 /home/tomcat_服务名称 名词解释: name :服务名称,需与war包名称一致。 ip :服务器ip地址。 serve :Tomcat部署路径。 执行脚本,“.. /unifyDeploy/conf”自动生成用户所需修改配置文件,配置文件是通过筛选后生成,所以一个服务不管需要配置多少文件,这里只生成一个,方便修改与管理。 3.2 自动化统一安装部署 自动化统一安装部署,包括:上传解压war包、同步配置、启动服务、监控服务等。 list.ll one.sh pass.war startup.sh syn.cn two.sh 部署支持统一安装于分布式安装,每个脚本可以拆分开任意组合使用,比如: 1) 一套新环境tomcat中还未部署服务,只需调整上传war包脚本顺序,先上传war后,后续操作正常执行。 2) 迭代更新,功能稍作修改,原配置项无需修改,也只需调整上传war包脚本顺序,先获取原有配置,再上传更新war包,后续操作正常执行。 3.3 优缺点描述 优点描述: * 适用于统一安装部署,也适用于单独服务安装部署。 * 保留原始备份,方便部署前后配置对比。 * 操作简单、需求扩展能力强。 不足描述: * 暂时只适用于基于tomcat服务器项目。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值