I have this code that is working fine in .NET 4.5.
var handler = new HttpClientHandler();
handler.UseDefaultCredentials = true;
handler.PreAuthenticate = true;
handler.ClientCertificateOptions = ClientCertificateOption.Automatic;
var client = new HttpClient(handler);
client.BaseAddress = new Uri("http://localhost:22678/");
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var loginBindingModel = new LoginBindingModel { Password = "test01", UserName = "test01" };
var response = await client.PostAsJsonAsync("api/Account/Login", loginBindingModel);
response.EnsureSuccessStatusCode(); // Throw on error code.
tokenModel = await response.Content.ReadAsAsync<TokenModel>();
Now I have to do the same thing in .NET 4.0.
But I am facing two problems I do not know how to resolve them.
In .NET 4.0. method client.PostAsJsonAsync does not exist.
The existing method is client.PostAsync and it needs HttpContext.
I do request within WPF client... Guys, I have no clue what I can do to archive the same functionality...
Please, help!
Suggest using the BCL / async / "Microsoft HTTP Client Libraries" helper projects to "supplement" .Net 4.0 with equivalent functionality to .Net 4.5 (Can find the latest versions in the NuGet package manager.)
See the following link for more info: http://www.nuget.org/packages/microsoft.bcl.async
(Note: you can get support for http client via same basic mechanism)
Just for someone who is looking for the same .NET 4.0 pure solution I found that code working fine. But It does not have ASYNC/AWAIT thing that should be implemented as well. Anyway it is working exactly the same way as my code in the question.
var webAddr = "http://localhost:22678/api/Account/Login";
var httpWebRequest = (HttpWebRequest)WebRequest.Create(webAddr);
httpWebRequest.ContentType = "application/json; charset=utf-8";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
var loginBindingModel = new WebAPILoginBindingModel { Password = "test01", UserName = "test01" };
var myJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(loginBindingModel);
streamWriter.Write(myJsonString);
streamWriter.Flush();
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
If you want to use use ASYNC/AWAIT for .NET 4.0 you have to install Microsoft.BCL dll and use async versions of HttpClient as well.
Even after installing the following packages i got other errors.
Install-Package Microsoft.Net.Http
Install-Package System.Net.Http.Formatting.Extension
Turns out Install-Package System.Net.Http.Formatting.Extension installs version of system.net that does not support dot net 4. So I has to stick to PostAsync and create an httpContent object from my custom object.
So
PostAsJsonAsync("api/Account/Login", loginBindingModel)
Becomes (Note i used json.net here )
public HttpContent CreateHttpContent(object data)
{
return new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");
}
PostAsync("api/Account/Login",CreateHttpContent(loginBindingModel))
Related
EDIT2: It also works with .NET 7.0, straight on my mac machine... I can't upgrade to 7.0 though, so I am still stuck...
EDIT: Running the exact same code on a docker container with .NET 6 also works... Could this problem only happens on MacOS ?
I am facing a weird issue in which I am trying to make an https call with a client certificate authentication and I am getting a "400 The SSL certificate error" response from the server.
The weirdness is that running the EXACT same code with .NET Core 3.1 simply works...
Has anyone seen anything like that?
I wrote a simplified version of my code, but it reproduces the problem perfectly:
const string url = "https://myservice";
const string path = "myendpoint";
var fileData = File.ReadAllBytes("/some/certificate.p12");
var certificate = new X509Certificate2(fileData, "the_cert_password");
var handler = new HttpClientHandler
{
ClientCertificateOptions = ClientCertificateOption.Manual
};
handler.ClientCertificates.Add(certificate);
var httpClient = new HttpClient(handler)
{
BaseAddress = new Uri(url)
};
var httpMessage = new HttpRequestMessage
{
Content = new StringContent("{}", Encoding.UTF8, "application/json"),
Method = HttpMethod.Post,
RequestUri = new Uri($"{httpClient.BaseAddress}{path}")
};
var result = await httpClient.SendAsync(httpMessage);
var content = await result.Content.ReadAsStringAsync();
Console.WriteLine(content);
Sorry for the awful title, I'm not really sure how to phrase my issue in a short title format.
I'm trying to communicate with an external API. I make a basic authentication request to that API and get an x-csrf-token and a session token from the api.
I then make another request to that API, now using the x-csrf-token as a header and attach the session token to the header as "cookie".
The team that maintains the API sent me an example project that handles all of the above, and it looks like this:
public static async Task<string> Send(string apiname, string value)
{
// Fetch the authorization tokens from SAP
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(basePath);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(user + ":" + password)));
client.DefaultRequestHeaders.Add("x-csrf-token", "Fetch");
string csrfToken = "";
string sessionCookie = "";
HttpResponseMessage response = await client.GetAsync(string.Empty);
IEnumerable<string> values;
if (response.Headers.TryGetValues("x-csrf-token", out values))
{
csrfToken = values.FirstOrDefault();
}
if (response.Headers.TryGetValues("set-cookie", out values))
{
sessionCookie = values.Where(s => s.StartsWith("SAP_SESSION")).FirstOrDefault();
}
// Reinstantiate the HttpClient, adding the tokens we just got from SAP
client = new HttpClient();
client.DefaultRequestHeaders.Add("x-csrf-token", csrfToken);
client.DefaultRequestHeaders.Add("cookie", sessionCookie);
client.BaseAddress = new Uri(basePath);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Have to parse the string this way otherwise it'll break the dates
JToken token;
using (var sr = new StringReader(value))
using (var jr = new JsonTextReader(sr) { DateParseHandling = DateParseHandling.None })
{
token = JToken.ReadFrom(jr);
}
HttpResponseMessage response2 = await client.PostAsJsonAsync(apiname, token);
string responseBody = await response2.Content.ReadAsStringAsync();
return responseBody;
}
This all works great as a .NET Core webAPI (and also as a .netcore console app).
Interestingly enough (in my opinion anyway), when I use the exact same code in a .net 4.7.2 project, it doesn't append the "cookie" header properly, and so I'm getting an unauthorized redirect back from the API.
To be absolutely sure that I didn't change any code, I started from scratch with a brand new .netcore 2.0 console app and a brand new .net 4.7.2 console app and copy-pasted the exact same code and installed the same nuget packages (Newtonsoft.JSON and Microsoft.WebApi.Client). I inspected my web traffic with fiddler (seen below) and you can see that in .netcore, the cookie appends properly and everything works, but in .net 4.7.2, the API returns a redirect to authenticate.
HttpClient will eat the custom cookie if you do not setUseCookies to false,
using (var handler = new HttpClientHandler { UseCookies = false })
using (client = new HttpClient(handler) { BaseAddress = new Uri(Path) }){
client.DefaultRequestHeaders.Add("cookie", cookieValue);
}
It will try to use the cookie container and at the same time ignore any custom cookie headers, very frustrating behavior if you ask me.
.Net Framework uses Cookie Container.
Also core, perhaps its a better implementation then what you are doing now and more supported.
Please see cookie container docs
Small example:
var cookieContainer = new CookieContainer();
this.handler = new HttpClientHandler
{
CookieContainer = cookieContainer,
UseCookies = true
};
client = new HttpClient(handler);
I have developed a Web API, I can access my api by using HttpClient in .NET 4 and 4.5 but I want to access this api from an existing .NET 3.5 application. Is it possible? I have learned from internet that HttpClient is not supported in .net 3.5, so how I consume this service in .net 3.5 application?
Checkout this link for .net version 3.5:
OR TRY THIS FOR 3.5
System.Net.WebClient client = new System.Net.WebClient();
client.Headers[HttpRequestHeader.ContentType] = "application/json";
client.BaseAddress = "ENDPOINT URL";
string response = client.DownloadString(string.Format("{0}?{1}", Url, parameters.UrlEncode()));
This is how I am making call in .net 4.5.
var url = "YOUR_URL";
var client = new HttpClient();
var task = client.GetAsync(url);
return task.Result.Content.ReadAsStringAsync().Result;
You could use WebRequest
// Create a request for the URL.
var request = WebRequest.Create ("http://www.contoso.com/default.html");
request.ContentType = contentType; //your contentType, Json, text,etc. -- or comment, for text
request.Method = method; //method, GET, POST, etc -- or comment for GET
using(WebResponse resp = request.GetResponse())
{
if(resp == null)
new Exception("Response is null");
return resp.GetResponseStream();//Get stream
}
I am using Microsoft.AspNet.WebApi.Client to consume rest services in my ASP.MVC 5 project. I am following the this tutorial to make use of HttpClient. The code is not compiling since ReadAsAsync method is no longer available in HttpContent. After digging a bit I came to know that it is an extension method defined in System.Net.Http.Formatting.dll. I found a nuget package for the same dll here but the package is deprecated and I am not able to install it. I also trid to search that dll in Program Files folder according to this post but I could not get it. Any ideas how to make ReadAsAsync work? Any help greatly appreiciated. Thanks.
What do you need to do is to add new reference System.Net.HttpClient; and System.Net.HttpClient.Formating;.
This is my sample codes in HttpClient:
The following codes is use to get a certificate from saba using HttpClient.
using System.Net.Http;
using System.Net.Http.Headers;
using GoSaba.Models.Saba;
namespace GoSaba.Controllers.Saba
{
class LoginController
{
//HTTP GET: Saba/api/login
public async Task<string> GetCertificate(string host, string user, string password, string site)
{
StringBuilder getCertificate = new StringBuilder();
if(!string.IsNullOrEmpty(host))
{
using(var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri(string.Format("http://{0}/", host));
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.DefaultRequestHeaders.Add("user", user);
httpClient.DefaultRequestHeaders.Add("password", password);
httpClient.DefaultRequestHeaders.Add("site", site);
HttpResponseMessage httpResponse = await httpClient.GetAsync("Saba/api/login");
if(httpResponse.IsSuccessStatusCode)
{
LoginModel.GetCertificate saba = await httpResponse.Content.ReadAsAsync<LoginModel.GetCertificate>();//LoginModel.GetCertificate is model.
getCertificate.Append(saba.certificate);
}
}
}
return getCertificate.ToString();
}
}
}
You can use this a reference in how to use a HttpClient.
Here is an alternate way using the same Microsoft.AspNet.WebApi.Client. The number of lines of code increase but you wont find any issue like Newtonsoft version issue, which prompted me to look at alternatives for ReadAsAsync.
Here is a link that explains the code - https://www.newtonsoft.com/json/help/html/Performance.htm
HttpClient client = new HttpClient();
using (Stream s = client.GetStreamAsync("http://www.test.com/large.json").Result)
using (StreamReader sr = new StreamReader(s))
using (JsonReader reader = new JsonTextReader(sr))
{
JsonSerializer serializer = new JsonSerializer();
// read the json from a stream
// json size doesn't matter because only a small piece is read at a time from the HTTP request
T p = serializer.Deserialize<T>(reader); // Where T is any type
}
I'm trying to download a string from ANY webpage within my portable class library. I've created the most basic setup:
created a new PCL project
compatible with WP8 and WinRT as well as the compulsory components such as Silverlight
As WebClient is not compatible across these systems, it is not possible to use:
string data = new WebClient().DownloadString();
I've tried using this as well (uses this):
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = HttpMethod.Get;
HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
string data = ""
using (var sr = new StreamReader(response.GetResponseStream()))
{
data = sr.ReadToEnd();
}
However, when I call the second set of code from an external C# application referencing the PCL, the debugger simply fails with NO warning or error message on:
request.GetResponseAsync();
Is there an easy way to download a string that I'm missing?
*also, why would the debugger simply exit with no explanation?
Edit:
Here is another method I have attempted - based on an answer already provided. Again, this method simply exits and force closes the debugger.
PCL Method:
public static async Task<string> DownloadString()
{
var url = "http://google.com";
var client = new HttpClient();
var data = await client.GetStringAsync(url);
return data;
}
Calling method:
private static async void Method()
{
string data = await PCLProject.Class1.DownloadString();
return data;
}
Install the NuGet packages:
Microsoft.Bcl.Async, which adds async/await support to PCLs.
Microsoft.Net.Http, which adds HttpClient support to PCLs.
Then you can do it the easy way:
var client = new HttpClient();
var data = await client.GetStringAsync(url);
This method worked for me, it returned the HTML source code from google.com:
public async void GetStringFromWebpage()
{
using (HttpClient wc = new HttpClient())
{
var data = await wc.GetStringAsync("http://google.com/");
Debug.WriteLine("string:" + data);
}
}