[教程]ASP.Net调试之三板斧

mikel阅读(715)

一、Config.web
用过ASP的人对它的调试应该是记忆深刻的。在整片整片的代码中找到那几个
出错的地方,难度可想而知。现在微软推出了ASP的更新换代产品ASP.NET。对于
ASP.NET的好处,我想很多网站都已经介绍了差不多的,不过对于ASP.NET的调试
讲得就不是很多了。所以,我就以我的一点个人经验写了这一篇文章。由于,我
也是接触ASP.Net不久,错漏之处在所难免,还请大家多多指正。好了,言归正传。
第一招:配置Config.web
一般,当我们写好的网页运行出错了,ASP.Net就会在页面上告诉我们程序有
错了,但究竟错在哪里,它是没有提示的。为了能让ASP.Net进一步提示我们出错
的信息。我们就有必要编辑Config.web中的配置信息。
可能还有很多刚刚接触ASP.Net的人不太了解Config.web这个文件。那我就顺便介绍一下。Config.web是ASP.Net的一个配置文件,它里面存放着关于ASP.Net的所有配置信息。当执行一个ASP.Net页面时,它会先到该页面所在的目录查找这个文件,如果没有找到,就往上一级目录找,一直到wwwroot目录。如果都没有,它就会调用X:\WINNT\Microsoft.NET\Framework\ v1.0.2204目录中的Config.web文件(X为系统目录)。所以,如果大家要想改变所有页面的配置,就应该改WINNT目录中的那个 Config.web。另外顺便说一下,当你打开Config.web后,你会发现这是一个XML结构的配置文件。
好了,介绍解说这么多了,回到我们的主题。现在你要做的第一步就是:打
开或者新建一个Config.web文件。我们分开来说:
如果是新建,你就需要用文本编辑器新建一个新的文档,然后往里面输入下
面的语句:



输完后选择另存为,输入文件名Config.web,将它保存到当前页面相同的文件夹中即可。如果是修改一个已经存在的Config.web文件,你只需要用文本编辑器打开它,然后在之间的任意地方输入:
即可。
二、<%@%>
上一次我们说到配置Config.web文件,让出错信息给出更多的提示。可光有
提示又有什么用呢?“最多就是知道错在哪里,可我还是不会改呀!”别急,别
急,看看咱们这篇文章叫什么来着,“三板斧”,那当然是一斧赛过一斧啦!上
次那招不够厉害,我们还有下面的那,所以别急啊,且听我慢慢道来。
第二招:Trace追踪
用过ASP的人应该都用过下面的语句吧:
Response.Write XXX
Response.End
虽然我不太喜欢ASP的编程方法,但是这种方便的调试手段还是很好的。换用
ASP.Net以后,我发现ASP.Net提供一种更强大的调试方法,它就是我们现在要说
的Trace。所谓Trace功能就是在网页的最前面加上一些标记,至于是什么标记呢?嘿嘿,我不能马上告诉你(不好,臭鸡蛋……哇!)。我是说,我要先介绍一点基础的知识啦!
我不知道大家对ASP.Net的页面标示了解多少,为了下面讲解的方便,我还是
概要的介绍一下吧!ASP.Net的页面标示指的是在每一个ASP.Net页面最上面,用
<%@和%>括起来的语句。它的功能是用来确定在处理ASP.Net文件的时候,需要系
统做一些什么特殊的设定。具体的语法如下:
<%@ directive attribute=value %>
其中:directive就是页面标示符;attribute是该标示符对应的一些属性。
注意:在属性之间需要空格,而在”=”之间不能有空格。
ASP.Net现在包含以下7种标识
@ Page,
@ Control,
@ Import,
@ Registe,
@ Assembly,
@ OutputCache,
@ Webservice
我们用得最多的就是@ Page标示,而现在我要讲的Trace功能,也要用到@ Page。(关于这七个标示的具体应用,我会在以后发贴讲述的。)好了,回到我们的主题。要用Trace功能,你必须在页面的最上面加上:<%@ Page Trace="true" %> 这句话。加好后,你就可以看看页面的运行情况了。运行该页面。你会发现在页面的下半部分出现了一大堆的数据。下面就来解释一下这些数据的含义:
Request Details:通过Request方式向浏览器所读取的数据;
Trace Information:事件发生或程序执行的过程信息;
Control Tree:网页所使用的控件及控件之间的阶层关系;
Cookies Collection:网页所使用的Cookie信息;
Headers Collection:浏览器的表头信息。
Server Variables:Server变量的数据信息。
有了这一大堆数据,我们的工作就好做多了,但且慢欢喜,Trace还提供了更强大的功能,请接着看下去。
除了让ASP.Net页面显示这一堆数据外,我们还可以将程序中用到的变量的
值实时的显示在Trace Information区段中,其方法是调用Trace.Warn或Trace.Write两个方法。他们的用法如下:
Trace.Warn(“Description”,Variables);
Trace.Write(“Description”,Variables);
我想你们一定会问,这两个有什么区别呢?回答是:在功能上,这两个是一模一样的,只是在显示上,Trace.Warn将会以红色字体表示。
三、 查错神器Debugger
要用好的兵器,没点准备是不行的,所以我们就先来做点准备运动。
1.Config.web的设定:还记得第一招中讲的吗?对了,还是这个文件,打开它,向里面加入这条语句

说明:由于在预设情况下,ASP.Net会以正常模式来运行页面,为了能让它以查错模式编译网页,我们就必须加入这句语句。
2.启动查错工具DbgUrt.exe:这个程序放在x:\Program Files\Microsoft.Net\FrameworkSDK\GuiDebug目录里,文件名是DbgUrt.exe
3.激活查错功能:
运行DbgUrt.exe程序
–〉选取菜单Debug/Processes
–〉在出现的Processes对话框中选中Show system processes和Show processes in all sessions
–〉在Available processes列表框的最下面找到xspwp.exe(如果没有,请运行一.aspx页面,然后按Refresh键。)
–〉选取该文件后,按Attach键
–〉在出现的对话框中选中Common Language Runtime,然后按OK,回到Processes对话框
–〉按Close键
–〉在程序的主菜单中选取File/Open/File,打开你想要检测的文件。
下面正式开始页面调试。
利用DbgUrt.exe打开欲调试的文件后,我们要做的第一件事情就是:设置断
点。是不是觉得和其它Windows应用程序的调试很像(什么很像?简直就是一模
一样吗!)加断点的方法很简单,先决定需要加断点的地方,然后将光标移动到
该行,按下F9或者在该行的最前面点击鼠标左键,该句前面就会出现一个问号的
标记,这就是断点!我们当然可以设定多个断点,只要你喜欢。你要是像取消一
个断点,只需在该行重复设置断点的动作即可。
设置好断点后,只要使用浏览器浏览被调试的页面,当程序运行到断点的位
置时,它就会自动弹出DbgUrt.exe,并且停在刚才的断点位置。这是,我们就可
以利用Command Window-Immediate窗口检查变量的值了。
当我们想继续执行当前页面时,我们有几种选择:
1、按F5键,运行到下一个断点,若没有断点,则运行完该页面;
2、按F11键,执行单步操作;
3、按F10键,同样是单步操作,但它会进入子程序(函数)中的语句。

[架构]超越SOA:动态业务应用的新企业应用框架

mikel阅读(825)

第一部分——即使拥有全部需求和最佳设计,你的架构仍然很可能失败,原因在于……

目前的管理学校,教育培养的是公司经营者。设计公司几乎没有引起重视……几乎从来没有任何人为了取得计划的增长和稳定性,有意识和有思想地设计一个组织。

相关厂商内容

Dev2Dev技术日:如何在SOA参考架构中使用Eclipse、Java、Flex和SOA?

SOA中国关键任务论坛(5.22北京)Free电子票下载

相关赞助商

5月6日至5月22日全国8站,BEA Dev2dev TechDays与您一起探讨Java2SOA最新技术变革。即刻免费报名参加,获赠BEA/Adobe软件和SOA书籍。

——  Jay W. Forrester,设计未来(1998)

介绍

在一篇名为《动态业务应用势在必行(The Dynamic Business Applications Imperative)》的论文中,Forrester的高级分析师John R. Rymer指出了当今应用的一个致命缺陷:

当今应用迫使人们去寻找一种将孤立的信息和功能组映射到他们任务和过程的方法,它们强迫IT人员花高额预算来跟踪不断变化的市场、策略、规章制度和业务模型。

在下一个5年内,IT的主要目标应该是发明新一代企业软件,适应业务和业务工作,同时能随业务演变而演变。

Forrester称这个新生代为动态业务应用, 强调了和业务过程及工作(为人而设计)的紧密配合,对业务变化的自适应(为变化而构建)。在这个阶段,动态业务应用的需求比创建它们所需的设计实践更清 晰。工具都是现成的:面向服务架构(SOA)、业务过程管理(BPM)和业务规则领域中的先驱——包括独立软件开发商(ISV)——已经开始向我们展示了 这种方法。现在就是开始这段旅程的时候。

在这篇由两部分组成的文章中,我们会从架构和方法论的角度,采用历史的观点来看待这些动态业务应用(DBA)的发展。我们的目标是获得一种能使应用容易适应业务变化和其他必要修改的构建方法。随着企业在21世纪关注灵活性,DBA是使业务和IT在未来几十年内成功的关键。

图 1. 灵活性和效率——21世纪企业的两个主要驱动力

动态性对我们意味着什么?

在软件工程领域,许多框架或产品都声称具有自适应性。在我们设法理解一个解决方案在适应变化方面究竟有多好之前,需要给系统是如何变化的——它们的动态性——下一个可靠的定义。

早期的面向对象方法论认识到[1]:为了使系统分析中立,它必须基于两类现实世界的需求:

  • 现实世界的实体 —— 收集现实世界实体的信息和它们间的关系,有助于分析师开始以一种系统的、结构的、客观的观点来看待需求,而非一种技术的、主观的观点
  • 现实世界的事件 —— 系统行为只由改变现实世界实体状态的事件的出现来驱动

在这样的背景下,对于每一个被分析的系统,我们总能识别一个或多个最重要的实体。每个实体都又包含3个关联元素:事件、状态和生命周期。每个事件代 表状态中的一个变化,所有普通实体状态的有序和代表了一个生命周期。但是,那些触发状态变化且是正常流程一部分的事件与那些触发状态变化但不是正常流程一 部分的事件之间有明显的差异。例如,当一个产品订单被提交之后,一组可能发生的事件包括付费处理和订单交付。当一个用户变更订单或当企业改变价格时,我们 不能认为这些动作是正常流程的一部分,因此它们与实体(如订单)的生命周期无关。核心实体实例的生命周期单独定义了在正常操作中系统最有可能处理的东西。 所有其他事件类型,如变化或中间步骤,被区别对待。

这个场景对很多工程师都不陌生:一个系统模型包含一个核心实体结构,该实体具有一组事件,这些事件组成了实体的生命周期。这个系统模型对分析师和设 计者都很清晰且易于理解。建模工具,如有限状态机、实体关系图、实体状态转换图和数据流图,为了帮助这种方法已经经过了快20年的完善。那些为复杂系统 (如空客380或F-22,后者是世界上最高级的战斗机)服务、拥有数十亿行代码的软件就是这样被编写出来的。使用对象流图(它是捕获事件和状态转换的基 础模型)虚拟化实体生命周期是这个模型的关键。在这个情况下,架构可以被认为是静态的,因为整个系统状态在时间轴上的任意一点都是确定的。

图 2. 事件模型、状态变化和生命周期是正常操作的核心

普通事件、状态、生命周期间的关系,以及从其他事件类型中分出的普通事件是理解所建议的动态操作框架的基础。正如James Martin 和James Odell很久以前在《面向对象分析设计》中所写的,分析师、设计师和实现者都应该使用同一系统模型。分析师使用数据流图思考,设计师使用结构图思考,程 序员使用Java和SQL思考。在数据流上下文中,分析师识别对象类型,并思考改变对象状态的事件。最终用户也理解这个相同的认识。他们也应该按照对象类 型、事件、对象状态的变化,以及触发和控制事件的业务规则进行思考。Martin和Odell强调了对象流图对系统设计师的重要性:“事件模式适合按照事 件、触发器、条件和操作来描述过程。但是这种方式不适合描述大型复杂过程。一个系统领域常常太大或太复杂,无法表示成事件和触发器。此外,可能只有一个高 级别的认识才是必要的。这对战略级别的规划尤其正确。在这样的情况下,一个对象流图是有用的。对象流图(OFD)与数据流图(DFD)类似,因为它们描述 了活动和其他活动间的接口。在DFD中,这个接口传递数据。在对象技术中,我们不再限于数据传递。相反,图应该表示从一个活动传递到另一个活动的任何类型 事物:不论它是报表、零部件、已完货物、设计、服务、硬件、软件——或数据。简而言之,OFD指的就是被产生的对象,以及产生和交换它们的活动。”

为了捕获与业务操作关联的信息流,业务分析师用价值流程图(Value Stream Mapping)对OO方法论进行了补充。价值流程图起源于丰田,与精益制造关系紧密。美国国家环境保护局将价值流程图定义为“用来认识那些产生产品或交 付服务的活动序列与信息流程的精益过程映射方法。”此处的关键词是“产品”和“服务”。它们显现了合适的信息流程在整个企业中扮演的统一角色。

把过程流图和价值流程图两个概念结合在一起后,它产生了一个完全代表整个企业经营范围、可被方便翻译成OO(图2)概念的框架基础。

但是,许多系统并不是静态的,它们变化无常的行为无法被一组关系和事件捕获。事实上,它们发生在不可知的[2]未来,传统用来捕获它们动态特点的工具不起作用。所有的业务应用和绝大多数现实世界的系统都归于此类。这些系统,基于它们和其他外部系统的交互方式,处理3类变化:

  • 正常工作 —— 组成主实体或实体们生命周期的正常事件序列。通过每个事件——实体改变其状态——通常可以方便地定义一个过程。在正常工作行为内部,有些操作上下文元素不 期望被改变。例如,当一个客户订购一个产品时,在整个提取订单、准备订单和交付订单的过程中,诸如价格、组成和交付方式等是不期望被改变的。
  • 内部变化 —— 如上所述,在整个核心实体生命周期内,某些上下文元素不期望被改变。在现实世界中,这并不总是真理,因为管理决策或其他因素会迫使上下文元素变化。我们称内部系统属性的变化是内部变化。
  • 外 部或环境变化 —— 不管一个企业如何相信他们“拥有”一个客户,但是这个客户总有保留改变他或她意志的自由。一个系统不太可能与外部系统(如客户或供应商)总是有一个“固定 的”合同。然而,正常工作很可能围绕这个“固定的”规则集合进行设计。我们称系统外部引起的变化为外部变化。

要对现实世界系统建模,就必须处理好这所有3种变化类型。这种模型与静态架构模型相比,在管理复杂性上有了极大的提高。从正常工作的观点来看,内部 和外部系统完全独立于主信息流运行。内部和外部系统甚至有它们自己的操作——管理有其自身的决策周期,客户有其自己的操作环境——由各自的信息流描述。就 信息流而言,这3种系统分别运行在3个平行宇宙中。解决这3种非同步信息流的唯一办法就是为每个信息流实现一个独立全面的变更管理。这种复杂交互在图3 (动态操作图)中表示。

邮轮公司给客户提供的服务可以作为解释动态操作的例子。在订购时,一个客户会决定在游览期间他计划参与的服务。但是,不仅客户可能在游览前和游览中 改变主意,而且邮轮公司也可能会为了利用新机会或应对未知事件改变服务。按照当前方法设计的系统,大部分变更都以极高的运营成本人工处理。使用基于动态业 务应用架构原则设计出的系统,来自客户和内部管理决策的变更由两个与正常工作完全集成的变更管理子系统负责。这不仅能降低成本,而且还提高了服务质量,甚 至可以最优化运营来提高利润。因为是完全通用的,它还可以重用标准组件。最终结果对于参与的每个人、业务、IT和客户来说是多赢的。

图 3. 动态操作有3个维度——正常事件、内部控制和外部反馈

动态业务应用的目标之一就是使设计和软件实现变得简单,以支持对所有业务来说司空见惯的动态系统。以我们的经验,与一个框架优先的工程学相结合是构建一个DBA的最有效的技术方法。

设计企业系统要求框架先行

构建动态业务应用说起来简单,做起来难。工程,包括软件工程,都采用了有百年历史的框架优先方法。设计一座桥梁、一架飞机或者甚至是一个软件应用都 使用相同的方法:一个设计团队先收集需求,然后使用一组定义良好的框架步骤来设计和构建系统。在设计桥梁和其他工程系统时,现有框架已被证明非常成功。但 在使用它来为业务系统开发软件时,却碰了壁。这两类系统之间有一个根本区别。在设计桥梁和飞机时,最终结果总是一个拥有静态架构的系统:当变更发生时,如 增加桥梁负重或飞机速度,整个系统可能就要重头重新设计。不幸的是,软件也常常使用一个静态架构进行设计:每当一个非预期的变更被引入到运营中时,很可能 所有事情都停了下来,使用包含新增功能的系统替代现有系统。因为业务运营在一个不断变化的环境中,而且比以往更依赖IT系统,这种停——走式的解决方案是 不可接受的。持续升级和在企业基础设施中集成系统的成本已经达到了无法支撑的地步。

依赖业务涉众作为我们全部需求的输入首先就是个问题。考虑到需求,目前还没有真正适合动态操作的“框架优先”软件设计方法。甚至卡内基梅隆软件工程 学院也表示架构是由场景驱动的,场景以涉众输入为基础被创建出来:“诱导一个软件密集型系统的业务目标是标准架构设计和分析方法的一个组成部分。业务目标 是驱动方法的引擎,通过将它们的实现作为场景……一个理想的设计方法或过程必须考虑众多涉众和众多影响。”

作为工程师,当我们收集系统需求时,我们怎能知道我们得到了正确的场景或是否遇上了正确的涉众?我们又如何能说明业务未来的变化,而这些变化通常连参与的涉众都不知道?

“企业经营者和企业设计师之间存在着根本区别。为了说明这点,考虑一下在一架飞机成功操作背后的两种最重要的人。一个是飞机设计师,另一个是这架飞 机的飞行员。设计师创造的飞机连平庸的飞行员都可成功驾驶。一般情况下,经理更像是飞行员而非一个设计师。一个经理管理一个组织,这和一个飞行员驾驶飞机 没什么两样。飞行员的成功依赖于那些创造了一架成功飞机的飞机设计师。另一方面,是谁来设计一家由管理者管理的公司呢?几乎从没有任何人有意识和有思想的 去设计一个组织,以取得有计划的增长和稳定性。在当前的管理学校中,教育培养的是企业的经营者,而如何设计企业几乎不受重视。”

在几年前完成的报告“设计未来”中,MIT的教授和系统动态之父Jay Forrester,指出这个问题是我们为企业设计系统的基本限制:

Forrester的观察进一步使当前的企业架构方法失效。在我们需要设计一个企业系统架构时,作为知识主要来源的涉众甚至是错误的分类。他们是企 业的“用户”,不是“设计师”。在设计飞机时,飞机设计师决不可能去询问飞行员或乘客关于飞机制造方面的事情。但是,在学校、工程或MBA课程中却没有企 业设计这门课。

那么回到企业架构,其中有一个根本的断档。企业架构的“用户”是企业涉众,很可能是熟悉企业动态性的企业毕业生,但是他们不熟悉工程方法。企业系统 的设计者和构建者——软件工程师——熟悉静态框架,但是对动态框架却很陌生。事实上,还没有说明业务动态的框架。根据企业架构框架,这是一个需要填补的缺 口。这个框架只描述企业是如何“被设计的”,但是也会定义开发路线图和主要组件,使用它们来构建企业的支持系统。

图 4. 企业架构的业务和工程方法

我们建议根本改变我们架构和设计信息系统的方式,以一种不要求业务涉众作为主要输入的方式。我们推荐利用一个以业务实体生命周期和事件模型为中心的框架作为架构的主要输入来源。业务场景只被用来微调一个已完架构,而不是作为主要驱动力。

这种框架优先方法从一开始就说明了业务动态,而不是事后诸葛亮。它暗示被设计的企业应用是动态适应的,而不是像由今天的方法论所实现的那样是静态适应的。这种方法成数量级的减小了开发和维护软件的成本,并砍掉了与改变和维护现有系统直接相关的超过70%的IT开销。

Fig 5. 基于框架的软件解决方案开发方法

在我们建议的方法中,业务场景只被作为一个已完架构的微调,而不是主要驱动力。我们将我们的直觉、经验和技巧输入到设计过程中越晚,产生导致巨大损失的错误的可能性就越少。由涉众输入引起的需求变更会在已经建好的现有解决方案框架中处理,减少了风险和延迟。

一份Standish报告研究表明,超过1千万美元的项目,成功率只有3%。行业咨询和哈佛商学院教授Andrew McAfee表示,部署如此高成本技术(如ERP、CRM、供应链管理、电子商务和其他企业应用)组织的成功率在25% ~ 70%之间。McAfee总结说:“这些面临的问题并非是单独的,它们都是同一事情的不同例子,基本上都是使用IT改变业务过程的结果。”。最近,这些百 分比有所提高,但是对于复杂系统IT仍缺乏清晰的路线。框架优先的方法能使业务变化集成到IT实现中,并提供了业务和技术之间更清晰的转换,可以将成功率 提高接近100%。建构复杂系统的时间由几个月或几年缩短至几天。

动态操作的服务器架构 —— 忘记SOA,迎接信息装配线

90年代早期,事件几乎是每本面向对象方法论书籍中的核心角色。随着象Windows这样基于GUI操作系统的出现,GUI开发平台依靠复杂事件模型来设计和构建单个应用。但是,在客户机-服务器环境中,服务器端的事件处理总是基于一个简单得多的模型。

当基于Web的技术(如J2EE和.NET)开始替代传统的客户机-服务器应用,客户机和服务器都经历了根本的转变。客户端的富OS事件模型由 Web浏览器和原始的脚本语言代替。在服务器端,事件处理由无状态、扁平的、静态架构所替代。其方式非常类似将网页传给Web浏览器的方式。

为了模拟现实世界的需求,需要一个有状态的、层次的、动态的和分布式的架构,设计必须严重依赖数据库来存储范围广泛的各种动态信息。但是根据其定 义,关系数据库非常适合存储不常变化的数据间关系。保存动态、分布式、层次的和有状态信息要求一个不同的基础设施,它不是以关系数据库为中心的。

基于Web的技术为支持现实世界系统引入了其他挑战。当J2EE应用服务器在一个分布式环境被使用时,使用Java作为编程语言的一个最大优势完全 没有了。Java虚拟机的垃圾回收从来没有被设计成能自动清除在多实例间交换的内存对象。在这种情况下,架构师和设计师必须编排整个对象生命周期,不考虑 编程语言的能力。甚至在数据保存在数据库中时,这种相同的数据清除问题也变得非常困难。

正如我们已经看到的,一旦我们能从正常工作中分离变化,架构就能只依赖事件和生命周期进行设计和实现。围绕生命周期进行系统设计已经经历了一个世纪——它被称为装配线。

在装配线于20世纪早期引入之前,制造业的工作方式多多少少和今天面向服务架构(SOA)处理信息的方式一样。每个对于SOA服务的调用一般都被视 为一个无状态调用。为了说明以前调用的历史,每个服务必须完全实现如何处理系统内部状态。一旦需求改变,几乎所有服务也需要以成本极高的方式重新编码来改 变它们各自的实现。

图 6. 服务器架构是以事件模型为基础的

我们建议使用以事件模型和生命周期为中心的信息架构作为业务需求和系统架构的双向翻译平台。事件模型在下一级被扩展成四个基本模型:状态、分布式、层次和动态。所有这5个模型可被基础需求和架构模型中的业务或技术人员方便地解释:

  • 事件模型/生命周期—— 它是构建其他模型的基础核心。对业务用户来说,它是价值流,反映产品/服务生命周期和为客户创造价值的过程序列。对技术人员来说,同一事件序列反映了代表 业务实体对象的状态变化。最终结果是,事件模型扮演了解耦元素,大大简化了设计和实现。事件模型还扮演了另一个重要角色。因为其他四个模型是围绕事件模型 而构建的,它还扮演一个集成平台。事实上,事件模型是创造实现变更、层次和分布式组件的唯一办法。
  • 状态模型—— 对业务用户来说,这个模型扮演了企业的面板,捕获当前经营的整体状况。对技术人员来说,它是系统的整体状态,它是全部生命周期实例的当前状态,以及它们的变化之和。
  • 分布式模型 —— 对业务用户来说,这个模型捕获了其生命周期内控制产品/服务的各种组织。对技术人员来说,主实体只能基于分布式模型来控制。
  • 层次模型—— 所有业务都有代表管理层级的层次结构。所有系统设计应该在架构上反映这种控制层次。正如销售VP不能给CEO下命令一样,低层级的组件不能给高层级的组件发送执行“命令”。
  • 动态模型—— 继事件模型之后最重要的模型。业务用户使用它来捕获平时必须被处理的全部变更。如前所述,有两种变化类型:外部,如客户输入;内部,如管理决策。对技术人员来说,动态模型被翻译成一个匹配各种事件、生命周期和变化类型的插件架构。

这5个模型不仅可以被用在初始设计,对贯穿整个系统生命周期的需求变更亦有裨益。它们一起形成了自适应系统设计所缺失的框架步骤。这5个模型排除了用例作为企业架构的主输入的必要性。它们可以被翻译成一个清晰和全面的工程问题集合,与在桥梁或飞机设计中使用的方法类似。

图 7. 自适应架构是以5个模型为基础的信息架构结果

这5个模型定义了以信息变化和装配线为中心的动态业务应用通用架构。最重要的子系统是:静态模型、变更管理、虚拟装配对象和事件处理。在下一个细化层级,还有两个子系统:系统命令和控制与持久化。

这个架构还解决了在寻求一个适用于事务型工作流隐喻的通用解决方案过程中长期存在的问题,它是由Jim Gray[3]在 几十年前提出的。因为整个设计以单个事件的执行为中心,不仅可以实现“移动到下一个装配步骤”,而且也可实现“移动到前一个装配步骤”。实现需要根据用户 的输入决定前往哪个“方向”。通过将多个步骤“链接”在一起,可以使用相同的架构实现一个事务型工作流的“撤销(Undo)”操作。

动态业务应用的一个关键元素是事件处理。使用新的自适应系统信息理论,可以使用一个通用组件结构来“执行”每个事件。这个组件使用声明性编程来内嵌 业务逻辑、调用工作流引擎、调度器和业务规则引擎。这个实现不仅可以极大加速自适应系统开发,而且可以使后期改变非常容易处理,也减少了维护复杂集成的需 要。

我们建议围绕事件(操作)和事件生命周期创建一个供给控制、运营和环境的物理模型。生命周期控制器为离散事件管理装配信息。变更管理功能指导标准事件模型和个体事件内外部变更的执行。

结论

我们已经讨论了扁平、无状态、静态、客户端——服务器、基于Web的解决方案的演变方式所带来的IT架构和层次、有状态、动态、分布式业务的现实世 界之间的脱节。我们还讨论了传统工程方法为什么不能支撑能支持动态业务的自适应系统的开发。我们展示这两个问题的可能解决方案可以用一种新的模型驱动架构 方法来找到。

本文的第二部分将描述动态业务应用的可能架构,并给出一个案例研究,介绍我们概念的实际实现。

参考文献

[1] Yourdon Systems Method —— Model Driven Systems Development —— Yourdon Press, 1993

[2] Eric D. Beinhocker —— "The origin of Wealth", HBS Press Book,2006 —— 在他的新书“The origin of Wealth”中,麦肯锡公司高级顾问Eric D. Beinhocker声称,将经济视为一种静态、平衡的系统的传统观点正在经受一场彻底的反思,包括为数众多的原则。新的中心是:“复杂经济学”,其中经 济被视为一种高度动态的、不断演变、几乎无法预测的系统。这个摘录涉及在未来未知时公司如何来制定战略。

[3] Mark Whitehorn ,The Register, Interview with Jim Gray —— http://www.regdeveloper.co.uk/2006/05/30/jim_gray/

查看英文原文Beyond SOA: A New Enterprise Architecture Framework for Dynamic Business Applications

[架构]什么是软件工厂

mikel阅读(906)

前言

  Microsoft Patterns & Practices已经提供了不少“软件工厂(Software Factory)”,例如Smart Client Software FactoryWeb Service Software FactoryMobile Client Software Factory。而在CodePlex上也已经有了Microsoft P & P Team正在开发的下一代产品:Web Client Software Factory。这是一个非常有价值,非常值得关注的项目,目前正在以Weekly Drop的形式发布,按照计划将会在年底发布。在Terry Lee和我都曾经对它进行过介绍。

  那么什么是“软件工厂”呢?它的作用又是什么呢?Jezz Santos在写了数篇有关这方面非常精彩的文章,他本人已经同意我将其文章进行翻译。我将陆续将它们翻译成中文,帮助大家和我自己理解一些概念。

原文信息

  原文《FAQ – What is a Software Factory?》公布在Jezz Santos的博客上,版权归作者所有。
 

正文翻译

  什么是“软件工厂”?这个问题经常能够引发下面的疑问:

  如何给出软件工厂的定义?紧接着考虑下面的问题:我创建了一个命令行程序/一个指导性的包(Package)/一段脚本用于生成一些有用的组件 – 请您作出选择,它们也是软件工厂吗?

  想用三言两语就给出清楚定义还真不是一件容易的事情。

背景

  事实上这并不是个足够完整的问题,大多数人也正有这样的疑问,而且他们正在通过一些已经做好的东西或者重新去理解它们的区别,来设法搞清楚自己是否已经有了一个“工厂”或者“工厂”对他们来说还是个新事物。

解答

  让我们先从“软件工厂”的官方定义开始谈起,然后我会尝试着使用更简单的词汇来解释它,并且使用一些示例来给出这些定义的衍生,希望能帮助您理解这些。

  您能在这里找到一个官方而泛泛的定义,但是我想从JackKeth的那本有关软件工厂的书中所使用的那段短小些的定义开始。您也能够在我们的术语表中找到另一些定义。

软件工厂是 使用一个基于软件工厂模式(Software Factory Schema)的软件工厂模版(Software Factory Template)来配置外部工具,过程和内容的一条产品线。通过适配(Adapting),装配(Assembling)和配置一些框架化的组件,能够 自动化地对一个典型架构的产品进行开发和维护变化的工作。”

  呃……好吧(“咕嘟”——咽了一下口水), 这是一个学院派定义,我们来将它进行一点小小的延伸:首先,“软件工厂”的基本元素是一条使用一系列的工具(比如编辑器,代码模版,领域专用语言,命令行 工具等等)创建出来的“产品线”。这些工具会是用一个被称为“工厂模版”的东西来配置普遍适用的,能够扩展的开发工具(就像Visual Studio)。工厂模版实际上只是“工厂规范”的一个物理实现(例如,一个工厂模版包含了工具,指导和这些工具创建和配置一些东西的蓝本)。接着,则会 通过组装一些必须的组件,把这些工厂创建出来的不同产品的开发和维护过程进行自动化操作——理想情况下,这个过程会复用那些作为产品基础而存在的框架。

  好吧,这里最关键的一点是产品线工厂规范,它的工厂模版以及一个产品。在我看来,如果您有了所有这些,您就已经基本上接近于有了一个工厂了,因为剩下的玩意儿都是通过这些东西来得到的。

  “框架”也是非常重要的东西,因为有了它, 您就已经在“为产品线上的产品定义变量”这个过程中迈出了一大步,大多数的工作它已经帮你完成了。请记住,您不应该为一个您还没有解决的方案创建一个工 厂,因此,创建一个工厂最基本的前提是:您已经有了对一些解决方案进行自动化操作的资本。

[当Visual Studio团队发布了一些能够帮助您自定义软件工厂的工具,那么微软对于这些术语的定义会变得更为具体,而且我猜想,如果要完全符合这个具体的工厂模 版,您只能使用被微软认可的软件工厂。但是就目前来说,您任何可以使用当前的工具和一些您自己的“创新”来创建符合上述定义的软件工厂。]

产品

  让我们先从产品谈起,首先搞清楚一点:一个产品是一个特定的工厂创建的产物。

“一个产品是一个工厂生产线的最终产物”

  千万不要将“生产线(production line)”和“产品线(product line)”混淆起来。

  现在,一个产品并不需要真正的完成,结束,包装成一个像“Microsoft Word”这样的东西,虽然可能大多数人听到“产品”这个词的第一反应是这个。这个单词的含义只是描述一个工厂的产出。

  例如,一个汽车引擎制造商生产出了汽车引擎,这就是它的“产品”,然后把引擎卖给其它的工厂,让它们将这些引擎组装进一辆汽车。一个汽车引擎依旧属于一个引擎工厂的“产品”。

  所以,所有的工厂会建造一个有用的产品,这个产品可能会被组装进入一个更大的产品,当然也有可能不会。

  工厂会为这个产品定义一个模型,这就是这个产品的“模式(schema)”,它包含了产品的各个部分和它们的变量。这个模型为用户提供了一个独立创建,配置或者维护产品各部分的方法。

工厂模式(Factory Schema)与工厂模版(Factory Template)

  我们已经花了不少功夫定义了工厂模式(Factory Schema),所以我不打算在这里再完全重复一遍。

  不过我们在这里这么说已经足够了:“工厂模式”是产品(和它的变量)以及它的各种配置的蓝图——也就是工厂产物的蓝图。它不只定义了工厂该建造那些东西,也包括建造这些东西方式,建造时所用的“零件”,以及在建造时所使用的工具。

  顺便提一下,“工厂模版(Factory Template)”则是指工具、运行时、文档和框架等其它作为您的工厂的的组成部分一起发布的那些东西——例如一起打包在一个MSI安装文件中。

产品线

  那么现在就谈一下产品线——这到底是什么?这可不是指“生产线”。

产品线,由工厂产物的变量组成。

  好,为了真正对开发有用,工厂需要能够创建产品的多个实例(我们把其中的一个叫做一个“产品变量”)。更准确的说,一个产品“变量”就是每一个您生产出的实例,而不是产品的实际类型。一个工厂能够定义多种产品的“类型”(每一个对应了产品的一个可变的方面)。

  因此,您的产品线定义了您工厂的解决方案领域

[您能够在这里得到有关一个产品可变性以及其变量(是什么?应该如何使用?)更深入的讨论。]

 

  那么,您的一个命令行程序/一个指导性的包(Package)/一段脚本是一个软件工厂吗?

[模式]软件工厂

mikel阅读(843)

Gunther Lenz是微软的一名架构师,Christoph Wienands是在西门子工作的一名软件工程师,两人担当起了一个项目,目标是评估以Microsoft Visual Studio 2005 Domain Specific Languages工具为基础建立的软件工厂(Software Factory)的优势

虽然对于目前基于文本的软件开发工作来说,重用增加、抽象层次提高、自动化水平提高这些都是显而易见的好处,但还不足以向管理层及其他利益相关者证明先期投入的必要性。因此我们着手寻找定量的数据,以图清楚地在商业上确立这种范型。

该分析的目标是在框架及应用程序开发领域识别出自动化和重用的机会。为此作者开发了一个软件工厂模板(Software Factory Template):

软件工厂模板是在Software Factory Schema的基础上实现的。我们提供了多个T4模板——有工件生成、向导和DSL——全都包含在安装包里。这些模板给开发者提供了额外的工具和上下文敏感的自动化机制。

他们的项目分为两个部分:

  • 用DSL生成框架性的C#工件
  • 通过指导(guidance)和自动化为应用程序开发者提供支持

经过初步研究,他们发现:

对于开发者来说,以前定义加上使用要输入320行的代码,而现在只需要输入几个字符串,然后决定几个选项就可以了。最终不但节省了时间,而且质量也提高了——因为只能在合理的选项中选择,而且在工件生成之前还会对输入进行验证。

总而言之,结论就是:

DSL开发成10倍地提高生产率,投资收益率超过100%。

对于指导包(guidance package),即使在最低投入的情况下也可以达到超过300%的投资收益率。

作者们计划在未来解决一些更复杂的问题:

  • 如何将此方法扩展到更广阔的领域?
  • 如何让工具适应更复杂的实现?
  • 能够节省多少维护工作?
  • 如何处理DSL元模型及模型的演进?

查看英文原文:Making the Business Case for Software Factories

[服务]豆瓣的API服务使用指南

mikel阅读(2342)

豆瓣 API 使用指南

豆瓣API是豆瓣为第三方开发人员提供的编程接口。利用豆瓣API,你可以在你的网站或程序中使用豆瓣的数据和功能。 目前的豆瓣API支持的功能包括:

  • 搜索并查看书籍、电影、音乐信息
  • 搜索并查看用户信息
  • 查看用户收藏
  • 添加、更新、删除用户收藏
  • 查看评论
  • 发布、修改、删除评论

在未来我们会支持更多的功能,例如查看、增删友邻.

本文档为需要快速了解豆瓣API的用户提供一个概览, 更为完整的豆瓣API信息请参阅 豆瓣API 参考手册. 现在可以使用Python 或者Javascript客户端进行开发,欢迎爱好者提供其他语言的客户端。

如果你编写了一个有趣的API应用,欢迎到API小组发布, 另外也欢迎到API小组参与豆瓣API的讨论,提出你对豆瓣API各种意见和建议。

Python客户端: http://code.google.com/p/douban-python/
Java客户端: http://code.google.com/p/douban-java/
ActionScript客户端: http://code.google.com/p/douhua/ (Meaglith Ma贡献)

目录

API Key

为了保护豆瓣用户的数据;防止API被滥用或恶意使用,豆瓣要求每个API的使用者申请一个API Key, 而每个API Key唯一标识一个API使用者. 你可以在申请页面获得API Key, 在页面中填写必要信息后提交,你会得到你的API Key,例如

c4579586f41a90372f762cb65c78be5d

在之后的API使用过程中,你需要在请求中包括apikey参数,例如

http://api.douban.com/people/1345767?apikey={apikey}

注:如果只是想试验一下API,豆瓣也允许在不申请API Key的情况下进行API调用。不过在这种情况下,API调用被限制为每分钟请求不超过10次。使用API Key时,对访问的限制较为宽松,为每分钟40次,超过限制的话会被封禁(包括豆瓣主站的访问)。

快速入门

示例

下面通过一个简单的示例来演示豆瓣API的使用.

这个示例中展示了使用API获得ID为1220562的书的信息, 请求的url如下(注意将{yourapikey}替换为你的API Key)

http://api.douban.com/book/subject/1220562?apikey={yourkeyapi}

返回值为XML文档

<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom"
xmlns:gd="http://schemas.google.com/g/2005"
xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/"
xmlns:db="http://www.douban.com/xmlns/">
<category scheme="http://www.douban.com/2007#kind"
term="http://www.douban.com/2007#book" />
<db:tag count="20" name="片山恭一" />
<db:tag count="14" name="日本" />
<db:tag count="10" name="小说" />
<db:tag count="8" name="日本文学" />
<db:tag count="4" name="爱情" />
<title>满月之夜白鲸现</title>
<author>
<name>(日)片山恭一</name>
</author>
<content>
冷静地想一想吧!公寓的一个房间里只有两上人,连被褥都铺好了,理应是犯
错误的时候,我为什么却这么拘谨?一直胆小的毛病又犯了。事到如今,不要
说上床,就连接吻也还差得很远。这就是横亘在男人和女人之间的又深又暗的
河流吗?
如果有可能,我希望把手伸进她的心里,把她内心所有的东西都掏出来。她对
我究竟是一种什么感觉呢?我在她的心昊确实占有一席之地吗?抑或只是她生
命中的匆匆过客?
</content>
<link rel="self" href="http://api.douban.com/book/subject/1220562" />
<link rel="alternate" href="http://www.douban.com/subject/1220562/" />
<link rel="image" href="http://otho.douban.com/spic/s1747553.jpg" />
<db:attribute name="author">(日)片山恭一</db:attribute>
<db:attribute name="isbn10">7543632608</db:attribute>
<db:attribute name="isbn13">9787543632608</db:attribute>
<db:attribute name="pages">180</db:attribute>
<db:attribute name="tranlator">豫人</db:attribute>
<db:attribute name="price">18.00</db:attribute>
<db:attribute name="publisher">青岛出版社</db:attribute>
<db:attribute name="binding">平装(无盘)</db:attribute>
<db:attribute name="author-intro">
片山恭一,1959年生于日本爱媛县,九州大学农学系农业经济学专业毕业。
学生时代通读了包括夏目漱石和大江健三郎在内的日本近现代文学全集,
同时读了笛卡尔、莱布尼茨到结构主义的欧洲近现代哲学。也读了马克思。
学士论文写的是马克思,硕士论文写的是恩格斯。二十二三岁开始创作小说。
代表作有《在世界中心呼唤爱》、《世界在你不知道的地方运转》、《气息》、
《别相信约翰·列侬》、《满月之夜白鲸现》、《空镜头》以及新作
《倘若我在彼岸》、《雨天的海豚们》等。
</db:attribute>
<id>http://api.douban.com/book/subject/1220562</id>
<gd:rating min="1" numRaters="39" average="3.69" max="5" />
</entry>

通过请求中包括alt参数,你可以改变返回值的格式。 目前支持的alt参数值包括:

  • atom (默认)
  • json

通过将alt设置为json来获得json格式的返回值:

{"category":{
"@scheme":"http://www.douban.com/2007#kind",
"@term":"http://www.douban.com/2007#book"},
"db:tag":[
{"@count":20,"@name":"片山恭一"},
{"@count":14,"@name":"日本"},
{"@count":10,"@name":"小说"},
{"@count":8,"@name":"日本文学"},
{"@count":4,"@name":"爱情"}
],
"title":{"$t":"满月之夜白鲸现"},
"author":[
{"name":{"$t":"(日)片山恭一"}}
],
"content":{"$t":"冷静地想一想吧!公寓的一个房间里只有两上人,连被褥都铺
好了,理应是犯错误的时候,我为什么却这么拘谨?一直胆小的毛病又犯了。事到
如今,不要说上床,就连接吻也还差得很远。这就是横亘在男人和女人之间的又深
又暗的河流吗?\n    如果有可能,我希望把手伸进她的心里,把她内心所有的东
西都掏出来。她对我究竟是一种什么感觉呢?我在她的心昊确实占有一席之地吗?
抑或只是她生命中的匆匆过客?"},
"link":[
{"@rel":"self","@href":"http://api.douban.com/book/subject/1220562"},
{"@rel":"alternate","@href":"http://www.douban.com/subject/1220562/"},
{"@rel":"image","@href":"http://otho.douban.com/spic/s1747553.jpg"}
],
"db:attribute":[
{"$t":"(日)片山恭一","@name":"author"},
{"$t":"7543632608","@name":"isbn10"},
{"$t":"9787543632608","@name":"isbn13"},
{"$t":"180","@name":"pages"},
{"$t":"豫人","@name":"tranlator"},
{"$t":"18.00","@name":"price"},
{"$t":"青岛出版社","@name":"publisher"},
{"$t":"平装(无盘)","@name":"binding"},
{"$t":"片山恭一,1959年生于日本爱媛县,九州大学农学系农业经济学专业
毕业。学生时代通读了包括夏目漱石和大江健三郎在内的日本近现代文学全集,
同时读了笛卡尔、莱布尼茨到结构主义的欧洲近现代哲学。也读了马克思。
学士论文写的是马克思,硕士论文写的是恩格斯。二十二三岁开始创作小说。
代表作有《在世界中心呼唤爱》、《世界在你不知道的地方运转》、《气息》、
《别相信约翰·列侬》、《满月之夜白鲸现》、《空镜头》以及新作《倘若我在
彼岸》、《雨天的海豚们》等。","@name":"author-intro"}
],
"id":{"$t":"http://api.douban.com/book/subject/1220562"},
"gd:rating":{"@min":1,"@numRaters":39,"@average":"3.69","@max":5}
}

JavaScript 支持

对于JavaScript开发人员,豆瓣API提供一种更简单的方式可以直接在HTML页面中使用API, 下面给出这种使用方式的简单示例。

首先你需要在HTML页面中如下script标签:

<script type="text/javascript" src="http://www.douban.com/js/api.js?v=2" />

之后你需要在JavaScript中设置好你的apikey:

DOUBAN.apikey = 'c4579586f41a90372f762cb65c78be5d'

而后你就可以调用豆瓣API,其中通过定义callback函数来操作返回的JSON数据:

DOUBAN.getMovie({
id:'2340927',
callback:function(movie){
var title = movie.title['$t'];
...
}
})

此外,豆瓣也提供了解析函数来帮助你更容易地使用JSON格式的返回值。使用豆瓣提供的解析函数,你需要在页面中添加如下的script标签:

<script type="text/javascript" src="http://www.douban.com/js/api-parser.js?v=1"></script>

接下来你就可以使用豆瓣提供的解析函数来处理返回值,例如:

var book = DOUBAN.parseSubject(result)

解析函数返回更容易使用的javascript对象,例如你可以这样得到书的封面图片:

book.link.image

下面HTML页面使用API获得ID为2340927电影的信息并展示在页面上(注意将{yourapikey}替换为你的API Key)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML xmlns="http://www.w3.org/1999/xhtml">
<HEAD>
<TITLE></TITLE>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<style>
body {padding:0;margin: 0;background: #FEFEFE;}
body,td,th { font: 12px Arial, Helvetica, sans-serif; line-height: 150%; }
span.title {
margin:5px;
}
</style>
<script type="text/javascript" src="http://www.douban.com/js/api.js?v=2"></script>
<script type="text/javascript" src="http://www.douban.com/js/api-parser.js?v=1"></script>
<BODY>
</BODY>
<script>
DOUBAN.apikey = {yourapikey}
DOUBAN.getMovie({
id:'2340927',
callback:function(re){
var subj = DOUBAN.parseSubject(re)
var tl = subj.title ? subj.title : "";
var author = subj.author ? subj.author : "";
var di = subj.attribute.director ? subj.attribute.director.join(' / ') : "";
var tmp = "<img src="+subj.link.image+" style='margin:10px;float:left'>";
tmp += "<div>Title : <a href="+subj.link.alternate+" target='_blank'>"+tl+"</a></div>";
if (subj.attribute.author) tmp += "<div>Authors : "+(subj.attribute.author.join(' / '))+"</div>";
if (subj.attribute.director) tmp += "<div>Director : "+(subj.attribute.director.join(' / '))+"</div>";
if (subj.attribute.cast) tmp += "<div>Casts : "+(subj.attribute.cast.join(' / '))+"</div>";
if (subj.attribute.aka) tmp += "<div>A.k.a : "+(subj.attribute.aka.join(' <br/>   '))+"</div>";
if (subj.attribute.language) tmp += "<div>Language : "+(subj.attribute.language.join(' / '))+"</div>";
if (subj.attribute.country) tmp += "<div>Country : "+(subj.attribute.country.join(' / '))+"</div>";
if (subj.rating.average)
tmp +="<div>Rating: "+subj.rating.average+" / "+subj.rating.numRaters+decodeURI("%E4%BA%BA")+ "</div>"
tmp += "<p>"+(subj.summary ? subj.summary : "")+"</p>";
document.body.innerHTML = tmp;
}
})
</script>
</HTML>

注:实现上,豆瓣API使用 JSONP 方式来支持跨域调用API 因此你也可以使用自己熟悉的javascript库来调用JSONP风格的豆瓣API. 此时,你需要将alt设置为xd同时提供callback参数。

例如使用JQuery,前面的例子则可以写为

$.getJSON("http://api.douban.com/movie/subject/2340927?alt=xd&callback=?", function(movie){
var title = movie.title['$t'];
...
});

[问题]Petshop4.0注册提示安全密码问题

mikel阅读(1204)

Petshop4.0 中注册时出现Please enter a more secure password.的解决方法:
在网上找到答案:

查看C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config
中membership/providers/add 属性inRequiredNonalphanumericCharacters="1"

知道密码中至少有一个非alpha字符,例如要出现一个@之类的

这 个主要是machine.config配置文件下面的<membership…><providers…> minRequiredPasswordLength="7",minRequiredNonalphanumericCharacters="1" 这两个项要设置
第一项要求了至少密码长度为7,第二项是要求了至少一个非字母数字字符.如果不更改设置,则在密码中包含以下字符"!@#$%^&*()"等中的一个可以解决。或者在web.config文件中更改设置。


<connectionStrings>
  
<add name="MySQLConnection" connectionString="Data Source=MySQLServer;Initial Catalog=aspnetdb;Integrated Security=SSPI;" />
</connectionStrings>
<system.web>
..
<membership defaultProvider="SQLProvider" userIsOnlineTimeWindow="15">
    
<providers>
      
<clear />
      
<add 
        name
="SQLProvider" 
        type
="System.Web.Security.SqlMembershipProvider" 
        connectionStringName
="MySqlConnection"
        applicationName
="MyApplication"
        minRequiredNonalphanumericCharacters
="0" 
        minRequiredPasswordLength
="6" 
        passwordStrengthRegularExpression
="" />
    
</providers>
</membership>

[资源]What is SWFObject 2.0?

mikel阅读(625)

What is SWFObject 2.0?

SWFObject 2.0:

Why should you use SWFObject 2.0?

SWFObject 2.0:

The A List Apart article Flash Embedding Cage Match [ http://www.alistapart.com/articles/flashembedcagematch/ ] describes the full rationale behind SWFObject 2.0.

Why does SWFObject 2.0 use JavaScript?

SWFObject 2.0 primarily uses JavaScript to overcome issues that cannot be solved by markup alone; it:

Should I use the static or dynamic publishing method?

SWFObject 2.0 offers two distinct methods to embed Flash Player content:

  1. The static publishing method embeds both Flash content and alternative content using standards compliant markup, and uses JavaScript to resolve the issues that markup alone cannot solve
  2. The dynamic publishing method is based on marked up alternative content and uses JavaScript to replace this content with Flash content if the minimal Flash Player version is installed and enough JavaScript support is available (similar like previous versions of SWFObject and UFO)

The advantages of the static publishing method are:

  1. The actual authoring of standards compliant markup is promoted
  2. The mechanism of embedding Flash content does not rely on a scripting language, so your Flash content can reach a significant bigger audience:

The advantages of the dynamic publishing method are:

  1. It avoids click-to-activate mechanisms to activate active content in Internet Explorer 6/7 and Opera 9+. Please note that Microsoft is currently phasing out all active content from its Internet Explorer browsers [ http://www.swffix.org/devblog/?p=19 ]
  2. It integrates very well with scripted applications

How to embed Flash Player content using SWFObject 2.0 static publishing

STEP 1: Embed both Flash content and alternative content using standards compliant markup

SWFObject's base markup uses the nested-objects method (with proprietary Internet Explorer conditional comments) [ http://www.alistapart.com/articles/flashembedcagematch/ ] to ensure the most optimal cross-browser support by means of markup only, while being standards compliant and supporting alternative content [ http://www.swffix.org/testsuite/ ]:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
  <head>
    <title>SWFObject v2.0 - step 1</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  </head>
  <body>
    <div>
      <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="780" height="420">
        <param name="movie" value="myContent.swf" />
        <!--[if !IE]>-->
        <object type="application/x-shockwave-flash" data="myContent.swf" width="780" height="420">
        <!--<![endif]-->
          <p>Alternative content</p>
        <!--[if !IE]>-->
        </object>
        <!--<![endif]-->
      </object>
    </div>
  </body>
</html>

NOTE: The nested-objects method requires a double object definition (the outer object targeting Internet Explorer and the inner object targeting all other browsers), so you need to define your object attributes and nested param elements twice.

Required attributes:

  • classid (outer object element only, value is always clsid:D27CDB6E-AE6D-11cf-96B8-444553540000)
  • type (inner object element only, value is always application/x-shockwave-flash)
  • data (inner object element only, defines the URL of a SWF)
  • width (both object elements, defines the width of a SWF)
  • height (both object elements, defines the height of a SWF)

Required param element:

  • movie (outer object element only, defines the URL of a SWF)

NOTE: We advise not to use the codebase attribute to point to the URL of the Flash plugin installer on Adobe's servers, because this is illegal according to the specifications which restrict its access to the domain of the current document only. We recommend the use of alternative content with a subtle message that a user can have a richer experience by downloading the Flash plugin instead.

How can you use HTML to configure your Flash content?

You can add the following often-used optional attributes [ http://www.w3schools.com/tags/tag_object.asp ] to the object element:

  • id
  • name
  • class
  • align

You can use the following optional Flash specific param elements [ http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=tn_12701 ]:

Why should you use alternative content?

The object element allows you to nest alternative content inside of it, which will be displayed if Flash is not installed or supported. This content will also be picked up by search engines, making it a great tool for creating search-engine-friendly content. Summarizing, you should use alternative content when you like to create content that is accessible for people who browse the Web without plugins [ http://www.adobe.com/devnet/flash/articles/progressive_enhancement_03.html ], create search-engine-friendly content [ http://www.adobe.com/devnet/flash/articles/progressive_enhancement_04.html ] or tell visitors that they can have a richer user experience by downloading the Flash plug-in.

STEP 2: Include the SWFObject JavaScript library in the head of your HTML page

The SWFObject library consists of one external JavaScript file. SWFObject will be executed as soon as it is read and will perform all DOM manipulations as soon as the DOM is loaded – for all browsers that support this, like IE, Firefox, Safari and Opera 9+ – or otherwise as soon as the onload event fires:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
  <head>
    <title>SWFObject v2.0 - step 2</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <script type="text/javascript" src="swfobject.js"></script>
  </head>
  <body>
    <div>
      <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="780" height="420">
        <param name="movie" value="myContent.swf" />
        <!--[if !IE]>-->
        <object type="application/x-shockwave-flash" data="myContent.swf" width="780" height="420">
        <!--<![endif]-->
          <p>Alternative content</p>
        <!--[if !IE]>-->
        </object>
        <!--<![endif]-->
      </object>
    </div>
  </body>
</html>

STEP 3: Register your Flash content with the SWFObject library and tell SWFObject what to do with it

First add a unique id to the outer object tag that defines your Flash content. Second add the swfobject.registerObject method:

  1. The first argument (String, required) specifies the id used in the markup.
  2. The second argument (String, required) specifies the Flash player version your content is published for. It activates the Flash version detection for a SWF to determine whether to show Flash content or force alternative content by doing a DOM manipulation. While Flash version numbers normally consist of major.minor.release.build, SWFObject only looks at the first 3 numbers, so both "WIN 9,0,18,0" (IE) or "Shockwave Flash 9 r18" (all other browsers) will translate to "9.0.18".
  3. The third argument (String, optional) can be used to activate Adobe express install [ http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75 ] and specifies the URL of your express install SWF file. Express install displays a standardized Flash plugin download dialog instead of your Flash content when the required plugin version is not available. A default expressInstall.swf file is packaged with the project. It also contains the corresponding expressInstall.fla and AS files (in the SRC directory) to let you create your own custom express install experience. Please note that express install will only fire once (the first time that it is invoked), that it is only supported by Flash Player 6.0.65 or higher on Win or Mac platforms, and that it requires a minimal SWF size of 310x137px.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
  <head>
    <title>SWFObject v2.0 - step 3</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <script type="text/javascript" src="swfobject.js"></script>
    <script type="text/javascript">
    swfobject.registerObject("myId", "9.0.0", "expressInstall.swf");
    </script>
  </head>
  <body>
    <div>
      <object id="myId" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="780" height="420">
        <param name="movie" value="myContent.swf" />
        <!--[if !IE]>-->
        <object type="application/x-shockwave-flash" data="myContent.swf" width="780" height="420">
        <!--<![endif]-->
          <p>Alternative content</p>
        <!--[if !IE]>-->
        </object>
        <!--<![endif]-->
      </object>
    </div>
  </body>
</html>

TIPS

How to embed Flash Player content using SWFObject 2.0 dynamic publishing

STEP 1: Create alternative content using standards compliant markup

SWFObject's dynamic embed method follows the principle of progressive enhancement [ http://www.adobe.com/devnet/flash/articles/progressive_enhancement.html ] and replaces alternative HTML content for Flash content when enough JavaScript and Flash plug-in support is available. First define your alternative content and label it with an id:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
  <head>
    <title>SWFObject v2.0 dynamic embed - step 1</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  </head>
  <body>
   
    <div id="myContent">
      <p>Alternative content</p>
    </div>
   
  </body>
</html>

STEP 2: Include the SWFObject JavaScript library in the head of your HTML page

The SWFObject library consists of one external JavaScript file. SWFObject will be executed as soon as it is read and will perform all DOM manipulations as soon as the DOM is loaded – for all browsers that support this, like IE, Firefox, Safari and Opera 9+ – or otherwise as soon as the onload event fires:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
  <head>
    <title>SWFObject v2.0 dynamic embed - step 2</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
 
    <script type="text/javascript" src="swfobject.js"></script>
  </head>
  <body>
    <div id="myContent">
      <p>Alternative content</p>
    </div>
  </body>
</html>

STEP 3: Embed your SWF with JavaScript

swfobject.embedSWF(swfUrl, id, width, height, version, expressInstallSwfurl, flashvars, params, attributes) has five required and four optional arguments:

  1. swfUrl (String, required) specifies the URL of your SWF
  2. id (String, required) specifies the id of the HTML element (containing your alternative content) you would like to have replaced by your Flash content
  3. width (String, required) specifies the width of your SWF
  4. height (String, required) specifies the height of your SWF
  5. version (String, required) specifies the Flash player version your SWF is published for (format is: "major.minor.release")
  6. expressInstallSwfurl (String, optional) specifies the URL of your express install SWF and activates Adobe express install [ http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75 ]. Please note that express install will only fire once (the first time that it is invoked), that it is only supported by Flash Player 6.0.65 or higher on Win or Mac platforms, and that it requires a minimal SWF size of 310x137px.
  7. flashvars (Object, optional) specifies your flashvars with name:value pairs
  8. params (Object, optional) specifies your nested object element params with name:value pairs
  9. attributes (Object, optional) specifies your object's attributes with name:value pairs

NOTE: You can omit the optional parameters, as long as you don't break the parameter order. If you don't want to use an optional parameter, but would like to use a following optional parameter, you can simply pass false as its value. For the flashvars, params and attributes JavaScript Objects, you can also pass an empty object instead: {}.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
  <head>
    <title>SWFObject v2.0 dynamic embed - step 3</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <script type="text/javascript" src="swfobject.js"></script>
   
    <script type="text/javascript">
    swfobject.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0");
    </script>
  </head>
  <body>
    <div id="myContent">
      <p>Alternative content</p>
    </div>
  </body>
</html>

How can you configure your Flash content?

You can add the following often-used optional attributes [ http://www.w3schools.com/tags/tag_object.asp ] to the object element:

  • id (NOTE: when undefined, the object element automatically inherits the id from the alternative content container element)
  • name
  • styleclass (used instead of class, because this is also an ECMA4 reserved keyword)
  • align

You can use the following optional Flash specific param elements [ http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=tn_12701 ]:

How do you use JavaScript Objects to define your flashvars, params and object's attributes?

You can best define JavaScript Objects using the Object literal notation, which looks like:

<script type="text/javascript">
var flashvars = {};
var params = {};
var attributes = {};
swfobject.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0","expressInstall.swf", flashvars, params, attributes);
</script>

You can add your name:value pairs while you define an object (note: please make sure not to put a comma behind the last name:value pair inside an object)

<script type="text/javascript">
var flashvars = {
  name1: "hello",
  name2: "world",
  name3: "foobar"
};
var params = {
  menu: "false"
};
var attributes = {
  id: "myDynamicContent",
  name: "myDynamicContent"
};
swfobject.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0","expressInstall.swf", flashvars, params, attributes);
</script>

Or add properties and values after its creation by using a dot notation:

<script type="text/javascript">
var flashvars = {};
flashvars.name1 = "hello";
flashvars.name2 = "world";
flashvars.name3 = "foobar";
var params = {};
params.menu = "false";
var attributes = {};
attributes.id = "myDynamicContent";
attributes.name = "myDynamicContent";
swfobject.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0","expressInstall.swf", flashvars, params, attributes);
</script>

Which can also be written as (the less readable shorthand version for the die-hard scripter who love one-liners):

<script type="text/javascript">
swfobject.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0","expressInstall.swf", {name1:"hello",name2:"world",name3:"foobar"}, {menu:"false"}, {id:"myDynamicContent",name:"myDynamicContent"});
</script>

If you don't want to use an argument you can define it as false or as an empty Object:

<script type="text/javascript">
var flashvars = false;
var params = {};
var attributes = {
  id: "myDynamicContent",
  name: "myDynamicContent"
};
swfobject.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0","expressInstall.swf", flashvars, params, attributes);
</script>

The flashvars Object is a shorthand notation that is there for your ease of use. You could potentially ignore it and specify your flashvars via the params Object:

<script type="text/javascript">
var flashvars = false;
var params = {
  menu: "false",
  flashvars: "name1=hello&name2=world&name3=foobar"
};
var attributes = {
  id: "myDynamicContent",
  name: "myDynamicContent"
};
swfobject.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0","expressInstall.swf", flashvars, params, attributes);
</script>

TIPS

SWFObject 1.5 to SWFObject 2.0 migration tips

  1. SWFObject 2.0 is NOT backwards compatible with SWFObject 1.5
  2. It is now preferred to insert all script blocks in the head of your HTML page
  3. The library itself is now written in lowercase: swfobject instead of SWFObject
  4. Methods can only be accessed via the library (instead via a SWFObject instance in SWFObject 1.5)
  5. The API is entirely different and more elaborate: [ http://code.google.com/p/swfobject/wiki/SWFObject_2_0_api_javascript_dev ]
  6. SWFObject 2.0 replaces your entire alternative HTML content block, including the referenced HTML container element, for Flash content when enough JavaScript and Flash support is available, while SWFObject 1.5 only replaces the content inside the referenced HTML container. When you don't specify an id attribute, the object element will automatically inherit the id of the HTML container element of your alternative content.

UFO to SWFObject 2.0 migration tips

  1. SWFObject 2.0 replaces your entire alternative HTML content block, including the referenced HTML container element, for Flash content when enough JavaScript and Flash support is available, while UFO only replaces the content inside the referenced HTML container. When you don't specify an id attribute, the object element will automatically inherit the id of the HTML container element of your alternative content.
  2. UFO's setcontainercss feature has not been incorporated in SWFObject 2.0, however it can easily be replicated by using the SWFObject 2.0 API, see: swfobject.createCSS(selStr, declStr) in [ http://code.google.com/p/swfobject/wiki/SWFObject_2_0_api_javascript_dev ]

Does SWFObject 2.0 support MIME type application/xhtml+xml?

SWFObject does NOT support XML MIME types, which is a design decision.

There are a number of reasons why we are not supporting this:

COMMENTS POLICY

We will try to keep this page lean and mean, because it is used by many people. For this purpose we will periodically review all comments and remove all comments that are outdated or irrelevant to this documentation page itself.

If you have any questions/comments about SWFObject 2.0 or have problems with an implementation:

  1. Please make sure you have read our FAQ [ http://code.google.com/p/swfobject/wiki/SWFObject_2_0_faq_web_authors ]
  2. Use the SWFObject 2.0 discussion group [ http://groups.google.com/group/swfobject ]

If you find any bugs or want to request a future enhancement, you can fill in an issue report on the SWFObject 2.0 issues page [ http://code.google.com/p/swfobject/issues/list ]

[教程]Live Camera Previews in Android

mikel阅读(805)

This code replaces an earlier version which is still available

The Android SDK provided by Google doesn't provide any camera emulation beyond a stand-in animation (see below). Since Google haven't yet provided a working implementation (or even a date by which one will be available), I'm publishing the source code for a set of temporary classes that I wrote to overcome this limitation. It's the first code I wrote on the Android platform, and it was written in haste, though it has functioned very well for me.

The code is public domain. I make no warranty as to its fitness for any particular purpose.

The code consists of:

  • CameraSource
    A light interface that protects client code from the choice of camera.
  • GenuineCamera
    A CameraSource implementation that uses the device's camera.
  • HttpCamera
    A CameraSource implementation that GETs images over an HTTP connection.
  • SocketCamera
    A CameraSource implementation that obtains images directly over a TCP/IP connection.
  • BitmapCamera
    A CameraSource implementation that uses a supplied bitmap.
  • WebcamBroadcaster
    A small Java application that uses JMF to broadcast captured stills over the network.

Results

When drawing the output of the genuine camera to screen, you will see something that looks like this:

Device's Camera preview output.

When drawing the output of a remote camera that is obtaining frames from a running webcam broadcaster you would see this (if you were stood over my desk).

Still obtained from a webcam broadcaster.

To save myself more time, I chose to produce a small settings configuration activity too (the code for which is not included).

A simple configuration activity for the camera settings.

Usage

Using a camera source is very simple:

CameraSource cs = new SocketCamera("192.168.0.100", 9889, 320, 240, true); if (!cs.open()) { /* deal with failure to obtain camera */ } while(/*some condition*/) { cs.capture(canvas) //capture the frame onto the canvas } cs.close();

The HttpCamera implementation should be able to obtain stills from any HTTP serving webcam or webcam software. At present I am using WebCam2000 which I run under Windows XP.

Fabian Necci kindly emailed me to let me know that he has successfully used this code on a MacBook using EvoCam to publish JPEG frames to an internal web server. Other software should be available on other systems.

Torben Vesterager has used the code with his MacBook Pro laptop which has Apple's own iSight built-in. He reports that the camera only supports YUVFormats and so had to change the code in the WebcamBroadcaster to use YUVFormat instead of RGBFormat.

Jeffrey Sharkey has used Gentoo Linux with a Logitech QuickCam express using the WebcamBroadcaster and the Linux-native JMF library. He followed this by using DV4Linux to get JMF to recognize his firewire MiniDV camera. This gave him much clearer pictures in Android; he wrapped his JMF calls using the dv4lstart utility:

dv4lstart jmfinit dv4lstart java WebcamBroadcaster

If you successfully use this code on a platform other than those listed above, or have used other webcam software, please let me know so that I can include it in this documentation for the benefit of others.

The SocketCamera implementation relies on a WebcamBroadcaster to be serving webcam stills from the address & port specified in its constructor.

To run a WebcamBroadcaster you will need JMF installed and you may need to supply the library location to the JVM when you run the application (this depends on how you install it). For example, on my machine (currently Windows XP) I use:

java "-Djava.library.path=C:\Program Files\JMF2.1.1e\lib" WebcamBroadcaster

You can pass the following combination of parameters to the application, all of which are strictly positive integers (all dimensions in pixels):

  • WebcamBroadcaster port
  • WebcamBroadcaster width height
  • WebcamBroadcaster width height port

Alternatively, you may provide no parameters, in which case the defaults are width: 320, height: 240 and port: 9889.

Notes

  • I am not able to provide support/advice relating to JMF. Sorry, but the library is old and the documentation stale. I am using it here because its the quickest option, not necessarily the best. You can reimplement the WebcamBroadcaster application using any language/library you choose, so long as it emulates the extremely simple behaviour of the WebcamBroadcaster class. For an easy life I recommend using the HttpCamera implementation.
  • The SocketCamera implementation can be expected to outperform the HttpCamera implementation significantly.
  • Obviously performance is poor, every frame needs to be compressed, sent over a network and then decompressed. This is not a useful long term implementation. Nevertheless, performance isn't so bad that the code is unusable. On my machine, capturing a frame using SocketCamera takes about 100-150ms, HttpCamera is typically two to three times slower.
  • Android currently features a very significant bug that disregards the connect timeout setting for URL connections. Until that bug is fixed, the HttpCamera implementation will hang the first time it fails to connect to the webcam server. I believe this bug was resolved in the m5 emulator releases, but have not confirmed it.
  • When capturing a sequence of stills, JMF has a habit of 'freezing' on a single frame. If this happens, just stop and start the WebcamBroadcaster application. You do not need to restart your Android application.
  • I don't recommend using "localhost" when specifying an address to which the camera should connect. The Android device will probably treat this as the loopback on the emulated device itself. Instead use the IP address of the machine which is hosting the webcam (or WebcamBroadcaster).