3 votes

Service WCF REST : WebInvoke avec JSON et polymorphisme ne fonctionne pas correctement

J'ai un service REST WCF typique en C# qui accepte une entrée JSON et renvoie une sortie JSON :

[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; }
} 

Cela fonctionne comme prévu mais je veux renvoyer des objets différents en cas d'exécution normale et en cas d'erreur. J'ai créé une classe de réponse de base et quelques héritiers. Maintenant le sérialiseur WCF JSON se plante et produit "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; }
}

J'ai essayé d'appliquer le [KnownType(typeof(ErrorResponse))] y [ServiceKnownType(typeof(ErrorResponse))] sans succès. Il semble qu'il y ait un bug dans le DataContractJsonSerializer qui déclare qu'il supporte le polymorphisme.

Mon service WCF REST utilise le WebServiceHostFactory :

<%@ ServiceHost Language="C#" Debug="true" 
    Service="WCFService" 
    CodeBehind="CryptoCharService.svc.cs"
    Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>

Dans mon Web.config, j'ai un point de terminaison HTTP standard :

<system.serviceModel>
  <standardEndpoints>
    <webHttpEndpoint>
      <standardEndpoint helpEnabled="true" defaultOutgoingResponseFormat="Json" />
    </webHttpEndpoint>
  </standardEndpoints>
</system.serviceModel>

Pensez-vous que cela puisse être réparé ? Je connais une solution de contournement (retourner une chaîne et sérialiser la sortie manuellement) mais pourquoi cela ne fonctionne-t-il pas ?

1voto

Svetlin Nakov Points 184

J'ai trouvé un moyen de surmonter partiellement le problème décrit. Lorsque j'ai besoin de renvoyer une valeur normale (par exemple BasicResponse), je la renvoie simplement (mon service renvoie l'objet BasicResponse). Quand j'ai besoin de renvoyer une réponse d'erreur, je la renvoie comme WebFaultException qui est aussi sérialisée comme JSON et est envoyée comme réponse HTTP au service WCF :

throw new WebFaultException<ErrorResponse>(
    new ErrorResponse() { errorMsg = "Error occured!" },
    HttpStatusCode.NotFound);

Maintenant, je peux envoyer le résultat attendu comme valeur de retour d'une méthode normale et tout résultat exceptionnel en cas d'erreur par le biais de cette WebFaultException.

1voto

xqqw Points 11

ServiceKnownTypeAttribute fonctionne pour moi. Essayez celui-ci :

[ServiceKnownType(typeof(ErrorResponse))] 
public BasicResponse RegisterNewUser(UserDTO newUser)
{
    return new ErrorResponse()
    {
        status = "ERR_USER_NAME",
        errorMsg = "Invalid user name."
    };
}

0voto

competent_tech Points 29781

Cela devrait fonctionner correctement :

[DataContract]
[KnownType(typeof(ErrorResponse)]
public class BasicResponse
{
    [DataMember]
    public string status { get; set; }
}

[DataContract]
public class ErrorResponse : BasicResponse
{
    [DataMember]
    public string errorMsg { get; set; }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X