WCF ResponseFormat для WebGet - PullRequest
       25

WCF ResponseFormat для WebGet

23 голосов
/ 14 июня 2009

WCF предлагает две опции для атрибута ResponseFormat в аннотации WebGet в ServiceContract.

[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.

Ответы [ 4 ]

47 голосов
/ 19 июня 2009

Попробуйте использовать

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));
8 голосов
/ 19 июня 2009

WebGetAttribute поставляется корпорацией Microsoft, и я не думаю, что вы можете расширить WebMessageFormat. Однако вы, вероятно, могли бы расширить WebHttpBinding, который использует WebGetAttribute. Вы можете добавить свой собственный атрибут, например

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

Как правило, настройка макета сообщения в WCF называется пользовательским кодировщиком сообщений / кодировкой. Microsoft предоставляет пример: Кодировщик пользовательских сообщений: Кодер сжатия . Еще одно распространенное расширение, которое делают люди, - это расширение поведения, чтобы добавить настраиваемую обработку ошибок, чтобы вы могли найти пример в этом направлении.

2 голосов
/ 19 декабря 2014

Я реализовал этот атрибут следующим образом, возможно, он поможет кому-то в будущем:

[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();
    }
}
0 голосов
/ 16 июля 2014

Есть один способ, как этого добиться, если вы имеете дело с HTTP, это не совсем хорошо, но я подумал, что могу упомянуть об этом.

Вы можете установить тип возвращаемого значения вашего метода как void и просто выводить необработанную строку прямо в ответ.

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