【问题标题】:WCF Service Doesn't Like My Content-TypeWCF 服务不喜欢我的内容类型
【发布时间】:2016-06-15 11:23:00
【问题描述】:

我正在使用 WCF 构建一组 Rest 服务。我正在使用 Postman 提出测试请求。一切都很顺利,直到我想在请求标头中指定“Content-Type”。

服务合同:

[OperationContract]
  [WebInvoke(Method = "POST",
              UriTemplate = "data")]
  Stream GetData(Stream iBody);

以及它背后的代码:

public Stream GetData(Stream iBody) {
     StreamReader objReader = new StreamReader(iBody);
     string strBody = objReader.ReadToEnd();

     XmlDocument objDoc = new XmlDocument();
     objDoc.LoadXml(strBody);

     return GetStreamData("Hello There. " + objDoc.InnerText);
}

private Stream GetStreamData(string iContent) {
     byte[] resultBytes = Encoding.UTF8.GetBytes(iContent);
     return new MemoryStream(resultBytes);
}

只要我不在请求标头中包含值为“text/xml”的“Content-Type”,这一切都可以正常工作。

有:

没有:

我也尝试过“text/xml; charset=utf-8”和“application/xml”的组合,但无济于事。它与服务方法接受的类型有什么关系吗?任何指针将不胜感激。

【问题讨论】:

    标签: c# xml wcf content-type postman


    【解决方案1】:

    由于您在 WCF 服务中使用 raw programming model(使用 Stream 作为参数/返回类型),您需要告诉 WCF 堆栈不要尝试将具有 XML 内容类型的传入请求解释为 XML , 而是让它通过。您可以使用WebContentTypeMapper 做到这一点,它将所有传入请求(无论其内容类型如何)映射到原始模式。顶部链接的博客文章有更多关于此的信息,下面的代码显示了一个处理您的案例的映射器示例。

    public class StackOverflow_35750073
    {
        [ServiceContract]
        public class Service
        {
            [OperationContract]
            [WebInvoke(Method = "POST", UriTemplate = "data")]
            public Stream GetData(Stream iBody)
            {
                StreamReader objReader = new StreamReader(iBody);
                string strBody = objReader.ReadToEnd();
    
                XmlDocument objDoc = new XmlDocument();
                objDoc.LoadXml(strBody);
    
                return GetStreamData("Hello There. " + objDoc.InnerText);
            }
            private Stream GetStreamData(string iContent)
            {
                byte[] resultBytes = Encoding.UTF8.GetBytes(iContent);
                return new MemoryStream(resultBytes);
            }
        }
        class RawMapper : WebContentTypeMapper
        {
            public override WebContentFormat GetMessageFormatForContentType(string contentType)
            {
                return WebContentFormat.Raw;
            }
        }
        public static void Test()
        {
            string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
            ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
            ServiceEndpoint endpoint1 = host.AddServiceEndpoint(
                typeof(Service),
                new WebHttpBinding { ContentTypeMapper = new RawMapper() },
                "withMapper");
            endpoint1.Behaviors.Add(new WebHttpBehavior());
    
            ServiceEndpoint endpoint2 = host.AddServiceEndpoint(
                typeof(Service), 
                new WebHttpBinding(),
                "noMapper");
            endpoint2.Behaviors.Add(new WebHttpBehavior());
    
            host.Open();
            Console.WriteLine("Host opened");
    
            var input = "<hello><world>How are you?</world></hello>";
            Console.WriteLine("Using a Content-Type mapper:");
            SendRequest(baseAddress + "/withMapper/data", "POST", "text/xml", input);
            SendRequest(baseAddress + "/withMapper/data", "POST", null, input);
    
            Console.WriteLine("Without using a Content-Type mapper:");
            SendRequest(baseAddress + "/noMapper/data", "POST", "text/xml", input);
            SendRequest(baseAddress + "/noMapper/data", "POST", null, input);
    
            Console.Write("Press ENTER to close the host");
            Console.ReadLine();
            host.Close();
        }
        public static string SendRequest(string uri, string method, string contentType, string body)
        {
            string responseBody = null;
    
            HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri);
            req.Method = method;
            if (!String.IsNullOrEmpty(contentType))
            {
                req.ContentType = contentType;
            }
    
            if (body != null)
            {
                byte[] bodyBytes = Encoding.UTF8.GetBytes(body);
                req.GetRequestStream().Write(bodyBytes, 0, bodyBytes.Length);
                req.GetRequestStream().Close();
            }
    
            HttpWebResponse resp;
            try
            {
                resp = (HttpWebResponse)req.GetResponse();
            }
            catch (WebException e)
            {
                resp = (HttpWebResponse)e.Response;
            }
    
            if (resp == null)
            {
                responseBody = null;
                Console.WriteLine("Response is null");
            }
            else
            {
                Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription);
                foreach (string headerName in resp.Headers.AllKeys)
                {
                    Console.WriteLine("{0}: {1}", headerName, resp.Headers[headerName]);
                }
                Console.WriteLine();
                Stream respStream = resp.GetResponseStream();
                if (respStream != null)
                {
                    responseBody = new StreamReader(respStream).ReadToEnd();
                    Console.WriteLine(responseBody);
                }
                else
                {
                    Console.WriteLine("HttpWebResponse.GetResponseStream returned null");
                }
            }
    
            Console.WriteLine();
            Console.WriteLine("  *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*  ");
            Console.WriteLine();
    
            return responseBody;
        }
    }
    

    【讨论】:

    • 谢谢。这现在更有意义了(WCF 的新手)。我正在构建它以接受 xml 或 json 但直到运行时才知道哪个。因此需要 content-type 来确定任意内容实际上是什么。
    猜你喜欢
    • 2012-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-17
    • 1970-01-01
    • 2020-01-21
    • 1970-01-01
    • 2013-08-15
    相关资源
    最近更新 更多