I accidentally cut the part where I show the HttpClient and DelegatingHandler association! To associate the handler to the client all you need to do is chain an AddHttpMessageHandler call to the AddHttpClient call like this: builder.Services.AddHttpClient("weather").AddHttpMessageHandler();
For me, I used this to check if I had a bearer token cached for a 3rd party API. If it was cached and not expired, set the authorization header. Otherwise, authenticate with the API and then add the header.
I do the same with tokens, I have scenario where I am using the _httpClientFactory.CreateClient("MyService") and then I add the Authorization token to the header and If two separate threads are calling _httpClientFactory.CreateClient("MyService") and the fact it will return the same instance. There could issues with this!. To overcome the problem I am using SemaphoreSlim(1,1). My question do I need to make use of SemaphoreSlim.? Thanks
I use those handlers for example to put the bearer token on the Authorization header of the request. A provider injected into the handler takes care of the caching and refreshing process of the token.
If you are using service repository pattern, you would typically do this kind of caching at the service level. That way, if your underlying API provider changes, format changes OR you have a backup API provider for weather, caching still happens at the service level. Caching it at the httpclient's message handler level does not look like an optimal choice for caching. We use message handlers all the time, for injecting tracking headers, missing authorization headers, add client certificates etc. Those are your typical use cases of using custom message handlers.
I feel the same. But if you want to throttle due to the licensing model of the underlying api, it seems legit to me. Nothing domain specific at this point.
@@sentenza5497this is the important point for me, the reason for caching. In this case it's because of cost per request so it makes sense to do a quick caching implementation at the level that's going to hurt. As the app grows I'd agree with caching at a higher level, but maybe not as a first pass where you want to get the MVP working and you don't want to hammer the API during dev testing.
I've used this in the past to manage rate limits on API's. One we used only allowed a request every 1 second. So I used a delegate handler to check when the previous request was sent and wait on the next one if required. Worked perfectly.
I did actually know about it! I used it to create a "mock" for use on certain environments, to prevent actually making http calls to any kind of 3rd party api. Very useful for testing and "mirror" environments!
Very useful content. Being dealing with DelegateHandlers lately and they are very flexible. This is a neat approach most notably to Mock you responses for UnitTesting. Delegating the Caching strategy to the Client seems to be a nice example like you said with minimum code base changes. The beauty of this is that it also helps any fallback logic that relies in your API response error avoiding going to other API if the current API is down or throttled
I have to say your timing on this is so perfect for me. I was literally sitting down to start working through how I was going to improve performance on several API calls using caching when I saw this!
I use it with Refit passing an object that represents the amount of time for each request. Also for body content with a simple interface you could cache it by sending the body as a Option in the HttpRequest
@@ShahidKhan-vs8bb I do not have it right here. What I did was that all the request which has a body and I wanted to cache I put the [Body, Property] attributes, and named all the objects body. Example Task GetResponse([Body, Property] Request body, [Property] int cacheTime). The Request object inherits from an interface that has a Method string GetKey(). With the URL+RequestObject you form the key and with the cacheTime you form the ExpirationTime. In the HttpRequest object you can access to both variables ( They are both in the Properties, which is deprecated, and in the Options)
The feature itself is useful, but generally, for a more simple shared concerns: logging, header injection, stuff like that. Not caching. As you've shown, generally you want to cache only successful responses. This and having cache in the handler forces you to: - duplicate response validation logic inside the handler and will need to recreate the response with enough information, which is a bloat. - wrapping the cached payload in pointless objects which increases the bloat. - if you want to cache only certain endpoints, you'll need to add branching logic in that handler. Bloat. - won't be able to add typed caching, since it'll force you to add add an extra serialization-deserialision step (to and from content) which is, again, an overhead. tldr: better to add cache before the client, for example, as a decorator to a service that handles calling an API.
The components of the key might depend on the end-point, so the handler is not quite the right place for the extraction of the components of the caching key. I prefer to use a typed IClient and decorate it. I use delegating handlers for concerns which don't depend on the end-point, such as header manipulations (as you said at the end)
The handler is only used by that specific endpoint so there is no problem with the implementation at all. Nothing else can instantiate it and no other endpoint can be used
That means that the handler is registered for every HttpClient that will be created so we actually would need a check for the uri so that it's only executed when necessary. At least in your current implementation. I guess it would have been good to also showcase the ability to register a handler for a specific HttpClient so that this uri check is not necessary.
@@nickchapsas You register the handler to the application, not directly to the named HttpClient. How does it know that it should only be attached to the named Weather HttpClient.
Hmm my last message might've been removed as I added a link to the Microsoft docs, You can use the following to add a handler to a specific HttpClient builder.Services.AddTransient(); builder.Services.AddHttpClient("HttpMessageHandler") .AddHttpMessageHandler();
I’ve used this a lot for mocking out requests in unit tests. Helpful if you are calling a third party api and just want to check success or specific errors
This is how I get and add the access token to the requests when using an nswag generated client, but I hadn't thought of doing other stuff with it. Never thought of caching at the webclient level. Great video.
Maybe I missed something, but since you registered the CachedWeatherHandler with the default DI method, does this mean it is used by all HttpClients in this project? Also, if I register multiple handlers, are they used in the same order as I registered them in the Program.cs?
Since the only thing that will instantiate the handlers is the NAMED http client, specific to the weather, it will only be used by the weather client. Regarding handlers, order matters in how they are added to the client, not registered in DI.
You can also explicity configure which handlers are used with which clients when registering clients in the DI. Not sure about named clients, but it works for typed clients.
Thank you Nick for sharing the usage of DelegatingHandlers with this particular example. IMHO and in this particular usage, I want to share another approach that I have used before: for caching purposes, I have used a typed HttpClient (instead of a named one) for the API I'm consuming, so that the lookup and write into the cache are both done in such typed client instead - I presume I could have used a HttpClient decorator as well, just like cached repositories are usually implemented. In that way we wouldn't be required to parse the query string or build the HttpMessageResponse and only use any of the corresponding DTO classes instead.
I tried using this approach to log http responses based on some initial configuration. e.g a whitelist of headers to add. You have to be careful that if you read the content body as a stream then you can't later consume the same stream. This was important because we were using it as a package to be available to other internal projects and we couldn't predict how the content would be read downstream. Well, we could because it was us using it... but you see what I mean.
It’s also very useful to inject a handler that stubs responses for testing. Implement your own caching is typically a bad idea (especially with HTTP). You should properly deal with caching headers and that’s not trivial. Please use a solid existing caching handler instead of wrapping your own.
You didn't check api call is success before adding it to cache. I mostly use messagehandlers for logging, security and injecting parameters into the request if it is needed.
Nice, I’m surprised Polly don’t include client caching, two points I believe could improve the solution: - implementation as a generic cache handler, means not specific to this controller. - having an status code or out header that indicates the result is from cache for troubleshooting. - having a header the cache handler read to avoid the cache. What do you think?
I've been using this feature for a while now, a very elegant way to manage HTTP requests without bloating your logic with repeating code. I just have one questuion - can you elaborate on why did you register your handler with a scoped lifetime? Examples in MS documentation use transient scope with the following explanation: "When IHttpClientFactory creates a new delegating handler, it uses DI to fulfill the handler's constructor parameters. IHttpClientFactory creates a separate DI scope for each handler, which can lead to surprising behavior when a handler consumes a scoped service."
You must register the handler as transient. It should be registered as transient primarily because it is not thread-safe. If it were registered as scoped, the same instance could be reused across multiple HTTP requests within the same scope, which could lead to unintended side effects, race conditions, or other threading issues.
Very interesting indeed. I'm at the start of a project for implementing a kind of proxy/anti-corruption layer providing a well-structured api and with dependencies to several other webapplications. Preferable I would like to have these webapplications available in a container so I can write integration tests as we do for code that only requires a database, but that is not the case. Using this feature is as close as the next best thing I can imagine. It's basically the same as regular mocking.
I use it for http logging. I've also used it for load testing where you want to load test services in isolation mode. It can help simulate latencies from different services very easily.
I've used this with Polly for retries on http calls. But I think, since then there's probably something that does this automatically. Also for global exception handling. I do custom parsing of the response, then throw an application exception that my app can handle.
I remember I used this ages ago to inject custom headers to pretend I was behind a reverse proxy and so the server would authenticate me. I’m sure there are utilities out there now that will do the same without any scripting. Maybe fiddler.
Hey Nick! Love your content, especially about Web API. I was wondering if you'd ever do videos on authentication between clients and .Net 6+ Web API? Specifically, authentication using a token rather than using user credentials. I find that most of the apps I see created internally for businesses don't warrant the use of full-fledged user credential authentication. Didn't know if you had suggestions for this route or even videos out/in the pipeline?
I just created a bare bones JWT token generator and verification library that's shared between projects. Barely a handful number of simple methods. Has been running smoothly for 5 years and counting. Might want to go down that route.
May I ask one thing - what's are advantages of this way of caching in comparison with standard (let's say use some service with the same InMemoryCache)? For me HttpClient should do 1 thing - send requests and receive response, that's it's responsibility and it doing it well, but changing it's pipeline, adding some caching possible may produce some "hard to debug" \ "understand the code" issues, especially for beginners. I also don't see any perf advantages, similar thing. + More difficult configuration - so if we have many APIs in our microservice, each service need specific configuration of HttpClient. Having specific MyServiceNameCache service, injecting it into MyServiceName and just before the call of httpClient check the cache is much easy to read and debug. Or I lost the idea?
I keep an extension class on hand for that, generic lazy loading cache helper (AddOrGetExistingCacheEntry) to use as localized cache for several internal processes. Have they added something like that to the basic system memorycache?
I really wish we would stop adding so much hidden indirection, making reading and debugging the code much harder than it need to be. In so many places, proper seperation of logic and IO will make things like DI and mocs not needed, but if i could choose to kill just one thing, it would be automapper - the destroyer of code navigation and turning compile errors into runtime errors.
The delegating handler has to be registered as transient. Not scoped. Look into it a bit more. It should be registered as transient primarily because it is not thread-safe. If it were registered as scoped, the same instance could be reused across multiple HTTP requests within the same scope, which could lead to unintended side effects, race conditions, or other threading issues.
Transient is the general recommendation by Microsoft because it’s the safest option but it’s not a "has to" thing. In this case for example there will be no scenario where scoped causes unexpected behaviour
What James said. Because it's a differnet layer of caching specific to the single API. You might not want that for the complete API response especially for things like auth
Isn't this an overengineering? You can add caching to the method that make the call to the API and that does the same thing without adding extra layer of classes
Does that class need to know about the caching? I would argue it doesn't. Same with something like adding retry policies or fallbacks. It's not the responsibility of that class to know that IMO but it heavily depends on context as well
great point. That's the usual implementation we do, usually we create a class responsible for dealing with weather data (CacheWeather), and that class would be the one with the logic for caching or httping it and later return to the service class
I can't help but feel like all of this could've been made simpler if some of the types related to HttpClient used interfaces so we could transparently decorate them with caches/retries if we wanted to.
every time I make a HTTPS post call with httpclient class, Httpclient response is very slow. any way to speed it up. Mean while post request to http is fast, its https that is causing issue
Caching should be done at the service level not the http client level. Like this, you're caching any request (weather API or not) plus other issues too.
@@nickchapsas You're right. I missed the named client part, but still, you don't control what the handler caches unless you write code that checks the content of the request and it can even run on non GET requests.
@@parlor3115 I agree with you. Caching of HTTP content should be based on HTTP cache control, etag, last modified and so on. This is what could be handled at the HTTP client side in a DelegatingHandler (or a reverse proxy cache). If an upstream service however does not provide HTTP level caching, and/or you do not have a reverse proxy cache, by all means introduce cache in your application if you need to have this data frequently, but keep it in the domain/service using a service decorator pattern or something alike.
Or you can just create an extension method so that future developers don't have to go through all the documentation to understand this hidden functionality. xD Nice video tho!
The approach looks clever but I don't like it. It increases the amount of magic in the app. A new dev who comes there after 3 years might be killed by this clever stuff when the app behaves not as expected. It would be much better to implement such a feature even with an abstract class despite the fact that abstract classes rarely a good solution. But here even an abstract class would be much better.
Just a friendly reminder that IMemoryCache is not thread safe, and could be choke point if impelemted the way Nick showed in this video. Nick has even video about that 😄: ruclips.net/video/Q3KzZeUudsg/видео.htmlsi=4HhjlX6bUbEHfV2R
Man, I was left with a bad taste in my mouth when I started watching this. You don't even have the guts to own your slip of tongue. Sorry if it was intentional, You lost me.
I accidentally cut the part where I show the HttpClient and DelegatingHandler association! To associate the handler to the client all you need to do is chain an AddHttpMessageHandler call to the AddHttpClient call like this: builder.Services.AddHttpClient("weather").AddHttpMessageHandler();
Sweet! That makes more sense. Looks sweet too! 😁
Thanks! I thought I'd blinked and missed it!
I was about to replay the video on 0.75x speed to see where I'd missed it, so I'm glad I read the comments first haha.
That's the most interesting part
You would think they could register the handler when you map it to the client 😢
If the user requests the weather for London you can just return a constant response "The weather is crap" and no need to cache.
That's what the real services do anyway.
For me, I used this to check if I had a bearer token cached for a 3rd party API. If it was cached and not expired, set the authorization header. Otherwise, authenticate with the API and then add the header.
yep this is exactly what we use it for
Same here. Checking a token for expiry and call refresh endpoint if expired
I do the same with tokens, I have scenario where I am using the _httpClientFactory.CreateClient("MyService") and then I add the Authorization token to the header and If two separate threads are calling _httpClientFactory.CreateClient("MyService") and the fact it will return the same instance. There could issues with this!. To overcome the problem I am using SemaphoreSlim(1,1). My question do I need to make use of SemaphoreSlim.? Thanks
I use those handlers for example to put the bearer token on the Authorization header of the request. A provider injected into the handler takes care of the caching and refreshing process of the token.
I do the same. It works great.
If you are using service repository pattern, you would typically do this kind of caching at the service level. That way, if your underlying API provider changes, format changes OR you have a backup API provider for weather, caching still happens at the service level. Caching it at the httpclient's message handler level does not look like an optimal choice for caching. We use message handlers all the time, for injecting tracking headers, missing authorization headers, add client certificates etc. Those are your typical use cases of using custom message handlers.
I feel the same. But if you want to throttle due to the licensing model of the underlying api, it seems legit to me. Nothing domain specific at this point.
@@sentenza5497this is the important point for me, the reason for caching. In this case it's because of cost per request so it makes sense to do a quick caching implementation at the level that's going to hurt.
As the app grows I'd agree with caching at a higher level, but maybe not as a first pass where you want to get the MVP working and you don't want to hammer the API during dev testing.
I've used this in the past to manage rate limits on API's. One we used only allowed a request every 1 second. So I used a delegate handler to check when the previous request was sent and wait on the next one if required. Worked perfectly.
I did actually know about it! I used it to create a "mock" for use on certain environments, to prevent actually making http calls to any kind of 3rd party api. Very useful for testing and "mirror" environments!
Very useful content. Being dealing with DelegateHandlers lately and they are very flexible.
This is a neat approach most notably to Mock you responses for UnitTesting.
Delegating the Caching strategy to the Client seems to be a nice example like you said with minimum code base changes. The beauty of this is that it also helps any fallback logic that relies in your API response error avoiding going to other API if the current API is down or throttled
I have to say your timing on this is so perfect for me. I was literally sitting down to start working through how I was going to improve performance on several API calls using caching when I saw this!
I’ve used this a ton for getting an auth token (or using a cached/unexpired token) to append to the request authorization header before sending
I use it with Refit passing an object that represents the amount of time for each request. Also for body content with a simple interface you could cache it by sending the body as a Option in the HttpRequest
I am using refit in a project that i am starting. Could you please share your solution?
@@ShahidKhan-vs8bb I do not have it right here. What I did was that all the request which has a body and I wanted to cache I put the [Body, Property] attributes, and named all the objects body. Example Task GetResponse([Body, Property] Request body, [Property] int cacheTime). The Request object inherits from an interface that has a Method string GetKey().
With the URL+RequestObject you form the key and with the cacheTime you form the ExpirationTime.
In the HttpRequest object you can access to both variables ( They are both in the Properties, which is deprecated, and in the Options)
The feature itself is useful, but generally, for a more simple shared concerns: logging, header injection, stuff like that. Not caching.
As you've shown, generally you want to cache only successful responses. This and having cache in the handler forces you to:
- duplicate response validation logic inside the handler and will need to recreate the response with enough information, which is a bloat.
- wrapping the cached payload in pointless objects which increases the bloat.
- if you want to cache only certain endpoints, you'll need to add branching logic in that handler. Bloat.
- won't be able to add typed caching, since it'll force you to add add an extra serialization-deserialision step (to and from content) which is, again, an overhead.
tldr: better to add cache before the client, for example, as a decorator to a service that handles calling an API.
The components of the key might depend on the end-point, so the handler is not quite the right place for the extraction of the components of the caching key. I prefer to use a typed IClient and decorate it. I use delegating handlers for concerns which don't depend on the end-point, such as header manipulations (as you said at the end)
this pretty much, def not the place for caching
The handler is only used by that specific endpoint so there is no problem with the implementation at all. Nothing else can instantiate it and no other endpoint can be used
That means that the handler is registered for every HttpClient that will be created so we actually would need a check for the uri so that it's only executed when necessary. At least in your current implementation.
I guess it would have been good to also showcase the ability to register a handler for a specific HttpClient so that this uri check is not necessary.
That's not correct. The HttpClient is named so only the weather httpclient will have this ability. The handler won't exist for other clients
@@nickchapsas You register the handler to the application, not directly to the named HttpClient. How does it know that it should only be attached to the named Weather HttpClient.
Hmm my last message might've been removed as I added a link to the Microsoft docs,
You can use the following to add a handler to a specific HttpClient
builder.Services.AddTransient();
builder.Services.AddHttpClient("HttpMessageHandler")
.AddHttpMessageHandler();
+1@@332glenn
@@nickchapsas @332glenn and @W1ese1 are right. You do not register the handles specifically for the named instance. Or not that we can spot anyway!
I’ve used this a lot for mocking out requests in unit tests. Helpful if you are calling a third party api and just want to check success or specific errors
This is how I get and add the access token to the requests when using an nswag generated client, but I hadn't thought of doing other stuff with it. Never thought of caching at the webclient level. Great video.
Maybe I missed something, but since you registered the CachedWeatherHandler with the default DI method, does this mean it is used by all HttpClients in this project?
Also, if I register multiple handlers, are they used in the same order as I registered them in the Program.cs?
Since the only thing that will instantiate the handlers is the NAMED http client, specific to the weather, it will only be used by the weather client. Regarding handlers, order matters in how they are added to the client, not registered in DI.
You can also explicity configure which handlers are used with which clients when registering clients in the DI. Not sure about named clients, but it works for typed clients.
@@nickchapsas Thank you, your pinned comment explained the part that confused me.
This handler was extremely helpful for me to implement Auth elegantly before to call an API.
Thank you Nick for sharing the usage of DelegatingHandlers with this particular example. IMHO and in this particular usage, I want to share another approach that I have used before: for caching purposes, I have used a typed HttpClient (instead of a named one) for the API I'm consuming, so that the lookup and write into the cache are both done in such typed client instead - I presume I could have used a HttpClient decorator as well, just like cached repositories are usually implemented. In that way we wouldn't be required to parse the query string or build the HttpMessageResponse and only use any of the corresponding DTO classes instead.
I tried using this approach to log http responses based on some initial configuration. e.g a whitelist of headers to add.
You have to be careful that if you read the content body as a stream then you can't later consume the same stream. This was important because we were using it as a package to be available to other internal projects and we couldn't predict how the content would be read downstream. Well, we could because it was us using it... but you see what I mean.
It’s also very useful to inject a handler that stubs responses for testing. Implement your own caching is typically a bad idea (especially with HTTP). You should properly deal with caching headers and that’s not trivial. Please use a solid existing caching handler instead of wrapping your own.
Can you recommend any?
You didn't check api call is success before adding it to cache. I mostly use messagehandlers for logging, security and injecting parameters into the request if it is needed.
This is my default way to
- mock external responses,
- add auth token and trigger refresh
Nice, I’m surprised Polly don’t include client caching, two points I believe could improve the solution:
- implementation as a generic cache handler, means not specific to this controller.
- having an status code or out header that indicates the result is from cache for troubleshooting.
- having a header the cache handler read to avoid the cache.
What do you think?
A generic cache handler might be tricky to pull off because of the cache key unicity which holds some business logic
Polly can do caching, supports in memory, distributed or redis
I've been using this feature for a while now, a very elegant way to manage HTTP requests without bloating your logic with repeating code. I just have one questuion - can you elaborate on why did you register your handler with a scoped lifetime? Examples in MS documentation use transient scope with the following explanation:
"When IHttpClientFactory creates a new delegating handler, it uses DI to fulfill the handler's constructor parameters. IHttpClientFactory creates a separate DI scope for each handler, which can lead to surprising behavior when a handler consumes a scoped service."
If you read the documentation carefully it talks about the using a scoped service inside the handler not the scope of the handler itself 😊
You must register the handler as transient. It should be registered as transient primarily because it is not thread-safe. If it were registered as scoped, the same instance could be reused across multiple HTTP requests within the same scope, which could lead to unintended side effects, race conditions, or other threading issues.
I can see this as being useful for a wide range of testing needs
Very interesting indeed. I'm at the start of a project for implementing a kind of proxy/anti-corruption layer providing a well-structured api and with dependencies to several other webapplications. Preferable I would like to have these webapplications available in a container so I can write integration tests as we do for code that only requires a database, but that is not the case. Using this feature is as close as the next best thing I can imagine. It's basically the same as regular mocking.
I use it for http logging.
I've also used it for load testing where you want to load test services in isolation mode. It can help simulate latencies from different services very easily.
5:56 using underscores for fields is like using capitalisation for public/private
I've used this with Polly for retries on http calls. But I think, since then there's probably something that does this automatically.
Also for global exception handling. I do custom parsing of the response, then throw an application exception that my app can handle.
Works nice for ratelimiting as well
I remember I used this ages ago to inject custom headers to pretend I was behind a reverse proxy and so the server would authenticate me. I’m sure there are utilities out there now that will do the same without any scripting. Maybe fiddler.
I think for london you can statically return "Rainy".
I think you missed the part where you should wrap your handler over defaultHttpHandler of HttpClient
There is no wrapping. I accidentally cut the registration part. Check the pinned comment
@@nickchapsas Yea that's right, but in a nutshell it's like wrapping, your handler wraps around inner one
Hey Nick! Love your content, especially about Web API. I was wondering if you'd ever do videos on authentication between clients and .Net 6+ Web API? Specifically, authentication using a token rather than using user credentials. I find that most of the apps I see created internally for businesses don't warrant the use of full-fledged user credential authentication. Didn't know if you had suggestions for this route or even videos out/in the pipeline?
I just created a bare bones JWT token generator and verification library that's shared between projects. Barely a handful number of simple methods. Has been running smoothly for 5 years and counting. Might want to go down that route.
May I ask one thing - what's are advantages of this way of caching in comparison with standard (let's say use some service with the same InMemoryCache)?
For me HttpClient should do 1 thing - send requests and receive response, that's it's responsibility and it doing it well, but changing it's pipeline, adding some caching possible may produce some "hard to debug" \ "understand the code" issues, especially for beginners.
I also don't see any perf advantages, similar thing.
+ More difficult configuration - so if we have many APIs in our microservice, each service need specific configuration of HttpClient. Having specific MyServiceNameCache service, injecting it into MyServiceName and just before the call of httpClient check the cache is much easy to read and debug.
Or I lost the idea?
Mentioning ValueTask when using a cache would have been nice. Otherwise great video!
thanks for video! I enjoed with it!
thanks Nick!
Not sure if its a big deal to you but you showed your API Key at 2:10.
If the past is any indicator, that API key will be deactivated before the video goes live
I keep an extension class on hand for that, generic lazy loading cache helper (AddOrGetExistingCacheEntry) to use as localized cache for several internal processes.
Have they added something like that to the basic system memorycache?
I really wish we would stop adding so much hidden indirection, making reading and debugging the code much harder than it need to be.
In so many places, proper seperation of logic and IO will make things like DI and mocs not needed, but if i could choose to kill just one thing, it would be automapper - the destroyer of code navigation and turning compile errors into runtime errors.
The delegating handler has to be registered as transient. Not scoped. Look into it a bit more. It should be registered as transient primarily because it is not thread-safe. If it were registered as scoped, the same instance could be reused across multiple HTTP requests within the same scope, which could lead to unintended side effects, race conditions, or other threading issues.
It can be registered as a singleton if the code you put in it is thread-safe.
Transient is the general recommendation by Microsoft because it’s the safest option but it’s not a "has to" thing. In this case for example there will be no scenario where scoped causes unexpected behaviour
If this vid came out one week earlier I would implement this, and not make a manual cache... Oh well there is always next time..
Isn't there an issue where you can read the response.Content only once or does that happen only if you wrap the content in a using block?
Why would you make a custom handler instead of just caching the response from the api?
Maybe you might have 2 different sets of business logic that do different things, but still depend on the same api.
What James said. Because it's a differnet layer of caching specific to the single API. You might not want that for the complete API response especially for things like auth
Can i use this iin tge multi tenent architecture
Is there any way the handle could pass custom information to the caller? For example whether the response comes from cache or the the actual api?
Just add custom header for cached cases or something like this - you are in full control there.
Why we need to use this methods and classes and not cache in our service layer?
I did the same thing for bearer token management.
Same thing 😅... Company OAuth lib
Isn't this an overengineering? You can add caching to the method that make the call to the API and that does the same thing without adding extra layer of classes
Does that class need to know about the caching? I would argue it doesn't. Same with something like adding retry policies or fallbacks. It's not the responsibility of that class to know that IMO but it heavily depends on context as well
great point. That's the usual implementation we do, usually we create a class responsible for dealing with weather data (CacheWeather), and that class would be the one with the logic for caching or httping it and later return to the service class
I can't help but feel like all of this could've been made simpler if some of the types related to HttpClient used interfaces so we could transparently decorate them with caches/retries if we wanted to.
every time I make a HTTPS post call with httpclient class, Httpclient response is very slow. any way to speed it up. Mean while post request to http is fast, its https that is causing issue
Caching should be done at the service level not the http client level. Like this, you're caching any request (weather API or not) plus other issues too.
No you’re not. This handler is only used by the weather api and only caches for the weather api
@@nickchapsas You're right. I missed the named client part, but still, you don't control what the handler caches unless you write code that checks the content of the request and it can even run on non GET requests.
@@parlor3115 I agree with you. Caching of HTTP content should be based on HTTP cache control, etag, last modified and so on. This is what could be handled at the HTTP client side in a DelegatingHandler (or a reverse proxy cache). If an upstream service however does not provide HTTP level caching, and/or you do not have a reverse proxy cache, by all means introduce cache in your application if you need to have this data frequently, but keep it in the domain/service using a service decorator pattern or something alike.
Anyone knows the screen magnyfier Amichai is using?
ZoomIt
@@birolaydin4731 ZoomIt does not support these rainbow colors. He‘s using macOS with Presentify in that case.
Do the courses give certificates?
Yes
That's Refit, with extra steps and less features.
Or you can just create an extension method so that future developers don't have to go through all the documentation to understand this hidden functionality. xD Nice video tho!
The approach looks clever but I don't like it. It increases the amount of magic in the app. A new dev who comes there after 3 years might be killed by this clever stuff when the app behaves not as expected. It would be much better to implement such a feature even with an abstract class despite the fact that abstract classes rarely a good solution. But here even an abstract class would be much better.
Just a friendly reminder that IMemoryCache is not thread safe, and could be choke point if impelemted the way Nick showed in this video.
Nick has even video about that 😄:
ruclips.net/video/Q3KzZeUudsg/видео.htmlsi=4HhjlX6bUbEHfV2R
you flash your API key
Go on, use it
laughed my arse off when I saw this comment ;) @@nickchapsas
Love your videos, have been a big fan for a while now but profanity is not cool my dude
Ha ha ha ha ha ... "In London, a lot" ..
He is not wrong, is he? 😂
calling http handlers a secret feature is a bit of an overstatement
Imagine using it in a company's project 😂
If it is "secret" it is poorly documented bij MS
Those click-bait titles Nick uses are really frustrating.
I understand why they are used, but anyway
Interesting topic, but no need to take the name of Jesus Christ in vain (around 3:25).
Man, I was left with a bad taste in my mouth when I started watching this. You don't even have the guts to own your slip of tongue. Sorry if it was intentional, You lost me.
Love your videos but please don’t use profanity.
First
Second
Охуенно