道。道。道

安全特性不等于安全的特性

   :: 首页 :: 联系 :: 聚合  :: 管理

常用链接

搜索

  •  

最新评论

添加Web引用的时候,WebService在客户端有一个代理,如下:
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "2.0.50727.42")]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Web.Services.WebServiceBindingAttribute(Name="WebService1Soap", Namespace="http://tempuri.org/")
   public partial class WebService1 : System.Web.Services.Protocols.SoapHttpClientProtocol
 
客户端调用WebServivce就是通过这个代理类来调用的。
 
2.       调用WebService方法,客户端和服务器端通信是Xml,所以代理类跟Xml之间就有序列化和反序列化的过程
3.       客户端调用WebService的过程如下
a)         客户端调用代理类Hello world方法
string str = (new Service2.WebService1()).HelloWorld ();
b)         代理类调用基类SoapHttpClientProtocal的Invoke方法
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/HelloWorld0766", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
        public string HelloWorld() {
            object[] results = this.Invoke("HelloWorld", new object[0]);
            return ((string)(results[0]));
        }
c)         SoapHttpClientProtocal进行Soap序列化Soap头和方法,都是这个类自己做的,但是输入参数和返回值,是利用的XmlSerializer,输入参数要序列化,返回值要反序列化。
        protected object[] Invoke(string methodName, object[] parameters)
        {
                
                try
                {
                    message1.SetStream(stream1);
                    this.Serialize(message1);//注1
                }
               
                response1 = this.GetWebResponse(request1);
                Stream stream2 = null;
                try
                {
                    stream2 = response1.GetResponseStream();
                    objArray1 = this.ReadResponse(message1, response1, stream2, false);//注2
                }
          }
         
          注1:this.Serialize中有一句参数序列化的代码如下
          method1.parameterSerializer.Serialize(writer1, message.GetParameterValues(), null, flag1 ? text2 : null);
          注2:this.ReadResponse中有一句返回值的反序列化的代码如下
          message.SetParameterValues((object[]) method1.returnSerializer.Deserialize(reader1, flag1 ? text1 : null));
d)         XmlSerializer会缓存临时程序集,这个程序集作用是序列化和反序列化,如果缓存中没有会调用TempAssembly产生一个
 
Static的缓存(就是我们每次调用慢的罪魁祸首):private static TempAssemblyCache cache;
获取缓存中的程序集:this.tempAssembly = XmlSerializer.cache[defaultNamespace, type];
缓存中没有就去加载:Assembly assembly1 = TempAssembly.LoadGeneratedAssembly(type, defaultNamespace, out implementation1);
加载没有就去产生(会生成临时文件并编译,很慢):
this.tempAssembly = new TempAssembly(new XmlMapping[] { this.mapping }, assembly1, implementation1);
 
e)         TempAssemlby这个类负责加载以及产生临时程序集
LoadGeneratedAssemlby方法中,有一段逻辑,就是默认去加载序列化类,这个类的命名是规则如下
        internal static string GetTempAssemblyName(AssemblyName parent, string ns)
        {
            return (parent.Name + ".XmlSerializers" + (((ns == null) || (ns.Length == 0)) ? "" : ("." + ns.GetHashCode())));
        }
       同时,如果加载失败会触发AppDomain.CurrentDomain.AssemblyResolve事件
        
4.       结论
1)   WebService的序列化是调用XmlSerializer
 
2)   WebService慢,是因为产生序列化类慢,所谓的临时文件都是XmlSerializer的中间代码。可以在config文件中加入如下的配置,临时序列化的文件就不会被删除了,WinForm程序是*.exe.config,asp.net是web.config。
        <configuration>
  <system.diagnostics>
    <switches>
      <add name="XmlSerialization.Compilation" value="4"/>
    </switches>
  </system.diagnostics>
</configuration>
 
临时文件在C:\Documents and Settings\抹布\Local Settings\Temp下,注意,因为名称是随机的,序列化的dll文件,并不能重用,重开进程会重新生成。
3)   如果自定义序列化类,可以跳过产生临时序列化的步骤,大大提高第一次加载的速度,也就是说,只要有一个
程序集名称+.XmlSerializers”的序列化类存在,就不会动态生成序列化程序集了。
 
4)   在代理类上可以加
[System.Xml.Serialization.XmlSerializerAssemblyAttribute(AssemblyName = "TestPerformance.XmlSerializers")]
指定Xml序列化的类,这个序列化的类可以通过一个工具产生,
但是根据研究TempAssemlby的LoadGeneratedAssemlby代码发现,这个Attribute可以不加的,只要你有一个GetTempAssemblyName返回值一样的名称的序列化类即可。
 
5)   根据加载失败会触发AppDomain.CurrentDomain.AssemblyResolve事件,可以在加载失败后动态产生序列化类,如下。
        http://support.microsoft.com/kb/872800/zh-cn,请参考这个kb
      private void Form1_Load(object sender, EventArgs e)
        {
            AppDomain.CurrentDomain.AssemblyResolve +=
                new ResolveEventHandler(MyResolveEventHandler);
        }
 
        static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
        {
            Assembly a = null;
            string[] arr = args.Name.Split(new string[] { "." }, StringSplitOptions.None);
            if (args.Name.IndexOf("XmlSerializers") >= 0)
            {
                if (!System.IO.File.Exists(args.Name + ".dll"))
                    PreGenNS.Pregen.Generate(new string[] { arr[0] });
                string sSerializersDLL = args.Name + ".dll";
                string smartDeploymentHostLocation = "";
                a = Assembly.LoadFrom(smartDeploymentHostLocation + sSerializersDLL);
            }
            return a;
        }
6)VS2005利用Release编译,会产生AssemblyName+"XmlSerializer.dll"的序列化文件,可以随着客户端一起部署,跟5这种方式不太一样,可以根据实际情况来选择。
利用5这种方式,是第一次调用WebService时,动态生成序列化类;而6是在软件发布时,生成这个类,并部署到客户端。
posted on 2007-11-07 15:35 独孤九剑 阅读(3619) 评论(0)  编辑 收藏 引用 所属分类: Learn articles