views:

106

answers:

2

i am receiving the follwing error when i am invoking a custom object "Object of type 'customObject' cannot be converted to type 'customObject'."

Following is the scenario when i am getting the error

i am invoking a method in a dll dynamically.

Load an assembly

CreateInstance....

calling MethodInfo.Invoke() passing int, string as a parameter for my method is working fine => No exceptions are thrown.

But if I try and pass a one of my own custom class objects as a parameter, then I get an ArgumentException exception, and it is not either an ArgumentOutOfRangeException or ArgumentNullException.

"Object of type 'customObject' cannot be converted to type 'customObject'."

I am doing this in a web application.

The class file containing the method is in a different proj . also the custom object is a sepearte class in the same file.

there is no such thing called a static aseembly in my code. I am trying to invoke a webmethod dynamically. this webmethod is having the customObject type as an input parameter. So when i invoke the webmethod i am dynamically creating the proxy assembly and all. From the same assembly i am trying to create an instance of the cusotm object assinging the values to its properties and then passing this object as a parameter and invoking the method. everything is dynamic and nothing is created static.. :(

add reference is not used. Following is a sample code i tried to create it

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; 
            } 
        } 
    } 

I cant find anything static being done by me.

any help is greatly appreciated.

Regards, Phani Kumar PV

+1  A: 

Have you looked at what the proxy class looks like that gets generated? You don't need the proxy to call a web service. Just create a class that inherits from SoapHttpClientProtocol and call Invoke(methodName, params).

You are making this SO much more complicated than you need to. Honestly.

EDIT If you create a class like this:

public class SoapClient : SoapHttpClientProtocol
{

    public SoapClient()
    {

    }

    public object[] Invoke(string method, object[] args)
    {
        return base.Invoke(method, args);
    }

}

and call it like this:

SoapClient soapClient = new SoapClient();
soapClient.Url = webServiceAsmxUrl;
soapClient.Invoke(methodName, args);

I think you will see that it has the exact same results as what you are doing.

Ryan Rinaldi
I went through the code that is shared in the link.It seems that can be used when the info abt the namespaces of the webservice and web methods are available. But in the application that i am currently developing i will get the wdsl url dynamically and it gets changed frquently. in that scenario the approach specified in the given url will not solve my problem. please let me know if i got it in the wrong direction.
Phani Kumar PV
Updated my answer with a code example to explain what I'm talking about.
Ryan Rinaldi
Yes, this answer is correct. The only reason you need to compile the web service code is if you need compile time type checking against a known web service URL. You are already at run time when you invoke this, so it really does you no good.
ZeroBugBounce
Sorry for the small amount of confusion that is created by most post with a bit of less clarity on the total implementation of my problem.Right,the type information of the webmethod parameters will be not available till the point i create a dynamic assembly. Once the dynamic assembly is created then i will get to know the type information of the input webmethod.Depending on that i will try to create args. I posted th answer for my prob
Phani Kumar PV
+1  A: 

Let me try to explain the most probable reason for the problem to come in my approach.

when i invoked a method in the assembly called as "methodname" in the webservice i am trying to pass the parameters required for that as args[] to the function "CallWebService" This args[] when passed will be successfully working when i try to pass a normal parameters like primitive types including string.

But this is what i did when i tried to pass a custom object as a parameter

Three things that are done in this.

  1. create an object of that type outside the CallWebService function (using reflection). when i did that way what happens is an instance of the customobject created with a temporary dll name internally.
  2. once i set the set the properties of the object and send it across to the CallWebService fuction as an object in the args array.
  3. i tired to create an instance fo the webservice by creating the dynamic dll.

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

When i finally tried to invoke the method with the instance of the dynamic assembly created i tried to pass the customobject that is created at step 1,2 via args property.

at the time of invocation the CLR tries to see if the customobject that is passed as input and the method that is being invoked are from the same DLL.

which is obviously not from the way the implementation is done.

So follwing is the appraoch that should be used to overcome the problem I need to create the cusotm object assembly with the same assembly that I used to the create the webserivce instance..

I implemented this approach completely and it worked out fine

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);

    //Some Junk Logic to get the set the values to the properties of the custom Object
    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;
}
Phani Kumar PV