2011-11-16 5 views
4

J'ai un service WCF 4.0 REST. Si j'active automaticFormatSelectionEnabled dans le fichier web.config, le service choisira correctement entre la sérialisation en XML ou JSON basée sur l'en-tête HTTP "Accept".WCF 4.0 Rest Service renvoie le type de contenu text/html

Toutefois, lorsque j'émets la commande GET avec un navigateur, le corps de la réponse revient au format XML, mais l'en-tête du type de contenu HTTP est "text/html". Cela amène le navigateur à ne pas réaliser que la réponse est XML et à essayer de la rendre en html (ce qui bien sûr ne fonctionne pas bien). Cela rend le test de mes méthodes GET dans un navigateur plus difficile. Si je désactive automaticFormatSelectionEnabled alors tout fonctionne comme prévu (le corps de la réponse contient XML et le type de contenu HTTP est "application/xml"), cependant, j'aimerais pouvoir passer automatiquement à JSON si demandé.

Existe-t-il un moyen de rétablir le type de contenu lors de la demande via le navigateur?

+0

Quel est le corps de la réponse quand il s'agit de text/html? Contient-il un message d'erreur (ce qui est souvent le cas)? – carlosfigueira

+0

Vous pouvez utiliser un outil comme fiddler pour voir ce que accepte le Header du navigateur (ou inspecter le WebOperationContext.Current.IncomingRequest en utilisant le débogueur). Au moins, vous pourriez exclure un problème de navigateur de cette façon. –

+0

L'en-tête Accept du navigateur est "text/html, application/xhtml + xml, application/xml; q = 0.9, */*; q = 0.8" ce que je suppose être juste la norme/défaut FireFox. Le corps de la réponse est XML (le XML correct et attendu), mais le problème est que le type de contenu de la réponse est text/html, de sorte que le navigateur ne le traite pas comme un document XML mais plutôt comme HTML. –

Répondre

3

J'ai rencontré le même problème, voici un travail autour. Essentiellement ce que vous devez faire est de créer une extension de comportement qui va changer le type de contenu lors de l'envoi de la réponse.

Votre web.config devrait inclure quelque chose comme:

<behaviors> 
    <serviceBehaviors> 
    <behavior name="WebServiceBehavior"> 
     <serviceMetadata httpGetEnabled="true" /> 
     <serviceDebug includeExceptionDetailInFaults="false" /> 
     <MessageInspector/> 
    </behavior> 
    </serviceBehaviors> 
</behaviors> 
<extensions> 
    <behaviorExtensions> 
    <add name="MessageInspector" 
      type="Namespace.ServiceContentTypeBehaviorExtensionElement, assembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 
    </behaviorExtensions> 
</extensions> 

Ensuite, vous devrez créer une classe qui hérite de BehaviorExtensionElement

public class ServiceContentTypeBehaviorExtensionElement : BehaviorExtensionElement 
{ 
    protected override object CreateBehavior() 
    { 
     return new ServiceContentTypeMessageInspector(); 
    } 

    public override Type BehaviorType 
    { 
     get 
     { 
      return typeof(ServiceContentTypeMessageInspector); 
     } 
    } 
} 

Et puis enfin une classe qui implémente IDispatchMessageInspector et IServiceBehavior qui effectue le dur travail de modification du type de contenu:

public class ServiceContentTypeMessageInspector : IDispatchMessageInspector, IServiceBehavior 
{ 

    #region IDispatchMessageInspector 

    public object AfterReceiveRequest(ref Message request, IClientChannel channel, 
     InstanceContext instanceContext) 
    { 
     return null; 
    } 

    public void BeforeSendReply(ref Message reply, object correlationState) 
    { 
     // inspect and/or modify the reply 
     if (WebOperationContext.Current.OutgoingResponse.Headers[HttpResponseHeader.ContentType] == "text/html; charset=utf-8" && 
      WebOperationContext.Current.OutgoingResponse.Format == WebMessageFormat.Xml) 
     { 
      WebOperationContext.Current.OutgoingResponse.Headers[HttpResponseHeader.ContentType] = "application/xml; charset=utf-8"; 
     } 
    } 

    #endregion 

    #region IServiceBehavior 

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, 
     ServiceHostBase serviceHostBase) 
    { 
     foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers) 
     { 
      foreach (var endpoint in dispatcher.Endpoints) 
      { 
       endpoint.DispatchRuntime.MessageInspectors.Add(new ServiceContentTypeMessageInspector()); 
      } 
     } 
    } 

    public void AddBindingParameters(ServiceDescription serviceDescription, 
     ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, 
     BindingParameterCollection bindingParameters) 
    { 
    } 

    public void Validate(ServiceDescription serviceDescription, 
     ServiceHostBase serviceHostBase) 
    { 
    } 

    #endregion 
} 

Devrait fonctionner comme prévu maintenant!

+0

vraiment bien, mais je voulais juste ajouter les usings pour ces classes, ils vont peut-être aider: La première classe: utilisant System.ServiceModel.Configuration La deuxième classe: utilisant System.ServiceModel.Web ; en utilisant System.ServiceModel; en utilisant System.ServiceModel.Dispatcher; en utilisant System.ServiceModel.Description; en utilisant System.Net; en utilisant System.ServiceModel.Channels; en utilisant System.Collections.ObjectModel; – Khattab

+0

Merci à Bevan pour une solution. Je noterai également que cela fonctionne comme prévu avec ASP.NET WebAPI. –

Questions connexes