I'm using the basic template that VS 2019 provides with the weather forecasting data when creating a ASP.NET WebAPI project and added some very basic authentication with user login and support for JWT Token which all works fine.
I'm trying to create a blazor client project to consume the API and display the data on the page. AFAIK Blazor doesn't support localstorage so I'm using Blazored LocalStorage package to give me this ability. My problem stems from fact using JS via OnInitializedAsync() is not possible in server-side blazor (https://github.com/aspnet/AspNetCore/issues/13396) as a result I'm not sure how one is suppose to consume these web api calls. As this will produce a null reference exception
protected override async Task OnInitializedAsync()
{
var client = HttpFactory.CreateClient();
var token = await LocalStorage.GetItemAsync<string>("authToken");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await client.GetAsync("url/WeatherForecast");
var str = await response.Content.ReadAsStringAsync();
Items = JsonConvert.DeserializeObject<IEnumerable<WeatherForecast>>(str);
}
One suggestion was to use OnAfterRenderAsync() method to call them as JS would be ready by then. Which semi-works but obviously the UI doesn't match because it needs to be refreshed - however to manually refresh it seems I have to call StateHasChanged(); which in turn calls OnAfterRender method again and as a result I had to put a check but this ultimately feels incredibly hacky.
private bool hasRendered;
protected override async Task OnAfterRenderAsync(bool _)
{
if (!hasRendered) return;
var client = HttpFactory.CreateClient();
var token = await LocalStorage.GetItemAsync<string>("authToken");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await client.GetAsync("https://url/WeatherForecast");
var str = await response.Content.ReadAsStringAsync();
Items = JsonConvert.DeserializeObject<IEnumerable<WeatherForecast>>(str);
StateHasChanged();
hasRendered = true;
}
What is the correct way to consume an API with authnetication and display the data correctly on the client side?
Side question HttpClient doesn't seem to be injectable in server-side and it's recommended to use HttpClientFactory - is it a good idea to create a client on every request or make a singleton and re-use thoughout the client project?
Q1
One suggestion was to use OnAfterRenderAsync() method to call them as JS would be ready by then. Which semi-works but obviously the UI doesn't match because it needs to be refreshed - however to manually refresh it seems I have to call StateHasChanged(); which in turn calls OnAfterRender method again and as a result I had to put a check but this ultimately feels incredibly hacky.
All people with the same issue, because this, at Lifecycle methods, new OnAfterRenderAsync with firstRender parm is documented:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await ... /// your auth code here.
}
}
Q2
Side question HttpClient doesn't seem to be injectable in server-side and it's recommended to use HttpClientFactory - is it a good idea to create a client on every request or make a singleton and re-use thoughout the client project?
Simplifying: I suggest to you to create two external libraries for your backend calls: one using http requests (for blazor wasm hosted model) and the other one just calling c# backend functions (for blazor server). Both with a common interface for backend calls. Use DI to set right library for each hosted model.
Related
I have got an web application that lacks to free memory.
I suspect HttpClient to be one of the issues, because the object count of HttpClient is increasing over time.
Therefore I want to migrate to the managed IHttpClientFactory, but now I'm stuck with how to best implement the call to the token service (I thought about using the typed client variant).
Right now it's implemented this way:
var myClient = new MyClient(credentials, baseUri, tokenUri, timeout);
Inside of MyClient HttpClient(1) takes care of calling the token service (credentials, tokenUri), storing the expiry date and returning the bearer token to HttpClient(2) that calls the endpoint (baseUri, timeout).
If myClient now tries to fetch some data, it checks if the token needs to be refreshed, if not it fetches the data.
How would I do this with IHttpClientFactory? Do I still need to handle HttpClient(1) myself (expiry date) or will the factory somehow detect if it needs to refresh the token or not?
I at least understood, that the factory decides if a connection stays open or not.
It sounds like you're on the right track with the transition to HttpClientFactory, and particularly a typed HttpClient.
Under the hood, HttpClientFactory's default implementation manages the pooling and disposal of the underlying primary message handler, which means that the actual HttpClient sitting on top of it can start being generated and disposed in a scoped fashion rather than trying to manage some global, long-running instance of it or creating and tearing down one-off instances, which is well described in Microsoft's own documentation: Use IHttpClientFactory to implement resilient HTTP requests
In cases like yours where the HttpClient was potentially long-lived, it may have made sense for the client itself to manage state within its instance (such as the token), but you end up needing to take a different path now that the client can (and should) be disposed of more frequently.
Do I still need to handle HttpClient(1) myself (expiry date) or will the factory somehow detect if it needs to refresh the token or not?
Yes you still need to handle it, but the HttpClientFactory pattern gives you some tools to help manage it. Since you're inherently leaning into dependency injection with the use of HttpClientFactory, there's a couple different paths you might go.
At the most basic would be just to add some sort of singleton token provider that manages the tokens for you and can be injected into the typed client by the DI container:
public interface ITokenProvider
{
string GetToken(string key);
void StoreToken(string key, string token);
}
// Incredibly basic example, not thread safe, etc...
public class InMemoryTokenProvider : ITokenProvider
{
private readonly Dictionary<string, string> _tokenList = new Dictionary<string, string>();
public string GetToken(string key)
{
return _tokenList.GetValueOrDefault(key);
}
public void StoreToken(string key, string token)
{
_tokenList.Remove(key); // upsert, you get the point...
_tokenList.Add(key, token);
}
}
public class TypedClient
{
private readonly HttpClient _client;
private readonly ITokenProvider _tokenProvider;
public TypedClient(HttpClient client, ITokenProvider tokenProvider)
{
_client = client;
_tokenProvider = tokenProvider;
}
public async Task DoYourThing()
{
var token = _tokenProvider.GetToken("token_A");
// ... if it failed, then UpdateTheAuth()
}
private async Task UpdateTheAuth()
{
var result = await _client.GetAsync("the auth process");
string token = "whatever";
// ...
_tokenProvider.StoreToken("token_A", token);
}
}
When you do your service registration at the start and register the token provider as a singleton, all your state (such as the token) is no longer part of the client itself, so your client can now be disposed and injected wherever. That provider could also be written off to a cache or a database, too.
This can still be a little clunky because its still putting all the logic for calling, failing, updating auth, retrying, etc. within your typed client logic -- it might be good enough if that covers what you need, or you may want something more robust. HttpClientFactory makes it easy to add a delegating handler pipeline as well as policies for resiliency with Polly, such as retry:
services.AddTransient<ExampleDelegatingHandler>();
services.AddHttpClient<IMyHttpClient, MyHttpClient>()
.AddHttpMessageHandler<TokenApplicationHandler>()
.AddPolicyHandler(GetRetryPolicy()); // see Microsoft link
The delegating handler pipeline attaches to your typed client and runs like middleware for every request and response (and can modify them in flight), so you could even move some of this token management off into a delegating handler instead:
public class TokenApplicationHandler : DelegatingHandler
{
private readonly ITokenProvider _tokenProvider;
private readonly IAuthRenewerClient _authRenewer;
public TokenApplicationHandler(ITokenProvider tokenProvider, IAuthRenewerClient authRenewer)
{
_tokenProvider = tokenProvider;
_authRenewer = authRenewer;
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
// All just demo level, take the implementation with a grain of salt...
string token = _tokenProvider.GetToken("token_A");
request.Headers.Add("x-token-header", token);
var response = await base.SendAsync(request, cancellationToken);
if (!response.IsSuccessStatusCode && response.StatusCode == HttpStatusCode.Unauthorized)
{
string newToken = _authRenewer.RefreshAuth();
_tokenProvider.StoreToken("token_A", newToken);
}
return response;
}
}
Paired with a retry policy, now any time a request goes out and comes back with an Unauthorized response, your delegating handler can handle the renewal and then the request gets resent the new token, and your typed HttpClient doesn't need to be any the wiser (or even necessarily deal with auth at all).
Key takeaways, make sure as you transition to this pattern that you're disposing of the clients you're creating when you're done with whatever scope they're in so HttpClientFactory can do its background magic.
I’m creating an API that serves as the bridge between the app and 2 other APIs. I want to know if what is the best way to do this. I’m using HttpClient. The app has almost a thousand users.
I read this article https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/. Should I really not use the using statement? Also I am doing synchronous api calls. Does this have any effect? Is what I did efficient?
Here is my code:
[HttpGet]
[Route("api/apiname")]
public String GetNumberofP([FromUri]GetNumberofPRequest getNPRequest){
var request = JsonConvert.SerializeObject(getNPRequest);
string errorMessage = "";
try{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.gettoken());
var response = httpClient.GetAsync("api/MobileApp/GetNumberP?"
+ "strCardNumber=" + getNPRequest.strCardNumber
+ "&strDateOfBirth=" + getNPRequest.strDateOfBirth).Result;
return response;
}
catch (Exception e){
throw utils.ReturnException("GetNumberofP", e, errorMessage);
}
}
HttpClient does not need to be disposed and you should hold on to it to reuse it later.
One thing you can use (from the thread you linked):
You just provide your HttpClient factory and dispose methods and the
LimitedPool does the rest:
_httpClientPool = new LimitedPool<httpclient>(
CreateHttpClient, client => client.Dispose(), HttpClientLifetime);
using (var httpClientContainer = _httpClientPool.Get())
{ ... use httpClientContainer.Value ... }
When httpClientContainer is disposed, the HttpClient is actually returned back to the pool for other threads to use. When
lifetime is reached next dispose will eventually call the Dispose
method.
See code here
Alternative for .Net Core
Implement it as described in this document.
The IHttpClientFactory can be registered by calling the AddHttpClient extension method on the IServiceCollection, inside the Startup.ConfigureServices method.
services.AddHttpClient();
Once registered, code can accept an IHttpClientFactory anywhere services can be injected with dependency injection (DI). The IHttpClientFactory can be used to create a HttpClient instance:
public MyConstructor(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task OnGet()
{
....
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
...
}
No need to use using().
If you are using asp.net core the right way to use HttpClient is explained in this article from Microsoft:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-2.2#typed-clients
I usually use the typed client approach explained in the article.
This basically means that I delegate to the asp.net core container the injection of the http client in my class (a controller class, a service, a filter, whatever)
Doing so you can safely modify the http client in your class by adding all the request headers you need (you usually do it inside the constructor of your class).
You do not have to call dispose on the injected http client, you simply use it.
The asp.net core container will manage the http client lifetime for you and the pool of resources used by http client instances so that your app do not leak resources. All of this happens automatically.
Do not use sync calls. Make your action method async, and await on async methods of http client. Asp.net core fully support async code and make blocking requests does not make sense, doing so you will limit the scalability of your app.
We have a custom implementation of IStringLocazlizer that Loads labels from our internal company CMS that exposes data via HTTP Rest interface.
We wanted to use NET Core built in locazlier but I do not like the GetAllStrings Sync method that will have to Block on Tasks to perfrom HTTP Call.
We have a cache obvioulsy but I do think that it does not seem right.
Any thoughts on that?
Example:
public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures)
{
Task<CmsLabelsModel> task = pipeline.SendAsync(new GetLabelsModelRequest(ResourceName));
CmsLabelsModel result = task.GetAwaiter().GetResult(); //Yuk Yuk
return result.LabelModels.Select(pair => new LocalizedString(pair.Key, pair.Value.Value));
}
For a work project, I'm building an application consisting of a frontend SPA (Aurelia), a WebAPI backend for that SPA, and a multitude of web service WebAPI projects contained in existing applications. (This application will perform data aggregation - it's a dashboard for our clients to show relevant information from many sources.)
Immediately, I was faced with some challenges. Using WebAPI, we wanted to expose the web services as REST endpoints. This works well for client applications and is very open. However, making server-to-server calls in .NET, I wanted to abstract away the REST calls and simply provide a method-based interface (so I could call, say, new MyWebServiceClient().getOrders() or something like that); I also did not want to have to duplicate data model classes across solutions, or worry about deserializing one JSON model type to another type. (Blegh.)
To achieve this goal, I've created an internal nuget package that a) provides access to the data model classes used in the service via the assembly, and b) provides an interface for HTTP calls, abstracting away the JSON serialization and deserialization, like so:
public async Task<T> Get<T>(string endpoint, IEnumerable<KeyValuePair<string, string>> parameters = null, CancellationToken cancellationToken = default(CancellationToken))
{
var builder = new UriBuilder(Properties.Settings.Default.MyEndpointHost + endpoint);
builder.Query = buildQueryStringFromParameters(parameters);
_httpClient.DefaultRequestHeaders.Accept.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
try
{
// After this, we really shouldn't continue.
var request = await _httpClient.GetAsync(builder.Uri, cancellationToken);
if (!request.IsSuccessStatusCode)
{
if (request.StatusCode >= HttpStatusCode.BadRequest && request.StatusCode < HttpStatusCode.InternalServerError)
{
throw new EndpointClientException("Service responded with an error message.", request.StatusCode, request.ReasonPhrase);
}
if (request.StatusCode >= HttpStatusCode.InternalServerError && (int)request.StatusCode < 600)
{
throw new EndpointServerException("An error occurred in the Service endpoint.", request.StatusCode, request.ReasonPhrase);
}
}
var json = await request.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(json);
}
catch (Exception ex)
{
throw;
}
}
The public methods are simply convenience methods, calling that function with the requisite arguments, like this:
public async Task<IEnumerable<MyModel>> SearchMyModelsByFooName(string fooName, CancellationToken cancellationToken)
{
var parameters = new List<KeyValuePair<string, string>>();
parameters.Add(new KeyValuePair<string, string>("searchText", fooName));
return await this.Get<List<MyModel>>("myModel", parameters, cancellationToken);
}
I've had good results with this, although I have to maintain it manually and update dependencies.
However, upon talking to my colleagues, I was introduced to WCF, and it looks as though it solves a lot of the issues I'm trying to solve manually. Looking into this, though, reveals that the setup can be tricky, and we're not sure if it's worth the trouble. (Additionally, we'd have to maintain two APIs.)
Although it's fun, I don't want to reinvent the wheel. Is there a way to bolt WCF on top of WebAPI for server-to-server calls only, or have WCF generate data for WebAPI controllers?
If you don't need to use REST, and personally I don't see any reason to do this in a .NET server to server scenario, you could just create a WCF service to expose your data. Then generate proxy classes in your WebAPI that calls the WCF service.
Using svutil to generate the proxy classes make it easy to adapt to changes in WCF "API". And you will have, as you call it, a method based interface to interact with the WCF service/s.
Reference for using svutil:
https://msdn.microsoft.com/en-us/library/ms733133(v=vs.110).aspx
I have this delegating handler in my api project:
class MyHandler : DelegatingHandler {
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken) {
var info = GrabSomeParametersFromHeader();
var isValid = await Validate(info); // this is a very light database query
if (!isValid) {
Log(request, info, false);
var response = new HttpResponseMessage(HttpStatusCode.Forbidden);
return response;
}
HttpContext.Current.SetMobileRequestInfo(info);
var result = await base.SendAsync(request, cancellationToken);
Log(request, info, result.IsSuccessStatusCode &&
result.StatusCode == HttpStatusCode.OK);
return result;
}
}
HttpContext.Current.SetMobileRequestInfo simply adds the info object to http-items to use later in app.
The Validate is a very light database query. And the Log method is inserting request's data (such as URI and query-string etc.) to database.
Sometimes, I'm getting a weird behavior of the app: it simply goes down! There is no log, no error, nothing. Just server doesn't response the requests. I have to restart app (for example by making a fake change in web.config) to get it back to work. The app is a pretty simple app. I'm using ASP.NET Web API 2 on .NET 4.5 platform which is running on a IIS 7.5 machine. The only place I can think about is the mentioned delegating handler, which may cause the error. Do you have any idea? Does delegating handlers have any performance side effects which may cause the app to shut down?
The (very) short answer to your question is no. There is nothing inherent to DelegatingHandlers themselves that would cause your app to grind to a halt. It's far more likely that the issue is with what you're doing inside of it. Could be the database call, could be the logging. I'd recommend using a profiling tool to figure out where things are getting hung up.