By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,501 Members | 2,871 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,501 IT Pros & Developers. It's quick & easy.

Downcasting from Interface on WCF Proxy

P: 8
I have created a basic WCF web service that returns a MessageContract class which has a member which is an interface called IOutcome (marked up as MessageBodyMember). There are two classes that implement IOutcome which are SuccessfulOutcome and FailureOutcome. FailureOutcome has a Property on it called ErrorDetails. Both of these subclasses are marked up as DataContracts and the members are marked as DataMembers, but the IOutcome class couldn't be marked up as [DataContract] without getting errors.

When I generate a proxy on the client application to call this service the FailureOutcome and SuccessfulOutcome classes do not get generated, so although I can refer to members of IOutcome, I can't get to the ErrorDetails on FailureOutcome as I don't have the type to downcast it to.

Am I coming at this problem from the wrong angle? It feels like it.

Initially I just wanted to return ErrorDetails on an exception but I couldn't figure out how to return a custom exception without it being turned into a FaultException and hence losing the custom fields. I suspect that FaultContract might help with this issue but I don't know much about that.

Suggestions on either of these approaches would be gratefully appreciated.
Jan 13 '09 #1
Share this Question
Share on Google+
7 Replies


Expert 100+
P: 190
Would something like this help?

Expand|Select|Wrap|Line Numbers
  1. IOutcome outcome = getOutcomeFromProxy();
  2. FailureOutcome failure = outcome as FailureOutcome;
  3. if(failure != null){
  4.   // handle failures
  5. }
  6. else{
  7.   SuccessfulOutcome success = outcome as SuccessfulOutcome;
  8.   if(success != null){
  9.     // handle success
  10.   }
  11.   else{
  12.     throw new InvalidOperationException("Return type unknown.");
  13.   }
  14. }
Jan 13 '09 #2

P: 8
Thanks for your reply, but unfortunately it doesn't offer me any help, but it does illustrate my point quite nicely. That is basically the code that I was trying to write, but my problem is that it won't compile as the types FailureOutcome and SuccessfulOutcome don't exist in my client solution, only in the service. I would have expected them to be generated as part of the proxy that appears when adding the reference but they don't. Surely all types in a MessageContract should get generated if they are correctly marked up with DataContract, DataMember etc.
Jan 13 '09 #3

Expert 100+
P: 190
Ah, I see. I am currently working on a proxy/server application and have run across the same issue.
If you only publish the interface, but your client wants to cast to the implementation, an exception will be thrown demanding a reference to the assembly containing the definition of the implementation as well.

One solution I can offer is not very elegant, but works:

In addition to (or in place of) the interface (IOutcome), you could publish the implementations (SuccessfulOutcome and FailureOutcome) as abstract classes to the public API which the client sees.

Your server would have actual implementations of the abstract classes. Your proxy would then return a copy of the server classes cast to the public abstract representation.

However, you will run across the exact same issue unless you implement a cloning method or a method or copy constructor in which each derived class on the server (SuccessfulOutcome for example) can COPY itself as an instance of the abstract class. This is tricky, because you cannot create an instance of an abstract class, but the copy can be done.

The other option is simply to have two concrete classes which both implement the IOutcome interface. One is published to the client with minimum implementation, perhaps holding only data; the other is internal to your server and would have the implementation details you do not want the client to have. If they are concrete classes, then the server can create a new instance of the client version, copy the client-only details to it, and serialize it through the proxy.
Jan 13 '09 #4

Expert 100+
P: 190
Wait - on closer reading of your post, my reply may be referring to a different client/proxy scenario (Remoting, not WebService).
Explain what protocol you are using and how you are "generating the proxy."
Jan 13 '09 #5

P: 8
This is a WCF web service that I am calling from a windows application. I generate the proxy using Visual Studio 2008 and going to the SolutionExplorer, then under my project name right click on Service References, select Add Service Reference then using the form that appears I paste in the URL for the web service, tweak a couple of minor settings then click OK. The new service proxy then appears under Service References in the Solution Explorer. I expect it does much the same as using svcutil.exe which I used to use with older versions of Visual Studio.
Jan 14 '09 #6

Expert 100+
P: 190
I see what you are doing and I understand the issue. Unfortunately, I haven't worked with the WCF Proxy/Serialization model. (I thought the names DataContract etc were your own class names). However, the overall proxy architecture is the same for different implementations, and the fundamental issue is still "how a client can cast to a specific implementation when the proxy only publishes an Interface?" - a common issue.

There might be someway to make your model work using WCF syntax/attributes, and if someone else sees the exact fix, I hope they jump in. Feel free to re-post your question to the forum, since I haven't helped much.

Nonetheless, I can suggest a workaround: Can you not add ErrorDetails to IOutcome, along with a boolean "HasErrors". This is the model of the AsyncCompletedEventArgs class. You check the "Error" property, and if it is null, you can check the "Result" property. If it is not null, you know your operation failed.

So a workaround could be essentially to make the Success/Failure Outcome classes into one.
Jan 15 '09 #7

P: 8
I think that may well be the way I have to go with it. I'm sure that way will work fine, just don't like to design code to avoid things I can't figure out. Oh well. Thanks for all your help anyway, much appreciated.
Jan 15 '09 #8

Post your reply

Sign in to post your reply or Sign up for a free account.