Getting Started

This is a tutorial that aims to help you to understand how to write a backend using Gazel. Before you begin, you need to create an empty solution.

You may download an empty solution to start right away. Once you open this solution, directory structure should look like this:

Inventiv.Todo
├── src
│   ├── Inventiv.Todo.App.Rest
│   ├── Inventiv.Todo.App.Service
│   └── Inventiv.Todo.Module.TaskManagement
└── test
    └── Inventiv.Todo.Test.TaskManagement

If you want to create an empty solution on your own, have a look at below pages;

Basically, you will need to create a new solution named Inventiv.Todo and add a new business module named Inventiv.Todo.Module.TaskManagement.

Now that you have done this, you are ready to get started 🚀

Hello World

In this tutorial, you will create a hello world service to have a quick feeling on how Gazel works.

Create a Hello World Service

To create a new business service, create a class named TaskManager in Inventiv.Todo.Module.TaskManagement project.

Inventiv.Todo
├── src
│   ├── Inventiv.Todo.App.Rest
│   ├── Inventiv.Todo.App.Service
│   └── Inventiv.Todo.Module.TaskManagement
│       └── TaskManager.cs
└── test
    └── Inventiv.Todo.Test.TaskManagement

Now add a new method called SayHello to TaskManager class as shown below.

namespace Inventiv.Todo.Module.TaskManagement
{
    public class TaskManager
    {
        public string SayHello()
        {
            return "Hello World";
        }
    }
}

public instance methods of classes within module projects are directly exposed as business services.

Now run Inventiv.Todo.App.Service project, and you will see a test page to be able to test your services.

On the left you will see that Gazel has rendered your TaskManagement module and listed TaskManager class as a service package, and under Task Manager it lists your SayHello method as a business service. Click Say Hello and press Call button to make a test service request. When you do, you will see a response saying Hello World.

Writing a Unit Test

Now that you have implemented the most basic business service, it is time to test it.

Create a class named TaskTest in Inventiv.Todo.Test.TaskManagement project.

Inventiv.Todo
├── src
│   ├── Inventiv.Todo.App.Rest
│   ├── Inventiv.Todo.App.Service
│   └── Inventiv.Todo.Module.TaskManagement
│       └── TaskManager.cs
└── test
    └── Inventiv.Todo.Test.TaskManagement
        └── TaskTest.cs

Write below code within this class;

using Gazel;
using Gazel.UnitTesting;
using Inventiv.Todo.Module.TaskManagement;
using NUnit.Framework;

namespace Inventiv.Todo.Test.TaskManagement
{
    [TestFixture]
    public class TaskTest : TestBase
    {
        static TaskTest()
        {
            Config.RootNamespace = "Inventiv";
        }

        [Test]
        public void SayHello__says_hello()
        {
            var taskManager = Context.Get<TaskManager>();

            Assert.AreEqual("Hello World", taskManager.SayHello());
        }
    }
}

Context property comes from TestBase which allows you to access IoC container. Manager classes are singleton by convention, so you can access to TaskManager instance by Context.Get<TaskManager>().

That's it. Now you can run this test to see if it succeeds.

Gazel uses NUnit for unit testing. For more information about NUnit see: NUnit Documentation

Summary of Hello World

As you can see no configuration is needed to create a new service. Once you've created your solution and projects, every public class in module projects becomes a service package and every public method becomes a service by convention.

Now try to add new methods or add parameters, re-run and see the results.

Once you are ready, you can proceed to create your first database operation using Gazel.


Here you can download source code for this tutorial.

Persistent Classes

In this tutorial, you will create a persistent class and make your first database operation using Gazel.

Create A Persistent Class

Database operations are done using Persistent objects.

An object is Persistent if its class injects its own repository. For more information see: Data Persistence

Create a new class named Task under TaskManagement module.

Inventiv.Todo
├── src
│   ├── Inventiv.Todo.App.Rest
│   ├── Inventiv.Todo.App.Service
│   └── Inventiv.Todo.Module.TaskManagement
│       ├── TaskManager.cs
│       └── Task.cs
└── test
    └── Inventiv.Todo.Test.TaskManagement
        └── TaskTest.cs

Add following code to your Task source file.

using Gazel;
using Gazel.DataAccess;

namespace Inventiv.Todo.Module.TaskManagement
{
    public class Task
    {
        private readonly IRepository<Task> repository;

        protected Task() { }
        public Task(IRepository<Task> repository)
        {
            this.repository = repository;
        }
    }

    public class Tasks : Query<Task>
    {
        public Tasks(IModuleContext context) : base(context) { }
    }
}

Each Task object will represent one row in Task table.

Tasks class is registered to IoC as a singleton by convention and it will consist of queries to that table. In this tutorial you will not write any queries. Leave this class empty for now.

Task class, by injecting its own repository, indicates that its a persistent class.

  • Notice that both classes are subject to dependency injection.
  • protected Task() { } constructor is there for NHibernate to create proxies for lazy loading.

Now you can add properties to your Task class as shown below;

...
public class Task
{
    ...
    public virtual int Id { get; protected set; }
    public virtual string Name { get; protected set; }
    public virtual bool Completed { get; protected set; }
    ...
}
...

First property is mandatory for all persistent classes. Gazel requires an integer Id column for every table.

  • The reason for protected setters is to implement domain logic inside persistent classes.
  • virtual keywords are there for NHibernate to create proxies for lazy loading.

These properties are automatically mapped to columns of Task table in gazel.tutorial.db database.

Note that you don't have to create tables and columns in your SQLite database. When in local development mode, Gazel configures NHibernate's SQLite connection to automatically create database schema.

Now add following method to Task class.

...
public class Task
{
    ...
    protected internal virtual Task With(string name)
    {
        Name = name;
        Completed = false;

        repository.Insert(this);

        return this;
    }
    ...
}
...

For persistent classes construction is in two steps. First step is the actual constructor, and second step is With methods which takes instance arguments and inserts a row to database via repository.

Go to TaskManager class in TaskManagement module and modify its content with the following code;

using Gazel;

namespace Inventiv.Todo.Module.TaskManagement
{
    public class TaskManager
    {
        private readonly IModuleContext context;

        public TaskManager(IModuleContext context)
        {
            this.context = context;
        }

        public Task CreateTask(string name)
        {
            return context.New<Task>().With(name);
        }
    }
}

You've created a business service named CreateTask that inserts a new task record with the given name. As mentioned above, construction is done in two steps;

  1. The first one is context.New<Task>() which initiates a new Task object using IoC container,
  2. And the second one is .With(name) which inserts a new record using its own repository.

So together you read this as "new task with name".

Now run App.Service project to see your new service Create Task and create tasks using it.

Note that Id's are assigned from database. This is the default mapping configuration Gazel applies to NHibernate.

Testing Persistent Objects

Go to TaskTest class in Test.TaskManagement add following test case;

...
[TestFixture]
public class TaskTest : TestBase
{
    ...
    [Test]
    public void CreateTask__creates_a_task_using_given_name()
    {
        var taskManager = Context.Get<TaskManager>();

        BeginTest();

        var actual = taskManager.CreateTask("Write Tests");

        Verify.ObjectIsPersisted(actual);
        Assert.AreEqual("Write Tests", actual.Name);
    }
    ...
}
...

You may remove SayHello__says_hello test case from previous tutorial.

Here is what this test does in terms of AAA pattern;

  • Arrange: Gets TaskManager instance from context
  • Act: Creates a task named "Write Tests"
  • Assert: Verifies that the Task object is persisted and its name is "Write Tests"
  • BeginTest() call prepares underlying mechanism for the execution of service under test.
  • Verify property comes from TestBase class. It basically helps you to check if object is persisted or deleted
  • When testing, Gazel configures a fake service application in which there is a database connection to an in-memory SQLite database. For every test case, it begins a transaction and rollbacks after execution.

Summary of Persistent Classes

Like manager classes, persistent classes also follow conventions. In this tutorial you've created a table and a create service using no configuration.

Now try to add new properties to Task class or add new persistent classes, re-run and see the results.

Once you are ready, you can proceed to learn how to update a record in database.


Here you can download source code for this tutorial.

Database Transactions

In this tutorial, you will create an update service and learn about how Gazel manages database transactions.

Business Service on Persistent Objects

Now that you've created tasks, it's time to complete them. To do this add following method to your Task class.

...
public class Task
{
    ...
    public virtual void Complete()
    {
        Completed = true;
    }
    ...
}
...

And that's it. You've created a Complete service.

There is no need to create a database transaction, before every service call Gazel automatically opens a database connection and begins a transaction.

Notice that you don't have to call an update method in repository. Gazel configures NHibernate in auto update mode. This means it makes a dirty check upon commit and update rows when there is a change.

Build and run App.Service again. Now you will see a Task service package and under this package there is Complete service. Since this service requires a row in database, Id parameter is added automatically.

Go and create a task using Task Manager/Create Task and use that object's Id in Target/Id field of Complete service.

When you press call button you will see following screen;

Important note on protected setters

You may remember that we used protected access modifier on property setters as shown below;

...
public class Task
{
    ...
    public virtual int Id { get; protected set; }
    public virtual string Name { get; protected set; }
    public virtual bool Completed { get; protected set; }
    ...
 }
 ...

As mentioned before protected setters ensure that data of a persistent object can only be updated within its own class. Gazel is designed to welcome business services on persistent classes.

If you allow public setters, that is fine too. But this would make it possible to update a property value from outside. This is because we use auto update feature of NHibernate.

Always remember that persistent objects in Gazel are not simle DTOs. They are context aware domain objects that manages a row in a database.

Testing an Update Service

Let's move on to testing. Now add following test to your TaskTest test class;

...
[TestFixture]
public class TaskTest : TestBase
{
    ...
    [Test]
    public void CompleteTask__marks_task_as_completed()
    {
        var taskManager = Context.Get<TaskManager>();
        var task = taskManager.CreateTask("Write Tests");

        BeginTest();

        task.Complete();

        Assert.IsTrue(task.Completed);
    }
}
...

Here's what you've done;

  • Arrange: Get TaskManager object and create a task named "Write Tests"
  • Act: Complete the new Task object
  • Assert: Assert that task is completed

Note that this time CreateTask is moved before BeginTest(). This is because for this test case creating a task is a part of the arrange step.

Summary of Database Transactions

In this tutorial you've learned how to write a simple update service to a method. Now try to add new properties and methods to your persistent classes, re-run and see the results.

Once you are ready, you can proceed to learn how to write query services.


Here you can download source code for this tutorial.

Query Classes

In this tutorial, you will create a query service and learn about query service conventions.

Create a Query Service

Now you will create a query service to see all completed tasks. Add below code to Tasks class in Task.cs.

...
public class Tasks : Query<Task>
{
    ...
    public List<Task> ByCompleted(bool completed)
    {
        return By(t => t.Completed == completed);
    }
    ...
}
...

By method is inherited from Query<T> base class, and it simply accepts a lambda expression with one parameter of type T which is Task in this example.

Like every public method, this query method is also exposed as a business service. Build and run AppHost.Service to see your completed tasks.

Query naming conventions;

  • When a query method returns a list of objects, the convention is to name it as By.
  • When a query method takes only one parameter, method name contains parameter name as a suffix.

So by these conventions we named this query as ByCompleted. For more information see: Queries

Testing Queries

Now add following test case to your TaskTest class;

...
[TestFixture]
public class TaskTest : TestBase
{
    ...
    [Test]
    public void Tasks_ByCompleted__filters_tasks_by_completed_column()
    {
        var taskManager = Context.Get<TaskManager>();

        taskManager.CreateTask("incomplete");
        taskManager.CreateTask("completed 1").Complete();
        taskManager.CreateTask("completed 2").Complete();

        BeginTest();

        var actual = Context.Query<Tasks>().ByCompleted(true);

        Assert.AreEqual(2, actual.Count);
        Assert.AreEqual("completed 1", actual[0].Name);
        Assert.AreEqual("completed 2", actual[1].Name);
    }
    ...
}
...

Note that there is a Context.Query<T>() shortcut to access query classes. Unlike Context.Get<T>() this shortcut is available in module projects as well, so that you don't have to inject query classes.

Summary of Query Classes

Query classes help you to organize your query methods for the same persistent class into one place, so that you can create reusable query methods.

Now try to create other query methods that accepts more than one parameter, re-run and see the results.

Once you are ready, you can proceed to learn how to create service packages and expose your business services publicly.


Here you can download source code for this tutorial.

Rest API

In this tutorial, you will create a Rest API and learn about configuration and api packaging.

Define a Service Interface

Until now you've created business services for internal use. By internal we mean that they are supposed to be consumed by your applications only. You can always publish your business services directly to outside but this would be hard for you to maintain and refactor your business code. For this reason, you will create an api package out of your business services.

First we will define which services to expose. To do this, create a folder named Service in TaskManagement module and under this folder create an interface named ITaskService as shown below;

Inventiv.Todo
├── src
│   ├── Inventiv.Todo.App.Rest
│   ├── Inventiv.Todo.App.Service
│   └── Inventiv.Todo.Module.TaskManagement
│       ├── Service
│       │   └── ITaskService.cs
│       ├── TaskManager.cs
│       └── Task.cs
└── test
    └── Inventiv.Todo.Test.TaskManagement
        └── TaskTest.cs

This interface is a service interface and it will contain the methods of Task class that you want to share with the outside world.

Now modify ITaskService service interface to include following method;

namespace Inventiv.Todo.Module.TaskManagement.Service
{
    public interface ITaskService
    {
        void Complete();
    }
}

Service interfaces are not only for persistent objects. Naming convention for adding service interfaces is I[ClassName]Service.

Following this convention ITaskManagerService and ITasksService would be correct names to create service interfaces for TaskManager and Tasks classes respectively.

Now go to Task.cs file and make your Task class implement ITaskService interface as shown below;

public class Task : ITaskService
{
    ...
}
...

Notice that you don't have to implement Complete method, since it is already implemented within Task class.

Create an API Package

To create an api package go to App.Service project and add a class named TaskApi as shown below;

Inventiv.Todo
├── src
│   ├── Inventiv.Todo.App.Rest
│   ├── Inventiv.Todo.App.Service
│   │   └── TaskApi.cs
│   └── Inventiv.Todo.Module.TaskManagement
│       ├── Service
│       │   └── ITaskService.cs
│       ├── TaskManager.cs
│       └── Task.cs
└── test
    └── Inventiv.Todo.Test.TaskManagement
        └── TaskTest.cs

And add below code to TaskApi class;

using Castle.MicroKernel;
using Gazel.Configuration;
using Inventiv.Todo.Module.TaskManagement;
using Inventiv.Todo.Module.TaskManagement.Service;
using Routine;
using Routine.Engine.Configuration.ConventionBased;

namespace Inventiv.Todo.App.Service
{
    public class TaskApi : ICodingStyleConfiguration
    {
        public void Configure(ConventionBasedCodingStyle codingStyle, IKernel kernel)
        {
            codingStyle.AddTypes(v => v.ApiPackage("Task", t => t
                .Methods.Add(c => c.Proxy<ITaskService>().TargetByParameter<Task>())
            ));
        }
    }
}

With this configuration, you've created a virtual class -which we call api package- and added all methods in ITaskService class to this virtual class.

Now build and run App.Service project.

As you can see, there is a new group called Api. Under this group you will see a new api package named ITaskService. You can see that this service package is marked as Virtual and Web Service. Under this package there is 'Complete' service.

Test your first endpoint

Now build and run both App.Service and App.Rest projects.

App.Rest is an application that acts as a gateway to your internal business services. It only allows access to the services under Api group.

Now your api is in this url;

POST http://localhost:{port}/tasks/{id}/complete

Try your endpoint by making an HTTP request to this URL, and make sure you use an id value from your test database in place of {id}.

We used Postman for this test, and the result is shown below;

URL breakdown

Your api consists of 3 parts;

  1. Resource name in plural - tasks
  2. Id of the resource - 6
  3. Operation/method name - complete

Resource name is in plural because you named your web service package after a persistent class, Task.

Improve your API Package

Now modify ITaskService.cs file as shown below;

using System.Collections.Generic;

namespace Inventiv.Todo.Module.TaskManagement.Service
{
    public interface ITaskService
    {
        void Complete();
    }

    public interface ITasksService
    {
        ITaskInfo GetTask(int taskId);
        List<ITaskInfo> GetTasks(bool completed);
    }

    public interface ITaskManagerService
    {
        ITaskInfo CreateTask(string name);
    }

    public interface ITaskInfo
    {
        int Id { get; }
        string Name { get; }
        bool Completed { get; }
    }
}

There are 3 new interfaces in your service definition;

  1. ITasksService to include services from Tasks query class.
  2. ITaskManagerService to include services from TaskManager manager class.
  3. ITaskInfo to include properties of Task class in responses.

Implement your new interfaces as shown below;

Task.cs
...
public class Task : ITaskService, ITaskInfo
{
    ...
}

public class Tasks : Query<Task>, ITasksService
{
    ...

    #region Service Mappings

    ITaskInfo ITasksService.GetTask(int taskId) =>
        SingleById(taskId);

    List<ITaskInfo> ITasksService.GetTasks(bool completed) =>
        ByCompleted(completed).Cast<ITaskInfo>().ToList();

    #endregion
}
...
TaskManager.cs
...
public class TaskManager : ITaskManagerService
{
    ...

    #region Service Mappings

    ITaskInfo ITaskManagerService.CreateTask(string name) =>
        CreateTask(name);

    #endregion
}
...

Notice that we make use of Explicit Interface Implementation to map interface methods to class methods. This is required for methods of service interfaces where return type in service interface is different than the return type in implementing class. e.g. CreateTask method returns Task in TaskManager class, but it returns ITaskInfo in ITaskManagerService interface.

And finally add new interfaces to your api package;

...
public class TaskApi : ICodingStyleConfiguration
{
    public void Configure(ConventionBasedCodingStyle codingStyle, IKernel kernel)
    {
        codingStyle.AddTypes(v => v.ApiPackage("Task", t => t
            .Methods.Add(c => c.Proxy<ITaskService>().TargetByParameter<Task>())
            .Methods.Add(c => c.Proxy<ITasksService>().TargetBySingleton(kernel))
            .Methods.Add(c => c.Proxy<ITaskManagerService>().TargetBySingleton(kernel))
        ));
    }
}
...

Now rebuild and run both App.Service and App.Rest projects.

You now have 4 endpoints to test;

  1. POST /tasks/{id}/complete mapped to ITaskService.Complete
  2. GET /tasks or GET /tasks?completed={bool} mapped to ITasksService.GetTasks
  3. GET /tasks/{id} mapped to ITasksService.GetTask
  4. POST /tasks mapped to ITaskManagerService.CreateTask

To test 4. endpoint you have to include a JSON request body like below. This is because CreateTask method accepts a parameter named name.

{
    "name": "task name goes here"
}

Summary of Rest API

In this section you've learned how to create a Rest API out of your business services.

Now try to create new persistent objects to enhance your to-do application.

You can move to next section to download a complete to-do application.


Here you can download source code for this tutorial

Sample Application

This tutorial is only a small portion of how you can build a backend solution, but there is much more to learn about Gazel.

Here you can download a complete to-do application with all endpoints and functionality. Examine it to have a better feeling of how you can build a similar solution.

More Reading

You can continue to read this documentation to have a deeper understanding of how Gazel works.

  • See conventions to see all conventions Gazel exposes.
  • See architecture to learn about the underlying architectural design.
  • See features to learn what options you have and how to change the way Gazel behaves.