Reputation: 1339
I created a ViewComponent
to display a List<Product>
, the list is valorized taken data from a REST API
service, this is my class implementation:
public class ProductsViewComponent : ViewComponent
{
private readonly HttpClient _client;
public ProductsViewComponent(HttpClient client)
{
_client = client ?? throw new ArgumentNullException(nameof(client));
}
public async Task<IViewComponentResult> InvokeAsync(string date)
{
using (var response = await _client.GetAsync($"/"product/get_products/{date}"))
{
response.EnsureSuccessStatusCode();
var products = await response.Content.ReadAsAsync<List<Product>>();
return View(products);
}
}
}
I load the List inside an html table which is available inside the Components
folder: Views\Shared\Components\Products\Default.cshtml
.
In each View
that needs to display the Products
I did:
@await Component.InvokeAsync("Products", new { date = myDate })
The REST API
is called using the HttpClient
configured in the Startup.cs
as following:
services.AddHttpClient<ProductsViewComponent>(c =>
{
c.BaseAddress = new Uri('https://api.myservice.com');
});
This works well, but the main problem is each time the user reload the page or maybe go inside another View which require to display the list of products, then the app will make another API
call.
Is possible store the list in something like a cache and prevent to call the API
again if the date is equal than the previous date selected?
I'm learning ASP.NET Core
so I'm not really expert on this argument.
Thanks in advance for any help.
Upvotes: 1
Views: 15231
Reputation: 2056
As per microsoft documentation https://learn.microsoft.com/en-us/aspnet/core/performance/caching/memory?view=aspnetcore-2.1
you can use IMemoryCache
to cache data
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
public void Configure(IApplicationBuilder app)
{
app.UseMvcWithDefaultRoute();
}
}
and create instance of IMemoryCache
. This is an example from Microsoft documentation. You can Create another class to handle this all together and In below example this is just saving DateTime But, you can save any object in cache and when you try to read that value from cache just need to cast that object into a Type.
I will strongly recommend you go through the above documentation.
public class HomeController : Controller
{
private IMemoryCache _cache;
public HomeController(IMemoryCache memoryCache)
{
_cache = memoryCache;
}
public IActionResult CacheTryGetValueSet()
{
DateTime cacheEntry;
// Look for cache key.
if (!_cache.TryGetValue(CacheKeys.Entry, out cacheEntry))
{
// Key not in cache, so get data.
cacheEntry = DateTime.Now;
// Set cache options.
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Keep in cache for this time, reset time if accessed.
.SetSlidingExpiration(TimeSpan.FromSeconds(3));
// Save data in cache.
_cache.Set(CacheKeys.Entry, cacheEntry, cacheEntryOptions);
}
return View("Cache", cacheEntry);
}
}
Update: CacheKeys.Entry
is a static class where all keys are defined. (Just coding standards). Please check the above documentation link.
public static class CacheKeys
{
public static string Entry { get { return "_Entry"; } }
public static string CallbackEntry { get { return "_Callback"; } }
public static string CallbackMessage { get { return "_CallbackMessage"; } }
public static string Parent { get { return "_Parent"; } }
public static string Child { get { return "_Child"; } }
public static string DependentMessage { get { return "_DependentMessage";} }
public static string DependentCTS { get { return "_DependentCTS"; } }
public static string Ticks { get { return "_Ticks"; } }
public static string CancelMsg { get { return "_CancelMsg"; } }
public static string CancelTokenSource { get { return "_CancelTokenSource";} }
}
Upvotes: 5
Reputation: 155
You can use a distributed cache and so use Redis for example with a ConnectionMultiplexer.
And so foreach call you can call your redis for the cache which is implement thanks to an interface call here 'IDistributedCache'
You can find a lot of documentation to implement cache and use it.
: .Net framework
DotNet Core
Your controller X :
[HttpGet]
[Route("{itemId}")]
public async Task<IHttpActionResult> GetItemById(int eventId, [FromUri]EventTabs tabId)
{
ServiceResponse<ItemDto> result = await _itemDispatcher.GetItemById(itemId);
return WrapResponse(result);
}
Your dispatcher to get the item by id which use redis cache (already implement)
public class ItemDispatcher : ItemDispatcher
{
private readonly IUnitOfWork _unitOfWork;
private readonly IDistributedCache _distributedCache; // use interface of your implementation of redis cache
private readonly int _cacheDuration;
private readonly bool _isCacheEnabled;
public EventDispatcher(IUnitOfWork unitOfWork, IDistributedCache distCache)
{
_unitOfWork = unitOfWork;
_distributedCache = distCache; // init cache in constructor
_cacheDuration = _configuration.Get<int>("cache.duration"); // duration of your cache
_isCacheEnabled = _configuration.Get<bool>("cache.isEnable"); // if the cache is enable or not
}
public async Task<ServiceResponse<ItemDto>> GetItemById(int id)
{
// Add this for each Task call
var cacheKey = string.Empty;
if (_isCacheEnabled)
{
cacheKey = CacheUtils.GetCacheKey(CacheKeys.Item, id);
itemDto cacheResult = await _distributedCache.Get<ItemDto>(cacheKey);
if (cacheResult != null)
return new ServiceResponse<Item>(cacheResult);
}
}
Upvotes: 1
Reputation: 882
Try This
Cache["KeyName"] = VariableOrTable; Cache.Insert("Key", VariableOrTable, null,
Cache.NoAbsoluteExpiration, ts);
Upvotes: 0