1

So I understands that ServiceStack is a different framework to AspNetcore, let's say a loyalty system where a user choose some criteria in filtering some customers using ServiceStack Autoquery, system will periodically send some newsletter to them, and the customers who fall into this criteria will change overtime, so instead saving all customer ids, I think it is more reasonable to save the QueryDb, for example, we decide serialize QueryMerchantCustomers and persist it in database and desterilize from database, when the hosted service needs to use it. So the question is how to call the below function in aspnetcore hostedservice ?

public ObjectsResponse<Customer> Any(QueryMerchantCustomers qry)
{
    if (!_authHandler.VerifyJwt(Request, out var claimsPrincipal, "user", qry.MerchantGuid))
    {
        base.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
        base.Response.EndRequest();
    }
    var res = new ObjectsResponse<Customer>();
    var customers = new List<Customer>();
    if (string.IsNullOrEmpty(qry.MerchantGuid))
    {
        res.Errors.Add("Merchant guid can not be null or empty");
        return res;
    }
    var merchant = _jointMerchantHandler.GetMerchantByGuidAsync(qry.MerchantGuid).GetAwaiter().GetResult();
    // make it re-usable in future
    if (qry.Page > 0 && qry.Limit > 0)
    {
        qry.Page -= 1;
        qry.Skip = qry.Page * qry.Limit;
        qry.Take = qry.Limit;
    }
    var q = AutoQuery.CreateQuery(qry, base.Request);
    q.And<UserDetail>(x => x.LicenseId == merchant.LicenseId && !x.IsDelete);
    var result = AutoQuery.Execute(qry, q);
    res.CountAll = result.Total;
    if (result.Results.Count > 0)
    {
        var details = _userDetailRepo.Select(x => x.LicenseId == merchant.LicenseId && Sql.In(x.UserId, result.Results.Select(x => x.Id).ToList()));
        foreach (var user in result.Results)
        {
            customers.Add(user.ToCustomer().MergeDetail(details.FirstOrDefault(x => x.UserId == user.Id)));
        }
    }
    res.Data = customers;
    return res;
}

mythz
  • 141,670
  • 29
  • 246
  • 390
Steven Li
  • 754
  • 1
  • 8
  • 16

1 Answers1

1

You're changing the expected typed Response Type of the AutoQuery Service from QueryResponse<Customer> to ObjectsResponse<Customer> which is going to cause issues in typed client which are expecting the AutoQuery Response DTO.

So you're going to have issues trying to call this with ServiceStack C#/.NET Clients or Service Gateway. If you want to change the response Type I would instead call a different API which uses the response from this API (e.g. with the Service Gateway) otherwise change QueryMerchantCustomers so that it's not an AutoQuery Service as it's currently lying about its Response Type.

As it stands with an incompatible Response Type you'll only be able to call the Service Directly using:

var req = HttpContext.ToRequest(); // Convert ASP.NET HttpContext to IRequest
using var merchantServices = HostContext.ResolveService<MerchantServices>(req);
var response = merchantServices.Any(new QueryMerchantCustomers { ... });

Your services should also never be doing sync over async:

var merchant = _jointMerchantHandler.GetMerchantByGuidAsync(qry.MerchantGuid).GetAwaiter().GetResult();

Instead change your ServiceStack API to use an async method:

public async Task<object> AnyAsync(QueryMerchantCustomers qry)
{
}
mythz
  • 141,670
  • 29
  • 246
  • 390
  • Thanks for your educational highlights. Meaning if I modify the response type, I will be able to call AutoQuery through GetServiceGateway ? – Steven Li Dec 05 '22 at 08:42
  • Yeah if you return the correct response type for the API (i.e. that matches its `IReturn` marker) you'll be able to call it through typed .NET clients and Service Gateway. – mythz Dec 05 '22 at 10:57
  • this is actually not what I want to achieve```var req = HttpContext.ToRequest(); // Convert ASP.NET HttpContext to IRequest using var merchantServices = HostContext.ResolveService(req); var response = merchantServices.Any(new QueryMerchantCustomers { ... });``` . is there a way to get the autoquery generated raw sql, so maybe I can store that and make future query using that. – Steven Li Dec 08 '22 at 03:25
  • @StevenLi please don't put code blocks in comments, add it to a new question instead. You can get generated SQL with `ToSelectStatement()` or `SelectInto*` APIs of the `q` typed SqlExpression, however that's incomplete without the parameters in `q.Params`. – mythz Dec 08 '22 at 03:44
  • Noted with your feedback. – Steven Li Dec 08 '22 at 05:28