views:

1034

answers:

6

I have this scenario where a webservice method I'm consuming in C# returns a Business object, when calling the webservice method with the following code I get the exception "Unable to cast object of type ContactInfo to type ContactInfo" in the reference.cs class of the web reference

Code:

ContactInfo contactInfo = new ContactInfo();
Contact contact = new Contact();

contactInfo = contact.Load(this.ContactID.Value);

Any help would be much appreciated.

+6  A: 

This is because one of the ContactInfo objects is a web service proxy, and is in a different namespace.

It's a known problem with asmx-style web services. In the past I've implemented automatic shallow-copy to work around it (here's how, although if I were doing it again I'd probably look at AutoMapper instead).

For example, if you have an assembly with the following class:

MyProject.ContactInfo

and you return an instance of it from a web method:

public class DoSomethingService : System.Web.Services.WebService
{
    public MyProject.ContactInfo GetContactInfo(int id)
    {
        // Code here...
    }
}

Then when you add the web reference to your client project, you actually get this:

MyClientProject.DoSomethingService.ContactInfo

This means that if, in your client application, you call the web service to get a ContactInfo, you have this situation:

namespace MyClientProject
{
    public class MyClientClass
    {
        public void AskWebServiceForContactInfo()
        {
            using (var service = new DoSomethingService())
            {
                MyClientProject.DoSomethingService.ContactInfo contactInfo = service.GetContactInfo(1);

                // ERROR: You can't cast this:
                MyProject.ContactInfo localContactInfo = contactInfo;
            }
        }
    }
}

It's on that last line that I use my ShallowCopy class:

namespace MyClientProject
{
    public class MyClientClass
    {
        public void AskWebServiceForContactInfo()
        {
            using (var service = new DoSomethingService())
            {
                MyClientProject.DoSomethingService.ContactInfo contactInfo = service.GetContactInfo(1);

                // We actually get a new object here, of the correct namespace
                MyProject.ContactInfo localContactInfo = ShallowCopy.Copy<MyClientProject.DoSomethingService.ContactInfo, MyProject.ContactInfo>(contactInfo);
            }
        }
    }
}

NOTE
This only works because the proxy class and the "real" class have exactly the same properties (one is generated from the other by Visual Studio).

Neil Barnwell
A: 

How are you referencing the class in your web service project as well as consumer project? If you have simply used a file link, this could well explain the cause of the error. The way serialiasation works for .NET (Web Services or otherwise I believe) is by using reflection to load/dump the data of an object. If the files are simply linked, then they are actually getting compiled to different types in different assemblies, which would explain why you have the same name but can't cast between them. I recommend creating a 'Core' library which both the web service and consumer project references, and contains the ContactInfo class which you use everywhere.

Noldorin
A: 

This isn't a problem - it's a feature.

They are two independent classes. Compare the two, and notice that the proxy class has none of the constructors, methods, indexers, or other behavior from the original class. This is exactly the same thing that would happen if you consumed the ASMX service with a Java program.

John Saunders
@Downvoter: want someone to care what you think? Then you'll have to say what you think. "-2" doesn't say much. Instead, say why you downvoted.
John Saunders
It should not behave this way. We have this issue when using a generated proxy only, not when using the CreateChannel method, but our issue is the same as this post. I dont think this is meant to be a feature.
schmoopy
@schmoopy: he's using ASMX web services, not WCF. There is no `CreateChannel` method.
John Saunders
A: 

As several of the other answers have suggested, it is because .NET sees them as two different classes. I personally would recommend using something like AutoMapper. I've been using it, and it seems pretty awesome. You can copy your objects in 1-2 lines of code.

Mapper.CreateMap<SourceClass, DestinationClass>();
destinationInstance = Mapper.Map<SourceClass, DestinationClass>(sourceInstance);
John Kraft
A: 

Seems like you have two different classes on both ends. Your application has ContactInfo class and your webservice also have the ContactInfo class. Both are two completely different classes. One way is to use the WebService class on your side. If you are using ContactInfo inside your web service then it will be serialized and will be available on the client side for use.

azamsharp
A: 

actually this is not a bug. its a problem with the version changes of your own project! because your final run don't use the original imported references on compile!

for example,

i was making a chat server, client. i used a packet structure to transmit data on client project. then imported the same reference to server project. when casting...

Packet packet = (Packet)binaryFormatter.Deserialize(stream);

i got the same error.because the actual running reference at server project is not the reference now at client project! because i have rebuilt client project many times after!

in casting .... =()

always the new object need to be a newer or same version as the old object!

so what i did was, i build a separate project to create a dll for the Packet class and imported the dll file to both projects. if i did any change to Packet class, i have to import the reference to both client and server again.

then the casting wont give above exception!

regards! [email protected]

chandpriyankara