【问题标题】:WCF ResponseFormat For WebGetWebGet 的 WCF 响应格式
【发布时间】:2016-11-28 20:12:19
【问题描述】:

WCF 为 ServiceContract 的 WebGet 注释中的 ResponseFormat 属性提供了两个选项。

[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();

ResponseFormat 的选项是 WebMessageFormat.Json 和 WebMessageFormat.Xml。是否可以编写我自己的网络消息格式?我希望当客户端调用 foo() 方法时,他得到原始字符串 - 没有 json 或 xml 包装器。

【问题讨论】:

    标签: c# wcf webget responseformat


    【解决方案1】:

    尝试使用

    BodyStyle = WebMessageBodyStyle.Bare
    

    然后从您的函数中返回一个 System.IO.Stream。

    这是我用来从数据库中返回图像的一些代码,但可以通过 URL 访问:

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

    实施:

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

    在您的情况下,要返回原始字符串,请将 ContentType 设置为“text/plain”之类的内容并将您的数据作为流返回。大概是这样的:

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

    【讨论】:

    • 不错。它有效 - 似乎仍然应该有一个 WebMessageFormat.Raw。谢谢。
    【解决方案2】:

    WebGetAttribute 由 Microsoft 提供,我认为您不能扩展 WebMessageFormat。但是,您可能可以扩展使用WebGetAttributeWebHttpBinding。您可以添加自己的属性,例如

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

    通常,在 WCF 中自定义消息布局称为自定义消息编码器/编码。 Microsoft 提供了一个示例:Custom Message Encoder: Compression Encoder。人们所做的另一个常见扩展是扩展行为以添加自定义错误处理,因此您可以在该方向寻找一些示例。

    【讨论】:

      【解决方案3】:

      我是这样实现这个属性的,也许将来会对某人有所帮助:

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

      【讨论】:

        【解决方案4】:

        如果您正在处理 HTTP,有一种方法可以实现这一点,它不是很好,但我想我可以提一下。

        您可以将方法的返回类型设置为 void,然后直接将原始字符串输出到响应中。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多