2009-06-14 14 views
21

WCF propose deux options pour l'attribut ResponseFormat dans l'annotation WebGet dans ServiceContract.WCF ResponseFormat pour WebGet

[ServiceContract] 
public interface IService1 
{ 
    [OperationContract] 
    [WebGet(UriTemplate = "greet/{value}", BodyStyle = WebMessageBodyStyle.Bare)] 
    string GetData(string value); 

    [OperationContract] 
    [WebGet(UriTemplate = "foo", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)] 
    string Foo(); 

Les options pour ResponseFormat sont WebMessageFormat.Json et WebMessageFormat.Xml. Est-il possible d'écrire mon propre format de message web? Je voudrais que lorsque le client appelle la méthode foo(), il obtient une chaîne brute - sans wrappers json ou xml.

Répondre

8

WebGetAttribute est livré par Microsoft, et je ne pense pas que vous pouvez étendre WebMessageFormat. Cependant, vous pouvez probablement étendre le WebHttpBinding qui utilise WebGetAttribute. Vous pouvez ajouter votre propre attribut comme

[WebGet2(UriTemplate = "foo", ResponseFormat = WebMessageFormat2.PlainText)] 
string Foo(); 

En général, la personnalisation de la mise en page des messages dans WCF est appelé encodeur message personnalisé/encodage. Microsoft fournit un exemple: Custom Message Encoder: Compression Encoder. Une autre extension courante consiste à étendre le comportement pour ajouter une gestion des erreurs personnalisée, afin que vous puissiez trouver un exemple dans cette direction.

45

Essayez d'utiliser

BodyStyle = WebMessageBodyStyle.Bare 

Retournez ensuite un System.IO.Stream de votre fonction.

Voici un code que j'utilise pour retourner une image sur une base de données, mais accessible via une URL:

[OperationContract()] 
[WebGet(UriTemplate = "Person/{personID}/Image", BodyStyle = WebMessageBodyStyle.Bare)] 
System.IO.Stream GetImage(string personID); 

Mise en œuvre:

public System.IO.Stream GetImage(string personID) 
{ 
    // parse personID, call DB 

    OutgoingWebResponseContext context = WebOperationContext.Current.OutgoingResponse; 

    if (image_not_found_in_DB) 
    { 
     context.StatusCode = System.Net.HttpStatusCode.Redirect; 
     context.Headers.Add(System.Net.HttpResponseHeader.Location, url_of_a_default_image); 
     return null; 
    } 

    // everything is OK, so send image 

    context.Headers.Add(System.Net.HttpResponseHeader.CacheControl, "public"); 
    context.ContentType = "image/jpeg"; 
    context.LastModified = date_image_was_stored_in_database; 
    context.StatusCode = System.Net.HttpStatusCode.OK; 
    return new System.IO.MemoryStream(buffer_containing_jpeg_image_from_database); 
} 

Dans votre cas, pour revenir une chaîne brute, Définissez le ContentType à quelque chose comme "text/plain" et renvoyez vos données en tant que flux. A une supposition, quelque chose comme ceci:

return new System.IO.MemoryStream(ASCIIEncoding.Default.GetBytes(string_to_send)); 
+4

Nice. Cela fonctionne - semble toujours qu'il devrait y avoir un WebMessageFormat.Raw. Merci. –

0

Il y a une façon comment y parvenir si vous traitez avec HTTP, ce n'est pas exactement agréable, mais je pensais que je pourrais mentionner.

Vous pouvez définir le type de retour de votre méthode pour annuler et simplement afficher votre chaîne brute directement dans la réponse.

[OperationContract] 
[WebGet(UriTemplate = "foo")] 
void Foo() 
{ 
    HttpContext.Current.Response.Write("bar"); 
} 
2

Je mis en œuvre cet attribut comme celui-ci, peut-être il aider quelqu'un à l'avenir:

[AttributeUsage(AttributeTargets.Method)] 
public class WebGetText : Attribute, IOperationBehavior 
{ 

    public void Validate(OperationDescription operationDescription) 
    { 
    } 

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) 
    { 
     dispatchOperation.Formatter = new Formatter(dispatchOperation.Formatter); 
    } 

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) 
    { 
    } 

    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) 
    { 
    } 
} 

public class Formatter : IDispatchMessageFormatter 
{ 
    IDispatchMessageFormatter form; 

    public Formatter (IDispatchMessageFormatter form) 
    { 
     this.form = form; 
    } 

    public void DeserializeRequest(Message message, object[] parameters) 
    { 
     form.DeserializeRequest(message, parameters) 
    } 

    public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result) 
    { 
     IEnumerable<object> cl = (IEnumerable<object>)result; 
     StringBuilder csvdata = new StringBuilder(); 


     foreach (object userVariableClass in cl) { 
      Type type = userVariableClass.GetType(); 
      PropertyInfo[] fields = type.GetProperties(); 

      //   Dim header As String = String.Join(";", fields.Select(Function(f) f.Name + ": " + f.GetValue(userVariableClass, Nothing).ToString()).ToArray()) 
      //   csvdata.AppendLine("") 
      //   csvdata.AppendLine(header) 
      csvdata.AppendLine(ToCsvFields(";", fields, userVariableClass)); 
      csvdata.AppendLine(""); 
      csvdata.AppendLine("=====EOF====="); 
      csvdata.AppendLine(""); 
     } 
     Message msg = WebOperationContext.Current.CreateTextResponse(csvdata.ToString()); 
     return msg; 
    } 

    public static string ToCsvFields(string separator, PropertyInfo[] fields, object o) 
    { 
     StringBuilder linie = new StringBuilder(); 

     foreach (PropertyInfo f in fields) { 
      if (linie.Length > 0) { 
      } 

      object x = f.GetValue(o, null); 

      if (x != null) { 
       linie.AppendLine(f.Name + ": " + x.ToString()); 
      } else { 
       linie.AppendLine(f.Name + ": Nothing"); 
      } 
     } 

     return linie.ToString(); 
    } 
}