我有一个客户视图模型,其中包含用于选择国家/地区,区域和语言的下拉列表。我正在使用ViewComponent为下拉列表加载必要的数据,它就像魅力一样。我的问题是,当它们是页面上的多个客户端模型时,我正在多次调用外部API来接收相同的数据。我试图将Component.InvokeAsync部分放在缓存标记帮助程序中,但它也保留了第一次调用时命名的元素并混淆了模型绑定。有没有办法避免多次调用相同的数据?
这是代码的样子。没什么特别的。视图只是绑定属性,并没有任何特殊的东西。
[ViewComponent(Name = "LocationSelector")]
public class LocationSelector : ViewComponent
{
private readonly ILocationService locationsService;
public LocationSelector(ILocationService locationService)
{
this.locationsService = locationService;
}
public async Task<IViewComponentResult> InvokeAsync()
{
var locationManager = new LocationSelectorViewModel();
locationManager.Areas = await this.locationsService.GetAreas();
locationManager.Countries = await this.locationsService.GetCountries();
return View("Default", locationManager);
}
}
这个组件在客户模型中被调用。问题是我的页面中可能有多个客户,他们都会向服务请求完全相同的数据。
@await Component.InvokeAsync(nameof(LocationSelector))
答案 0 :(得分:1)
您应该考虑缓存数据。您可以使用IMemoryCache imeplemenation。我更喜欢创建自己的抽象层,我会在任何需要的地方使用它。
public interface ICache
{
T Get<T>(string key, Func<T> updateExpression = null, int cacheDuration=0);
}
public class InMemoryCache : ICache
{
readonly IMemoryCache memoryCache;
public InMemoryCache(IMemoryCache memoryCache)
{
this.memoryCache = memoryCache;
}
public T Get<T>(string key, Func<T> updateExpression = null,int cacheDuration=0)
{
object result;
if (memoryCache.TryGetValue(key,out result))
{
return (T) result;
}
else
{
if (updateExpression == null)
{
return default(T);
}
var data = updateExpression();
if (data != null)
{
var options = new MemoryCacheEntryOptions
{
AbsoluteExpiration = DateTime.Now.AddSeconds(cacheDuration)
};
this.memoryCache.Set(key, data, options);
return data;
}
return default(T);
}
}
}
现在在你的启动类的ConfigureServices方法中,启用缓存并定义我们的自定义ICache-InMemoryCache映射。
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<ICache, InMemoryCache>();
services.AddMemoryCache();
}
现在,您可以将ICache
注入任何类,并使用它来获取/存储数据。
public class LocationSelector : ViewComponent
{
private readonly ILocationService locationsService;
private readonly ICache cache;
public LocationSelector(ILocationService locationService,ICache cache)
{
this.locationsService = locationService;
this.cache = cache;
}
public async Task<IViewComponentResult> InvokeAsync()
{
var locationManager = new LocationSelectorViewModel();
var areas = await this.cache.Get(CacheKey.Statuses, () =>
this.locationsService.GetAreas(),360);
locationManager.Areas = areas;
return View("Default", locationManager);
}
}