Подтвердить что ты не робот

Тело запроса доступа в службе WCF RESTful

Как мне получить доступ к телу запроса HTTP POST в службе WCF REST?

Вот определение службы:

[ServiceContract]
public interface ITestService
{
    [OperationContract]
    [WebInvoke(Method = "POST", UriTemplate = "EntryPoint")]
    MyData GetData();
}

Вот реализация:

public MyData GetData()
{
    return new MyData();
}

Я использую следующий код для доступа к HTTP-запросу:

IncomingWebRequestContext context = WebOperationContext.Current.IncomingRequest;

Но IncomingWebRequestContext дает доступ только к заголовкам, а не к телу.

Спасибо.

4b9b3361

Ответ 1

Лучший способ, я думаю, не включает WebOperationContext

[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "EntryPoint", BodyStyle = WebMessageBodyStyle.Bare)]
MyData GetData(System.IO.Stream pStream);

Ответ 2

Используйте

OperationContext.Current.RequestContext.RequestMessage

Ответ 3

Извините за поздний ответ, но я подумал, что добавлю, что работает с параметрами UriTemplate, чтобы получить тело запроса.

[ServiceContract]
public class Service
{        
    [OperationContract]
    [WebInvoke(UriTemplate = "{param0}/{param1}", Method = "POST")]
    public Stream TestPost(string param0, string param1)
    {

        string body = Encoding.UTF8.GetString(OperationContext.Current.RequestContext.RequestMessage.GetBody<byte[]>());

        return ...;
    }
}

body назначается строка из необработанных байтов тела сообщения.

Ответ 4

Похоже, что поскольку WCF предназначен для транспортного протокола-агностик, метод службы не предоставляет доступ к HTTP-специфической информации по умолчанию. Тем не менее, я просто столкнулся с хорошей статьей, описывающей "Режим совместимости ASP.Net", который по сути позволяет вам указать, что ваша служба действительно предназначена для просмотра через HTTP.

http://blogs.msdn.com/b/wenlong/archive/2006/01/23/516041.aspx

Добавление конфигурации aspNetCompatibilityEnabled в Web.config, в сочетании с атрибутом AspNetCompatibilityRequirements к требуемым операциям обслуживания, должно сделать трюк. Я собираюсь попробовать это сам.

Haw-бен

Ответ 5

Вышеупомянутые ответы помогли мне придумать это решение. Я получаю json с парами имя/значение. { "p1": 7514, "p2": 3412, "p3": "joe smith"...}

[OperationBehavior(Impersonation = ImpersonationOption.Allowed)]
    [WebInvoke(Method = "POST",
        BodyStyle = WebMessageBodyStyle.Bare, 
        RequestFormat = WebMessageFormat.Json
        )]

public Stream getJsonRequest()
    {

        // Get the raw json POST content.  .Net has this in XML string..
        string JSONstring = OperationContext.Current.RequestContext.RequestMessage.ToString();

        // Parse the XML string into a XML document
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(JSONstring);

        foreach (XmlNode node in doc.DocumentElement.ChildNodes)
        {
                node.Name // has key
                node.InnerText;  // has value

Ответ 6

Мои извинения за предыдущий ответ, я тупо предположил, что я просто бросил WebOperationContext, чтобы получить в OperationContext, к сожалению, реальный ответ намного уродлив.

Позвольте мне предисловие к этому, должен быть лучший способ!

Сначала я создал свой собственный объект контекста, который может быть привязан к существующему объекту OperationContext.

public class TMRequestContext : IExtension<OperationContext>  {

    private OperationContext _Owner;

        public void Attach(OperationContext owner) {
            _Owner = owner;
        }

     public void Detach(OperationContext owner) {
            _Owner = null;
        }

    public static TMRequestContext Current {
            get {
                if (OperationContext.Current != null) {
                    return OperationContext.Current.Extensions.Find<TMRequestContext>();
                } else {
                    return null;
                }
            }
        }
}

Чтобы получить доступ к этому новому объекту контекста, вам нужно добавить его как расширение к текущему. Я сделал это, создав класс инспектора сообщений.

public class TMMessageInspector : IDispatchMessageInspector {

        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) {

            OperationContext.Current.Extensions.Add(new TMRequestContext());
            return null;
        }
}

Для того, чтобы инспектор сообщений работал, вам нужно создать новое "поведение". Я сделал это, используя следующий код.

    public class TMServerBehavior : IServiceBehavior {

        public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) {
            //Do nothing
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase) {

            foreach (ChannelDispatcher chDisp in serviceHostBase.ChannelDispatchers) {

                foreach (EndpointDispatcher epDisp in chDisp.Endpoints) {
                    epDisp.DispatchRuntime.MessageInspectors.Add(new TMMessageInspector());
                }
            }

        }
}

Поведение, которое вы должны добавить в конфигурационный файл, хотя я сделал это, создав новый хост и добавив объект поведения вручную в метод OnOpening. Я закончил использование этого класса гораздо больше, чем просто доступ к объекту OperationContext. Я использовал их для регистрации и переопределения обработки ошибок и доступа к объекту запроса http и т.д. Таким образом, это не совсем нелепое решение, как кажется. Почти, но не совсем!

Я действительно не помню, почему я не мог просто напрямую обратиться к OperationContext.Current. У меня слабое воспоминание о том, что он всегда пуст, и этот неприятный процесс был единственным способом получить экземпляр, на самом деле содержащий достоверные данные.

Ответ 7

Вот что я сделал:

using System.IO;
using System.ServiceModel;
using System.ServiceModel.Web;
using System;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Text;

namespace YourSpaceName
{
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public class YourClassName
    {
        [OperationContract]
        [WebInvoke(Method = "POST", UriTemplate = "YourMethodName({id})", BodyStyle = WebMessageBodyStyle.Bare)]
        public Stream YourMethodName(Stream input, string id)
        {
            WebOperationContext ctx = WebOperationContext.Current;
            ctx.OutgoingResponse.Headers.Add("Content-Type", "application/json");

            string response = [email protected]"{{""status"": ""failure"", ""message"": ""Please specify the Id of the vehicle requisition to retrieve."", ""d"":null}}";
            try
            {
                string response = (new StreamReader(input)).ReadToEnd();
            }
            catch (Exception ecp)
            {
                response = [email protected]"{{""status"": ""failure"", ""message"": ""{ecp.Message}"", ""d"":null}}";
            }

            return new MemoryStream(Encoding.UTF8.GetBytes(response));
        }
    }
}

Этот код просто читает входные данные и записывает их. тело запроса POST автоматически присваивается вводу независимо от имени переменной. Как видите, в вашем UriTemplate все еще могут быть переменные.