重复 ViewComponent 数据

Repeating ViewComponent data

我有一个客户视图模型,其中包含用于选择国家、地区和语言的下拉列表。我正在使用 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))

您应该考虑缓存数据。您可以使用 IMemoryCache 实现。我更喜欢创建自己的抽象层,我会在任何需要的地方使用它。

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

现在在您的启动 class 的 ConfigureServices 方法中,启用缓存并定义我们的自定义 ICache-InMemoryCache 映射。

public void ConfigureServices(IServiceCollection services)
{
   services.AddTransient<ICache, InMemoryCache>();
   services.AddMemoryCache();
}

现在您可以将 ICache 注入任何 class 并将其用于 get/store 数据。

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