代码之家  ›  专栏  ›  技术社区  ›  urini

WCF RESTful服务中的访问请求主体

  •  16
  • urini  · 技术社区  · 16 年前

    如何访问WCF REST服务中的httppost请求体?

    以下是服务定义:

    [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只提供对头的访问,而不是对主体的访问。

    谢谢。

    6 回复  |  直到 16 年前
        1
  •  11
  •   kasthor    16 年前

    我认为最好的方式不涉及网络运营环境

    [OperationContract]
    [WebInvoke(Method = "POST", UriTemplate = "EntryPoint", BodyStyle = WebMessageBodyStyle.Bare)]
    MyData GetData(System.IO.Stream pStream);
    
        2
  •  9
  •   SajithK    15 年前

    使用

    OperationContext.Current.RequestContext.请求消息

        3
  •  7
  •   Gerard Sexton    10 年前

    很抱歉迟来的答复,但我想我应该添加与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
  •  1
  •   Haw-Bin    16 年前

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

    添加 aspNetCompatibilityEnabled 配置到 Web.config ,与 AspNetCompatibilityRequirements 属性到所需的服务操作中,应做到这一点。我要自己试试。

        5
  •  1
  •   amackay11    14 年前

    以上的答案帮助我想出了这个解决方案。我收到了带有名称/值对的json。{“p1”:7514,“p2”:3412,“p3”:“乔·史密斯”。。。}

    [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
  •  0
  •   Darrel Miller    16 年前

    我为之前的回答道歉,我愚蠢地以为我只是投了WebOperationContext来获取OperationContext,不幸的是,真正的答案更难看。

    让我先说,一定有更好的办法!

    首先,我创建了自己的context对象,它可以附加到现有的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请求对象的访问等,因此,这并不是看起来那么荒谬的解决方案。差不多,但不完全是!

    我真的不记得为什么我不能操作上下文。当前直接。我有一个模糊的回忆,它总是空的,这个讨厌的进程是唯一的方法,我可以得到一个实际包含有效数据的实例。

        7
  •  0
  •   GuruKay    6 年前

    以下是我所做的:

    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 = $@"{{""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 = $@"{{""status"": ""failure"", ""message"": ""{ecp.Message}"", ""d"":null}}";
                }
    
                return new MemoryStream(Encoding.UTF8.GetBytes(response));
            }
        }
    }
    

    这段代码只是读取输入并将其写出。 不可忽略的是,POST的名字被自动分配给请求的主体。如您所见,您的UriTemplate中仍然可以有变量。

    推荐文章