WCF + REST: Где данные запроса? - PullRequest
       23

WCF + REST: Где данные запроса?

9 голосов
/ 05 декабря 2009

В настоящее время я разрабатываю службу WCF RESTful. В рамках проверки данных POST я выдаю исключения, если XML-запрос не соответствует нашим бизнес-правилам.

Цель состоит в том, чтобы отправить электронное письмо соответствующему персоналу, если поступит запрос, который считается недействительным. Но наряду с заголовками входящего запроса, методом и URI я также хотел бы отправить опубликованный XML.

Мне не удалось найти способ доступа к этим данным. Действительно ли WCF уничтожает тело запроса / данные до того, как у меня появляется возможность получить к нему доступ, или я что-то упускаю?

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

Ответы [ 5 ]

9 голосов
/ 05 декабря 2009

Итак, если вы объявите свой контракт что-то вроде:

[WebInvoke(Method = "POST", UriTemplate = "create", ResponseFormat=WebMessageFormat.Json)]
 int CreateItem(Stream streamOfData);

(вместо этого вы можете использовать XML) StreamOfData должен быть телом HTTP POST. Вы можете десериализовать его, используя что-то вроде:

 StreamReader reader = new StreamReader(streamId);
 String res = reader.ReadToEnd();
 NameValueCollection coll = HttpUtility.ParseQueryString(res);

По крайней мере, так у нас работает. Вы можете использовать другой подход, чтобы получить строку в XMLDocument или что-то еще. Это работает для наших сообщений JSON. Возможно, это не самое элегантное решение, но оно работает.

Надеюсь, это поможет.

Glenn

9 голосов
/ 05 декабря 2009

К сожалению, это не поддерживается - у нас была похожая потребность, и мы сделали это, вызвав внутренних членов с отражением. Мы просто используем его в обработчике ошибок (чтобы мы могли выводить необработанный запрос), но он работает нормально. Я бы не рекомендовал ее для системы, которой вы не владеете и которой не пользуетесь (например, не отправляйте этот код клиенту), поскольку он может измениться в любое время с помощью пакета обновления или чего-либо еще.

public static string GetRequestBody()
{
    OperationContext oc = OperationContext.Current;

    if (oc == null)
        throw new Exception("No ambient OperationContext.");

    MessageEncoder encoder = oc.IncomingMessageProperties.Encoder;
    string contentType = encoder.ContentType;
    Match match = re.Match(contentType);

    if (!match.Success)
        throw new Exception("Failed to extract character set from request content type: " + contentType);

    string characterSet = match.Groups[1].Value;

    object bufferedMessage = operationContextType.InvokeMember("request",
        BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField,
        null, oc, null);

    //TypeUtility.AssertType(bufferedMessageType, bufferedMessage);

    object messageData = bufferedMessageType.InvokeMember("MessageData",
        BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetProperty,
        null, bufferedMessage, null);

    //TypeUtility.AssertType(jsonBufferedMessageDataType, messageData);

    object buffer = jsonBufferedMessageDataType.InvokeMember("Buffer",
        BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty,
        null, messageData, null);

    ArraySegment<byte> arrayBuffer = (ArraySegment<byte>)buffer;

    Encoding encoding = Encoding.GetEncoding(characterSet);

    string requestMessage = encoding.GetString(arrayBuffer.Array, arrayBuffer.Offset, arrayBuffer.Count);

    return requestMessage;
}
2 голосов
/ 21 декабря 2011

Вот как вы делаете это без раздумий:

using (var reader = OperationContext.Current.RequestContext.RequestMessage.GetReaderAtBodyContents ()) {
    if (reader.Read ())
        return new string (Encoding.ASCII.GetChars (reader.ReadContentAsBase64 ()));
                return result;
    }
}

Если читатель - HttpStreamXmlDictionaryReader (как это было в моем случае), реализация метода класса ReadContentAsBase64(byte[] buffer, int index, int count) просто передает эти параметры методу Stream.Rea d.

Получив byte[], я преобразую байты в строку с помощью кодировки ASCII. Для правильной реализации вы можете использовать тип содержимого и кодировку из заголовков сообщения, чтобы сделать это для спецификации HTTP.

2 голосов
/ 09 сентября 2010

Попробуйте это,

OperationContext.Current.RequestContext.RequestMessage
0 голосов
/ 26 августа 2015

Вы можете арестовать HttpApplication.Request.InputStrea m в пользовательском HttpModule Сервиса WCF, прочитать поток и снова установить его позицию в 0 в обработчике событий пользовательского HttpModule. Затем сохраните его в сеансе и получите доступ к нему в текущем OperationContract.

Например:

public class CustomModule : IHttpModule
{
    public void Dispose()
    {

    }

    public void Init(HttpApplication context)
    {
        context.AcquireRequestState +=context_AcquireRequestState;
    }

    void context_AcquireRequestState(object sender, EventArgs e)
    {
        HttpApplication application = sender as HttpApplication;
        Stream str = application.Request.InputStream;
        StreamReader sr = new StreamReader(str);
        string req = sr.ReadToEnd();
        str.Position = 0;
        application.Session["CurrentRequest"] = req;
    }
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...