【问题标题】:Getting a POST endpoint to work in self-hosted (WebServiceHost) C# webservice?让 POST 端点在自托管 (WebServiceHost) C# web 服务中工作?
【发布时间】:2012-10-15 15:53:31
【问题描述】:

所以,我一直在搞乱网络服务有一段时间了,而且我一直在回归一些基础知识,但我似乎永远不会正确。

问题一:

在 .NET/C# 中使用 WebServiceHost 时,您可以将方法/端点定义为使用 GET/POST/等。设置一个 GET 方法很简单,它几乎可以直接工作,而且很容易理解它是如何工作的。例如:

[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "/PutMessage/{jsonString}", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
string PutMessage(string jsonString);

如果我调用 http:///MyWebService/PutMessage/{MyJsonString} 我会通过该方法,一切都很好(或多或少)。

但是,当我将其定义为 POST 时,这意味着什么?

[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "/PutMessage/{jsonString}", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
string PutMessage(string jsonString);

UriTemplate 在这里做什么? 如果我执行 POST,我希望数据不会包含在 URI 中,而是包含在帖子的“数据部分”中。但是我是否在数据部分定义变量名? WebServiceHost/.NET如何知道post的“数据部分”中包含的内容是要放入变量jsonString中的?如何从客户端(不是 C#,让我们说 JQuery)发布数据,以便在服务器端正确解释?

(WebMessageFormat 是如何影响事物的?我到处都阅读过这方面的内容(MSDN、Stackoverflow 等),但还没有找到明确而好的答案。)

问题 2:

在尝试理解这一点时,我想我会做一个非常简单的 POST 方法,如下所示:

[OperationContract]
[WebInvoke]
string PutJSONRequest(string pc);

然后我尝试使用 Fiddler 调用此方法,但这根本不起作用。我只是收到一个 400 错误,说“HTTP/1.1 400 Bad Request”。我在方法代码的第一行有一个断点,而方法本身不包含任何内容:

public string PutJSONRequest(string pc)
{
    return null;
}

同样,.NET 怎么知道我使用 Fiddler 发布的内容应该包含在“字符串 pc”中? 它如何将其解释为字符串,以及什么类型的字符串(UT8、 ASCII 等)?

这是从 Fiddler 发送的 RAW HTTP 请求:

POST http://<myip>:8093/AlfaCustomerApp/PutJSONRequest HTTP/1.1
User-Agent: Fiddler
Host: <myip>:8093
Content-Length: 3
Content-type: application/x-www-form-urlencoded; charset=UTF-8

asd

据我所知,我使用什么类型的 Content-type 并不重要。

反应是标准的,我无法控制自己:

HTTP/1.1 400 Bad Request
Content-Length: 1165
Content-Type: text/html
Server: Microsoft-HTTPAPI/2.0
Date: Mon, 15 Oct 2012 15:45:02 GMT

[then HTML code]

任何帮助将不胜感激。谢谢。

【问题讨论】:

    标签: c# wcf web-services http-post webservicehost


    【解决方案1】:

    我认为一个简单的代码可以回答你所有的问题

    Task.Factory.StartNew(()=>StartServer());
    Thread.Yield();
    StartClient();
    

    void StartServer()
    {
        Uri uri = new Uri("http://localhost:8080/test");
        WebServiceHost host = new WebServiceHost(typeof(WCFTestServer), uri);
        host.Open();
    }
    
    void StartClient()
    {
        try
        {
            WebClient wc = new WebClient();
    
            //GET
            string response1 = wc.DownloadString("http://localhost:8080/test/PutMessageGET/abcdef");
            //returns: "fedcba"
    
            //POST with UriTemplate
            string response2 = wc.UploadString("http://localhost:8080/test/PutMessagePOSTUriTemplate/abcdef",
                                                JsonConvert.SerializeObject(new { str = "12345" }));
            //returns: fedcba NOT 54321
    
    
            //POST with BodyStyle=WebMessageBodyStyle.WrappedRequest
            //Request: {"str":"12345"}
            wc.Headers["Content-Type"] = "application/json";
            string response3 = wc.UploadString("http://localhost:8080/test/PutMessagePOSTWrappedRequest",
                                                JsonConvert.SerializeObject(new { str="12345" }));
    
            //POST with BodyStyle=WebMessageBodyStyle.Bare
            wc.Headers["Content-Type"] = "application/json";
            string response4 = wc.UploadString("http://localhost:8080/test/PutMessagePOSTBare", "12345" );
    
        }
        catch (WebException wex)
        {
            Console.WriteLine(wex.Message);
        }
    }
    

    [ServiceContract]
    public class WCFTestServer
    {
        [OperationContract]
        [WebInvoke(Method = "GET", UriTemplate = "/PutMessageGET/{str}", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        public string PutMessageGET(string str)
        {
            return String.Join("", str.Reverse());
        }
    
        [OperationContract]
        [WebInvoke(Method = "POST", UriTemplate = "/PutMessagePOSTUriTemplate/{str}", BodyStyle = WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        public string PutMessagePOSTUriTemplate(string str)
        {
            return String.Join("", str.Reverse());
        }
    
        [OperationContract]
        [WebInvoke(Method = "POST", BodyStyle=WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        public string PutMessagePOSTWrappedRequest(string str)
        {
            return String.Join("", str.Reverse());
        }
    
        [OperationContract]
        [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        public string PutMessagePOSTBare(string str)
        {
            return String.Join("", str.Reverse());
        }
    }
    

    PS:你可以找到JsonConvert here

    【讨论】:

    • 谢谢... 那么,在 PutMessagePOSTUriTemplate 中 - JSON 部分在哪里?
    • 您介意将回复/答案发布到 PutMessagePOSTWrappedRequest 和 PutMessagePOSTBare 吗?
    • 最后,如果我尝试一个简单的 POST 方法,如我的问题中所述,服务器端的方法永远不会被调用。
    • a) PutMessagePOSTUriTemplate: 服务器忽略 json 并使用 url 中的参数 b) 回复:PutMessagePOSTWrappedRequest and PutMessagePOSTBare:“54321” c) 我不知道你如何使用 fiddler 来发布消息,但它可以与 Content-Type (application/json) 相关
    • 我还没有弄清楚如何访问 POST 中的“数据”。上面的示例假设有一个名为“str”的变量,但该变量在哪里定义?它从何而来? .NET 如何知道将“数据”放在“字符串 str”中?
    【解决方案2】:

    我找到了答案。这是如何定义一个方法,该方法可以获取在 HTTP POST 中发送的原始数据:

    [OperationContract]
    [WebInvoke(BodyStyle=WebMessageBodyStyle.Bare)]
    Stream PutMessage(Stream data);
    

    实现是这样的:

    public Stream PutMessage(Stream data)
    {
        byte[] buffer = new byte[65535];
    
        int bytesRead, totalBytes = 0;
        do
        {
            bytesRead = data.Read(buffer, 0, 65535);
            totalBytes += bytesRead;
        }
        while (bytesRead > 0);
    
        // Then you could interpret it as a String for example:
        string jsonString = Encoding.UTF8.GetString(buffer, 0, totalBytes);
        // yada yada
    }
    

    【讨论】:

    • 否决票的任何理由?这个答案就像一个魅力,并且表现得和预期一样。
    • 只有流是最灵活的方法。我推荐这个答案!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-19
    • 2010-09-17
    相关资源
    最近更新 更多