简体   繁体   中英

How to store data in cache?

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.

As per microsoft documentation https://docs.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";} }   
}

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);
            }
    }

Try This

Cache["KeyName"] = VariableOrTable;  Cache.Insert("Key", VariableOrTable, null, 
Cache.NoAbsoluteExpiration, ts);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM