0

First of all keep in mind, that I followed a very much stuff in google about this subject.
I am using WCF, to exposing some services. I have something like:

[DataContract]
[KnownType(typeof(Sub))]
public class Base
{
    [DataMember]
    public int base;

}

[DataContract]
public class Sub : Base
{
    [DataMember]
    public int sub;
}

[ServiceContract]
[ServiceKnownType(typeof(Sub))]
public interface IServices
{
    [OperationContract]
    public void test(Base b);
}

I would like to be able, as XML, send both Sub object and Base object. When I break with debugger in first line of test(Base b) in b I can't see sub field.

The problem is:

<?xml version="1.0"?>

<soapenv:Envelope
xmlns:xs="http://www.w3.org/2003/05/soap-envelope/"
soapenv:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
   <soapenv:Header/>
   <soapenv:Body>
      <xs:test>
         <xs:b>
           <xs:base>123</xs:base>
           <xs:sub>1234</xs:sub>
        </xs:b>
   </xs:test>
 </soapenv:Body>
</soapenv:Envelope>

This XML is successfully deserialized, but in object I can see only base field (equals to 123), however I can't see field sub.
Where Am I wrong ?

Cœur
  • 37,241
  • 25
  • 195
  • 267
  • Im clearly failing to understand Sub is not based on base, nor does it have any relation to it, and foo wouldnt pass for your class of sub. In your example code, sub has no point and may have been stripped out at compile. – BugFinder Feb 17 '17 at 10:12
  • Like @BugFinder, I fail to see the relation between your _sub_ and _base_ class. However, if _sub_ is meant to inherit from _base_, then I think and **_guess_** you've forgotten to make your member function `virtual`. See this (C++) question: http://stackoverflow.com/questions/2391679/why-do-we-need-virtual-functions-in-c . Same idea for C#. – Wololo Feb 17 '17 at 10:29
  • Don't consider if `foo` is virtual. It doesn't matter here, as I mentioned data are not transported and it is base problem. (lack of fields from sub class). I edited and added relation between class (during writing this post I made this typo) –  Feb 17 '17 at 10:39
  • and how are you actually calling to get that xml? as "foo" is for base only.. – BugFinder Feb 17 '17 at 10:40
  • please, don't consider foo at this moment. Lets suppose that there is not this method and calling this metod. Let focus on lacking fields –  Feb 17 '17 at 10:41
  • Please post your *real* code as a [MCVE]. There's too many small errors that probably stem from shortening your code. For example, your data fields are private right now... – nvoigt Feb 17 '17 at 10:43
  • Ok, I edited now. –  Feb 17 '17 at 11:05
  • What exactly do you mean by "cannot see" the field sub? Where do you look? – nvoigt Feb 17 '17 at 11:12
  • In debugger I can't see it. I am break in first line of `test` and I am looking into `Base b`. Thanks for your involvement. –  Feb 17 '17 at 11:18
  • So your client sent a "sub"? We are still relying on guesswork here until you post a [MCVE]. – nvoigt Feb 17 '17 at 11:20
  • Yes, client also send a *sub*. I show a xml with this field. I think that this xml should tell something about type. –  Feb 17 '17 at 11:21
  • @nvoigt any ideas? –  Feb 17 '17 at 12:18
  • Not until you post a [MCVE]. – nvoigt Feb 17 '17 at 12:19
  • Hmm, but Did you look at it after edition ? –  Feb 17 '17 at 12:20
  • I used a different approach to resolve known types, see this one: http://stackoverflow.com/a/8399402/217823 and with it everything seemed just work automatically. All of my serializable entities inherited form the same base class and were located in a separate dll, so I was able to collect them easily. I'll add a Gist link in a moment. – JustAMartin Feb 17 '17 at 15:43
  • https://gist.github.com/midix/c7ca87a709c2ea89a617c05c2baa6cd4 try this and see if it helps. It might be an overkill in your case, but it seems a good generic solution I have used in almost every WCF project to avoid manually resolving all those KnownTypes related issues. – JustAMartin Feb 17 '17 at 15:51
  • @JustAMartin can you add some details how to use it ? In my case I have no dll files at whole. And I have the same issue as *llvm_questioner* –  Feb 23 '17 at 06:59
  • @JustAMartin, in particular - what changes your approach require ? And Does it work in case described by OP ? –  Feb 23 '17 at 07:12
  • @HaskellFun I'm not 100% sure if this would help for the OP's case, but I remember that in my project I too had complex entity hierarchies and I did not use `KnownType` attribute at all - the code in Gist seemed to cover all my needs. The only change you need is adding `[ServiceKnownType("GetKnownTypes", typeof(ServiceKnownTypesDiscovery))]` right below all of your `[ServiceContract]`. – JustAMartin Feb 23 '17 at 07:51
  • @HaskellFun If your entities are not in a separate dll, it gets more tricky to enumerate all entities to add to the known types, especially in a ASP.NET app. You might find the suggestions here http://stackoverflow.com/questions/4692340/find-types-in-all-assemblies useful. – JustAMartin Feb 23 '17 at 07:53
  • @JustAMartin my classes are traditional models (with DataMember annotations). Can you show how should be written xml to point that I would like to pass inherited object in place where arugment is *Base* ? –  Feb 23 '17 at 08:04

2 Answers2

0

First, your classes don't inherit from each other. I guess base should be the base class of sub? You will need to fix that first.

Then, the foo method has to be virtual to be overriden in sub. Fix that next.

And last but not least, WCF does not transport methods. It transports data only.

If you need executable code, put it into other classes. It's very confusing for users and yourself when you are tempted to think that your class will actually be transferred. It won't. Only it's data.

nvoigt
  • 75,013
  • 26
  • 93
  • 142
  • I know that it transport only data. Don't consider if foo is virtual. It doesn't matter here, as I mentioned data are not transported. (lack of fields from sub class) –  Feb 17 '17 at 10:37
  • OK, is it impossible to get polymorphism with WCF ? ( –  Feb 17 '17 at 10:40
  • You can do it, there is just no point to it. Maybe if you explained the business case instead of the technical part, you may get an answer that goes more in depth. – nvoigt Feb 17 '17 at 10:41
  • I added entire xml –  Feb 19 '17 at 12:17
0

As I understand, you want to manually send correct XML to your service and make it recognize the Sub entity. In my comments to your question I mentioned approach with KnownTypes discovery, but it is solving another kind of problems.

Your current C# code looks ok, but you are missing some type attributes in the XML. It should look like this:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:tem="http://tempuri.org/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:wcf="http://schemas.datacontract.org/2004/07/<PUT THE C# NAMESPACE OF YOUR ENTITIES HERE>">
   <soapenv:Header/>
   <soapenv:Body>
      <tem:Test>
         <tem:b xsi:type="wcf:Sub">
            <wcf:base>1</wcf:base>
            <wcf:sub>2</wcf:sub>
         </tem:b>
      </tem:Test>
   </soapenv:Body>
</soapenv:Envelope>

I just tested it and it worked fine in a WCF project created with VS 2015 and tested with SoapUI. Both sub and base values reached the test method and Sub entity was available inside of it.

A similar question on StackOverflow with the same xsi:type solution also given here.

If this does not help enough, I can upload the demo project somewhere on GitHub.

Community
  • 1
  • 1
JustAMartin
  • 13,165
  • 18
  • 99
  • 183