servicestackservicestack-razorservicestack-autoquery

ServiceStack - Autoquery & Swapping Client Templates


Using ServiceStack's Autoquery I have a simple Request DTO defined (example below). I would like to swap templates (Layouts) to use a different Razor layout (as per the SS templates swap documentation here)?

Example of Request DTO:

Route("/customers", "GET")]
public class QueryCustomers : QueryDb<FindFilesResponse>
{

}

Example of Layouts: _Layout.cshtml and _PrintFriendly.cshtml templates

For above query I would like to swap layouts at the client level.


Solution

  • All the ClientCanSwapTemplatesAttribute does is populate the IRequest.Items dictionary from the HTTP Request params:

    public class ClientCanSwapTemplatesAttribute : RequestFilterAttribute
    {
        public override void Execute(IRequest req, IResponse res, object requestDto)
        {
            req.Items["View"] = req.GetParam("View");
            req.Items["Template"] = req.GetParam("Template");
        }
    }
    

    So you could choose to do this in a Request Filter, e.g:

    RegisterTypedRequestFilter<QueryCustomers>((req, res, dto) =>
    {
        req.Items["View"] = req.GetParam("View");
        req.Items["Template"] = req.GetParam("Template");
    });
    

    Alternatively in order to be able to use Filter Attributes on AutoQuery Services since they're implementation is auto-generated is to create a Custom AutoQuery implementation, e.g:

    [ClientCanSwapTemplates]
    public class MyQueryServices : Service
    {
        public IAutoQueryDb AutoQuery { get; set; }
    
        //Override with custom implementation
        public object Any(QueryCustomers query)
        {
            var q = AutoQuery.CreateQuery(query, base.Request);
            return AutoQuery.Execute(request, q);
        }
    }
    

    Whilst Filter attributes would also work when annotated on the Request DTO, i,e:

    [ClientCanSwapTemplates]
    [Route("/customers", "GET")]
    public class QueryCustomers { ... }
    

    They're usage is discouraged because they would add dependencies to your Service Model. But another solution could be to add Attributes dynamically in your AppHost constructor, e,g:

    public class AppHost : AppHostBase
    {
        public AppHost() 
        { 
            typeof(QueryCustomers)
                .AddAttributes(new ClientCanSwapTemplatesAttribute());
        }
    
        public override void Configure(Container container) { ... }
    }