Reputation: 1669
I have a typical WCF REST service in C# which accepts JSON input and returns a JSON output:
[ServiceContract]
public class WCFService
{
[WebInvoke(Method = "POST", UriTemplate = "register", ResponseFormat = WebMessageFormat.Json)]
public BasicResponse RegisterNewUser(UserDTO newUser)
{
return new BasicResponse()
{ status = "ERR_USER_NAME" };
}
}
public class BasicResponse
{
public string status { get; set; }
}
public class UserDTO
{
public string username { get; set; }
public string authCode { get; set; }
}
This works as expected but I want to return different objects in case of normal execution and in case of error. I created a base response class and few inheritors. Now the WCF JSON serializer crashes and produces "400 Bad Request":
[ServiceContract]
public class WCFService
{
[WebInvoke(Method = "POST", UriTemplate = "register",
ResponseFormat = WebMessageFormat.Json)]
public BasicResponse RegisterNewUser(UserDTO newUser)
{
return new ErrorResponse()
{
status = "ERR_USER_NAME",
errorMsg = "Invalid user name."
};
}
}
public class BasicResponse
{
public string status { get; set; }
}
public class ErrorResponse : BasicResponse
{
public string errorMsg { get; set; }
}
public class UserDTO
{
public string username { get; set; }
public string authCode { get; set; }
}
I tried to apply the [KnownType(typeof(ErrorResponse))]
and [ServiceKnownType(typeof(ErrorResponse))]
attributes without any success. Seems like a bug in the DataContractJsonSerializer
which states it supports polymorphism.
My WCF REST service uses the WebServiceHostFactory:
<%@ ServiceHost Language="C#" Debug="true"
Service="WCFService"
CodeBehind="CryptoCharService.svc.cs"
Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>
In my Web.config I have standard HTTP endpoint:
<system.serviceModel>
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint helpEnabled="true" defaultOutgoingResponseFormat="Json" />
</webHttpEndpoint>
</standardEndpoints>
</system.serviceModel>
Do you think this is fixable? I know a workaround (to return string and serialize the output manually) but why this does not work?
Upvotes: 3
Views: 3013
Reputation: 11
ServiceKnownTypeAttribute works for me. Try this one:
[ServiceKnownType(typeof(ErrorResponse))]
public BasicResponse RegisterNewUser(UserDTO newUser)
{
return new ErrorResponse()
{
status = "ERR_USER_NAME",
errorMsg = "Invalid user name."
};
}
Upvotes: 1
Reputation: 1669
I found a way to partially overcome the described problem. When I need to return a normal value (e.g. BasicResponse), I just return it (my service returns BasicResponse object). When I need to return an error response, I return it as WebFaultException which is also serialized as JSON and is sent as HTTP response to the WCF service:
throw new WebFaultException<ErrorResponse>(
new ErrorResponse() { errorMsg = "Error occured!" },
HttpStatusCode.NotFound);
Now I can send the expected result as a normal method return value and any exceptional result in case of error through this WebFaultException.
Upvotes: 1
Reputation: 44931
This should work correctly:
[DataContract]
[KnownType(typeof(ErrorResponse)]
public class BasicResponse
{
[DataMember]
public string status { get; set; }
}
[DataContract]
public class ErrorResponse : BasicResponse
{
[DataMember]
public string errorMsg { get; set; }
}
Upvotes: 0