Ottenere un endpoint POST per lavorare in C # webservice self-hosted (WebServiceHost)?

Quindi, da un pò sono in giro con i webservice, e continuo a tornare su alcune nozioni di base, che non sembra mai avere ragione.

Domanda 1:

Quando si utilizza un WebServiceHost in .NET / C #, è ansible definire un metodo / endpoint come GET / POST / ecc. L’impostazione di un metodo GET è semplice e funziona praticamente direttamente, ed è facile capire come funziona. Per esempio:

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

Se chiamo http: /// MyWebService / PutMessage / {MyJsonString} vengo passato al metodo, e tutto va bene (più o meno).

Ma cosa significa quando definisco questo come un POST ?

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

Cosa fa l’UriTemplate qui? Se faccio un post, mi aspetto che i dati non siano contenuti nell’URI, ma nella “sezione dati” del post. Ma definisco il nome della variabile nella sezione dei dati? In che modo WebServiceHost / .NET sa che ciò che è contenuto nella “sezione dati” del post deve essere inserito nella variabile jsonString? Come posso inviare i dati dal lato client (non C #, diciamo invece JQuery) in modo che sia interpretato correttamente sul lato serer?

(E come agisce il WebMessageFormat? Ho letto ovunque su questo (MSDN, StackOverflow ecc.) Ma non ho trovato una risposta chiara e buona.)

Domanda 2:

Nei miei tentativi di capirlo, ho pensato di creare un metodo POST molto semplice, come questo:

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

Quindi provo a chiamare questo metodo usando Fiddler, ma questo non funziona affatto. Ho appena ricevuto un errore di 400, dicendo “HTTP / 1.1 400 Bad Request”. Ho un breakpoint sulla prima riga del codice del metodo, e il metodo stesso non contiene nulla:

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

Ancora una volta, in che modo .NET sa che quello che ho inserito usando Fiddler dovrebbe essere contenuto nel “string pc”? Come lo interpreta come una stringa e quale tipo di stringa (UT8, ASCII, ecc.)?

Questa è la richiesta HTTP RAW, inviata da Fiddler:

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

e non importa che tipo di tipo di contenuto che uso, per quanto posso vedere.

La risposta è una cosa standard, che non ho il controllo di me stesso:

 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] 

Qualsiasi aiuto sarebbe apprezzato. Grazie.

Penso che un semplice codice possa rispondere a tutte le tue domande

 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: puoi trovare JsonConvert qui

Ho trovato la risposta. Ecco come definire un metodo, che può prendere i dati grezzi inviati in un POST HTTP:

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

e l’implementazione è come questa:

 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 }