You can use the object caching infrastructure to cache your user data in Episerver. That way the client (browser) can call the API again and again, without also hitting your back-office system all the time.
I actually wrote a long blog post about this scenario, where I described how to read through the cache, and how to force invalidation of cache objects. It's called Caching data that depends on Episerver content.
Hope it helps you out.
Hi Steffen
Thanks for your quick reply. We have three different types of classes which are calling API endpoints, blockcontrollers,pagecontrollers,VisitorGroups Criteria for pages/blocks. Right now i have implemented methods in base controllers of both page & block. Where should the method be residing, as right now I am sending all the arguemnts from Controller as they are being inject there through DI. The other question is som API endpoints can be cached for 10 or more minutes, while others for 2-3 minutes (data can be changed quickly), should I created method overload with different CacheEvicationPolicy.
I am gernerating cache key for each cache object by setting masterkey(unique) with object name. Should this key be dependent on Masterkey, so If i want to remove cached object i can do so by master key ?
If the user sign out should the caching be invalidated or its ok to let it be as 10 minutes will expire the caching.
Tak på forhånd
protected T APICaching<T>(Func<T> act, ISynchronizedObjectInstanceCache objectCaching, IAuthPersister authPersister) where T : class
{
return objectCaching.ReadThrough(objectCaching.GenerateCacheKey<T>(authPersister.GetCacheKey()),
act.Invoke,
x => new CacheEvictionPolicy(
TimeSpan.FromMinutes(10),
CacheTimeoutType.Absolute), ReadStrategy.Wait);
}
Det var så lidt. 😉
Here are my answers to your questions:
HI Steffen
Thanks for your input.
Now I have created a service class which I inject in Controllers. The issue I am facing is that page controller can call API endpoints async while blocks call sync. How can the method be made async. I could not find any reference where ReadThrough() is async.
Here is the code:
public T ApiCachi<T>(Func<T> act, int minutes = 10) where T : class
{
var masterkey= "masterkey";
return _cacheWithHelper.ReadThrough(_cacheWithHelper.GenerateCacheKey<T>(userCacheKey),
act,
x =>
{
string[] dependentKeys =
{
masterkey
};
return new CacheEvictionPolicy(
TimeSpan.FromMinutes(minutes),
CacheTimeoutType.Absolute, dependentKeys);
}, ReadStrategy.Wait);
}
//Page Controller Async Index method
var data = await _Caching.ApCachi(()=> _member.Data());
//Block controller
var xx = _Caching.ApiCachi(()=> _yt.IndexAsync()).Result;
The other issue I am facing is that I am using ReadStrategy.Wait due to having many blocks on the page. Is this the best way, because when the method is called by the page, then there is only one call to this method ?
It's true that the ReadThrough
method is not seen with async reader functions.
If it can't be adjusted to async, you can use the TryGet
and Insert
methods instead, where your perform your async call in between.
ReadStrategy.Wait
is great if the fetching method is resource-intensive. So Episerver will keep all simultaneous requests to the same cache key on hold, while one request fetches the data from the external system. Then it will serve the other requests from the cache.
Also, don't use .Result
on a Task
instance. It's much better and safer to copy and use this AsyncHelper
class.
Thanks alot
Can caching of user data (in thousands) have an impact on EPIServer Database ? And will caching obejcts get deleted from memory on timeout?
I am also trying to unit test the method by mocking it.
var dataClient = new Mock<IDataClient>();
dataClient.Setup(mock => mock.DataAync()).ReturnsAsync(_userPreferences);
var apiCache = new Mock<IApiCaching>();
apiCache.Setup(mock => mock.ApiCachi(() => dataClient.Object.DataAsync(), It.IsAny<int>())).ReturnsAsync(_userPreferences);
// Block controller
var data = _apiCaching.apiCache(() => _mdClient.DataAsync().Result);
Data is always null
Hi
We have an internal API, which is called after authenticate to get the user info, details etc. The problem we are facing right now is that on one page there are serveral blocks which call the same endpoint plus some other endpoints on API. If i call the API direct from browser then the browser is able to cache the response even though the reponse headers include cache-control:"Private". I know the browser is a client application and can cache the reponse. How can I cache the same reponse in EPiServer, as the samme calls to the API server is giving a lot of performance issue especially in peak times ?
We are using HttpClient object (namespace: System.Net.Http)to send HTTP requests to internal API. As these are blocks so asynchronous calls are not possible due to the child actions.
What will be the best strategy to handle the caching as this is user data which can be changed so it shouldn't be cached for long time.