zoukankan      html  css  js  c++  java
  • Flex4中使用WCF

    虽然flex跟.net交互的首选是FluorineFx,但是如果在某些特定情况下(比如服务端是现成的,不允许修改,或者服务端开发方不懂FluorineFx为何物),这时webService还是挺有用的。

    WebService完全可以用"以BasicHttpBinding方式运行的WCF"代替。经过我的实际测试:对于基本类型(比如int,string,datetime以及它们对应的arrry以list),flex调用时能正确识别并“翻译”成as3中对应的int,String,Date以及Array类型,而复杂类型(比如自己在c#中定义的实体类或DataTable),flex调用时会报错,这类复杂类型我建议在wcf中用序列化技术处理成String后再返回。

    考虑到xml格式序列化后的信息量比较大,我倾向于选择json这种轻量级的格式,而且在.net4.0中新增了System.Runtime.Serialization.Json;能处理大多数的复杂对象序列化(但是DataTable处理不了)

    为了方便起见,我把一些序列化/反序列化的操作封装了一下:
    using System;
    using System.IO;
    using System.Runtime.Serialization.Json;
    using System.Text;
    using System.Data;
    
    namespace Helper
    {
        public static class Utils
        {
            /// <summary>
            /// 将对象序列化成json字符串(注:obj的类定义中要加正确的可序列化标志)
            /// </summary>
            /// <param name="obj"></param>
            /// <returns></returns>
            public static string ToJsonString(object obj)
            {
                string result = string.Empty;
                DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(obj.GetType());
    
                using (MemoryStream ms = new MemoryStream())
                {
                    jsonSerializer.WriteObject(ms, obj);
                    result = Encoding.UTF8.GetString(ms.ToArray());
                }
    
                return result;
            }
    
            /// <summary>
            /// json字符串反序列为对象
            /// </summary>
            /// <param name="jsonString"></param>
            /// <param name="objType"></param>
            /// <returns></returns>
            public static Object ToJsonObject(string jsonString, Type objType)
            {
                Object result = null;
                DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(objType);
    
                using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonString)))
                {
                    result = jsonSerializer.ReadObject(ms);
                }
    
                return result;
            }
    
            /// <summary>
            /// 将DataTable序列化成json字符串
            /// </summary>
            /// <param name="dt"></param>
            /// <returns></returns>
            public static string ToJsonString(this DataTable dt)
            {
              
                StringBuilder JsonString = new StringBuilder();
                //Exception Handling        
                if (dt != null && dt.Rows.Count > 0)
                {
                    JsonString.Append("{ ");
                    JsonString.Append("\"Rows\":[ ");
                    for (int i = 0; i < dt.Rows.Count; i++)
                    {
                        JsonString.Append("{ ");
                        for (int j = 0; j < dt.Columns.Count; j++)
                        {
                            if (j < dt.Columns.Count - 1)
                            {
                                JsonString.Append("\"" + dt.Columns[j].ColumnName.ToString().Replace("\"", "\\\"") + "\":" + "\"" + dt.Rows[i][j].ToString().Replace("\"", "\\\"") + "\",");
                            }
                            else if (j == dt.Columns.Count - 1)
                            {
                                JsonString.Append("\"" + dt.Columns[j].ColumnName.ToString().Replace("\"", "\\\"") + "\":" + "\"" + dt.Rows[i][j].ToString().Replace("\"", "\\\"") + "\"");
                            }
                        }
                        /**/
                        /*end Of String*/
                        if (i == dt.Rows.Count - 1)
                        {
                            JsonString.Append("} ");
                        }
                        else
                        {
                            JsonString.Append("}, ");
                        }
                    }
                    JsonString.Append("]}");
                    return JsonString.ToString();
                }
                else
                {
                    return null;
                }
            }
        }
    }
    
    不过,在开始正文之前,先提醒一下System.Runtime.Serialization.Json在序列化中要注意的问题:
    比如有一个类Person,定义如下:
        [Serializable]
        public class Person 
        {
            private string _name;
            private int _age;
            private float _salary;
    
            public string Name { set { _name = value; } get { return _name; } }        
            public int Age { set { _age = value; } get { return _age; } }        
            public float Salary { set { _salary = value; } get { return _salary; } }
            
        }
    
    对象
    Person p = new Person(){Age=30, Name="jimmy.yang", Salary=5000};
    
    序列后的字符串为
    {"_age":30,"_name":"jimmy.yang","_salary":5000}

    注意:这里并不是我所期待的{"Age":30,"Name":"jimmy.yang","Salary":5000},其实出现这样的结果也可以理解,因为属性的set,get内部就是方法调用,因此最终序列化的只是私有字段。但是如果把[Serializable]标志去掉,确能得到正确的结果:{"Age":30,"Name":"jimmy.yang","Salary":5000} 不知道这个算不算是System.Runtime.Serialization.Json的一个bug.
     
    实际flex应用中,用于传输的实体类99%以上保存的只是一些常规的基元类型(即int,string,date之类),所以为了避免上面提到的问题,我建议:
    1、实体类定义中只使用基本类型,去掉[Serializable]
    2、或者直接把实例成员用类似public string Name;的方式暴露出来,不过估计大数多酷爱OO的同学们要吐血了.

    ok,切入正题吧:
    1、先创建一个asp.net项目,然后添加一个wcf service,文件命名为:Sample.svc,对应的后端代码文件Sample.svc.cs内容如下:
    using System.Collections.Generic;
    using System.Data;
    using System;
    using Helper;
    using Entity;
    
    namespace WcfApp
    {
        // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Sample" in code, svc and config file together.
        public class Sample : ISample
        {
            
    
            public string ObjectTest()
            {
                return Utils.ToJsonString(new Person() { Age=30, Name="jimmy.yang", Salary=3000 });
            }
    
    
            public string DataTableTest()
            {
                DataTable tbl = new DataTable();
                tbl.Columns.Add("Name");
                tbl.Columns.Add("Age");
                tbl.Rows.Add("Jimmy.Yang", 30);
                tbl.Rows.Add("Mike", 20);
                return tbl.ToJsonString();
            }
    
    
            public string ListObjectTest()
            {
                return Utils.ToJsonString(
                    new List<Person>() { 
                        new Person() { Age = 20, Name = "张三", Salary = 5000 }, 
                        new Person() { Age = 30, Name = "李四", Salary = 8000 } 
                    }
                );
            }
        }
    }
    

    2、创建flex项目,然后在Data/Services面板中,添加一个webSerivce的引用
    点击Next之后,出现下面的界面
    设置wcf所在的WSDL URI后,一路next,最终Data/WebServices面板会变成下面这样
    注意上图中右侧工具栏上的几个小按钮,自己去试试吧,会有意外发现哦
    同时flex会生成几个as类文件(类似于wcf中svcutil.exe在client端自动生成的cs文件)
    剩下的事情,就很容易了,在mxml中测试一番,代码如下:
    <?xml version="1.0" encoding="utf-8"?>
    <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    			   xmlns:s="library://ns.adobe.com/flex/spark" 
    			   xmlns:mx="library://ns.adobe.com/flex/mx"  xmlns:sample="services.sample.*">
    	
    
    	<fx:Script>
    		<![CDATA[
    			
    			import com.adobe.serialization.json.JSONDecoder;			
    			import mx.controls.Alert;
    			import mx.rpc.events.FaultEvent;
    			import mx.rpc.events.ResultEvent;			
    			import valueObjects.Person;
    			
    			
    			private function dataTableTest():void
    			{
    				DataTableTestResult.token = sample.DataTableTest();
    				DataTableTestResult.addEventListener(ResultEvent.RESULT,onDataTableTestResult);
    				DataTableTestResult.addEventListener(FaultEvent.FAULT,onDataTableTestFault);
    			}
    			
    			private function onDataTableTestFault(e:FaultEvent):void
    			{
    				Alert.show("dataTableTest调用失败,result="+ e);
    				trace("dataTableTest.Fault=",e);
    			}
    			
    			private function onDataTableTestResult(e:ResultEvent):void
    			{
    				this.txtDataTable.text = "dataTableTest调用成功,结果:" + e.result;
    			}
    			
    			
    			private function listObjectTest():void
    			{
    				ListObjectTestResult.token = sample.ListObjectTest();
    				ListObjectTestResult.addEventListener(ResultEvent.RESULT,onListObjectTestResult);
    				ListObjectTestResult.addEventListener(FaultEvent.FAULT,onListObjectFault);
    			}
    			
    			private function onListObjectTestResult(e:ResultEvent):void
    			{
    				this.txtList.text = "listObjectTest调用成功,结果:" + e.result;
    				var jsonDecoder:JSONDecoder = new JSONDecoder(e.result.toString(),true);
    				var obj:Object = jsonDecoder.getValue();
    				//把结果转化为强类型的集合
    				var list:Vector.<Person> = new Vector.<Person>();
    				for(var i:int=0;i<obj.length;i++)
    				{
    					list[i] = new Person(obj[i].Name,obj[i].Age,obj[i].Salary);
    				}				
    				trace(list);				
    			}
    			
    			private function onListObjectFault(e:FaultEvent):void
    			{
    				Alert.show("listObjectTest调用失败,result="+ e);
    				trace("listObjectTest.Fault=",e);
    			}			
    			
    			private function objectTest():void
    			{
    				ObjectTestResult.token = sample.ObjectTest();
    				ObjectTestResult.addEventListener(ResultEvent.RESULT,onObjectTestResult);
    				ObjectTestResult.addEventListener(FaultEvent.FAULT,onObjectTestFault);
    			}
    			
    			private function onObjectTestResult(e:ResultEvent):void
    			{
    				this.txtObject.text = "objectTest调用成功,返回值:" + e.result;
    				var jsonDecoder:JSONDecoder = new JSONDecoder(e.result.toString(),true);
    				var obj:Object = jsonDecoder.getValue();
    				var p:Person = new Person(obj.Name,obj.Age,obj.Salary);					
    				this.txtObject.text += "\n" + "p.Age=" + p.Age + ",p.Name=" + p.Name + ",p.Salary=" + p.Salary;
    			}
    			
    			private function onObjectTestFault(e:FaultEvent):void
    			{				
    				this.txtObject.text = "objectTest调用失败,原因="+ e;
    			}			
    			
    			private function doClick():void
    			{				
    				objectTest();				
    				listObjectTest();
    				dataTableTest();
    			}	
    			
    		]]>
    	</fx:Script>
    	<fx:Declarations>
    		<s:CallResponder id="ArrayTestResult"/>
    		<sample:Sample id="sample" fault="Alert.show(event.fault.faultString + '\n' + event.fault.faultDetail)" showBusyCursor="true"/>
    		<s:CallResponder id="DataTableTestResult"/>
    		<s:CallResponder id="ListObjectTestResult"/>		
    		<s:CallResponder id="ObjectTestResult"/>	
    	</fx:Declarations>
    	<s:Panel right="10" left="10" bottom="10" top="10" title="WCF 调用实例">
    		<s:layout>
    			<s:BasicLayout/>
    		</s:layout>
    		<mx:VDividedBox left="10" bottom="40" right="10" top="0">
    			<s:TextArea height="33%" width="100%" id="txtObject">
    				
    			</s:TextArea>
    			<s:TextArea height="33%" width="100%" id="txtList">
    				
    			</s:TextArea>
    			<s:TextArea height="33%" width="100%" id="txtDataTable">
    				
    			</s:TextArea>
    		</mx:VDividedBox>
    		<s:Button label="Call Wcf" horizontalCenter="0" id="btnCall" click="doClick()"  bottom="10"/>
    	</s:Panel>
    </s:Application>
    
    后记:在实际开发中发现flex ide环境对于wcf的wsdl解析要比asmx慢不止N倍,但是一旦解析完成,生成相应的as类后,在运行时二耆速度相同。
    作者:菩提树下的杨过
    出处:http://yjmyzz.cnblogs.com
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    Python for Infomatics 第14章 数据库和SQL应用四(译)
    展望2017
    bing的简单英文字典工具
    自我安慰
    Python for Infomatics 第14章 数据库和SQL应用三(译)
    Python for Infomatics 第14章 数据库和SQL应用二(译)
    Python for Infomatics 第14章 数据库和SQL应用一(译)
    希望父亲早日恢复
    Python for Infomatics 第13章 网页服务四(译)
    Python for Infomatics 第13章 网页服务三(译)
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/2010228.html
Copyright © 2011-2022 走看看