[Flash]Flash到Javascript的通信

mikel阅读(687)

Flash到JavaScript的通信
从HTML可以发送数据到Flash,反过来也可以. 这个例子演示了如何应用Flash的Fscommand来发送数据到JavaScript.

查看示例:示例2
下载源文件: flash_to_JavaScript.zip(10K)
简要步骤:
Flash中
新建一个文件,保存为flash_to_javascript.fla
创建一个文本域,设置成输入文本(Input Text),选择"border"以便我们能看到他,指定他的变量为inputVar
创建一个按钮,在按钮上添加如下的as:

on (release) {
  fscommand ("send_var", inputVar);
}

保存文件,导出HTML和SWF
Dreamweaver中
1.打开导出HTML文件,修改<OBJECT>和<EMBED>标签,结果同上:
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/
flash/swflash.cab#version=5,0,0,0"
width=366 height=142 id="myFlash">
<embed src="javascript_to_flash.swf" quality=high
width=366 height=142
type="application/x-shockwave-flash"
pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?
P1_Prod_Version=ShockwaveFlash" name="myFlash" swLiveConnect="true">
</embed>

 2. 插入如下的Javascript到<Body>标签内:
<SCRIPT LANGUAGE=JavaScript>
<!–
var InternetExplorer = navigator.appName.indexOf("Microsoft") != -1;
function myFlash_DoFSCommand(command, args)                {
  var myFlashObj = InternetExplorer ? myFlash : document.myFlash;
  alert (args);
}

if (navigator.appName && navigator.appName.indexOf("Microsoft") != -1 &&
  navigator.userAgent.indexOf("Windows") != -1 && navigator.userAgent.indexOf("Windows 3.1") == -1) {
  document.write('<SCRIPT LANGUAGE=VBScript\> \n');
  document.write('on error resume next \n');
  document.write('Sub myFlash_FSCommand(ByVal command, ByVal args)\n');
  document.write(' call myFlash_DoFSCommand(command, args)\n');
  document.write('end sub\n');
  document.write('</SCRIPT\> \n');
}
//–>
</SCRIPT>

出处:蓝色理想
责任编辑:qhwa

[Flash]JavaScript 和 Flash 的通信

mikel阅读(682)

转载:http://www.blueidea.com/tech/multimedia/2004/1712.asp

JavaScript和Macromedia Flash的通信示例
原文地址: www.macromedia.com/support/flash/ts/documents/java_script_comm.htm
说明: 略作修改,主要是一些很初级的操作; 又很多相似的文章,不过这个很权威
下面是一些在Flash和使用JavaScript的HTML文件直接通信的示例,每个示例都有简略的步骤
本文讨论了3种基本的Flash/JavaScript通信方式:
Javascript 到 Flash的通信—-使用Flash播放器的javascript方法
Flash 到 Javascript的通信—-使用Flash的fscommand
Flash 到 Flash的通信———-使用本地连接对象或综合上2种技术
并不是所有的浏览器都很重视脚本.为了和Flash播放器通信,浏览器必须有内置的钩子以便Flash播放器可以'监听'.浏览器必须是下列的几种:
Netscape Navigator 3.0-4.7x, 和 Netscape 6.2或更高
(Windows 95/98/NT/2000/XP 或 MacOS; 允许Java和LiveConnect)
Internet Explorer 3.0 或更高
(仅Windows 95/98/NT/2000/XP; 允许ActiveX)
注意:Macintosh上的Internet Explorer和早期版本的Netscape6不支持这种方法.请查看本文的附加信息
Javascript到Flash的通信

这个例子演示了如何使用Flash的method把变量从HTML的input text 发送到该页面中的Flash文件中.HTML input的数据通过Flash的SetVariable方法传送到Flash文件中.

查看示例:示例
下载源文件: javascript_to_flash.zip(17k)
步骤:

Flash中
1.新建一个文件,保存为javascript_to_flash.fla
2.用文字工具在舞台上创建一个文本域
3.选择这个文本域,在属性面板中,从下拉列表中选择动态文本(Dynamic Text),在变量(variable)栏填上"myVar"
注意:最好的习惯是使用Instance,用myVar.text更改myVar的值.为了简单起见和兼容Flash4和Flash5,我们使用的是变量名的形式.
4.保存文件
5.发布HTML文件和SWF文件

Dreamweaver中
下一步的工作转移到Dreamweaver中了,当然也可以是其他的HTML编辑器
1.打开上一步发布的HTML文件
2.插入生成的SWF文件和OBJECT/EMBED标签
(1) Insert>Media>Flash,并选择这个Flash
(2) 切换到代码视图,我们需要修改被选中的<OBJECT>和<EMBED>标签
(3) 在OBJECT标签中,插入id="myFlash"

<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/
flash/swflash.cab#version=5,0,0,0"
width=366 height=142 id="myFlash">

注意:如果你是粘贴复制代码的话,确保删除不必要的换行.否则可能会引起错误; id也可以在属性面板里直接输入
(4) 在EMBED标签中,插入name="myFlash"和swLiveConnect="true",确保没有使用id属性!代码应当是这样子的:

<embed src="javascript_to_flash.swf" quality=high width=366 height=142
type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?
P1_Prod_Version=ShockwaveFlash"
name="myFlash" swLiveConnect="true">
</embed>

3.创建表单域
(1) 回到设计视图
(2) 插入文本域(Insert> Form Object> Text Field),如果询问是否添加表单域,选择是
(3) 把文本域的HTML标签修改成这样:

<input type="text" name="sendText" maxlength="45" onChange="doPassVar(this)">
每当文本域内容发生变化时,onChange就被触发,doPassVar()函数就被调用

4.创建传递变量值的Javascript函数
复制下面的Javascript到<head></head>标签内

<SCRIPT LANGUAGE=JavaScript>
<!–
function doPassVar(args){
var sendText = args.value;
   window.document.myFlash.SetVariable("myVar", sendText);
}
//–>
</SCRIPT>

5.保存文件,测试一下(F12)

出处:蓝色理想
责任编辑:qhwa

[MVC]ASP.NET MVC雕虫小技 1-2

mikel阅读(819)

转载:http://www.cnblogs.com/chsword/archive/2009/05/08/mvcskill_1.html

看到AnyTao和TerryLee分享的关于ASP.NET MVC使用和优化的技巧,不免手痒,也分享一下这一年多来ASP.NET MVC开发的积累。

其中未必是一些高效的技巧,但是的确是能解决问题,也未必有什么高深的原理,只是我觉得值得分享。

1.Controller来控制HTML的Title

我想大部分朋友都有在Controller里面指定Html页面Title的需求。

我习惯于先写使用的代码再去完善其实现,而指定一个Title最方便的形式莫过于:

   1: public ActionResult Index(int id) {

   2:     var article=Db.GetArticle(id);//获取数据库里的文章

   3:     Title=article.Name;

   4:     return View();

   5: }

当然,这段代码是不能执行的,因为Controller并没有内建的Title属性,不过没关系,我们可以自定义一个:

   1: abstract public class MyBaseController : Controller {

   2:        public string Title {

   3:            set {

   4:                ViewData["Page_Title"] = value;

   5:            }

   6:        }

   7: }

然后将我们的Controller换为这个MyBaseController,之后在Master中写ViewData[“Page_Title”]的输出就好了。

   1: <title><%=ViewData["Page_Title"] %></title>

OK,这个愿意实现了。

当然做SEO的话Keyword和Description也可以这样来搞。

2.ViewModel中传递Controller中定义的上下文

老赵十分推ViewModel于是我也做了不少这方面的实践,发现的确不错。但是有个问题,就是Controller中产生的上下文怎么传到View中去,比如说自定义的用户信息,等一些非static的类型,而我又不想到View中再实例化一遍。

解决方法:ViewModel中另加一上下文属性(在我和程序中这些上下文继承于IContext接口,而在Controller中它的属性是CHContext)

   1: public class HomeIndexViewModel {

   2:     public IContext Context { get; set; }//这个属性就是解决它的方法

   3:     public string Message { get; set; }

   4: }

而我在Controller中:

   1: public ActionResult Index() {

   2:     HomeIndexViewModel model = new HomeIndexViewModel {

   3:         Context = CHContext,//这里传递

   4:         Message="Welcome to ASP.NET MVC!"

   5:     };

   6:     return View(model);

   7: }

而View中:

   1: <%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"

   2: Inherits="System.Web.Mvc.ViewPage<HomeIndexViewModel>" %>

   3: <asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent" runat="server">

   4:     Home Page

   5: </asp:Content>

   6: <asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">

   7:     <h2><%= Html.Encode(Model.Message) %></h2>

   8: </asp:Content>

这样我们就可以实现将Controller中产生的自定义上下文传递了。不过每个ViewModel都初始化一个IContext,未免太过频繁, 也累人,于是进一步改进,我们利用作用在Controller上的Filter,在Controller的基类我们自定义的 MyBaseController中写如下Filter,而实现这个功能则要所有的ViewModel继承于一个类:MyBaseViewModel:

MyBaseViewModel与Model:

   1: public class MyBaseViewModel {

   2:     public IContext Context { get; set; }

   3: }

   4:  

   5: public class HomeIndexViewModel:MyBaseViewModel {

   6:     public string Message { get; set; }

   7: }

Controller与Filter

   1: abstract public class BaseController : Controller {

   2:     protected override void OnResultExecuting(ResultExecutingContext filterContext) {

   3:         var m = ViewData.Model as BaseViewModel;

   4:         if (m != null){

   5:             m.Context = CHContext;//在这里初始化

   6:         }

   7:     }

   8: }

这回我们在Controller里使用时就清爽了,不用再传递CHContext了。

[Flash]纯AS代码实现可预览本地图片的flash上传客户端

mikel阅读(780)

转载:http://www.klstudio.com/post/182.html
[AS3]纯AS代码实现可预览本地图片的flash上传客户端
    需要Flash Player 10+版本的支持,原理就是主要利用fp10中的FileReference.load(),FileReference.data和 Loader.loadBytes()三个方法通过图片加载到内存中,来实现预览本地图片,但这个方式不太适用大图片预览,图片越大内存消耗就越大。

[注意]
1.我这边图片上传路径是无效的,所以图片上传失败是正常的,你们可以改一下上传路径即可;
2.需要Flash Player 10的支持;
3.这次主要研究是预览本地图片功能。

演示效果

实现代码

  1. package project.test   
  2. {  
  3.     import flash.display.*;  
  4.     import flash.geom.Rectangle;  
  5.     import flash.net.*;  
  6.     import flash.text.*;  
  7.     import flash.filters.*;  
  8.     import flash.events.*;  
  9.     import flash.system.Security;  
  10.       
  11.     import fl.controls.Button;  
  12.     import fl.controls.ProgressBar;  
  13.     import fl.controls.ProgressBarMode;  
  14.       
  15.     /** 
  16.      * @link kinglong@gmail.com 
  17.      * @author Kinglong 
  18.      * @playerversion fp10    
  19.      */  
  20.     [SWF(width="500", height="300", frameRate="24", backgroundColor="#FFFFFF")]  
  21.     public class TestUpload extends Sprite {  
  22.           
  23.         private const DEFAULT_UPLOAD_PAGE:String = "http://test.klstudio.com/upload.asp";         
  24.         private const BOX_WIDTH:uint = 500;  
  25.         private const BOX_HEIGHT:uint = 300;  
  26.           
  27.         private const STATE_CACHE:String = "cache";  
  28.         private const STATE_UPLOAD:String = "upload";  
  29.           
  30.         private var _filters:Array;  
  31.         private var _file:FileReference;  
  32.         private var _loader:Loader;  
  33.         private var _progress:ProgressBar;  
  34.         private var _state:String;  
  35.         private var _buttons:Array;  
  36.         private var _labels:Array;  
  37.         private var _txts:Array;  
  38.         private var _rect:Rectangle;  
  39.         private var _state_txt:TextField;  
  40.           
  41.         public function TestUpload() {  
  42.             Security.allowDomain("*");  
  43.               
  44.             _buttons = [];  
  45.             _txts = [];  
  46.             _labels = ["文件名称:","文件类型:","文件大小:","修改时间:"];  
  47.               
  48.             _rect = new Rectangle(2080180180);  
  49.             _state = STATE_CACHE;  
  50.               
  51.             //背景;  
  52.             this.graphics.beginFill(0x333333);  
  53.             this.graphics.drawRoundRect(00, BOX_WIDTH, BOX_HEIGHT, 1010);  
  54.             this.graphics.endFill();  
  55.             this.graphics.beginFill(0xEFEFEF);  
  56.             this.graphics.drawRoundRect(11, BOX_WIDTH – 2, BOX_HEIGHT – 21010);  
  57.             this.graphics.endFill();  
  58.             this.graphics.beginFill(0x666666);  
  59.             this.graphics.drawRoundRect(1030, BOX_WIDTH – 20, BOX_HEIGHT – 602020);             
  60.             this.graphics.endFill();  
  61.             this.graphics.beginFill(0xFEFEFE);  
  62.             this.graphics.drawRoundRect(1131, BOX_WIDTH – 22, BOX_HEIGHT – 622020);  
  63.             this.graphics.endFill();  
  64.               
  65.             this.graphics.beginFill(0xCCCCCC);  
  66.             this.graphics.drawRect(1170, BOX_WIDTH – 221);  
  67.             this.graphics.endFill();  
  68.               
  69.             this.graphics.beginFill(0x000000);  
  70.             this.graphics.drawRect(_rect.x-1, _rect.y-1, _rect.width+2, _rect.height+2);  
  71.             this.graphics.endFill();              
  72.             this.graphics.beginFill(0xEEEEEE);  
  73.             this.graphics.drawRect(_rect.x, _rect.y, _rect.width, _rect.height);  
  74.             this.graphics.endFill();  
  75.               
  76.               
  77.             //标题;  
  78.             var label:TextField;              
  79.             label = getLabel("图片上传(预览图片版) by Kinglong", getTextFormat(0xFFFFFF14true));  
  80.             label.x = 10;  
  81.             label.y = 5;  
  82.             label.filters = [getLabelFilter(0x000000)];  
  83.             this.addChild(label);  
  84.               
  85.             for (var i:uint = 0; i < _labels.length; i++ ) {           
  86.                 label = getLabel(_labels[i], getTextFormat(0x33333312), falsefalse);                  
  87.                 label.x = _rect.right+5;  
  88.                 label.y = _rect.y + 25 * i;  
  89.                 label.width = 280;  
  90.                 label.height = 20;  
  91.                 _txts.push(label);  
  92.                 this.addChild(label);  
  93.             }             
  94.               
  95.             _state_txt = getLabel("状态:", getTextFormat(0x33333312));  
  96.             _state_txt.x = 10;  
  97.             _state_txt.y = BOX_HEIGHT – _state_txt.height – 5;  
  98.             this.addChild(_state_txt);  
  99.               
  100.             //按钮;  
  101.             var button:Button;  
  102.             button = getButton("选择文件"80);           
  103.             button.move(2040);  
  104.               
  105.             button = getButton("上传文件"80);           
  106.             button.move(10540);  
  107.             button.enabled = false;  
  108.               
  109.             //进度条;  
  110.             _progress = new ProgressBar();  
  111.             _progress.move(19040);  
  112.             _progress.setSize(290,22);  
  113.             _progress.mode = ProgressBarMode.MANUAL;                          
  114.             this.addChild(_progress);  
  115.               
  116.             //文件类型;  
  117.             _filters = [];  
  118.             var filter:FileFilter;            
  119.             filter = new FileFilter("所有支持图片文件(*.jpg,*.jpeg,*.gif,*.png)""*.jpg;*.jpeg;*.gif;*.png");  
  120.             _filters[_filters.length] = filter;  
  121.             filter = new FileFilter("JPEG files(*.jpg,*.jpeg)","*.jpg;*.jpeg");  
  122.             _filters[_filters.length] = filter;  
  123.             filter = new FileFilter("GIF files (*.gif)","*.gif");  
  124.             _filters[_filters.length] = filter;  
  125.             filter = new FileFilter("PNG files(*.png)","*.png");  
  126.             _filters[_filters.length] = filter;   
  127.               
  128.             _file = new FileReference();   
  129.             _file.addEventListener(Event.COMPLETE, fileHandler);  
  130.             _file.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, fileHandler);  
  131.             _file.addEventListener(Event.Select, fileHandler);  
  132.             _file.addEventListener(Event.OPEN, fileHandler);              
  133.             _file.addEventListener(ProgressEvent.PROGRESS, fileHandler);  
  134.             _file.addEventListener(SecurityErrorEvent.SECURITY_ERROR, fileHandler);  
  135.             _file.addEventListener(IOErrorEvent.IO_ERROR, fileHandler);  
  136.             _file.addEventListener(HTTPStatusEvent.HTTP_STATUS, fileHandler);  
  137.               
  138.             _loader = new Loader();  
  139.             _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadHandler);  
  140.             this.addChild(_loader);  
  141.         }  
  142.           
  143.         public function get state():String {  
  144.             return _state;  
  145.         }  
  146.           
  147.         private function clickHandler(event:MouseEvent):void {  
  148.             switch(event.target) {  
  149.                 case _buttons[0]:  
  150.                     _file.browse(_filters);  
  151.                     break;  
  152.                 case _buttons[1]:  
  153.                     _file.upload(new URLRequest(DEFAULT_UPLOAD_PAGE));  
  154.                     _state = STATE_UPLOAD;                    
  155.                     _buttons[0].enabled = false;  
  156.                     _buttons[1].enabled = false;  
  157.                     break;  
  158.             }  
  159.         }  
  160.           
  161.         private function loadHandler(event:Event):void {  
  162.             _loader.scaleX = _loader.scaleY = 1;  
  163.             var w:uint = _loader.width;  
  164.             var h:uint = _loader.height;  
  165.             if (w > _rect.width || h > _rect.height) {                  
  166.                 var ip:Number = w / h;  
  167.                 var lp:Number = _rect.width / _rect.height;           
  168.                 _loader.width = (ip > lp)?_rect.width:_rect.height*ip;  
  169.                 _loader.height = (ip > lp)?_rect.width / ip:_rect.height;  
  170.             }  
  171.             _loader.x = _rect.x + (_rect.width – _loader.width) / 2;  
  172.             _loader.y = _rect.y + (_rect.height – _loader.height) / 2;            
  173.             _loader.visible = true;  
  174.         }  
  175.           
  176.         private function fileHandler(event:Event):void {  
  177.             switch(event.type) {  
  178.                 case Event.COMPLETE:  
  179.                     if(state == STATE_CACHE){  
  180.                         _loader.loadBytes(_file.data);  
  181.                     }  
  182.                     break;  
  183.                 case DataEvent.UPLOAD_COMPLETE_DATA:  
  184.                     Debug("图片上传完成!");  
  185.                     _buttons[0].enabled = true;  
  186.                     _buttons[1].enabled = false;  
  187.                     _progress.setProgress(01);  
  188.                     break;  
  189.                 case Event.Select:  
  190.                     _txts[0].text = _labels[0] + _file.name;  
  191.                     _txts[1].text = _labels[1] + _file.type;  
  192.                     _txts[2].text = _labels[2] + ((_file.size > 1024 * 1024)?Math.round(_file.size * 10 / (1024*1024))/10 + "MB":Math.round(_file.size * 10 / 1024)/10 + "KB");                    
  193.                     _txts[3].text = _labels[3] + date2str(_file.modificationDate);  
  194.                     _buttons[0].enabled = true;  
  195.                     _buttons[1].enabled = true;  
  196.                     _file.load();  
  197.                     _state = STATE_CACHE;  
  198.                     _loader.visible = false;  
  199.                     Debug("图片已经准备!");  
  200.                     break;  
  201.                 case Event.OPEN:  
  202.                     if(state == STATE_UPLOAD){  
  203.                         debug("正在上传图片…");  
  204.                     }  
  205.                     break;  
  206.                 case ProgressEvent.PROGRESS:  
  207.                     if (state == STATE_UPLOAD) {  
  208.                         var pEvent:ProgressEvent = event as ProgressEvent;  
  209.                         _progress.setProgress(pEvent.bytesLoaded, pEvent.bytesTotal);  
  210.                     }  
  211.                     break;  
  212.                 case SecurityErrorEvent.SECURITY_ERROR:  
  213.                 case IOErrorEvent.IO_ERROR:  
  214.                 case HTTPStatusEvent.HTTP_STATUS:                     
  215.                     if (state == STATE_UPLOAD) {  
  216.                         debug("图片上传失败!");  
  217.                         _buttons[0].enabled = true;  
  218.                         _buttons[1].enabled = true;  
  219.                     }else {  
  220.                         debug("图片缓冲失败!");  
  221.                     }  
  222.                     _progress.setProgress(01);  
  223.                     break;  
  224.                   
  225.             }  
  226.         }  
  227.           
  228.         private function getButton(lbl:String,width:uint=120):Button {  
  229.             var button:Button = new Button();  
  230.             button.label = lbl;  
  231.             button.setSize(width, 22);    
  232.             button.setStyle("textFormat", getTextFormat());  
  233.             button.setStyle("disabledTextFormat", getTextFormat(0x999999));  
  234.             button.setStyle("textPadding",4);  
  235.             button.addEventListener(MouseEvent.CLICK, clickHandler);              
  236.             this.addChild(button);  
  237.             _buttons.push(button);  
  238.             return button;  
  239.         }  
  240.           
  241.         private function getLabel(label:String, format:TextFormat, selectable:Boolean = false, autoSize:Boolean = true):TextField {           
  242.             var lbl:TextField = new TextField();  
  243.             lbl.selectable = selectable;  
  244.             lbl.defaultTextFormat = format;  
  245.             if(autoSize){  
  246.                 lbl.autoSize = TextFieldAutoSize.LEFT;  
  247.             }  
  248.             lbl.text = label;  
  249.             return lbl;  
  250.         }  
  251.           
  252.         private function getTextFormat(color:uint=0x000000,size:uint = 12,bold:Boolean=false):TextFormat {  
  253.             var format:TextFormat = new TextFormat();  
  254.             format.font = "宋体";  
  255.             format.color = color;  
  256.             format.size = size;  
  257.             format.bold = bold;  
  258.             return format;  
  259.         }  
  260.           
  261.         private function getLabelFilter(color:uint=0xFFFFFF):BitmapFilter {  
  262.             var alpha:Number = 0.8;  
  263.             var blurX:Number = 2;  
  264.             var blurY:Number = 2;  
  265.             var strength:Number = 3;  
  266.             var inner:Boolean = false;  
  267.             var knockout:Boolean = false;  
  268.             var quality:Number = BitmapFilterQuality.HIGH;  
  269.   
  270.             return new GlowFilter(color,  
  271.                                   alpha,  
  272.                                   blurX,  
  273.                                   blurY,  
  274.                                   strength,  
  275.                                   quality,  
  276.                                   inner,  
  277.                                   knockout);  
  278.         }  
  279.           
  280.         private function date2str(day:Date):String {  
  281.             var str:String = day.getFullYear() + "-";  
  282.             str += num2str(day.getMonth() + 1) + "-";  
  283.             str += num2str(day.getDate()) + " ";  
  284.             str += num2str(day.getHours()) + ":";  
  285.             str += num2str(day.getMinutes()) + ":";  
  286.             str += num2str(day.getSeconds());  
  287.             return str;  
  288.         }  
  289.           
  290.         private function num2str(val:Number):String {  
  291.             var str:String = "00" + val;  
  292.             return str.substr(str.length – 22);             
  293.         }  
  294.           
  295.         private function debug(message:String):void {  
  296.             _state_txt.text = message;  
  297.         }  
  298.           
  299.     }  
  300.       

[Flash]Flash实现多文件上传

mikel阅读(751)

转载:http://blog.iyi.cn/start/2007/06/ajaxflash.html

FancyUpload,用flash和mootools实现的一款多文件无刷新上传工具。
最大的特点是可以一次选择多个文件,无刷新上传。
早些时候曾想过一次选择多个文件的问题,浏览器默认的file标签一次只能选择一个文件,要浏览并读取本地文件就必须调用本地的组件或命令,所以单纯用JavaScript+html无解。
今天查看订阅的feeds时,无意中在Ajaxian看到这个演示图片上选择了多个文件:

非常好奇,过去看了一下demo,果然可以一次选择多个文件!

Browsfile的button没什么特别,就是一个button,肯定是通过js触发了某个动作。前面说过js和html是不能实现这个功能的,那么肯定是flash实现了这个功能。

文件里面有个Swiff.Uploader.swf,就是这个swf实现了文件浏览的功能,as在这:http://digitarald.de/workspace/packages/Uploader/Swiff.Uploader.as

google了一下flash filebrowserflash fileupload果然找到很多内容

这片中文的详细说明了那个flash的原理:
http://www.cnblogs.com/walkingboy/archive/2007/02/09/Flash_FileUpload_FileReference.html
出处可能是这个:
http://www.codeproject.com/aspnet/FlashUpload.asp

原理是用了flash的FileReferenceList API实现的多文件选取。
http://markshu.ca/imm/flash/tutorial/fileReference.html

另外还有几个实例:
http://www.betriebsraum.de/blog/2006/01/13/download-flash-8-file-browser/

http://www.extremefx.com.ar/blog/flash-textarea

[REST]深入浅出REST

mikel阅读(806)

作者 Stefan Tilkov 译者 苑永凯 发布于 2007年12月25日 下午10时10分

社区
Architecture,
SOA
主题
REST,
企业架构
标签
Web服务

不 知你是否意识到,围绕着什么才是实现异构的应用到应用通信的“正确”方式,一场争论正进行的如火如荼:虽然当前主流的方式明显地集中在基于SOAP、 WSDL和WS-*规范的Web Services领域,但也有少数人用细小但洪亮的声音主张说更好的方式是REST,表述性状态转移(REpresentational State Transfer)的简称。在本文中,我不会涉及争论的话题,而是尝试对REST和RESTful HTTP应用集成做实用性的介绍。以我的经验,有些话题一旦触及就会引来众多的讨论,当涉及到这方面话题的时候,我会深入详细地阐述。

REST关键原则

大部分对REST的介绍是以其正式的定义和背景作为开场的。但这儿且先按下不表,我先提出一个简单扼要的定义:REST定义了应该如何正确地使用 (这和大多数人的实际使用方式有很大不同)Web标准,例如HTTP和URI。如果你在设计应用程序时能坚持REST原则,那就预示着你将会得到一个使用 了优质Web架构(这将让你受益)的系统。总之,五条关键原则列举如下:

  • 为所有“事物”定义ID
  • 将所有事物链接在一起
  • 使用标准方法
  • 资源多重表述
  • 无状态通信

下面让我们进一步审视这些原则。

为所有“事物”定义ID

在这里我使用了“事物”来代替更正式准确的术语“资源”,因为一条如此简单的原则,不应该被淹没在术语当中。思考一下人们构建的系统,通常会找到一 系列值得被标识的关键抽象。每个事物都应该是可标识的,都应该拥有一个明显的ID——在Web中,代表ID的统一概念是:URI。URI构成了一个全局命 名空间,使用URI标识你的关键资源意味着它们获得了一个唯一、全局的ID。

对事物使用一致的命名规则(naming scheme)最主要的好处就是你不需要提出自己的规则——而是依靠某个已被定义,在全球范围中几乎完美运行,并且能被绝大多数人所理解的规则。想一下你 构建的上一个应用(假设它不是采用RESTful方式构建的)中的任意一个高级对象(high-level object),那就很有可能看到许多从使用唯一标识中受益的用例。比如,如果你的应用中包含一个对顾客的抽象,那么我可以相当肯定,用户会希望将一个指 向某个顾客的链接,能通过电子邮件发送到同事那里,或者加入到浏览器的书签中,甚至写到纸上。更透彻地讲:如果在一个类似于Amazon.com的在线商 城中,没有用唯一的ID(一个URI)标识它的每一件商品,可想而知这将是多么可怕的业务决策。

当面对这个原则时,许多人惊讶于这是否意味着需要直接向外界暴露数据库记录(或者数据库记录ID)——自从多年以来面向对象的实践告诫我们,要将持 久化的信息作为实现细节隐藏起来之后,哪怕是刚有点想法都常会使人惊恐。但是这条原则与隐藏实现细节两者之间并没有任何冲突:通常,值得被URI标识的事 物——资源——要比数据库记录抽象的多。例如,一个定单资源可以由定单项、地址以及许多其它方面(可能不希望作为单独标识的资源暴露出来)组成。标识所有 值得标识的事物,领会这个观念可以进一步引导你创造出在传统的应用程序设计中不常见的资源:一个流程或者流程步骤、一次销售、一次谈判、一份报价请求—— 这都是应该被标识的事物的示例。同样,这也会导致创建比非RESTful设计更多的持久化实体。

下面是一些你可能想到的URI的例子:

http://example.com/customers/1234
http://example.com/orders/2007/10/776654
http://example.com/products/4554
http://example.com/processes/salary-increase-234 

正如我选择了创建便于阅读的URI——这是个有用的观点,尽管不是RESTful设计所必须的——应该能十分容易地推测出URI的含义:它们明显地标识着单一“数据项”。但是再往下看:

http://example.com/orders/2007/11
http://example.com/products?color=green 

首先,这两个URI看起来与之前的稍有不同——毕竟,它们不是对一件事物的标识,而是对一类事物集合的标识(假定第一个URI标识了所有在2007年11月份提交的定单,第二个则是绿颜色产品的集合)。但是这些集合自身也是事物(资源),也应该被标识。

注意,使用唯一、全局统一的命名规则的好处,既适用于浏览器中的Web应用,也适用于机对机(machine-to-machine,m2m)通信。

来对第一个原则做下总结:使用URI标识所有值得标识的事物,特别是应用中提供的所有“高级”资源,无论这些资源代表单一数据项、数据项集合、虚拟亦或实际的对象还是计算结果等。

将所有事物链接在一起

接下来要讨论的原则有一个有点令人害怕的正式描述:“超媒体被当作应用状态引擎(Hypermedia as the engine of application state)”,有时简写为HATEOAS。(严格地说,这不是我说的。)这个描述的核心是超媒体概念,换句话说:是链接的思想。链接是我们在HTML中常见的概念,但是它的用处绝不局限于此(用于人们网络浏览)。考虑一下下面这个虚构的XML片段:


23


 

如果你观察文档中product和customer的链接,就可以很容易地想象到,应用程序(已经检索过文档)如何“跟随”链接检索更多的信息。当然,如果使用一个遵守专用命名规范的简单“id”属性作为链接,也是可行的——但是仅限于应用环境之内。使用URI表示链接的优雅之处在于,链接可以指向由不同应用、不同服务器甚至位于另一个大陆上的不同公司提供的资源——因为URI命名规范是全球标准,构成Web的所有资源都可以互联互通。

超媒体原则还有一个更重要的方面——应用“状态”。简而言之,实际上服务器端(如果你愿意,也可以叫服务提供者)为客户端(服务消费者)提供一组链 接,使客户端能通过链接将应用从一个状态改变为另一个状态。稍后我们会在另一篇文章中探究这个方面的影响;目前,只需要记住:链接是构成动态应用的非常有 效的方式。

对此原则总结如下:任何可能的情况下,使用链接指引可以被标识的事物(资源)。也正是超链接造就了现在的Web。

使用标准方法

在前两个原则的讨论中暗含着一个假设:接收URI的应用程序可以通过URI明确地一些有意义的事情。如果你在公共汽车上看到一个URI,你可以将它输入浏览器的地址栏中并回车——但是你的浏览器如何知道需要对这个URI做些什么呢?

它知道如何去处理URI的原因在于所有的资源都支持同样的接口,一套同样的方法(只要你乐意,也可以称为操作)集合。在HTTP中这被叫做动词 (verb),除了两个大家熟知的(GET和POST)之外,标准方法集合中还包含PUT、Delete、HEAD和OPTIONS。这些方法的含义连同 行为许诺都一起定义在HTTP规范之中。如果你是一名OO开发人员,就可以想象到RESTful HTTP方案中的所有资源都继承自类似于这样的一个类(采用类Java、C#的伪语法描述,请注意关键的方法):

class Resource {
Resource(URI u);
Response get();
Response post(Request r);
Response put(Request r);
Response delete();
} 

由于所有资源使用了同样的接口,你可以依此使用GET方法检索一个表述(representation)——也 就是对资源的描述。因为规范中定义了GET的语义,所以可以肯定当你调用它的时候不需要对后果负责——这就是为什么可以“安全”地调用此方法。GET方法 支持非常高效、成熟的缓存,所以在很多情况下,你甚至不需要向服务器发送请求。还可以肯定的是,GET方法具有幂等性[译 注:指多个相同请求返回相同的结果]——如果你发送了一个GET请求没有得到结果,你可能不知道原因是请求未能到达目的地,还是响应在反馈的途中丢失了。 幂等性保证了你可以简单地再发送一次请求解决问题。幂等性同样适用于PUT(基本的含义是“更新资源数据,如果资源不存在的话,则根据此URI创建一个新 的资源”)和Delete(你完全可以一遍又一遍地操作它,直到得出结论——删除不存在的东西没有任何问题)方法。POST方法,通常表示“创建一个新资 源”,也能被用于调用任过程,因而它既不安全也不具有幂等性。

如果你采用RESTful的方式暴露应用功能(如果你乐意,也可以称为服务功能),那这条原则和它的约束同样也适用于你。如果你已经习惯于另外的设计方式,则很难去接受这条原则——毕竟,你很可能认为你的应用包含了超出这些操作表达范围的逻辑。请允许我花费一些时间来让你相信不存在这样的情况。

来看下面这个简单的采购方案例子:

Sample Scenario

可以看到,例子中定义了两个服务程序(没有包含任何实现细节)。这些服务程序的接口都是为了完成任务(正是我们讨论的 orderManagement和CustomerManagement服务)而定制的。如果客户端程序试图使用这些服务,那它必须针对这些特定接口进行 编码——不可能在这些接口定义之前,使用客户程序去有目的地和接口协作。这些接口定义了服务程序的应用协议(application protocol)。

在RESTful HTTP方式中,你将通过组成HTTP应用协议的通用接口访问服务程序。你可能会想出像这样的方式:

Sample Scenario, done RESTfully

可以看到,服务程序中的特定操作被映射成为标准的HTTP方法——为了消除歧义,我创建了一组全新的资源。“这是骗人的把戏”,我听见你叫嚷着。 不,这不是欺骗。标识一个顾客的URI上的GET方法正好相当于getCustomerDetails操作。有人用三角形形象化地说明了这一点:

Knobs one can turn

把三个顶点想象为你可以调节的按钮。可以看到在第一种方法中,你拥有许多操作,许多种类的数据以及固定数量的“实例”(本质上和你拥有的服务程序数 量一致)。在第二种方法中,你拥有固定数量的操作,许多种类的数据和许多调用固定方法的对象。它的意义在于,证明了通过这两种方式,你基本上可以表示任何 你喜欢的事情。

为什么使用标准方法如此重要?从根本上说,它使你的应用成为Web的一部分——应用程序为Web变成Internet上最成功的应用所做的贡献,与 它添加到Web中的资源数量成比例。采用RESTful方式,一个应用可能会向Web中添加数以百万计的客户URI;如果采用CORBA技术并维持应用的 原有设计方式,那它的贡献大抵只是一个“端点(endpoint)”——就好比一个非常小的门,仅仅允许有钥匙的人进入其中的资源域。

统一接口也使得所有理解HTTP应用协议的组件能与你的应用交互。通用客户程序(generic client)就是从中受益的组件的例子,例如curl、wget、代理、缓存、HTTP服务器、网关还有Google、Yahoo!、MSN等等。

总结如下:为使客户端程序能与你的资源相互协作,资源应该正确地实现默认的应用协议(HTTP),也就是使用标准的GET、PUT、POST和Delete方法。

资源多重表述

到目前为止我们一直忽略了一个稍微复杂的问题:客户程序如何知道该怎样处理检索到的数据,比如作为GET或者POST请求的结果?原因是,HTTP 采取的方式是允许数据处理和操作调用之间关系分离的。换句话说,如果客户程序知道如何处理一种特定的数据格式,那就可以与所有提供这种表述格式的资源交 互。让我们再用一个例子来阐明这个观点。利用HTTP内容协商(content negotiation),客户程序可以请求一种特定格式的表述:

GET /customers/1234 HTTP/1.1
Host: example.com
Accept: application/vnd.mycompany.customer+xml  

请求的结果可能是一些由公司专有的XML格式表述的客户信息。假设客户程序发送另外一个不同的请求,就如下面这样:

GET /customers/1234 HTTP/1.1
Host: example.com
Accept: text/x-vcard 

结果则可能是VCard格式的客户地址。(在这里我没有展示响应的内容,在其HTTP Content-type头中应该包含着关于数据类型的元数据。)这说明为什么理想的情况下,资源表述应该采用标准格式——如果客户程序对HTTP应用协 议和一组数据格式都有所“了解”,那么它就可以用一种有意义的方式与世界上任意一个RESTful HTTP应用交互。 不幸的是,我们不可能拿到所有东西的标准格式,但是,或许我们可以想到在公司或者一些合作伙伴中使用标准格式来营造一个小环境。当然以上情况不仅适用于从 服务器端到客户端的数据,反之既然——倘若从客户端传来的数据符合应用协议,那么服务器端就可以使用特定的格式处理数据,而不去关心客户端的类型。

在实践中,资源多重表述还有着其它重要的好处:如果你为你的资源提供HTML和XML两种表述方式,那这些资源不仅可以被你的应用所用,还可以被任意标准Web浏览器所用——也就是说,你的应用信息可以被所有会使用Web的人获取到。

资源多重表述还有另外一种使用方式:你可以将应用的Web UI纳入到Web API中——毕竟,API的设计通常是由UI可以提供的功能驱动的,而UI也是通过API执行动作的。将这两个任务合二为一带来了令人惊讶的好处,这使得 使用者和调用程序都能得到更好的Web接口。

总结:针对不同的需求提供资源多重表述。

无状态通信

无状态通信是我要讲到的最后一个原则。首先,需要着重强调的是,虽然REST包含无状态性(statelessness)的观念,但这并不是说暴露功能的应用不能有状态——
事 实上,在大部分情况下这会导致整个做法没有任何用处。REST要求状态要么被放入资源状态中,要么保存在客户端上。或者换句话说,服务器端不能保持除了单 次请求之外的,任何与其通信的客户端的通信状态。这样做的最直接的理由就是可伸缩性—— 如果服务器需要保持客户端状态,那么大量的客户端交互会严重影响服务器的内存可用空间(footprint)。(注意,要做到无状态通信往往需要需要一些 重新设计——不能简单地将一些session状态绑缚在URI上,然后就宣称这个应用是RESTful。)

但除此以外,其它方面可能显得更为重要:无状态约束使服务器的变化对客户端是不可见的,因为在两次连续的请求中,客户端并不依赖于同一台服务器。一 个客户端从某台服务器上收到一份包含链接的文档,当它要做一些处理时,这台服务器宕掉了,可能是硬盘坏掉而被拿去修理,可能是软件需要升级重启——如果这 个客户端访问了从这台服务器接收的链接,它不会察觉到后台的服务器已经改变了。

理论上的REST

我承认:以上我所说的REST不是真正的REST,而且我可能有点过多地热衷于简单化。但因为我想有一个与众不同的开场,所以没有在一开始就介绍其正式的定义和背景。现在就让我们稍微简要地介绍一下这方面的内容。

首先,先前我并没有明确地区分HTTP、RESTful HTTP和REST。要理解这些不同方面之间的关系,我们要先来看看REST的历史。

Roy T. Fielding在他的博士学位论文(实际上你应该访问这个链接——至少对于一篇学术论文来说,它是相当易读的。此论文已被翻译成中文) 中定义了术语REST。Roy曾是许多基本Web协议的主要设计者,其中包括HTTP和URIs,并且他在论文中对这些协议提出了很多想法。(这篇论文被 誉为“REST圣经”,这是恰当的——毕竟,是作者发明了这个术语,所以在定义上,他写的任何内容都被认为是权威的。)在论文中,Roy首先定义一种方法 论来谈论架构风格——高级、抽象的模式,来表达架构方法背后的核心理念。每一个架构风格由一系列的约束(constraints)定义形成。架构风格的例子包括“没有风格”(根本没有任何约束)、管道和过滤器(pipe and filter)、客户端/服务器、分布式对象以及——你猜到它了——REST。

如果对你来说这些听起来都太抽象了,那就对了——REST在本质上是一个可以被许多不同技术实现的高层次的风格,而且可以被实例化——通过为它的抽 象特性赋上不同的值。比如,REST中包含资源和统一接口的概念——也就是说,所有资源都应该对这些相同的方法作出反应。但是REST并没有说明是哪些方 法,或者有多少方法。

REST风格的一个“化身”便是HTTP(以及一套相关的一套标准,比如URI),或者稍微抽象一些:Web架构自身。接着上面的例子,HTTP使 用HTTP动词作为REST统一接口的“实例”。由于Fielding是在Web已经(或者至少是大部分)“完善”了之后才定义的REST风格,有人可能 会争论两者是不是100%的匹配。但是无论如何,整体上来说Web、HTTP和URI仅仅是REST风格的一个主要实现。不过,由于Roy Fielding即是REST论文的作者,又对Web架构设计有过深远的影响,两者相似也在情理之中。

最后,我在前面一次又一次地使用着术语“RESTful HTTP”,原因很简单:许多使用HTTP的应用因为一些理由并没有遵循REST原则,有人会说使用HTTP而不遵循REST原则就等同于滥用HTTP。 当然这听起来有点狂热——事实上违反REST约束的原因通常是,仅仅因为每个约束带来的设计权衡可能不适合于一些特殊情况。但通常,违背REST约束的原 因可归咎于对其好处认知的缺乏。来看一个明显的反面案例:使用HTTP GET调用类似于删除对象的操作,这违反了REST的安全约束和一般性常识(客户程序不应为此负责,服务器端开发人员大概不是有意而为之)。但在随后的文 章中,我会提及更多这样或那样的对HTTP的滥用。

总结

本文试图对REST(Web架构)背后的概念提供快速的介绍。RESTful HTTP暴露功能的方式与RPC、分布式对象以及Web Services是不相同的;要真正理解这些不同是需要一些心态的转变。不管你构建的应用是仅仅想暴露Web UI还是想把API变成Web的一份子,了解下REST的原则还是有好处的。

Stefan Tilkov是InfoQ SOA社区的首席编辑,并且是位于德国和瑞士的innoQ公司的共同创始人、首席顾问和REST狂热分子首领。

查看英文原文A Brief Introduction to REST

[REST]什么是REST

mikel阅读(773)

什么是REST?
  REST是Roy Fielding在他的博士论文中提出的词汇,是对网络系统构架的一个描述。REST是表现性状态传输首字母缩写(Representational State Transfer)。
Roy Feilding这么解释表现性状态传输的意义:

引用 “表现性状态传输试图描述一个设计优良的Web是如何运转的:用户在web网络(虚拟状态机)里通过点击链接处理应用(状态传输),结果就是传输并渲染下一个页面给用户(应用程序的下一个状态的表现性)。“

REST的目的
  REST的目的是寻找让Web如此成功的特性。然后再使用这些特性指导Web变革。
REST是一个结构设计,而不是一个标准
   REST不是一个标准,你永远也不会看到W3C发布REST白皮书。你也不会看到微软或者IBM销售REST开发工具。为什么?REST它仅仅是一个结 构设计而不是一个标准。你不能控制这个设计,你仅能够理解并且应用在你的Web服务中。(类似的C/S结构也是一种结构设计,而不是一个C/S标准)。
虽然REST不是一个标准,但它确实使用标准:
HTTP
URL
XML/HTML/GIF/JPEG等等(状态表现)
text/xml, text/html, image/gif, image/jpeg等等(MIME类型)
经典的REST系统
  Web就是REST系统,有很多你使用了很多年的服务就是基于REST的Web服务,例如:订书服务、搜索服务、在线电子字典。
  REST是关于Web的一张“大蓝图”,它不负责处理具体的执行细节(例如:使用Java还是CGI来实现一个Web服务)。所以让我们用REST“大蓝图”的观点来设计一个Web服务。
REST Web服务的特征
C/S结构:一个完全基于交互的设计
无状态:每个发送给服务器的信息必须包含服务器处理所需的所有信息,不能通过在服务器保存相关信息而获益。
缓存:为了提供网络的效率,响应必须标志出是否可以缓存。
统一的接口:所有的资源都可以通过一个通用的接口访问(例如:HTTP GET、POST、PUT、Delete)。
命名的资源:组成系统的资源使用URL来命名。
互联资源表现性:资源的表现性通过URL实现互联,因此客户可以一个状态接着一个状态处理。
组件层:可以在客户和资源间插入用于提高效率,增强安全的的中间件,象代理服务、缓存服务、网关等。
REST Web服务设计原则
1.以REST网络建立Web服务的关键(例如Web)是确定想作为服务展现的所有概念化的实体。
2.为每个资源提供URL。资源应该是名词,不是动词
3.根据客户处理资源的方式分类,可以分为客户仅接收资源的表现性,客户能够修改(增加)资源。对于前者,提供HTTP GET方法访问。对于后者,提供HTTP POST、PUT和(或)Delete。

我们在 Web 应用中处理来自客户端的请求时,通常只考虑 GET 和 POST 这两种 HTTP 请求方法。实际上,HTTP 还有 HEAD、PUT、Delete 等请求方法。而在 REST 架构中,用不同的 HTTP 请求方法来处理对资源的 CRUD(创建、读取、更新和删除)操作:

  • POST: 创建
  • GET: 读取
  • PUT: 更新
  • Delete: 删除

经过这样的一番扩展,我们对一个资源的 CRUD 操作就可以通过同一个 URI 完成了:

http://www.example.com/photo/logo(读取)
仍然保持为 [GET] http://www.example.com/photo/logo

http://www.example.com/photo/logo/create(创建)
改为 [POST] http://www.example.com/photo/logo

http://www.example.com/photo/logo/update(更新)
改为 [PUT] http://www.example.com/photo/logo

http://www.example.com/photo/logo/delete(删除)
改为 [Delete] http://www.example.com/photo/logo

从而进一步规范了资源标识的使用。

通过 REST 架构,Web 应用程序可以用一致的接口(URI)暴露资源给外部世界,并提供对资源的操作服务。这对于以资源为中心的 Web 应用来说非常重要。例如照片共享网站、用户社区等。

 

 

4.所有通过HTTP GET访问的资源应该是无副作用的,也就是说,这些资源仅仅向客户返回一个资源的表现性,客户调用他们不应该对它们产生影响。
5.没有孤立的人,同样,没有孤立的表现性。换言之,在资源的表现性中提供链接,让客户能更深入的获取更多的信息,或者相关信息。
6.逐步的提供数据,不应该在一个文档里提供所有的内容,可以为更详细的信息提供链接。
7.使用模式(DTD、W3C Schema、RelaxNG或者Schematron)指定响应数据的格式。如果服务需要POST或PUT,也同样使用一个模式规定这些响应。
8.通过WSDL文档或者HTML页面描述如何调用你的服务。

(转载)

[REST]REST构架风格介绍之一:状态表述转移

mikel阅读(850)

转载:http://www.cnblogs.com/weidagang2046/archive/2009/05/08/1452322.html

REST(Representational State Transfer)HTTP协议的作者Roy Fielding博士在其博士论文中提出的一种互联网应用构架风格。与以远程对象为核心的ORB和以服务为核心的SOA相比,以资源为核心的REST让我们从崭新的视角审视互联网应用。REST为互联网应用量身定做的简洁模型和其高扩展性,为互联网应用构架设计和异构系统集成设计带来了一股清新的空气。

本文希望与大家分享REST风格构架设计的体会,错误不足之处欢迎批评指正。

语言生态环境

计算机发展至今,产生了许许多多不同的语言,每种语言都定义了自己独特的生态环 境。在这个生态环境内,所有程序共享相同的类型系统、运行时环境、并发模型等。虽然所有程序的本质是相同的:从问题领域到机器领域的映射,但无法回避的是 不同生态环境的程序很难跨越彼此的边界。同样是int,在AB语言通常截然不同(CLRJVM能部分解决类型共享问题),更不用说A语言具有但B语言不具有的某些语言特性(CLRJVM没法解决)

当系统可以在单一的生态环境中自给自足时,跨越生态环境的问题并不存在;但在多数互联网应用中,系统的各个部分通常既是生产者又是消费者,必须要打破生态环境的界限才能相互协作。比如,A公司的Service A,需要对外提供服务,而Service A又依赖于B公司的Service BC公司的Service C;由于无法保证不同公司都采用同样的语言,因此各服务的接口必须保证语言无关性。在我所了解的范围内,有3种跨域生态环境的方式:

1.      ORB(Object Request Broker)

CORBA为代表,其核心概念是远程对象(remote object)。熟悉.Net Remoting的朋友应该能体会其风格(需要说明的是.Net Remoting只跨越微软的生态环境)。不同生态环境的程序可以像调用本地对象一样调用远程对象代理的方法,ORB会负责连接到远程的对象,并处理数据的序列化与反序列化。

2.      SOA

其核心概念是服务(Service)。比如:我们要提供整数加法Web服务,我们会很自然地想到通过类似下面的url来表达服务接口:

http://www.example.com/add?a=1&b=2

并通过xml结构表达结果:

<sum>3</sum>

3.      REST

其核心概念是资源(Resource)。在REST的世界中,没有服务的概念,同样是上面的例子,在REST的世界中,http://www.example.com/add?a=1&b=2是一个xml网页资源的id,而非服务的接口。所以,REST让我们从资源的角度来审视互联网应用并指导我们的设计,这是它与ORB和SOA最本质的区别。下面我们将更详细的介绍,REST以资源为核心的模型和相应的设计风格。

状态表述转移

REST的世界中,互联网就是一个巨大的状态机:每个网页是其一个状态(资源);url则是状态的表述。互联网应用是地从一个状态迁移到下一个状态的状态转移过程。这个状态表述转移过程正是互联网形成初期通过超链接在静态网页间浏览跳转的page->link->page->link…模式。REST风格应用可以实现交互,但它却天然地具有服务器无状态的特征。PS:更准确地说,除资源本身是状态以外,服务器不需要保存会话状态,本文提到的无状态服务均指无会话状态服务。在状态迁移的过程中,服务器不需要记录任何Session,所有的状态都通过url的形式记录在了客户端。

举个例子:一个心理测试的应用,需要用户做2次选择题,每次可选AB两种答案,2次选择完毕之后将告知用户属于何种心理类型。

如果按SOA的服务思维,很容易想到在服务器端保存Session,每次选择以后修改Session。但如果按REST的状态转移思维方式,我们会得出这样设计:

每一个页面表示一个状态(存在于客户端),页面包含了到下一个页面的超链接,当用户选a和选b时分别转移到相应的状态。这样,所有的会话状态其实都是通过url的形式保存在了客户端,服务器端实现了无状态模式。需要说明的是,虽然上图有7个状态,但并非一定需要在服务器预先生成7个静态页面,它们完全可以是动态页面,这不影响状态转移的概念模型以及服务器无状态的特征。

有构架设计经验的朋友应该很清楚,与有状态服务设计相比,无状态服务容易实现系统性能的横向扩展。通过增加硬件,部署多个无状态服务,并进行load balance不会受到制约;而有状态服务模式,Session的存储、共享都会带来性能瓶颈,且无法通过增加硬件消除。

Google搜索就是一个典型的无状态服务。试想一下,当你搜索“周杰伦”以后,Google提示你有数百万的结果,并每10条一页分成若干 页,Google会把结果保存进服务器Session吗,然后当你翻页的时候,再从Session中取吗?显然这样庞大的Session,即使是 Google也无法承受。看看Google的url就清楚了:

第一页:http://www.google.cn/search?q=%E5%91%A8%E6%9D%B0%E4%BC%A6&hl=zh-CN&newwindow=1&start=0&sa=N 

第二页:http://www.google.cn/search?q=%E5%91%A8%E6%9D%B0%E4%BC%A6&hl=zh-CN&newwindow=1&start=10&sa=N

当你点击第二页的链接时,无非是从一个状态跳到了下一个状态而已。对于Google而言,其实是一条新的查询,而两次查询很可能是由不同的服务器在处理,而用户却感觉Google记住了会话。

最后,需要说明的是,REST风格包含了无状态服务的特征,但并非具有无状态服务特征的都是REST。SOA同样可以是无状态的,REST的核心还是资源,下一节将会继续就这个话题进行探讨,谢谢关注!

[MVC]ASP.NET MVC Performance Tips(1):RenderPartial

mikel阅读(929)

转载:http://www.cnblogs.com/Terrylee/archive/2009/05/08/ASPNET-MVC-Performance-Tips-Part1.html

背景

ASP.NET MVC中,HtmlHelper的扩展方法RenderPartial为我们使用UserControl带来了极大的方便,当我们指定一个 UserControl时,RenderPartial会在当前View文件夹下查找相应的UserControl,如果没有找到则会到Shared文件 夹下查找。然后在使用RenderPartial方法有一些性能方面的考虑,值得我们去关注。

设想有这样一个场景,一篇文章有很多个评论,在页面中我们需要呈现出一个评论列表,自然我们会定义一个评论的UserControl,如下代码所示:

Code 1:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Comment>" %>
<%@ Import Namespace="TerryLee.MvcPerformance01.Models" %>
<p>
ID: <%=Model.ID %> <br />
Author: <%=Model.Author %> <br />
Description: <%= Model.Description %>
</p>
<hr />

在页面中呈现评论列表,代码非常简单,仅仅是遍历所有的评论而已:

Code 2:

<div>
<%
     foreach (var comment in Model.Comments)
{
Html.RenderPartial("CommentsItem", comment);
}
%>
</div>

运行后效果如下,可以看到正确的输出了评论:

aspnetmvc_performance_tips_001 

性能优化1

然而当我们同时输出200条评论的时候, 却要花费大量的时间,用Stopwatch来测量一下会发现,输出200条评论花费的时间基本在210ms左右,也就是说平均每条评论的输出花费了 1ms。我们不妨看一下ASP.NET MVC的源代码,在WebFormViewEngine中当查找UserControl时,遵循如下查找模式:

Code 3:

public WebFormViewEngine() {
MasterLocationFormats = new[] {
"~/Views/{1}/{0}.master",
"~/Views/Shared/{0}.master"
};
ViewLocationFormats = new[] {
"~/Views/{1}/{0}.aspx",
"~/Views/{1}/{0}.ascx",
"~/Views/Shared/{0}.aspx",
"~/Views/Shared/{0}.ascx"
};
PartialViewLocationFormats = ViewLocationFormats;
}

所以如果我们在RenderPartial方法中,指定了UserControl的完全路径,是不是可以避免这个查找过程呢?修改Code 2代码如下所示:

Code 4:

<div>
<%
       foreach (var comment in Model.Comments)
{
Html.RenderPartial("~/Views/Shared/CommentsItem.ascx", comment);
}
%>
</div>

现在再测试一下会发现呈现200条评论的时间平均值保持在10ms左右,比前面的方式提升了近200ms。然而我们是否真的找到了解决问题的方 法?ASP.NET MVC难道不对查找的View路径进行缓存?带着这样的疑问,我们在ASP.NET MVC源代码VirtualPathProviderViewEngine的构造函数中,找到这样一段代码:

Code 5:

protected VirtualPathProviderViewEngine() {
if (HttpContext.Current == null || HttpContext.Current.IsDebuggingEnabled) {
ViewLocationCache = DefaultViewLocationCache.Null;
}
else {
ViewLocationCache = new DefaultViewLocationCache();
}
}

这里的判断说明如果启用了Debug模式,将会使用NullViewLocationCache,即不进行缓存,否则会使用DefaultViewLocationCache对View路径进行缓存。所以上面的测试结果都是基于Debug模式:

Code 6:

<compilation debug="true">

如果关闭了Debug模式,测试结果又该如何呢?使用下面代码关闭Debug模式:

Code 7:

<compilation debug="false">

再次进行测试,会发现使用Code 2代码呈现200条评论时,花费的时间平均值也是在10ms左右。所以在使用RenderPartial方法时,大可不必为了提升性能而指定 UserControl的完全路径,ASP.NET MVC已经为我们做好了这一切,我们要做的仅仅是在发布到生产环境时,别忘了关闭Debug模式!在本示例中,开启Debug和关闭Debug模式在一次调用时的性能差距如下图所示:

aspnetmvc_performance_tips_002 

性能优化2

现在回过头来看前面的代码,其实并没有做什么性能优化,仅仅时给大家提个醒而已。在Code 2中,我们的遍历代码放在了主页面中,即在每一次迭代中调用RenderPartial方法,尽管ASP.NET MVC在RenderPartial时,对于UserControl路径做了缓存,但是200次的调用仍然有不小的开销。如果我们的遍历代码放在 UserControl中,而在主页面中只进行一次调用RenderPartial方法,结果又将如何呢?修改UserControl为下代码所示:

Code 8:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IList<Comment>>" %>
<%@ Import Namespace="TerryLee.MvcPerformance01.Models" %>
<%
    foreach(Comment comment in Model)
{
%>
<p>
ID: <%= comment.ID%> <br />
Author: <%= comment.Author%> <br />
Description: <%= comment.Description%>
</p>
<%} %>
<hr />

这样在主页面中,只进行一次RenderPartial调用,如下代码所示:

<div>
<%
     Html.RenderPartial("CommentsItem", Model.Comments);
%>
</div>

此时再次测试,可以看到呈现200条评论所花费的时间不足1ms!为了直观期间,我们仍然使用图形表示如下:

aspnetmvc_performance_tips_003 

从上图中可以看到,通过在UserControl中进行遍历,减少RenderPartial方法调用,带来的性能提升还是非常可观的。

总结

本文主要讨论在ASP.NET MVC中使用RenderPartial方法时的一些性能问题,记住两点:一是在ASP.NET MVC应用程序发布到生产服务器时,别忘了关闭Debug模式(对于ASP.NET WebForm应用程序也是一样);二时尽可能的减少调用RenderPartial方法的次数,如通过在UserControl中进行遍历等方法。希望 对大家有用。

作者:TerryLee
出处:http://terrylee.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

[Flash]Flash实现文件上传

mikel阅读(879)

 

********************************************************************
*                                                 版权声明
*
* 本文以Creative Commons的知识共享署名-非商业性使用-相同方式共享发布,请严格遵循该授权协议。
* 本文首发于博客园, 此声明为本文章中不可或缺的一部分。
* 作者网名:    浪子
* 作者EMAILdayichen (at)163.com
* 作者BLOG:  Http://Www.Cnblogs.Com/Walkingboy
*
********************************************************************

[Flash FileUpload]用flash.net.FileReference实现无刷新文件上传

-Written by http://walkingboy.cnblogs.com/ (07-02-07)

摘要:

还在用UpdatePanel嘛?是否还为文件上传苦恼?

还在用Callback嘛?是否对文件上传无计可施?

还在用Ajax上传组件嘛?是否为其不稳定性而头疼不已?

兄弟忘了这些吧,让我们拾起古老的Flash,跟我一道将积蓄已久的无奈、郁闷踩于脚下……

一、楔子

一直都无法忘怀那段痴迷Flash的大学时代,从认识动画,到ActionScript,再到苦练鼠绘,所有付出的时间和睡眠都代表了我对 Flash的情有独钟,曾经一直都在幻想毕业后可以从事Flash编程工作。可能自己的先天美感不足或者运气不佳,最终还是远离了自己一直钟爱的 Flash。

时隔多年,Flash有了长足的发展,Flex更是呈现一片喜人的景象。

但是个人认为,如果Flash定位为富客户端,而不掺合服务端的推广,我相信现在的很多js类库将失去他们的市场。

喂,谁的臭袜子,稍微理解下我沉浸往事,不能自拔的心情嘛:)

二、上传难题

以前用UpdatePanel的时候,涉及到上传都只能在做一个小页面用Postback来做;

现在用Callback,还是只能使用新页面在Postback;

尝试过好几个Ajax 上传组件,最终败倒在其不稳定下。

昨天偶在codeproject查找资料,看到Flash 上传文件的介绍,才突然想起这个被自己遗忘在角落里的咚咚。

察看了下Flash 的API,发现FileReference和FileReferenceList对文件的上传支持已经相当的好了。 

事件摘要
事件        说明
 
onCancel = function(fileRef:FileReference) {}
当用户取消文件浏览对话框时调用。
 
onComplete = function(fileRef:FileReference) {}
当上载或下载操作成功完成时调用。
 
onHTTPError = function(fileRef:FileReference, httpError:Number) {}
当上载由于 HTTP 错误而失败时调用。
 
onIOError = function(fileRef:FileReference) {}
当发生输入/输出错误时调用。
 
onOpen = function(fileRef:FileReference) {}
当上载或下载操作开始时调用。
 
onProgress = function(fileRef:FileReference, bytesLoaded:Number, bytesTotal:Number) {}
在文件上载或下载操作期间定期调用。
 
onSecurityError = function(fileRef:FileReference, errorString:String) {}
当上载或下载由于安全错误而失败时调用。
 
onSelect = function(fileRef:FileReference) {}
当用户从文件浏览对话框选择要上载或下载的文件时调用。
 
 

基本上上传文件所需要的功能都有了。

三、SWF FileUpload

很久没有写ActionStcript,变得好生疏了,熟悉了一个下午才算缓过气来了。定下了这个上传组件的需求:

接受Handler:支持内嵌的HttpHandler处理和自定义的Aspx处理(提供传递参数)

进度条显示:计算总数和已上传数

提供结束JS事件:上传结束触发指定的js方法,并将文件名作为参数

花了一个晚上才写好这个swf,调用相当的简单 

     内嵌HttpHandler,不做任何处理的调用
         <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"
                width="250" height="80" id="SWFFileUpload" align="middle">
                <param name="allowScriptAccess" value="sameDomain" />
                <param name="movie" value="SWFFileUpload.swf" />
                <param name="quality" value="high" />    
                <param name="FlashVars" value="CompletedFunction=OnCompleted">        
                <embed src="SWFFileUpload.swf" name="fileUpload1" align="middle" allowscriptaccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
            </object>

 使用内置的HttpHandler,需要在WebConfig配置HttpHandler信息: 

<httpHandlers>
    <add verb="*" path="SWFFileUpload.axd" type="SWFFileUpload.SWFFileUpload" validate="false"/>
</httpHandlers>

 

 然后文件会默认被上传到root/UploadFiles/底下,文件名与客户端文件名同,同名则覆盖 

        指定HttpHandler,指定参数    
        <br />
             <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"
                width="250" height="80" id="Object1" align="middle">
                <param name="allowScriptAccess" value="sameDomain" />
                <param name="movie" value="SWFFileUpload.swf" />
                <param name="quality" value="high" />
                <param name="wmode" value="transparent">
                <%--flash组件的参数传递:
                    UploadPage:自定义的ASPX文件接受Handler
                    Args:传递到UploadPage的参数,最终以QueryString的形式传递,以;分割
                    CompletedFunction:上传结束后调用的js方法
                    FileExtension:上传文件类型过滤,以;分割
                    --%>
                <param name="FlashVars" value="UploadPage=CustomerHandler.aspx&Args=name=cdy;blog=walkingboy.cnblogs.com&CompletedFunction=OnCompleted&FileExtension=*.jpg;*.txt">
                <embed src="SWFFileUpload.swf" name="fileUpload2" align="middle"
                    allowscriptaccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
            </object>

         如果文件大的话,需要在webconfig配置(Macromedia官方声称可以支持100M的上传) 

<httpRuntime maxRequestLength="1550000"/>

 

四、扩展&Demo

目前我只做了单文件的上传,可以利用FileReferenceList将其扩展为多文件上传。

如果你的IE打了最新的补丁,你可能发现出现“单击以激活并使用此控件”的问题,可以考虑封装一个js类,来动态Writer swf object,就可以搞定这个问题。 

function FileUpload(){
return{
     Show:function(){
    //TODO:
     },
     Hide:function(){
    //TODO:
     }
}
}();

DEMO代码下载:SWFFileUpload.WetTest.rar
有些朋友使用过程中出现问题,没办法得到真正的错误信息,现将flash的源代码fla上传,有问题的朋友自己测试下吧: SwfFileUpload.fla updated by langzi at 07.11.21 
 Update 07.12.19 原来上传的swffileupload.fla丢失了,重新上传。