/// <summary> /// 增加程序集路径和端口类,并序列化到XML文件 /// </summary> /// <param name="assemblyPath"></param> /// <param name="portType"></param> public static void Add(String assemblyPath, String portType) { AssemblyType assType = GetInstance(assemblyPath); if (assType == null) { //s_lstAssemblyType.Add(new AssemblyType(assemblyPath, portType)); s_dictAssemblyType[assemblyPath] = new AssemblyType(assemblyPath, portType); } else { assType.PortType = portType; } s_needWriteToDisk = true; // 表示需要序列化到磁盘上 }
/// <summary> /// 编译程序集 /// </summary> /// <param name="url"></param> /// <param name="serviceName"></param> /// <returns></returns> private static String CompilerAssembly(String url, String serviceName, String assemblyPath) { // 1. 使用 WebClient 下载 WSDL 信息。 WebClient web = new WebClient(); using (Stream stream = web.OpenRead(url + "?WSDL")) { // 2. 创建和格式化 WSDL 文档。 ServiceDescription description = ServiceDescription.Read(stream); // 3. 创建客户端代理代理类。 ServiceDescriptionImporter importer = new ServiceDescriptionImporter(); importer.ProtocolName = "Soap"; // 指定访问协议。 importer.Style = ServiceDescriptionImportStyle.Client; // 生成客户端代理。 importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync; importer.AddServiceDescription(description, null, null); // 添加 WSDL 文档。 // 4. 使用 CodeDom 编译客户端代理类。 CodeNamespace nmspace = new CodeNamespace(serviceName); // 为代理类添加命名空间,缺省为全局空间。 CodeCompileUnit unit = new CodeCompileUnit(); unit.Namespaces.Add(nmspace); ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit); CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp"); // 4.1 根据ESB的需要修正自动生成的代码, 只针对Java进行修正 if (!url.EndsWith(".asmx")) { FixAutoGenCode(nmspace, description); } CompilerParameters parameter = new CompilerParameters(); parameter.GenerateExecutable = false; parameter.GenerateInMemory = false; parameter.OutputAssembly = assemblyPath; // 可以指定你所需的任何文件名。 parameter.ReferencedAssemblies.Add("System.dll"); parameter.ReferencedAssemblies.Add("System.XML.dll"); parameter.ReferencedAssemblies.Add("System.Web.Services.dll"); parameter.ReferencedAssemblies.Add("System.Data.dll"); CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit); // 5. 如果编译出现异常,则直接抛出 if (result.Errors.HasErrors) { System.Text.StringBuilder sb = new StringBuilder(); sb.AppendLine("编译代理程序集出现异常:"); foreach (CompilerError ce in result.Errors) { sb.Append(ce.ToString() + System.Environment.NewLine); } throw new Exception(sb.ToString()); } // 6. 返回代理类的名词 Regex regSoap = new Regex("Soap$"); // 注意:此处要用全名,因为可能存在多个服务共用一个DLL的情况 String portTypeFullName = serviceName + "." + regSoap.Replace(description.PortTypes[0].Name, ""); //--记录代理程序集的端口类名,当不需要编译程序集的时候可以直接从AssemblyType.GetInstance(assemblyPath).PortType获取 AssemblyType.Add(assemblyPath, portTypeFullName); return(portTypeFullName); } }
/// <summary> /// 加载代理程序集 /// </summary> /// <param name="url"></param> /// <param name="serviceName"></param> /// <returns></returns> private static SoapClientItem LoadAssembly(String url, String serviceName) { String assemblyPath = GetAssemblyPath(url); String portTypeFullName = String.Empty; // 注意此处要用全名:命名空间.类名 // 如果代理程序集不存在则编译生成代理程序集,否则直接加载 if (!File.Exists(assemblyPath)) { portTypeFullName = CompilerAssembly(url, serviceName, assemblyPath); } else { portTypeFullName = AssemblyType.GetInstance(assemblyPath).PortType; } // 如果没有获取到端口类型则清空程序集缓存并抛出异常 if (portTypeFullName == String.Empty) { ClearCache(url); throw new Exception(String.Format("获取服务:{0}『{1}』的端口类型失败!", serviceName, url)); } Assembly asm = null; using (FileStream fs = File.OpenRead(assemblyPath)) { asm = Assembly.Load(fs.ReadBytes(fs.Length)); // 此处采用文件流进行加载,使得加载后的程序集仍然可以被重新编译 } if (asm == null) { throw new Exception(String.Format("加载代理程序集{0}失败!", assemblyPath)); } //Assembly asm = result.CompiledAssembly; //Type portType = asm.GetType(String.Format("{0}.{1}", serviceName, portTypeName)); //Type reqType = asm.GetType(String.Format("{0}.request", serviceName)); // 如果在前面为代理类添加了命名空间,此处需要将命名空间添加到类型前面。 Type portType = GetTypeFromAssembly(asm, portTypeFullName, assemblyPath); Type reqType = GetTypeFromAssembly(asm, String.Format("{0}.request", portTypeFullName.Split('.')[0]), assemblyPath); // 创建端口类对象 Object port = Activator.CreateInstance(portType); if (port == null) { throw new Exception(String.Format("创建:{0}『{1}』的端口类型对象失败!", serviceName, url)); } // 将超时设置为10分钟 portType.InvokeMember("Timeout", BindingFlags.SetProperty, null, port, new Object[] { 10 * 60 * 1000 }); SoapClientItem item = new SoapClientItem() { ProxyAssembly = asm, PortObject = port, PortType = portType, RequestType = reqType }; return(item); }