How to configure NodaTime serialization for System.Text.Json in Blazor WASM .Net 6 - serialization

How to configure NodaTime serialization for System.Text.Json in Blazor WASM .Net 6? In a WebApi you would do
builder.Services.AddControllers().AddJsonOptions(settings => settings.JsonSerializerOptions.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb));
but there are no controllers in Blazor WASM.
This does not work either:
builder.Services.Configure<JsonSerializerOptions>(options => options.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb));
var options = new JsonSerializerOptions().ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
and providing to HttpClient does not work either.

This works.
JsonSerializerOptions default = new JsonSerializerOptions(JsonSerializerDefaults.Web).ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);

This is a hack and a workaround, but I ended up using Newtonsoft for this
//Should work but doesn't
var options = new JsonSerializerOptions().ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
var customClassList = await Http1.GetFromJsonAsync<List<customClass>>($"api/CustomClass", options);
//First: Get the raw json string
var response = await Http1.GetAsync($"api/CustomClass");
var content = await response.Content.ReadAsStringAsync();
//Second: Deserialize with Newtonsoft
var settings = new JsonSerializerSettings();
settings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
var customClassList = JsonConvert.DeserializeObject<List<CustomClass>>(content, settings);
//Doesn't work (System.Text.Json)
var customClassList = JsonSerializer.Deserialize<List<CustomClass>>(content, options);
I suspect this has something to do with Blazor/WASM since the above code is basically the default example for json and nodatime with System.Text.Json. However, I don't get any weird errors or exceptions with in my Blazor app. It just doesn't deserialize properly.

Related

C# HttpClient failing to make GET requests with Windows Authentication

I have a .NET Core 3.1 Api application with the following configuration of HttpClient. In Startup.cs
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddHttpClient("myapi", c =>
{
c.BaseAddress = new Uri(Configuration["endpoint"]);
c.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(
IISDefaults.AuthenticationScheme, Convert.ToBase64String(
System.Text.Encoding.UTF8.GetBytes($"{Configuration["username"]}:{Configuration["password"]}")));
});
I then try to make an HTTP call like this:
var client = clientFactory.CreateClient(clientName);
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
return await response.Content.ReadAsStringAsync();
however I always get an Unauthorized response when calling an internal api. Under Debug I have Windows authentication and Anonymous authentication both enabled.
With Postman my api calls go through, which verifies that I got the right credentials.
Can you suggest any alterations to make this work?
Instead of c.DefaultRequestHeaders.Authorization =, I'm having config like this
c.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
{
Credentials = new NetworkCredential("username", "password"),
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
PreAuthenticate = true
});
I guess this will not work as-is in your case, but I hope this can get you on track.

App stops working when calling Http.PostAsync when returning a string

I have a Blazor app that's calling a WebAPI method that returns a string, however when it runs, it just stops. The app remains open but nothing appears to happen.
When i put a breakpoint in the controller it does run.
var ms = new System.IO.MemoryStream();
await file.Data.CopyToAsync(ms);
status = $"Finished loading {file.Size} bytes from {file.Name}";
var content = new MultipartFormDataContent {
{ new ByteArrayContent(ms.GetBuffer()), "\"upload\"", file.Name }
};
string featureImage = await Http.PostAsync("api/Blog/ReturnString", content).Result.Content.ReadAsStringAsync();
Above is the code that calls the WebAPI method. Below is the Controller that returns a very simple string.
[Authorize]
[HttpPost("[action]")]
public async Task<string> ReturnString()
{
return "123456";
}
Apart from the comment by #enet, there're likely two more bugs:
There's a risk of dead lock in the way you get Result by using .Result.Content. You need change the code to await ...
Also, if you're using Blazor Server side, be aware that invoking Http in Blazor ServerSide App is different from the Blazor WebAssembly App. You need create your own HttpClient or inject one and then provide base uri for it.
Hope the below helps:
(if you're using Blazor ServerSide) register HttpClient related services in your startup:
services.AddHttpClient(); // only if you're using Blazor ServerSide
And within your Blazor component/page:
#using System.Net.Http
#inject IHttpClientFactory HttpClientFactory #*if you're using Blazor ServerSide*#
#inject NavigationManager navMgr #*if you're using Blazor ServerSide*#
#code{
var Http = HttpClientFactory.CreateClient(); //if you're using Blazor ServerSide
Http.BaseAddress = new Uri(navMgr.BaseUri); //if you're using Blazor ServerSide
// ... add credentials if you're using Blazor ServerSide
//... your code
// don't block it by access the`.Result` property, await it!
await Http.PostAsync("api/Blog/ReturnString", content).Result.Content.ReadAsStringAsync();
var resp= await Http.PostAsync("api/Blog/ReturnString", content);
var featureImage = await resp.Content.ReadAsStringAsync();
Finally, if above code doesn't address the problem, could you please Press F12 within the browser and show us the error message ?

.NET Core 2 programmatically authentcation on Keycloak example

I'm trying to authenticate through a device (it's a barcode reader) that use .NET Core. I'm a newbie on .NET Core.
Now I need to write some program that gives me the possibility that given a username/password I make authentication on a Keycloak server with openidconnect. Is there some sample that shows how from a username/password string I can make the authentication programmatically?
I find a lot of examples that use .NET Core as a server that has Controllers that exposes rest API for user that have to be authenticated. But I need some example/hint to follow where the .NET Core makes the request.
Update
I could figure out (with curl) what exactly I have to do. Two calls to the Keycloak server.
call:
http://keycloakserver/auth/realms/realmName/protocol/openid-connect/token?grant_type=password&client_id=demo-app&username=username&password=password
This gives me back an object containing the access_token.
invoke the secured service adding in the header
"Authorization: bearer +access_token"
I try to develop this two calls with .NET Core.
I found this way to resolve it. But I'm sure is not the best way. I think there is a lot of improvement of security:
var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json"));
client.DefaultRequestHeaders.Add("User-Agent", ".NET Foundation Repository Reporter");
var values = new Dictionary<string, string>
{
{ "client_id", "myClientId" },
{ "grant_type", "password" },
{ "username", "usernaName" },
{ "password", "password" }
};
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("http://domain/auth/realms/realmName/protocol/openid-connect/token", content);
var responseString = await response.Content.ReadAsStringAsync();
var responseToken = JsonConvert.DeserializeObject<ResponseToken>(responseString);
Console.WriteLine("accessToken: " + responseToken.AccessToken);
var client2 = new HttpClient();
client2.DefaultRequestHeaders.Accept.Clear();
client2.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json"));
client2.DefaultRequestHeaders.Add("User-Agent", ".NET Foundation Repository Reporter");
client2.DefaultRequestHeaders.Add("Authorization", "bearer "+ responseToken.AccessToken);
var dataResponse = client2.GetStreamAsync("http://serviceDomain/api/SampleData/WeatherForecasts");
var serializer = new DataContractJsonSerializer(typeof(List<Weather>));
var tempData = serializer.ReadObject(await dataResponse) as List<Weather>;
Console.WriteLine(tempData);
If you have a better solution then don't hesitate to post it.

How to add Header values to HttpWebRequest in .Net Core

I am developing simple Http client to consume an Asp.Net Core Web API. I want to pass few http header values to the Web API via HttpHeaderCollection. In previous versions of .Net framework allowed to add header values to the HttpHeaderCollection as following
WebHeaderCollection aPIHeaderValues = new WebHeaderCollection();
aPIHeaderValues .Add("UserName","somevalue");
aPIHeaderValues .Add("TokenValue", "somevalue");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Headers.add(aPIHeaderValues);
HttpWebResponse response = (HttpWebResponse)_request.GetResponse();
But in .Net Core there is no way to add headers to request.Headers collection. As well as we cannot add headers by defining new WebHeaderCollection
WebHeaderCollection aPIHeaderValues = new WebHeaderCollection();
Is there any alternative way to do this in .Net Core
The question is about HttpWebRequest, which is different than HttpClient.
Using HttpWebRequest, you simply assign to a header you want like this:
request.Headers["HeaderToken"] = "HeaderValue";
.NET core will create the header if it does not exist.
Here is an example:
SampleClass sampleClass= null;
using (HttpClient client = new HttpClient()){
client.DefaultRequestHeaders.Add("Authorization", "TOKEN");
var data = await client.GetAsync("MY_API_URL");
var jsonResponse = await data.Content.ReadAsStringAsync();
if (jsonResponse != null)
sampleClass= JsonConvert.DeserializeObject<SampleClass>(jsonResponse);
return sampleClass;
}

Avoid HttpWebRequest GET and ProtocolViolationException

Is there anyway to prevent HttpWebRequest.GetRequestStream from throwing an exception when the method is GET? I know that HEAD and GET should not contain a body in valid HTTP, but some servers accept bodies for these methods anyway (e.g., Elasticsearch's _search feature). I have an open source project for doing REST calls and I was wondering if I could circumvent this behavior to avoid surprises.
At some point, I will probably create a version of my library using the new System.Net.Http.HttpClient class. Does this class have the same restrictions?
.Net Core 2.0:
System.Net.Http.HttpClient (Version=4.2.0.0) does not have this restriction if you use the SendAsync method.
var request = new HttpRequestMessage(HttpMethod.Get, "http://example.com/api/_search");
request.Content = new StringContent(jsonSearchCriteria, Encoding.UTF8, "application/json");
var response = await httpClient.SendAsync(request,
HttpCompletionOption.ResponseContentRead);
var jsonResponse = await response.Content.ReadAsStringAsync();