在不添加WebReference的情况下调用Webservice - 使用复杂类型

cjk*_*cjk 1 c# web-services

我正在使用此站点上的代码动态调用Web服务.

[SecurityPermissionAttribute(SecurityAction.Demand, Unrestricted = true)]
    public static object CallWebService(string webServiceAsmxUrl, string serviceName, string methodName, object[] args)
    {
        System.Net.WebClient client = new System.Net.WebClient();
        //-Connect To the web service
        using (System.IO.Stream stream = client.OpenRead(webServiceAsmxUrl + "?wsdl"))
        {
            //--Now read the WSDL file describing a service.
            ServiceDescription description = ServiceDescription.Read(stream);
            ///// LOAD THE DOM /////////
            //--Initialize a service description importer.
            ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
            importer.ProtocolName = "Soap12"; // Use SOAP 1.2.
            importer.AddServiceDescription(description, null, null);
            //--Generate a proxy client. importer.Style = ServiceDescriptionImportStyle.Client;
            //--Generate properties to represent primitive values.
            importer.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties;
            //--Initialize a Code-DOM tree into which we will import the service.
            CodeNamespace nmspace = new CodeNamespace();
            CodeCompileUnit unit1 = new CodeCompileUnit();
            unit1.Namespaces.Add(nmspace);
            //--Import the service into the Code-DOM tree. This creates proxy code
            //--that uses the service.
            ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit1);
            if (warning == 0) //--If zero then we are good to go
            {
                //--Generate the proxy code 
                CodeDomProvider provider1 = CodeDomProvider.CreateProvider("CSharp");
                //--Compile the assembly proxy with the appropriate references
                string[] assemblyReferences = new string[5] { "System.dll", "System.Web.Services.dll", "System.Web.dll", "System.Xml.dll", "System.Data.dll" };
                CompilerParameters parms = new CompilerParameters(assemblyReferences);
                CompilerResults results = provider1.CompileAssemblyFromDom(parms, unit1);
                //-Check For Errors
                if (results.Errors.Count > 0)
                {
                    StringBuilder sb = new StringBuilder();
                    foreach (CompilerError oops in results.Errors)
                    {
                        sb.AppendLine("========Compiler error============");
                        sb.AppendLine(oops.ErrorText);
                    }
                    throw new System.ApplicationException("Compile Error Occured calling webservice. " + sb.ToString());
                }
                //--Finally, Invoke the web service method 
                Type foundType = null;
                Type[] types = results.CompiledAssembly.GetTypes();
                foreach (Type type in types)
                {
                    if (type.BaseType == typeof(System.Web.Services.Protocols.SoapHttpClientProtocol))
                    {
                        Console.WriteLine(type.ToString());
                        foundType = type;
                    }
                }

                object wsvcClass = results.CompiledAssembly.CreateInstance(foundType.ToString());
                MethodInfo mi = wsvcClass.GetType().GetMethod(methodName);
                return mi.Invoke(wsvcClass, args);
            }
            else
            {
                return null;
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

当我使用内置类型时,这工作正常,但对于我自己的类,我得到这个:

Event Type: Error
Event Source:   TDX Queue Service
Event Category: None
Event ID:   0
Date:       12/04/2010
Time:       12:12:38
User:       N/A
Computer:   TDXRMISDEV01
Description:
System.ArgumentException: Object of type 'TDXDataTypes.AgencyOutput' cannot be converted to type 'AgencyOutput'.

Server stack trace: 
   at System.RuntimeType.CheckValue(Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr)
   at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at TDXQueueEngine.GenericWebserviceProxy.CallWebService(String webServiceAsmxUrl, String serviceName, String methodName, Object[] args) in C:\CkAdmDev\TDXQueueEngine\TDXQueueEngine\TDXQueueEngine\GenericWebserviceProxy.cs:line 76
   at TDXQueueEngine.TDXQueueWebserviceItem.Run() in C:\CkAdmDev\TDXQueueEngine\TDXQueueEngine\TDXQueueEngine\TDXQueueWebserviceItem.cs:line 99
   at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr md, Object[] args, Object server, Int32 methodPtr, Boolean fExecuteInContext, Object[]& outArgs)
   at System.Runtime.Remoting.Messaging.StackBuilderSink.PrivateProcessMessage(RuntimeMethodHandle md, Object[] args, Object server, Int32 methodPtr, Boolean fExecuteInContext, Object[]& outArgs)
   at System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(IMessage msg, IMessageSink replySink)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.EndInvokeHelper(Message reqMsg, Boolean bProxyCase)
   at System.Runtime.Remoting.Proxies.RemotingProxy.Invoke(Object NotUsed, MessageData& msgData)
   at TDXQueueEngine.TDXQueue.RunProcess.EndInvoke(IAsyncResult result)
   at TDXQueueEngine.TDXQueue.processComplete(IAsyncResult ar) in C:\CkAdmDev\TDXQueueEngine\TDXQueueEngine\TDXQueueEngine\TDXQueue.cs:line 130

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.
Run Code Online (Sandbox Code Playgroud)

这些类引用相同的程序集和相同的版本.在构建临时组件时,是否需要将组件作为参考?如果是这样,怎么样?

谢谢.


更新

似乎最好的解决方案是构建一个可以映射AssemblyX.MyCustomType到等效的例程GeneratedAssembly.MyCustomType.

在我的示例中,MyCustomType包含更多类型(应该都是生成的程序集的一部分)所以看来我需要一个方法来执行"深度复制".此外,TDXDataTypes.AgencyOutput的一些属性是其他类的数组,只是为了让事情变得更有趣......

我已经为映射创建了一个新问题.

Pha*_* PV 6

我在我的本地机器上复制了这个问题并解决了这个问题.

以下是使自定义对象起作用所需的操作

Ur当前代码是这样的

   object wsvcClass = results.CompiledAssembly.CreateInstance(foundType.ToString());   
   MethodInfo mi = wsvcClass.GetType().GetMethod(methodName);   
   return mi.Invoke(wsvcClass, args);   
Run Code Online (Sandbox Code Playgroud)

让我试着解释一下问题的最可能原因.

当我在webservice中调用一个名为"methodname"的程序集中的方法时,你试图将args []所需的参数传递给函数"CallWebService"当你尝试传递时,传递的args []将成功运行包括字符串在内的基本类型等常规参数.

但是,当您尝试将自定义对象作为参数传递时,这就是您可能正在做的事情

在这方面做了三件事.

  1. 在CallWebService函数之外创建该类型的对象(使用反射).当你这样做时会发生什么是在内部用临时dll名称创建的customobject的实例.
  2. 一旦设置了对象的属性,并将其作为args数组中的对象发送到CallWebService函数.
  3. 您正在尝试通过创建动态dll来创建Web服务的实例.

    object wsvcClass = results.CompiledAssembly.CreateInstance(foundType.ToString());

当您最终尝试使用创建的动态程序集的实例调用该方法时,您尝试通过args属性传递在步骤1,2中创建的customobject.

在调用时,CLR尝试查看作为输入传递的customobject和正在调用的方法是否来自同一DLL.

这显然不是从实现的方式来看.

以下是应该用于解决问题的方法U需要使用您用于创建webservice实例的相同程序集创建自定义对象程序集...

我完全实现了这种方法并且效果很好:

MethodInfo m = type.GetMethod(methodName);
ParameterInfo[] pm = m.GetParameters();
object ob;
object[] y = new object[1];
foreach (ParameterInfo paraminfo in pm)
{
    ob = this.webServiceAssembly.CreateInstance(paraminfo.ParameterType.Name);

    foreach (PropertyInfo propera in ob.GetType().GetProperties())
    {
        if (propera.Name == "AppGroupid")
        {
            propera.SetValue(ob, "SQL2005Tools", null);
        }
        if (propera.Name == "Appid")
        {
            propera.SetValue(ob, "%", null);
        }
    }
    y[0] = ob;
}
Run Code Online (Sandbox Code Playgroud)