I am struggling sending data from my rest client to my rest server...
I have created a rest server sending xml to the client, and that works well. However, sending data from the client to the server, I am having a hard time.
Client:
_httpClientRead = new HttpClient("http://127.0.0.1:8000/");
var form = new HttpUrlEncodedForm();
form.Add("startDate", startDate);
_httpClientRead.Post("test", form.CreateHttpContent())
Server:
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "test")]
Meeting CreateNewMeeting(string startDate);
The problem seems to be the HttpUrlEncodedForm on the client side. If I am sending an empty HttpUrlEncodedForm object in the post request, the server receives the request. When adding the HttpUrlEncodedForm attributes, the server never receives the request, and there are no error messages!
What am I missing here? ( the server is returning xml )
How should the post data be sent to the server?
Thanks
I think it is a problem that you use HttpUrlEncodedForm on the client side, while the default on the server side is Xml. To make it clear set the request format on the server side to be RequestFormat = WebMessageFormat.Xml (set this in the WebIncoke attribute). After doing this you can configure your client to send valid xml. Also make sure you use the correct xml namespace. The easiest way to handle this is to use a function that will create the content automagically for you:
var httpContent = HttpContentExtensions.CreateDataContract(objectToSendToServer);
// And then send it using post:
_httpClient.Post("serviceUrl", httpContent);
Note that you also need set the DefaultHeader on the HttpClient to "application/xml".
WCF expects the data to be sent serialized by the DataContractSerializer. You cannot send other media types like application/x-www-form-urlencoded by default.
See this question on how to do it. Best way to support "application/x-www-form-urlencoded" post data with WCF?
Related
I want to send information about the current client version from the server in all responses to the callers.
I want to have this information in the HTTP header. But I am not able to read the headers in the client.
I call the method WriteResponseHeaderAsync in the server method or interceptor (tried both). I see (Fiddler) that the header is in the response header.
But, I cannot read this header on the client or in the interceptor on the client. I tried everything.
My code in method:
var result = AuthorizationClient.LoginAsync(loginRequest);
var responseHeaders = await result.ResponseHeadersAsync;
ResponseHeaders is empty (responseHeaders.Count is 0) all time. I am able to use Trailers but the right place is HTTP header.
Is possible to read the response headers? Is possible to read the response headers in interceptors?
If yes, how?
I am using: C#, Grpc.AspNetCore.Web 2.51.0 (on server), Grpc.Net.Client.Web 2.51.0 (Client. Blazor WebAssembly)
I have self-hosted WCF service. It works as charm, when the input data format is known, but it's not my case.
My service would be invoked like a HTML form would be posted to it, but I don't know exact list of parameters which would be sent.
External web service would send a HTTP request with content "a=foo&b=bar", yes, URL-encoded. Parameters in content may vary. Their count may vary. Some parameters may or may not be present. So I'm perfectly fine with whole URL-encoded string, I'll decode it myself. I have to reply with ASCII string "OK".
How to access this "a=foo&b=bar" text from the request? Can I create my own encoder? How it's done?
Here's what I started with, the contract:
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "test", BodyStyle = WebMessageBodyStyle.Bare)]
Stream TestPostRequest();
And here's the method:
public Stream TestPostRequest() {
var maxByteSize = 16384;
var messageStream = new MemoryStream(maxByteSize);
var messageBuffer = OperationContext.Current.RequestContext.RequestMessage.CreateBufferedCopy(maxByteSize);
messageBuffer.WriteMessage(messageStream);
var rawRequestData = new byte[maxByteSize];
messageStream.Read(rawRequestData, 0, maxByteSize);
var requestDataString = Encoding.UTF8.GetString(rawRequestData);
Console.WriteLine(requestDataString);
var responseData = new byte[2] { 79, 75 }; // OK
var responseStream = new MemoryStream(responseData);
return responseStream;
}
Obviously it doesn't work, because CreateBufferedCopy method expects XML as input data, but gets URL-encoded string. As all the other methods I found.
I'm not afraid of creating new class implementing IEndpointBehavior or IDispatchMessageInspector, but I just don't see where I could implement something allowing me to access the request data raw, as bytes, not XML.
Maybe there is a point where I could convert raw data to XML?
EDIT:
My fault, there was a broken behavior in my operation stack which messed with message content type badly. The moral is - test new features isolated, in a clean test project. The second moral is WCF can everything ;) And the third is: if there is no XML in message internal data - you broke it ;)
I am using RestSharp for developing on the client side. I am also using Ruby Grape gem for my custom API on server side. Grape gem can do versioning by setting Accept HTTP header f.e to application/vnd.twitter-v1+json
And test command via console works perfect
curl -H Accept=application/vnd.twitter-v1+json /statuses/public_timeline
But when I am trying to set up header for RestRequest I am getting error 404 on the server.
I have no idea why so. I have found another issue that server returns 406 error - but in my case 404.
How can I put custom value for Accept header?
You can set a custom Accept header with the AddHeader method...
var client = new RestClient("http://example.com/api");
var request = new RestRequest("statuses/public_timeline", Method.GET);
request.AddHeader("Accept", "application/vnd.twitter-v1+json");
var response = client.Execute(request);
var json = response.Content;
This should work fine if you are willing to deserialize the JSON yourself.
If you want to make use of the generic Execute<T> method, which does automatic deserialization for you, you will run into problems...
From the RestSharp documentation about deserialization:
RestSharp includes deserializers to process XML and JSON. Upon receiving a response, RestClient chooses the correct deserializer to use based on the Content Type returned by the server. The defaults can be overridden (see Customization). The built-in content types supported are:
application/json – JsonDeserializer
application/xml – XmlDeserializer
text/json – JsonDeserializer
text/xml – XmlDeserializer
* – XmlDeserializer (all other content types not specified)
This is saying that, by default, if the response's content type is not one of those listed, RestSharp will attempt to use the XmlDeserializer on your data. This is customizable though with extra work.
Trying to receive COSM Trigger HTTP Post via a C# RESTful service, not receiving the alert. I took the COSM API JSON payload and used it from a test client - that worked. When I setup my feed and either try the debug trigger test, or just force the trigger to fire normally, my REST service doesn't get called. If I try any form of test client the service processes the JSON POST just fine.
C# service is here:
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "cosm",
RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
string CosmAlert(CosmTrigger data);
Where CosmTrigger is my class mirroring the COSM Trigger fields.
My COSM feed is here.
I'm starting from the COSM portal to fire a trigger, Twitter based trigger works fine, the HTTP Post to my URL isn't. How to debug this?
A Cosm trigger currently doesn't send triggers as a JSON body, it actually sends a URL encoded request with the JSON trigger body encoded as a parameter called 'body'.
Using http://requestb.in on a test trigger, and viewing the raw output this shows the basic request looks like this:
POST /103s0dh1 HTTP/1.1
X-Request-Id: e05e9d699edbd5f584fc491cf9416df747be4df4
User-Agent: Cosm Deliverator (Axino/0.3.02) - https://cosm.com
Host: requestb.in
Content-Type: application/x-www-form-urlencoded
Content-Length: 918
Connection: close
body=%7B%22id%22%3A7443%2C%22url%22%3A%22http%3A%2F%2Fapi.cosm.com%2Fv2%2Ftriggers%2F7443%22%2C%22type%22%3A%22lt%22%2C%22threshold_value%22%3A%2220%22%2C%22timestamp%22%3A%222013-04-14T09%3A50%3A47.590044Z%22%2C%22environment%22%3A%7B%22id%22%3A57346%2C%22feed%22%3A%22http%3A%2F%2Fapi.cosm.com%2Fv2%2Ffeeds%2F57346%22%2C%22title%22%3A%22Macbook+Battery+Level%22%2C%22description%22%3A%22%22%2C%22private%22%3Afalse%2C%22location%22%3A%7B%22lat%22%3Anull%2C%22lon%22%3Anull%2C%22name%22%3A%22%22%7D%7D%2C%22triggering_datastream%22%3A%7B%22id%22%3A%22battery%22%2C%22url%22%3A%22http%3A%2F%2Fapi.cosm.com%2Fv2%2Ffeeds%2F57346%2Fdatastreams%2Fbattery%22%2C%22at%22%3A%222013-04-14T09%3A50%3A02.406927Z%22%2C%22value%22%3A%7B%22max_value%22%3A1724.0%2C%22min_value%22%3A0.0%2C%22value%22%3A%2226.28%22%7D%2C%22units%22%3A%7B%22type%22%3Anull%2C%22symbol%22%3A%22%25%22%2C%22label%22%3Anull%7D%7D%2C%22debug%22%3Atrue%7D
I'm not a C# expert unfortunately but I suspect the problem is something to do with the service not being configured to extract the JSON body from a standard urlencoded request body, but perhaps this might give a clue to how to figure out what is going wrong for someone who does know C#.
Tested and working code -
[OperationContract]
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.WrappedRequest,
UriTemplate = "cosm")]
string cosmStream(Stream body);
when using HttpClient and performing a PostAsync I am able to add a contract with HttpContent. for example
HttpContent content = new ObjectContent<myContractType>(MyContract, xmlFormatter);
var resp myClient.PostAsync(myUri,content).Result
when doing a GetAsync I am unable to pass a HttpContract object. That said do I need to just add the members of the contract in a query string or is there a better way to go about it?
The nature of GET requests does not provide a way to send large amounts of data to the server as might be done with a POST request. In practice, a limited amount of data can be sent in the form of headers or as part of a querystring.
There won't be a way to convert the XML data directly to a querystring, but this is an example of a request with a querystring:
var client = new HttpClient()
client.GetAsync(String.Format("http://service.example.com/api/{0}?foo=bar", id))