简体   繁体   中英

Passing inherited object to a WCF service using JSON

I have two classes that I have listed below

public Class Vehicle
{
   int wheels { get ; set}
}

public Class Car:Vehicle
{
   int topspeed { get; set ;}
}

//This is the container class

public Class Message
{
   string ConatinerName { get; set;}
   Vehicle Container;
}

I have defined a service contract which looks like the one below. This webservice has two end points enabled. One is SOAP and the other is Json

//this function gets a message object, looks into the container
public Message GetMessage(Message Input)
{
   Car mycar = (Car)Message.Container;
   mycar.topspeed = 200;
   Message retMessage = new Message();
   retMessage.ContainerName ="Adjusted Car Speed";
   retMessage.Container = mycar;
   return retMessage;
}

When I run the WCF webservice, visual studios native test client is able to call the service with a Message object and provided the option to pass in either a car or a vehcile objet in the Message container. The VS client uses the soap endpoint as per the raw data that gets passed in. To test the json endpoint of the service

I am using a simple client written in Python that calls the above webservice GetMessage() method using json data format. I pass in a Car object but when the service actually get

The webservice method gets the data, the container inside the object only contains the Vehicle object. I have examined the Request Context that the webmethod receives and it shows the correct json string is received(as it was sent) but .net somehow strips away the Car class property and only passes in the Vehicle property. So the cast to car inside GetMessage() throws an exception saying you are trying to cast a vehicle to a car which is an invalid cast.

Now I understand the Container inside the Message is of type Vehicle , but for the SOAP end point, I am able to pass in a car object and a vehicle object but for the json end point only a Vehicle object can be passed in through the Message container.

My question is how can I make the .NET runtime recognize that I am trying to pass in a Car and not a Vehicle ?

My json client code is posted below

import urllib2, urllib, json

def get_json(url):
                f = urllib2.urlopen(url)
                resp = f.read()
                f.close()
                return json.loads(resp)

def post(url, data):
                headers = {'Content-Type': 'application/json'}
                request = urllib2.Request(url, data, headers)
                f = urllib2.urlopen(request)
                response = f.read()
                f.close()
                return response

geturl = 'http://localhost:24573/Service1.svc/json/GetMessage'
sendurl = 'http://localhost:24573/Service1.svc/json/SendMessage'

msg = get_json(geturl)
print 'Got', msg
print 'Sending...'
retval = post(sendurl, json.dumps(msg))
print 'POST RESPONSE', retval

I have a similar problem using Python to call a WCF with JSON. Remarkably, what fixed it for me was ensuring that the __type key came first in the post request.

For example, json.dumps(data, sort_keys=True) would return something like this. The WCF service didn't like that because __type was not first in the Container . So, my suggestion would be to ensure that __type is first. (Also, I'm quite surprised that sort_keys is not recursive.)

Wrong:

{"Container": {"Model": "El Camino", "TopSpeed": 150, "Wheels": 0, "__type": "Car:#WcfService1"},"WrapperName": "Car Wrapper"}

Right:

{"Container": {"__type": "Car:#WcfService1", "Model": "El Camino", "TopSpeed": 150, "Wheels": 0},"WrapperName": "Car Wrapper"}

Simple python test client.

import urllib2, urllib, json

def get_json(url):
    f = urllib2.urlopen(url)
    resp = f.read()
    f.close()
    return json.loads(resp)


def post(url, data):
    headers = {'Content-Type': 'application/json'}
    request = urllib2.Request(url, data, headers)
    f = urllib2.urlopen(request)
    response = f.read()
    f.close()
    return response

geturl = 'http://localhost:24573/Service1.svc/json/GetMessage'
sendurl = 'http://localhost:24573/Service1.svc/json/SendMessage'

msg = get_json(geturl)
print 'Got', msg
print 'Sending...'
retval = post(sendurl, json.dumps(msg))
print 'POST RESPONSE', retval

Add this attribute to Vehicle class

[KnownType(typeof("Car"))]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM