使用Servicestack,如何在将AutoQuery与ServiceSource一起使用时缓存结果集?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (1)
  • 关注 (0)
  • 查看 (22)

我试图将ServiceStack的AutoQuery与服务源一起使用,但要么无法使缓存正常工作,要么误解了它应该如何工作。

我想要实现的是向“边缘”微服务添加查询功能,该微服务调用提供完整数据列表的内部服务。

重现我的问题的最小代码:

class Program
{
    static async Task Main(string[] args)
    {
        IWebHost host = new WebHostBuilder()
            .UseKestrel((builderContext, options) => options.Configure(builderContext.Configuration.GetSection("Kestrel")))
            .UseStartup<Startup>()
            .Build();
        await host.RunAsync();
    }
}

public class Startup
{
    public void ConfigureServices(IServiceCollection services) {}
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseServiceStack(new AppHost());
        app.Run(context => Task.FromResult(0));
    }
}

public class AppHost : AppHostBase
{
    public AppHost() : base("Hello Web Services", typeof(HelloService).Assembly){ }

    public override void Configure(Funq.Container container)
    {
        container.AddSingleton<ICacheClient, MemoryCacheClient>(); // Otherwise HostContext.Cache is null
        Plugins.Add(new AutoQueryDataFeature { MaxLimit = 3, IncludeTotal = true }.AddDataSource(ctx => ctx.ServiceSource<string>(new Hello(), HostContext.Cache, TimeSpan.FromMinutes(5))));
    }
}

// Request DTO
[Route("/hello")]
[Route("/hello/{Name}")]
public class Hello : QueryData<NameDto>
{
    [QueryDataField(Condition = "StartsWith", Field = nameof(Name))]
    public string Name { get; set; }
}

public class NameDto
{
    public string Name { get; set; }
}

public class HelloService : Service
{
    public IAutoQueryData AutoQuery { get; set; }
    public async Task<object> Any(Hello query)
    {
        //Imagine I was making a service call to another microservice here...
        var data = new List<NameDto> { new NameDto { Name = "Bob" }, new NameDto { Name = "George" }, new NameDto { Name = "Baldrick" }, new NameDto { Name = "Nursey" }, new NameDto { Name = "Melchett" }, new NameDto { Name = "Kate" } };

        DataQuery<NameDto> dataQuery = AutoQuery.CreateQuery(query, Request, new MemoryDataSource<NameDto>(data, query, Request));

        return AutoQuery.Execute(query, dataQuery);
    }
}   

Nuget包:Mircosoft.AspNetCore.All(2.2.1)和ServiceStack(5.4.0)

因此,在控制台(.NET Core 2.2)中,上面的代码将启动并侦听端口5000。

如果我查询,我得到我的列表,这是限于预期的结果数量,我也可以跳过/采取预期。

但是,每次调用服务方法时,结果都不会被缓存(在我注册插件时指定 - 缓存5分钟),如果我在服务方法中放置断点,则“名称”列表为每次都重新创建。即使我向服务提出相同的请求,也会发生这种情况。

我希望能够缓存结果集(在内存中很好),并且只在缓存过期时点击服务方法。我在这里做错了什么(或误解)?

提问于
用户回答回答于

如果您在Service实现中使用AutoQuery,它只是一个自定义AutoQuery实现,而不是查询普通服务结果的AutoQuery服务数据源

在这种情况下,听起来你确实需要一个可缓存的自动查询服务数据源,文档在其GetGithubRepos服务中显示了一个示例,该服务对GitHub的第三方API进行API调用:

public class QueryGithubRepo : QueryData<GithubRepo> 
{
    public string User { get; set; }
    public string Organization { get; set; }
}

public object Get(GetGithubRepos request)
{
    if (request.User == null && request.Organization == null)
        throw new ArgumentNullException("User");

    var url = request.User != null
        ? $"https://api.github.com/users/{request.User}/repos"
        : $"https://api.github.com/orgs/{request.Organization}/repos";

    return url.GetJsonFromUrl(requestFilter:req => req.UserAgent = GetType().Name)
        .FromJson<List<GithubRepo>>();
}

然后在注册Service DataSource时注册它是一个缓存的服务数据源

Plugins.Add(new AutoQueryDataFeature { MaxLimit = 100 }
    .AddDataSource(ctx => ctx.ServiceSource<GithubRepo>(ctx.Dto.ConvertTo<GetGithubRepos>(), 
        HostContext.Cache, TimeSpan.FromMinutes(5)));
);

您可以使用HostContext.LocalCache它将其缓存在本地内存缓存中,而不是注册的ICacheClient 缓存提供程序中

扫码关注云+社区

领取腾讯云代金券