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"))]
精彩评论