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

How to: Extend A Service With A New Method

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 topic describes how to extend the generated ServiceStack service with custom service methods. Suppose you have a solution in which the Category entity (based on the Northwind sample database) is exposed through ServiceStack with the help of Service Wizard. By default, the CRUD operations for Category will be supported by the five service methods defined in the CategoryService class. Suppose that your scenario requires you to have a service method, which will retrieve a category by its name. To implement it, you can use one of the following approach:

Do not modify the original source files generated by the Service Wizard. If you re-generate your ServiceStack layer later, all changes will be lost. Instead, you can use partial types and new class files for your custom code.

  1. In the DTO project, add a class file called CategoryServiceMessages.partial.cs(.vb). This file will hold the request and response messages used by ServiceStack for the new service method.
  2. Open the newly added file, and make sure that the namespace in it is the same as the one in the CategoryServiceMessages.cs(.vb) file. Inside this namespace define the GetCategoryByName class and the GetCategoryByNameResponse class. For example:

    using EntitiesModelServicesDTOs.CoreDTOs;
    using ServiceStack;
    namespace EntitiesModelServicesDTOs.CategoryServiceMessages
    {
        public partial class GetCategoryByName : IReturn<GetCategoryByNameResponse>
        {
            public String CategoryName { get; set; }
        }
        public partial class GetCategoryByNameResponse
        {
            public CategoryDTO Category { get; set; }
        }
    }
    
    Imports EntitiesModelServicesDTOs.CoreDTOs
    Imports ServiceStack
    Namespace EntitiesModelServicesDTOs.CategoryServiceMessages
        Partial Public Class GetCategoryByName
            Implements IReturn(Of GetCategoryByNameResponse)
            Public Property CategoryName() As String
        End Class
        Partial Public Class GetCategoryByNameResponse
            Public Property Category() As CategoryDTO
        End Class
    End Namespace
    
  3. In the project which holds the code base of the ServiceStack layer, add a new class called CategoryService.partial.cs(.vb). This file will hold the custom code required for the new service method.

  4. Open the newly added file, and make sure that the namespace in it is the same as the one in the CategoryService.cs(.vb) file. Depending on whether your code is on C# or on VB, you can choose from the following options:

    • For C# - In the same namespace, extend the ICategoryServiceImplementation interface with the signature of the new service method:

        public partial interface ICategoryServiceImplementation
        {
            GetCategoryByNameResponse Get(GetCategoryByName request);
        }
      
    • For VB - Open the CategoryService.vb file and in the body of the ICategoryServiceImplementation interface, add the signature of the new service method:

        Public Interface ICategoryServiceImplementation
            Property ServiceReference() As Service
            Function [Get](request As QueryCategories) As QueryResponse(Of CategoryDTO)
            Function [Get](request As GetCategoryById) As GetCategoryByIdResponse
            Function Post(request As AddCategory) As HttpResult
            Sub Put(request As UpdateCategory)
            Sub Delete(request As DeleteCategory)
            '
            'The signature of the new method
            Function [Get](request as GetCategoryByName) As GetCategoryByNameResponse
            '
        End Interface
      

      On VB, if you re-generate the service layer, you will have to repeat this step.

  5. In the same file and namespace, extend the CategoryServiceImplementation type with the actual logic of the new service method:

    public partial class CategoryServiceImplementation
    {
        public virtual GetCategoryByNameResponse Get(GetCategoryByName request)
        {
            ServiceStack.Model.Category category = this.repository.
                                                        GetBy(c => c.CategoryName == 
                                                                   request.CategoryName);
            if (category == null)
            {
                throw new HttpError(HttpStatusCode.NotFound, 
                                    "Resource not available.", 
                                    "A Category object with the specified name is not available.");
            }
            GetCategoryByNameResponse response = new GetCategoryByNameResponse();
            response.Category = category.ConvertTo<CategoryDTO>();
            return response;
        }
    }
    
    Partial Public Class CategoryServiceImplementation
        Public Overridable Function [Get](ByVal request As GetCategoryByName) As GetCategoryByNameResponse _ 
        Implements ICategoryServiceImplementation.Get
            Dim category As Category = Me._repository.GetBy(Function(c) c.CategoryName = 
                                                                request.CategoryName)
            If category Is Nothing Then
                Throw New HttpError(HttpStatusCode.NotFound, 
                                    "Resource not available.", 
                                    "A Category object with the specified name is not available.")
            End If
            Dim response As New GetCategoryByNameResponse()
            response.Category = category.ConvertTo(Of CategoryDTO)()
            Return response
        End Function
    End Class
    
  6. Again in the same file and namespace, add a partial class, which will extend the CategoryService class with the definition of the new method. For example:

    using EntitiesModelServicesDTOs.CategoryServiceMessages;
    using EntitiesModelServicesDTOs.CoreDTOs;
    using System.Web;
    namespace ServiceStack.Demo
    {
        public partial class CategoryService
        {
            public GetCategoryByNameResponse Get(GetCategoryByName request)
            {
                return this.categorySvcImp.Get(request);
            }
        }
    }
    
    Imports EntitiesModelServicesDTOs.CategoryServiceMessages
    Imports EntitiesModelServicesDTOs.CoreDTOs
    Imports ServiceStack.Demo.VB
    Imports ServiceStack.Model.VB
    Imports System.Net
    Partial Public Class CategoryService
        Public Function [Get](ByVal request As GetCategoryByName) As GetCategoryByNameResponse
            Return Me._categorySvcImp.Get(request)
        End Function
    End Class
    
  7. The new service method has to be register it in the ServiceStack service host. This means, that you need to extend the AppHost class in a partial class, and to implement the RegisterCustomRoutes method. To do this, you need to add a new class in the application that hosts the service layer. Call it AppHost.partial.cs. Make sure that the namespace of the newly added class is the same as the one of the AppHost class. In the class body add the implementation of the RegisterCustomRoutes method. For example:

    using EntitiesModelServicesDTOs.CategoryServiceMessages;
    namespace ServiceStack.Demo
    {
        public partial class AppHost
        {
            partial void RegisterCustomRoutes(ref bool shouldRegisterDefaultRoutes)
            {
                shouldRegisterDefaultRoutes = true;
                this.Routes.Add<GetCategoryByName>(CategoryService.CategoriesBasePath + 
                                                   "/ByName/{CategoryName}", ApplyTo.Get);
            }
        }
    }
    
    Imports EntitiesModelServicesDTOs.CategoryServiceMessages
    Partial Public Class AppHost
        Private Sub RegisterCustomRoutes(ByRef shouldRegisterDefaultRoutes As Boolean)
            shouldRegisterDefaultRoutes = True
            Me.Routes.Add(Of GetCategoryByName)(CategoryService.CategoriesBasePath & _
                "/ByName/{CategoryName}", ApplyTo.Get)
        End Sub
    End Class
    
  8. Build the solution and start the web application.
  9. You can test the new web service on URL similar to the following:

    http://localhost:<port_number>/Categories/ByName/{CategoryName}