Data Access has been discontinued. Please refer to this page for more information.

Handling Query Request Parameters

This article is relevant to entity models that utilize the deprecated Visual Studio integration of Telerik Data Access. The current documentation of the Data Access framework is available here.

This article will give you details about the handling of the parameters provided by the query request, when you call a queryable SeviceStack service method.

General Information

Suppose you have a ServiceStack layer generated with Service Wizard. The layer exposes the Category and Product entities from the Northwind sample database. If you take a look at the generated service messages for the CategoryDTO class (in the EntitiesModelServicesDTOs class library), you will notice that the QueryCategories message implements the IQueryRequest interface.

public partial class QueryCategories 
    : QueryBase<CategoryDTO>, IQueryRequest
{
    public string Filter { get; set; }
    public string Include { get; set; }
    public bool InlineCount { get; set; }
}
Partial Public Class QueryCategories 
    Inherits QueryBase(Of CategoryDTO)
    Implements IQueryRequest
    Public Property Filter As String Implements IQueryRequest.Filter
    Public Property Include As String Implements IQueryRequest.Include
    Public Property InlineCount As Boolean Implements IQueryRequest.InlineCount
    Public Property Skip_Reroute As Nullable(Of Integer) Implements IQueryRequest.Skip
        Get
            Return MyBase.Skip
        End Get
        Set(value As Nullable(Of Integer))
            MyBase.Skip = value
        End Set
    End Property
    Public Property Take_Reroute As Nullable(Of Integer) Implements IQueryRequest.Take
        Get
            Return MyBase.Take
        End Get
        Set(value As Nullable(Of Integer))
            MyBase.Take = value
        End Set
    End Property
    Public Property OrderBy_Reroute As String Implements IQueryRequest.OrderBy
        Get
            Return MyBase.OrderBy
        End Get
        Set(value As String)
            MyBase.OrderBy = value
        End Set
    End Property
    Public Property OrderByDesc_Reroute As String Implements IQueryRequest.OrderByDesc
        Get
            Return MyBase.OrderByDesc
        End Get
        Set(value As String)
            MyBase.OrderByDesc = value
        End Set
    End Property
End Class

This interface, gives Telerik Data Access the ability to do server-side filtering, sorting, paging, and loading of related objects based on parameters provided in the query string. The ServiceStack layers generated with Service Wizard support the following keywords:

Parameter Syntax Example
Filter <PropertyName> <ComparisonOperator> ‘<Value>’ <and/or> … http://localhost/Categories?filter=CategoryID+gt+'3'
OrderBy* <PropertyName> http://localhost/Categories?OrderBy=CategoryName
OrderByDesc* <PropertyName> http://localhost/Categories?OrderByDesc=CategoryName
GroupBy* <PropertyName> http://localhost/Categories?GroupBy=CategoryID
Include <PropertyName> http://localhost/Categories?Include=Products
InlineCount <true/false> http://localhost/Categories?InlineCount=true
Skip* <SkipCount> http://localhost/Categories?Skip=1
Take* <TakeCount> http://localhost/Categories?Take=2
Format* <xml/json/jsv/csv> http://localhost/Categories?Format=xml

*These properties are inherited from the QueryBase<T> class.

For example, the parameters in the query request can be combined like this:

http://localhost/Categories?filter=CategoryID+gt+'3'&GroupBy=CategoryID&InlineCount=true&Include=Products&Skip=1&Take=2&Format=xml

By design, such query request will evoke the QueryResponse Get(QueryCategories request) method of CategoryService, and it will return in the XML format, the second and the third categories with IDs greater than 3 along with their relevant products.

How to: Handle The Include Parameter

Through the Include parameter you can expose a single navigational property. If your scenario requires you to expose more navigational properties, you need to implement the workflow demonstrated in the How to: Retrieve Related Entities article.

By default, the DTO classes generated by Service Wizard do not expose the navigational properties of a given entity, and the service methods neither retrieve them, nor populate them. To change this, you need to make a few modifications in the default behaviour of the queryable methods (for examle, the QueryResponse Get(QueryCategories request) method). The next steps will help you in this task:

  1. In the DTOs project, add a class file called CategoryDTO.partial.cs(.vb). In it file you will extend CategoryDTO in a partial class. For example:

    namespace EntitiesModelServicesDTOs.CoreDTOs
    {
        public partial class CategoryDTO
        {
            public IList<ProductDTO> Products { get; set; }
        }
    }
    
    Namespace CoreDTOs
        Partial Public Class CategoryDTO
            Public Property Products() As IList(Of ProductDTO)
        End Class
    End Namespace
    

    When your ServiceStack layer exposes multiple related entities, make sure to avoid circular references between the corresponding DTO classes.

  2. In the project which holds the code base of the ServiceStack layer, add a new class file called CategoryServiceImplementationExtended.cs(.vb). In it you will create a new class, which derives from the generated CategoryServiceImplementation. In this class you will override QueryResponse Get(QueryCategories request) in order to implement the required handling for the navigational property. The new body of the method will use the code from the base implementation with a few additional statements. These statements will build the IList<ProductDTO> Products property for each of the returned categories. For example:

    public partial class CategoryServiceImplementationExtended : 
        CategoryServiceImplementation, 
        ICategoryServiceImplementation
    {
        private ICategoryRepository repository;
        public CategoryServiceImplementationExtended(ICategoryRepository repository)
            : base (repository)
        {
            this.repository = repository;
        }
        public override QueryResponse<CategoryDTO> Get(QueryCategories request)
        {
            IDynamicQueryInfo dynamicQuery = 
                new DynamicQueryInfo<ServiceStack.Model.Category>(request);
            int? totalCategoriesCount = null;
            List<ServiceStack.Model.Category> categories = 
                this.repository.GetAllDynamic(dynamicQuery, 
                out totalCategoriesCount).ToList();
            List<CategoryDTO> responseCategories = new List<CategoryDTO>();
            foreach (ServiceStack.Model.Category category in categories)
            {
                //Code which handles the Products navigational property
                List<ProductDTO> products = new List<ProductDTO>();
                foreach (ServiceStack.Model.Product product in category.Products)
                {
                    ProductDTO productDTO = product.ConvertTo<ProductDTO>();
                    products.Add(productDTO);
                }
                CategoryDTO categoryDTO = category.ConvertTo<CategoryDTO>();
                categoryDTO.Products = products;
                responseCategories.Add(categoryDTO);
                //
            }
            QueryResponse<CategoryDTO> response = new QueryResponse<CategoryDTO>();
            response.Results = responseCategories;
            if (totalCategoriesCount.HasValue)
            {
                response.Total = totalCategoriesCount.Value;
            }
            if (request.Skip.HasValue && request.Skip.Value > 0)
            {
                response.Offset = request.Skip.Value;
            }
            return response;
        }
    }
    
    Imports ServiceStack.Demo.Repositories
    Imports EntitiesModelServicesDTOs.CategoryServiceMessages
    Imports ServiceStack.Demo.DynamicQueryUtils
    Imports EntitiesModelServicesDTOs.CoreDTOs
    Partial Public Class CategoryServiceImplementationExtended
        Inherits CategoryServiceImplementation
        Implements ICategoryServiceImplementation
        Private repository As ICategoryRepository
        Public Sub New(ByVal repository As ICategoryRepository)
            MyBase.New(repository)
            Me.repository = repository
        End Sub
        Public Overrides Function [Get](ByVal request As QueryCategories) As QueryResponse(Of CategoryDTO)
            Dim dynamicQuery As IDynamicQueryInfo = New DynamicQueryInfo(Of ServiceStack.Model.Category)(request)
            Dim totalCategoriesCount? As Integer = Nothing
            Dim categories As List(Of ServiceStack.Model.Category) = Me.repository.GetAllDynamic(dynamicQuery, totalCategoriesCount).ToList()
            Dim responseCategories As New List(Of CategoryDTO)()
            For Each category As ServiceStack.Model.Category In categories
                'Code which handles the Products navigational property
                Dim products As New List(Of ProductDTO)()
                For Each product As ServiceStack.Model.Product In category.Products
                    Dim productDTO_Renamed As ProductDTO = product.ConvertTo(Of ProductDTO)()
                    products.Add(productDTO_Renamed)
                Next product
                Dim categoryDTO_Renamed As CategoryDTO = category.ConvertTo(Of CategoryDTO)()
                categoryDTO_Renamed.Products = products
                responseCategories.Add(categoryDTO_Renamed)
                '
            Next category
            Dim response As New QueryResponse(Of CategoryDTO)()
            response.Results = responseCategories
            If totalCategoriesCount.HasValue Then
                response.Total = totalCategoriesCount.Value
            End If
            If request.Skip.HasValue AndAlso request.Skip.Value > 0 Then
                response.Offset = request.Skip.Value
            End If
            Return response
        End Function
    End Class
    
  3. In the web application that holds your ServiceStack layer, add a new class file called AppHost.partial.cs(.vb). In it you will extend the ServiceStack service host, in order to register the newly created service implementation class. This requires you to implement the ApplyCustomIocContainerServiceImplementationsConfiguration method. For example:

    public partial class AppHost : AppHostBase
    {
        partial void ApplyCustomIocContainerServiceImplementationsConfiguration(Funq.Container container, 
            ref bool shouldRegisterDefaultServiceImplementations)
        {
            shouldRegisterDefaultServiceImplementations = false;
            container.RegisterAutoWiredAs<CategoryServiceImplementationExtended, ICategoryServiceImplementation>()
                .ReusedWithin(ReuseScope.None);
            container.RegisterAutoWiredAs<ProductServiceImplementation, IProductServiceImplementation>()
                .ReusedWithin(ReuseScope.None);
        }
    }
    
    Partial Public Class AppHost
        Inherits AppHostBase
        Private Sub ApplyCustomIocContainerServiceImplementationsConfiguration(ByVal container As Funq.Container, _ 
            ByRef shouldRegisterDefaultServiceImplementations As Boolean)
            shouldRegisterDefaultServiceImplementations = False
             container.RegisterAutoWiredAs(Of CategoryServiceImplementationExtended, ICategoryServiceImplementation)() _
                .ReusedWithin(ReuseScope.None)
            container.RegisterAutoWiredAs(Of ProductServiceImplementation, IProductServiceImplementation)() _ 
                .ReusedWithin(ReuseScope.None)
        End Sub
    End Class
    

    At this point it is important to set shouldRegisterDefaultServiceImplementations to false before registering the new service implementation, and to make sure that the registrations for the rest of the entities in your service layer is placed in this method.

  4. Build your solution and run the application.

  5. You can test the new method on a URL similar to the following:

http://localhost/Categories?filter=CategoryID+gt+'3'&GroupBy=CategoryID&InlineCount=true
&Include=Products&Skip=1&Take=2&Format=xml