Получение конечной точки POST для работы в самодостаточном (WebServiceHost) C# webservice?

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

Вопрос 1:

При использовании WebServiceHost в.NET/C# вы можете определить метод / конечную точку как 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 узнает, что то, что содержится в "разделе данных" поста, должно быть помещено в переменную jsonString? Как мне разместить данные со стороны клиента (не C#, скажем, вместо этого JQuery), чтобы они правильно интерпретировались на стороне сервера?

(И как WebMessageFormat влияет на вещи? Я читал об этом везде (MSDN, Stackru и т. Д.), Но не нашел четкого и хорошего ответа.)

Вопрос 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, должно содержаться в "string pc"? Как он интерпретирует ее как строку и какой тип строки (UT8, ASCII и т. Д.)?

Это RAW HTTP-запрос, отправленный Fiddler:

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]

Любая помощь будет оценена. Благодарю.

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
}

Я думаю, что простой код может ответить на все ваши вопросы

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 здесь

Другие вопросы по тегам