Send a string in body via SendRequestAsync - c#

I need to send a Patch request to a backend API via SendRequestAsync func. This is regarding a UWP C# app.
Backend expected to like this:
On the app this is the code I wrote. But doesn't work
if (requestMehtod == ApplicationConstants.RequestType.PATCH)
{
Uri uri = new Uri(requestUrl);
HttpRequestMessage requestMessage = null;
if (postData != null)
{
var itemAsJson = JsonConvert.SerializeObject(postData);
requestMessage = new HttpRequestMessage(HttpMethod.Patch, uri)
{
Content = new HttpStringContent(itemAsJson, Windows.Storage.Streams.UnicodeEncoding.Utf8, "application/json-patch+json")
};
}
else
{
requestMessage = new HttpRequestMessage(HttpMethod.Patch, uri);
}
response = await httpClient.SendRequestAsync(requestMessage).AsTask(cancellationTokenSource.Token);
var rdModel = ProcessResponseData(response);
return await Handle401Error(rdModel, response, postData, url, requestMehtod, isDownloadSite, OnSendRequestProgress, requestData);
}
The above code fine to send JSON data to the same API and works fine. But I need to know how to send just a string in the body. Thank for the consideration
NOTE: App uses HttpClient from Windows.Web.Http and will not be able to use anything inside System.Net.Http namespace.

The answer is given by the #gusman and #Simon Wilson. Just to amend to their answer, in order to be able to send a string in the request body, the string needs to be within double-quotes.
var requestData = "\"hello world\"";
var request = new HttpRequestMessage(HttpMethod.Post, uri)
{
Content = new HttpStringContent(requestData, Windows.Storage.Streams.UnicodeEncoding.Utf8, "application/json")
};
response = await httpClient.SendRequestAsync(request);
This worked in my scenario.

Related

C# Post Variables can't be read on Website - HttpClient PostAsync()

I have a web server on which I'm hosting my own api for one of my projects.
This is the php-code of the api-website:
$user = $_POST['username'];
$password = $_POST['password'];
if(strcmp($user, "username") == 0 && strcmp($password, "password") == 0) {
...
} else {
die("No Permissions");
}
I want to send the two variables username and password with a HttpClient and the postAsync-method to this website and if the right log in data is detected, it returns the data I want.
For this I have the following code in C#:
Task<HttpResponseMessage> response;
var url = "www.url.de"; //not the url I'm actually calling!
var vars = "[{\"username\":\"username\", \"password\":\"password\"}]";
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
response = client.PostAsync(url, new StringContent(vars, Encoding.UTF8));
Console.WriteLine(response.Result.Content.ReadAsStringAsync().Result);
if (response.IsCompleted)
{
Console.WriteLine(response.Result.Content.ReadAsStringAsync().Result);
}
}
But the problem is that no matter what I have tried the output from this code is, that i have no permissions. And I have changed the php-code, so that I can see which data is stored in $username and $password, but they are empty and I don't know why. I hope somebody can help me with this.
Your PHP code is expecting the data sent as application/x-www-form-urlencoded, but your C# code is sending it as JSON.
As mentioned in the comment by M. Eriksson, you either need to change your PHP to accept JSON, or change your C# to send as form data.
This answer shows how to use HTTPClient to send data like that.
Here's my modification of your code based on the above code (I did test it):
public static async Task DoSomething()
{
string url = "http://httpbin.org/post"; //not the url I'm actually calling!
Dictionary<string, string> postData = new();
postData["username"] = "username";
postData["password"] = "password";
using HttpClient client = new();
client.DefaultRequestHeaders.Accept.Add(new("application/json"));
HttpRequestMessage request = new(HttpMethod.Post, url);
request.Content = new FormUrlEncodedContent(postData);
HttpResponseMessage response = await client.SendAsync(request);
Console.WriteLine(response.Content.ReadAsStringAsync().Result);
}

Trying to pass several headers in get request [duplicate]

I'm trying to set the Content-Type header of an HttpClient object as required by an API I am calling.
I tried setting the Content-Type like below:
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri("http://example.com/");
httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
httpClient.DefaultRequestHeaders.Add("Content-Type", "application/json");
// ...
}
It allows me to add the Accept header but when I try to add Content-Type it throws the following exception:
Misused header name. Make sure request headers are used with
HttpRequestMessage, response headers with HttpResponseMessage, and
content headers with HttpContent objects.
How can I set the Content-Type header in a HttpClient request?
The content type is a header of the content, not of the request, which is why this is failing. AddWithoutValidation as suggested by Robert Levy may work, but you can also set the content type when creating the request content itself (note that the code snippet adds application/json in two places-for Accept and Content-Type headers):
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://example.com/");
client.DefaultRequestHeaders
.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/json"));//ACCEPT header
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "relativeAddress");
request.Content = new StringContent("{\"name\":\"John Doe\",\"age\":33}",
Encoding.UTF8,
"application/json");//CONTENT-TYPE header
client.SendAsync(request)
.ContinueWith(responseTask =>
{
Console.WriteLine("Response: {0}", responseTask.Result);
});
For those who didn't see Johns comment to carlos solution ...
req.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
If you don't mind a small library dependency, Flurl.Http [disclosure: I'm the author] makes this uber-simple. Its PostJsonAsync method takes care of both serializing the content and setting the content-type header, and ReceiveJson deserializes the response. If the accept header is required you'll need to set that yourself, but Flurl provides a pretty clean way to do that too:
using Flurl.Http;
var result = await "http://example.com/"
.WithHeader("Accept", "application/json")
.PostJsonAsync(new { ... })
.ReceiveJson<TResult>();
Flurl uses HttpClient and Json.NET under the hood, and it's a PCL so it'll work on a variety of platforms.
PM> Install-Package Flurl.Http
try to use TryAddWithoutValidation
var client = new HttpClient();
client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8");
.Net tries to force you to obey certain standards, namely that the Content-Type header can only be specified on requests that have content (e.g. POST, PUT, etc.). Therefore, as others have indicated, the preferred way to set the Content-Type header is through the HttpContent.Headers.ContentType property.
With that said, certain APIs (such as the LiquidFiles Api, as of 2016-12-19) requires setting the Content-Type header for a GET request. .Net will not allow setting this header on the request itself -- even using TryAddWithoutValidation. Furthermore, you cannot specify a Content for the request -- even if it is of zero-length. The only way I could seem to get around this was to resort to reflection. The code (in case some else needs it) is
var field = typeof(System.Net.Http.Headers.HttpRequestHeaders)
.GetField("invalidHeaders", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)
?? typeof(System.Net.Http.Headers.HttpRequestHeaders)
.GetField("s_invalidHeaders", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
if (field != null)
{
var invalidFields = (HashSet<string>)field.GetValue(null);
invalidFields.Remove("Content-Type");
}
_client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "text/xml");
Edit:
As noted in the comments, this field has different names in different versions of the dll. In the source code on GitHub, the field is currently named s_invalidHeaders. The example has been modified to account for this per the suggestion of #David Thompson.
For those who troubled with charset
I had very special case that the service provider didn't accept charset, and they refuse to change the substructure to allow it...
Unfortunately HttpClient was setting the header automatically through StringContent, and no matter if you pass null or Encoding.UTF8, it will always set the charset...
Today i was on the edge to change the sub-system; moving from HttpClient to anything else, that something came to my mind..., why not use reflection to empty out the "charset"? ...
And before i even try it, i thought of a way, "maybe I can change it after initialization", and that worked.
Here's how you can set the exact "application/json" header without "; charset=utf-8".
var jsonRequest = JsonSerializeObject(req, options); // Custom function that parse object to string
var stringContent = new StringContent(jsonRequest, Encoding.UTF8, "application/json");
stringContent.Headers.ContentType.CharSet = null;
return stringContent;
Note: The null value in following won't work, and append "; charset=utf-8"
return new StringContent(jsonRequest, null, "application/json");
EDIT
#DesertFoxAZ suggests that also the following code can be used and works fine. (didn't test it myself, if it work's rate and credit him in comments)
stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
Some extra information about .NET Core (after reading erdomke's post about setting a private field to supply the content-type on a request that doesn't have content)...
After debugging my code, I can't see the private field to set via reflection - so I thought I'd try to recreate the problem.
I have tried the following code using .Net 4.6:
HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Get, #"myUrl");
httpRequest.Content = new StringContent(string.Empty, Encoding.UTF8, "application/json");
HttpClient client = new HttpClient();
Task<HttpResponseMessage> response = client.SendAsync(httpRequest); //I know I should have used async/await here!
var result = response.Result;
And, as expected, I get an aggregate exception with the content "Cannot send a content-body with this verb-type."
However, if i do the same thing with .NET Core (1.1) - I don't get an exception. My request was quite happily answered by my server application, and the content-type was picked up.
I was pleasantly surprised about that, and I hope it helps someone!
Call AddWithoutValidation instead of Add (see this MSDN link).
Alternatively, I'm guessing the API you are using really only requires this for POST or PUT requests (not ordinary GET requests). In that case, when you call HttpClient.PostAsync and pass in an HttpContent, set this on the Headers property of that HttpContent object.
The trick is that you can just set all kinds of headers like:
HttpRequestMessage request = new HttpRequestMessage();
request.Headers.Add("Accept-Language", "en"); //works OK
but not any header. For example:
request.Headers.Add("Content-Type", "application/json");//wrong
will raise the run-time exception Misused header name. It may seem that this will work:
request.Headers.Add(
HttpRequestHeader.ContentType.ToString(), //useless
"application/json"
);
but this gives a useless header named ContentType, without the hyphen. Header names are not case-sensitive, but are very hyphen-sensitive.
The solution is to declare the encoding and type of the body when adding the body to the Content part of the http request:
string Body = "...";
request.Content =
new StringContent(Body, Encoding.UTF8, "application/json");
Only then the applicable http header is automatically added to the request:
Content-Type: application/json; charset=utf-8
It was hard to find this out, with Fiddler, on a machine without a proxy server. Visual Studio used to have a Network Tool where you could inspect all headers, but only in version 2015, not in newer versions 2017 or 2022. If you use the debugger to inspect request.Headers, you will not find the header added automagically by StringContent().
var content = new JsonContent();
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
content.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("charset", "utf-8"));
content.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("IEEE754Compatible", "true"));
It's all what you need.
With using Newtonsoft.Json, if you need a content as json string.
public class JsonContent : HttpContent
{
private readonly MemoryStream _stream = new MemoryStream();
~JsonContent()
{
_stream.Dispose();
}
public JsonContent(object value)
{
Headers.ContentType = new MediaTypeHeaderValue("application/json");
using (var contexStream = new MemoryStream())
using (var jw = new JsonTextWriter(new StreamWriter(contexStream)) { Formatting = Formatting.Indented })
{
var serializer = new JsonSerializer();
serializer.Serialize(jw, value);
jw.Flush();
contexStream.Position = 0;
contexStream.WriteTo(_stream);
}
_stream.Position = 0;
}
private JsonContent(string content)
{
Headers.ContentType = new MediaTypeHeaderValue("application/json");
using (var contexStream = new MemoryStream())
using (var sw = new StreamWriter(contexStream))
{
sw.Write(content);
sw.Flush();
contexStream.Position = 0;
contexStream.WriteTo(_stream);
}
_stream.Position = 0;
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
return _stream.CopyToAsync(stream);
}
protected override bool TryComputeLength(out long length)
{
length = _stream.Length;
return true;
}
public static HttpContent FromFile(string filepath)
{
var content = File.ReadAllText(filepath);
return new JsonContent(content);
}
public string ToJsonString()
{
return Encoding.ASCII.GetString(_stream.GetBuffer(), 0, _stream.GetBuffer().Length).Trim();
}
}
It appears that Microsoft tries to force the developers to follow their standards, without even giving any options or settings to do otherwise, which is really a shame especially given that this is a client and we are dictated by the server side requirements, especially given that Microsoft server side frameworks themselves require it!
So basically Microsoft tries to force us good habits when connecting to their server technologies that force us non good habits...
If anyone from Microsoft is reading this, then please fix it...
Either way for anyone that needs the content-type header for Get etc., while in an older .Net version it is possible to use the answer of #erdomke at https://stackoverflow.com/a/41231353/640195 this unfortunately no longer works in the newer .Net core versions.
The following code has been tested to work with .Net core 3.1 and from the source code on GitHub it looks like it should work with newer .Net versions as well.
private void FixContentTypeHeaders()
{
var assembly = typeof(System.Net.Http.Headers.HttpRequestHeaders).Assembly;
var assemblyTypes = assembly.GetTypes();
var knownHeaderType = assemblyTypes.FirstOrDefault(n => n.Name == "KnownHeader");
var headerTypeField = knownHeaderType?
.GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
.FirstOrDefault(n => n.Name.Contains("HeaderType"));
if (headerTypeField is null) return;
var headerTypeFieldType = headerTypeField.FieldType;
var newValue = Enum.Parse(headerTypeFieldType, "All");
var knownHeadersType = assemblyTypes.FirstOrDefault(n => n.Name == "KnownHeaders");
var contentTypeObj = knownHeadersType.GetFields().FirstOrDefault(n => n.Name == "ContentType").GetValue(null);
if (contentTypeObj is null) return;
headerTypeField.SetValue(contentTypeObj, newValue);
}
You can use this it will be work!
HttpRequestMessage msg = new HttpRequestMessage(HttpMethod.Get,"URL");
msg.Content = new StringContent(string.Empty, Encoding.UTF8, "application/json");
HttpResponseMessage response = await _httpClient.SendAsync(msg);
response.EnsureSuccessStatusCode();
string json = await response.Content.ReadAsStringAsync();
Ok, it's not HTTPClient but if u can use it, WebClient is quite easy:
using (var client = new System.Net.WebClient())
{
client.Headers.Add("Accept", "application/json");
client.Headers.Add("Content-Type", "application/json; charset=utf-8");
client.DownloadString(...);
}
try to use HttpClientFactory
services.AddSingleton<WebRequestXXX>()
.AddHttpClient<WebRequestXXX>("ClientX", config =>
{
config.BaseAddress = new System.Uri("https://jsonplaceholder.typicode.com");
config.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
config.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8");
});
======================
public class WebRequestXXXX
{
private readonly IHttpClientFactory _httpClientFactory;
public WebRequestXXXX(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public List<Posts> GetAllPosts()
{
using (var _client = _httpClientFactory.CreateClient("ClientX"))
{
var response = _client.GetAsync("/posts").Result;
if (response.IsSuccessStatusCode)
{
var itemString = response.Content.ReadAsStringAsync().Result;
var itemJson = System.Text.Json.JsonSerializer.Deserialize<List<Posts>>(itemString,
new System.Text.Json.JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
return itemJson;
}
else
{
return new List<Posts>();
}
}
}
}
I got the answer whith RestSharp:
private async Task<string> GetAccessTokenAsync()
{
var client = new RestClient(_baseURL);
var request = new RestRequest("auth/v1/login", Method.POST, DataFormat.Json);
request.AddHeader("Content-Type", "application/json");
request.AddHeader("x-api-key", _apiKey);
request.AddHeader("Accept-Language", "br");
request.AddHeader("x-client-tenant", "1");
...
}
It worked for me.
You need to do it like this:
HttpContent httpContent = new StringContent(#"{ the json string }");
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage message = client.PostAsync(#"{url}", httpContent).Result;
For those wanting to set the Content-Type to Json specifically, you can use the extension method PostAsJsonAsync.
using System.Net.Http.Json; //this is needed for PostAsJsonAsync to work
//....
HttpClient client = new HttpClient();
HttpResponseMessage response = await
client.PostAsJsonAsync("http://example.com/" + "relativeAddress",
new
{
name = "John Doe",
age = 33
});
//Do what you need to do with your response
The advantage here is cleaner code and you get to avoid stringified json. More details can be found at: https://learn.microsoft.com/en-us/previous-versions/aspnet/hh944339(v=vs.118)
I find it most simple and easy to understand in the following way:
async Task SendPostRequest()
{
HttpClient client = new HttpClient();
var requestContent = new StringContent(<content>);
requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await client.PostAsync(<url>, requestContent);
var responseString = await response.Content.ReadAsStringAsync();
}
...
SendPostRequest().Wait();
I end up having similar issue.
So I discovered that the Software PostMan can generate code when clicking the "Code" button at upper/left corner. From that we can see what going on "under the hood" and the HTTP call is generated in many code language; curl command, C# RestShart, java, nodeJs, ...
That helped me a lot and instead of using .Net base HttpClient I ended up using RestSharp nuget package.
Hope that can help someone else!
Api returned
"Unsupported Media Type","status":415
Adding ContentType to the jsonstring did the magic and this is my script working 100% as of today
using (var client = new HttpClient())
{
var endpoint = "api/endpoint;
var userName = "xxxxxxxxxx";
var passwd = "xxxxxxxxxx";
var content = new StringContent(jsonString, Encoding.UTF8, "application/json");
var authToken = Encoding.ASCII.GetBytes($"{userName}:{passwd}");
client.BaseAddress = new Uri("https://example.com/");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(authToken));
HttpResponseMessage response = await client.PostAsync(endpoint, content);
if (response.IsSuccessStatusCode)
{
// Get the URI of the created resource.
Uri returnUrl = response.Headers.Location;
Console.WriteLine(returnUrl);
}
string responseBody = await response.Content.ReadAsStringAsync();
return responseBody;
}
For my scenario, a third-party API was creating the HttpRequestMessage, so I was not able to use the top-voted answers to resolve the issue. And I didn't like the idea of messing with reflection so the other answers didn't work either.
Instead, I extended from AndroidMessageHandler and used this new class as a parameter to HttpClient. AndroidMessageHandler contains the method SendAsync which can be overridden in order to make changes to the HttpRequestMessage object before it is sent. If you don't have access to the Android Xamarin libaries, you may be able to figure something out with HttpMessageHandler.
public class XamarinHttpMessageHandler : global::Xamarin.Android.Net.AndroidMessageHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// Here I make check that I'm only modifying a specific request
// and not all of them.
if (request.RequestUri != null && request.RequestUri.AbsolutePath.EndsWith("download") && request.Content != null)
{
request.Content.Headers.Add("Content-Type", "text/plain");
}
return base.SendAsync(request, cancellationToken);
}
}
Then to use:
var client = new HttpClient(new XamarinHttpMessageHandler());
So if you're trying to do a /$batch OData request like this Microsoft article demonstrates where you're supposed to have a Content-Type header like:
Content-Type: multipart/mixed;boundary=batch_d3bcb804-ee77-4921-9a45-761f98d32029
string headerValue = "multipart/mixed;boundary=batch_d3bcb804-ee77-4921-9a45-761f98d32029";
//You need to set it like thus:
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(headerValue);
Again, the magic you need is: MediaTypeHeaderValue.Parse(...)
stringContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
And 🎉 YES! 🎉 ... that cleared up the problem with ATS REST API: SharedKey works now! 😄 👍 🍻
Source: https://github.com/dotnet/runtime/issues/17036#issuecomment-212046628

Rewriting a Java HttpURLConnection method using C# HttpClient

I've got a working Java method that uses java.net.HttpURLConnection that I should re-implement in C# using the .NET HttpClient.
Java method:
public static String getMyThingAPIToken() throws IOException{
URL apiURL = new URL("https://myThingAPI/token");
HttpURLConnection apiConnection = (HttpURLConnection) apiURL.openConnection();
apiConnection.setRequestMethod("POST");
apiConnection.setDoOutput(true);
String apiBodyString = "myThingAPI login id and secret key";
byte[] apiBody = apiBodyString.getBytes(StandardCharsets.UTF_8);
OutputStream apiBodyStream = apiConnection.getOutputStream();
apiBodyStream.write(apiBody);
StringBuffer apiResponseBuffer;
try (BufferedReader in = new BufferedReader(new InputStreamReader(apiConnection.getInputStream()))){
String inputline;
apiResponseBuffer = new StringBuffer();
while((inputline = in.readLine()) != null) {
apiResponseBuffer.append(inputline);
}
}
}
So far, my C# looks like below, and you'll notice that this early form of my implementation does not interpret the response. Nor does it have a string return type required for the token string.
This is because when I test it, the response has:
StatusCode: 400
ReasonPhrase: 'Bad Request'
So something in my apiBody byte array or use of PostAsync must be different to what the Java method does, but I cannot work out what it could be.
public async static Task<HttpResponseMessage> getMyThingAPIToken(HttpClient client)
{
var apiURI = new Uri("https://myThingAPI/token");
string apiBodystring = "myThingAPI login id and secret key";
byte[] apiBody = System.Text.Encoding.UTF8.GetBytes(apiBodystring);
var response = await client.PostAsync(apiURI, new ByteArrayContent(apiBody));
return response;
}
The Java code doesn't specify a type which means that by default the request uses application/x-www-form-urlencoded. This is used for FORM POST requests.
The default content type for ByteArrayContent on the other hand is application/octet-stream while for StringContent it's text/plain.
FORM content is used through the FormUrlEncoodedContent class which can accept any Dictionary<string,string> as payload.
The input in the question is not in a x-www-form-urlencoded form so either it's not the real content or the API is misusing content types.
Assuming the API accepts proper x-www-form-urlencoded content, the following should work:
var data=new Dictionary<string,string>{
["login"]=....,
["secret"]=.....,
["someOtherField"]=....
};
var content= new FormUrlEncodedContent(data);
var response=await client.PostAsync(apiURI,content);
To send any text using application/x-www-form-urlencoded, we need to specify the content type in StringContent's constructor:
var contentType="application/x-www-form-urlencoded";
var content= new StringContent(apiBodyString, Encoding.UTF8,contentType);
var response=await client.PostAsync(apiURI,content);
Can you try using following code:
client.BaseAddress = new Uri("https://myThingAPI/");
var message = new HttpRequestMessage(HttpMethod.Post, "/token");
// Add your login id and secret key here with the format you want to send
message.Content = new StringContent(string.Format("userName={0}&password={1}", UserName, Password));
var result = await client.SendAsync(message);
return result;

PATCH request to the service doesn't work within my C# application, but works in Fiddler

I am currently developing a REST-ful C# application that works with an external service. I have gotten basic 'GET', 'POST', 'PUT', and 'DELETE' requests to work, however whenever I attempt to send a PATCH request to the same service, it does not work. I get a 200 message (meaning it was successful), but doing a GET on the subject that I am trying to attempt the PATCH request on shows that no change occurred.
Additionally, whenever I use Fiddler to form PATCH requests, using the same URL and content string, it works as expected.
I am attempting to ensure that it isn't something I am doing wrong in regards to how I am sending the HTTP request.
My call that interacts with all of the different above REST functions is as follows:
public async Task<T> GetResultFromService<T>(string requesttype, string url, string request = "")
{
HttpRequestMessage message;
switch (requesttype)
{
case "Post":
message = PostRequest(url, client, request);
break;
case "Put":
message = PutRequest(url, client, request);
break;
case "Patch":
message = PatchRequest(url, client, request);
break;
case "Delete":
message = DeleteRequest(url, client);
break;
default:
message = GetRequest(url, client);
break;
}
var response = await client.SendAsync(message);
var responseString = await response.Content.ReadAsStringAsync();
return IModel.FromJson<T>(responseString);
}
My function for forming the PATCH request:
public HttpRequestMessage PatchRequest(string url, HttpClient client, string content = "")
{
var request = new HttpRequestMessage(new HttpMethod("PATCH"), url);
return request;
}
Adding a GET request for comparison:
public HttpRequestMessage GetRequest(string url, HttpClient client)
{
var request = new HttpRequestMessage(HttpMethod.Get, url);
return request;
}
And my Httpclient code (if it is at all relevant...):
var proxy = new WebProxy
{
Address = ServerEnv.ProxyUri
};
var httpHandler = new HttpClientHandler
{
Proxy = proxy,
UseProxy = true
};
client = new HttpClient(httpHandler, true);
Any sort of direction you can point me in would be greatly appreciated.
Thanks a ton!
edit: I realized my mistake due to the answerer's reply. Basically I accidentally left out the body on my PATCH, but it was on my POST and PUT and I had overlooked that detail. POST code for detail:
public HttpRequestMessage PostRequest(string url, HttpClient client, string content)
{
var request = new HttpRequestMessage(HttpMethod.Post, url)
{
Content = new StringContent(content,
Encoding.UTF8,
"application/json")
};
return request;
}
and the revised PATCH:
public HttpRequestMessage PatchRequest(string url, HttpClient client, string content = "")
{
var request = new HttpRequestMessage(new HttpMethod("PATCH"), url)
{
Content = new StringContent(content,
Encoding.UTF8,
"application/json")
};
return request;
}
If any lesson can be learned from this, it would be that you should double and triple check copy and pasted code. Thanks again!
Your POST, PUT and PATCH requests are missing a body. How should the service handing the request know what you want to change on the resource? You need to set the Content property on the HttpRequestMessage.
See this answer for an example.

Send and receive a post variable

I'm trying to send a post variable to the url which I'm redirecting to.
I'm currently using the Get method and sending it like this:
// Redirect to page with url parameter (GET)
Response.Redirect("web pages/livestream.aspx?address="+ ((Hardwarerecorders.Device)devices[arrayIndex]).streamAddress);
And retrieving it like this:
// Get the url parameter here
string address = Request.QueryString["address"];
How do I convert my code to use the POST method?
B.T.W., I don't want to use a form to send the post variable.
Using HttpClient:
To send POST query:
using System.Net.Http;
public string sendPostRequest(string URI, dynamic content)
{
var client = new HttpClient();
client.BaseAddress = new Uri("http://yourBaseAddress");
var valuesAsJson = JsonConvert.SerializeObject(content);
HttpContent contentPost = new StringContent(valuesAsJson, Encoding.UTF8, "application/json");
var result = client.PostAsync(URI, contentPost).Result;
return result.Content.ReadAsStringAsync().Result;
}
Where 'client.PostAsync(URI, contentPost)' is where the content is being sent to the other website.
On the other website, an API Controller needs to be established to receive the result, something like this:
[HttpPost]
[Route("yourURI")]
public void receivePost([FromBody]dynamic myObject)
{
//..
}
However, you might also want to look into using a 307 re-direct, especially if this is a temporary solution.
https://softwareengineering.stackexchange.com/a/99966
using System.Net.Http;
POST
using (var client = new HttpClient())
{
var values = new Dictionary<string, string>
{
{ "thing1", "hello" },
{ "thing2", "world" }
};
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("http://www.example.com/recepticle.aspx", content);
var responseString = await response.Content.ReadAsStringAsync();
}
GET
using (var client = new HttpClient())
{
var responseString = client.GetStringAsync("http://www.example.com/recepticle.aspx");
}
My Personal Choice is Restsharp it's fast but for basic operations you can use this

Categories