Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I receive the following error when I invoke a custom object
"Object of type 'customObject' cannot be converted to type 'customObject'."

Following is the scenario when I am get this error:

  • I invoke a method in a dll dynamically.
  • Load an assembly
  • CreateInstance....

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

But if I try and pass 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 project. Also the custom object is a separate class in the same file.

There is no such thing called a static assembly 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 can't find anything static in what I do.

Any help is greatly appreciated.

Regards, Phani Kumar PV

like image 391
Phani Kumar PV Avatar asked Apr 12 '10 13:04

Phani Kumar PV


2 Answers

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.

like image 189
Ryan Rinaldi Avatar answered Sep 26 '22 01:09

Ryan Rinaldi


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 function as an object in the args array.
  3. I tired to create an instance of 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 following is the approach that should be used to overcome the problem I need to create the custom object assembly with the same assembly that I used to the create the webservice 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;
}
like image 24
Phani Kumar PV Avatar answered Sep 26 '22 01:09

Phani Kumar PV