When we think of building web applications or services in .NET, we usually confine ourselves to core ASP.NET technologies. There is no doubt that Microsoft has put in a lot of efforts in building some awesome web frameworks and tools to make our lives easier, but there are alternatives to Microsoft's set of technologies that are worth taking a look at. ServiceStack is one such option.
ServiceStack is a thoughtfully architected, obscenely fast, thoroughly enjoyable web services for all.
This article is published from the DotNetCurry .NET Magazine – A Free High Quality Digital Magazine for .NET professionals published once every two months. Subscribe to this eMagazine for Free and get access to hundreds of free .NET tutorials from experts
ServiceStack is a configuration free, code-first, light-weight framework built on top of ASP.NET for building services and web applications. As the name suggests, it is a stack of services. It provides with just everything that one needs for building end-to-end web services. In a way, we can say that it is a light-weight alternative to WCF, Web API, ASP.NET MVC, ASP.NET Web Forms and any framework using which we can develop web apps or APIs.
What is the ‘Stack’ in ServiceStack?
ServiceStack has a big list of features stacked in that is just enough to build any kind of service. The following are key components in the stack:
1. REST, SOAP and Message Queuing Services
2. Automatic Serialization/Deserialization to/from a variety of data formats including JSON, XML and CSV (JSON parser is the fastest parser in .NET)
3. A light weight ORM package called OrmLite
4. Dependency Injection
5. Razor views
6. Logging
7. Bundling
8. Security
To learn more about the features, you can visit https://servicestack.net/features. The good thing is, ServiceStack doesn’t depend on any third party to support any of its feature. It is a self-contained and self-independent framework.
Why ServiceStack?
Using ServiceStack, one can quickly build APIs that can be hosted anywhere (IIS, Windows Service, Self-host or Mono) and consumed from anywhere. Building a ServiceStack API is really easy as it doesn’t need a lot of configurations before getting the service up and running. ServiceStack defines a set of conventions that make the job of writing and exposing services easy.
The pieces in the ServiceStack are totally independent of each other and can be used in isolation. For example, if you only want the JSON parser of ServiceStack for your application, you can include it alone and use it.
In addition to all the rich features, ServiceStack embraces the practices of clean code, which means, the logic that we write to expose services using ServiceStack are fully testable.
As listed in the features, ServiceStack supports Razor views. This feature enables to create Razor pages to render the data exposed by the Services.
Student Report Application
In this article, we will build a Student Report application using ServiceStack. By the end of this article, you will be familiar with the following features of ServiceStack:
1. REST Services
2. OrmLite
3. Dependency Injection
4. Razor Views
Setting up the project
Open Visual Studio 2013 and choose File > New > Project, create an empty ASP.NET web application and name it StudentReports. Install the following NuGet packages in this project:
1. Bootstrap
2. ServiceStack
3. ServiceStack.OrmLite.SqlServer
4. ServiceStack.Razor
To bootstrap ServiceStack, we need to register the ServiceStack components when the application starts. To do this, add a new class to the project and name it AppHost. This class should inherit from ServiceStack.AppHostBase class.
The class AppHostBase doesn’t have a non-parameterized constructor. The constructor expects a name for the service and a list of assemblies where the services are defined. As we haven’t created services yet, add a class named StudentService to the project. This class can be left empty for now. We will come back to this class later to add code to it.
The AppHostBase class has an abstract method, Configure which will be overridden in our AppHost class. This method is used to configure the components in ServiceStack. We can leave it empty for now. Following is the code in AppHost as of now:
public class AppHost : AppHostBase
{
public AppHost() : base("Student report Service", typeof(StudentService).Assembly) { }
public override void Configure(Funq.Container container)
{
}
}
And finally to finish the setup, we need to invoke Init() method of the AppHost in Application_Start event of Global.asax. If the project doesn’t have a Global.asax file yet, add it and modify the Application_Start event:
protected void Application_Start(object sender, EventArgs e)
{
(new AppHost()).Init();
}
Note: If you want to avoid the above steps while creating a ServiceStack project, install the ServiceStackVS extension through extensions gallery. It installs some project templates that include all the required hooks to build a ServiceStack application.
Writing basic services using ServiceStack
ServiceStack is based on DTOs (Data Transfer Object model). To define a service, we need at least one request DTO class. For instance, say we need the ID of a student in the service, then the request DTO can be a class with the field ID. If you need data, additional properties can be added to the DTO class.
We need to expose any service through an endpoint. Endpoints can be created using Route attribute defined on ServiceStack namespace. Unlike ASP.NET Web API, where we define routes in the service controller, ServiceStack routes are defined on DTOs.
Following is the DTO for student data:
[Route("/students")]
[Route("/students/{Id}")]
public class StudentRequestDto
{
public int Id { get; set; }
}
As you see, the above DTO exposes two endpoints: one plain endpoint with no parameters and the second one with Id as the parameter.
You can optionally define response DTO as well. Response DTO can be specified as return type on the request DTO as follows:
public class StudentRequestDto : IReturn
Now let’s define a service method to respond to the requests. A service class should be a child to ServiceStack.Service class. Open the StudentService class created earlier and add the following code to it:
public class StudentService : Service
{
public object Any(StudentRequestDto dto)
{
if (dto.Id != default(int))
{
return new { Id = dto.Id, Name = "Ravi" };
}
else
{
return new ArrayList {
new { Id = 1, Name = "Ravi" },
new { Id = 2, Name = "Kiran" }
};
}
}
}
Names of the methods defined in the service classes have to follow conventions to get some magic applied on them. Here, the method Any would respond to any kind of request sent to the endpoints defined over StudentRequestDto. Now if you run the application, the following page would appear in the browser:
The service by default supports all the formats listed on the page and as we can see, it can be consumed as a SOAP as well as a REST service. The links in the page provide help information about consuming the API. Change the URL to:
http://localhost:/students?format=json
It would display the data in the form of JSON in the browser:
You may not like the Pascal Case notation in JSON data. You can modify format of the cases in Configure method of the AppHost class. Add the following statement to convert JSON data into camel case:
ServiceStack.Text.JsConfig.EmitCamelCaseNames = true;
Similarly, change value of format to any of the supported types and you will see the corresponding result.
To restrict a route to HTTP methods, we can specify the list of methods in the Route attribute. Following routes demonstrate 2 cases of restricting:
[Route("/students", Verbs = "GET, POST")] //Only GET and POST requests are allowed on this route
[Route("/students/{id}", Verbs = "GET")] //Only GET request is allowed on this route
public class StudentRequestDto
{}
In the service class, we need to define the corresponding methods following their conventions.
public class StudentService : Service
{
public object Get(StudentRequestDto dto)
{
//Implementation
}
public object Post(StudentRequestDto dto)
{
//Implementation
}
}
For the demo Student Reports application, we don’t need the POST event on Student. But we will be performing GET, POST and PUT operations on Marks. Following is the Marks DTO with required Routes:
[Route("/marks/student/{StudentId}", Verbs = "GET")]
[Route("/marks/{MarksId}", Verbs = "GET, PUT")]
[Route("/marks",Verbs="POST")]
public class MarksRequestDto
{
public int MarksId { get; set; }
public int StudentId { get; set; }
public int MarksAwarded { get; set; }
public int MaxMarks { get; set; }
public string Subject { get; set; }
}
Notice the first route in the above snippet. This route is to enable fetching marks of a particular student. The route is defined this way to avoid confusion between accepting MarksId and StudentId into the API. We will define a service for this DTO later.
Using OrmLite and Dependency Injection
ServiceStack includes a light-weight micro ORM called OrmLite. It is one of the fastest .NET ORMs. It is not as configurable as Entity Framework, but still provides a good set of features to interact with databases. OrmLite has DB specific implementations for all major databases including SQL Server, Oracle and MySql and some others like PostgreSQL, FirebirdSql and Sqlite. We will be using the SQL Server version.
As a first step, create a new database on SQL Server and name it StudentDb. Add the following connection string to the Web.config:
To work with the database, we need an object of IDbConnectionFactory type. OrmLiteConnectionFactory is an implementation of this interface. Following statement creates an object of this class:
var ormLiteConnectionFactory = new OrmLiteConnectionFactory(ConfigurationManager.ConnectionStrings["studentDbConn"].ConnectionString,
ServiceStack.OrmLite.SqlServer.SqlServerOrmLiteDialectProvider.Instance);
Let’s make this object available to the entire application through the built-in IoC container of ServiceStack Funq. Funq in ServiceStack is based on an open-source IoC container named Funq (http://funq.codeplex.com/) with the framework adding more capabilities to its implementation. ServiceStack internally uses Funq to register objects of the Service classes, Filters and Validators.
Let’s register the above object to the container of Funq. Configure method of the AppHost class already has a reference to Funq’s container. Following statement registers the dependency:
container.Register(ormLiteConnectionFactory);
Objects registered to Funq are injected through both constructor and property injection.
To read more about Funq, visit ServiceStack’s wiki on GitHub (http://bit.ly/dncm15-sswiki).
Let’s set up the database with two tables to store Student data and marks and fill-in some data into the tables. Following are the classes for Student and Marks tables:
public class Student
{
[AutoIncrement]
public int StudentId { get; set; }
public string Name { get; set; }
public string City { get; set; }
public int CurrentClass { get; set; }
}
public class Marks
{
[AutoIncrement]
public int Id { get; set; }
public int MarksAwarded { get; set; }
public int MaxMarks { get; set; }
public string Subject { get; set; }
[References(typeof(Student))]
public int StudentId { get; set; }
}
The AutoIncrement attribute in above snippets denotes a table column with auto incrementing values, which is Identity column in case of SQL Server. References attribute in the Marks class defines a foreign key reference.
To fill these tables with data, let’s create a new class DbInitializer. This class will have just one static method InitializeDb. This method checks for existence of tables, creates the tables and fills in data if the tables don’t exist yet.
public class DbInitializer
{
public static void InitializeDb(IDbConnectionFactory dbConnectionFactory)
{
var students = new List()
{
new Student(){Name="Andrew",City="Boston",CurrentClass=2},
new Student(){Name="Richa",City="Chicago",CurrentClass=3},
new Student(){Name="Dave",City="Phoenix",CurrentClass=4},
new Student(){Name="Ema",City="Washington",CurrentClass=5},
new Student(){Name="Filip",City="Texas",CurrentClass=6},
new Student(){Name="Maggi",City="Los Angeles",CurrentClass=7},
new Student(){Name="Nathan",City="Atlanta",CurrentClass=8}
};
var studentMarks = new List()
{
new Marks(){Subject="Mathematics",MarksAwarded=80,MaxMarks=100, StudentId=1},
new Marks(){Subject="English",MarksAwarded=70,MaxMarks=100, StudentId=1},
new Marks(){Subject="Hindi",MarksAwarded=75,MaxMarks=100, StudentId=1},
new Marks(){Subject="Mathematics",MarksAwarded=60,MaxMarks=100, StudentId=2},
new Marks(){Subject="English",MarksAwarded=90,MaxMarks=100, StudentId=3},
new Marks(){Subject="Hindi",MarksAwarded=85,MaxMarks=100, StudentId=2},
new Marks(){Subject="Mathematics",MarksAwarded=90,MaxMarks=100, StudentId=2},
new Marks(){Subject="English",MarksAwarded=80,MaxMarks=100, StudentId=3},
new Marks(){Subject="Hindi",MarksAwarded=80,MaxMarks=100, StudentId=3}
};
using (var db = dbConnectionFactory.OpenDbConnection())
{
if (!db.TableExists("Student"))
{
db.CreateTable();
db.InsertAll(students);
}
if (!db.TableExists("Marks"))
{
db.CreateTable();
db.InsertAll(studentMarks);
}
}
}
}
To operate with these tables, we need repositories. As we have just two tables and we need limited number of operations to be performed on the tables, one repository class will suffice. The repository class would be performing the following operations:
- Get all students
- Get student details by id
- Get marks of a student
- Get marks by marks ID
- Add marks of a student
- Update marks of a student
We need a connection factory object to establish a connection to the database. As the object is already added to Funq, we will get it through property injection. Following is the repository class with a method that fetches all students from the DB:
public class StudentDbRepository
{
public IDbConnectionFactory DbConnectionFactory { get; set; }
public List GetStudents()
{
using (var db = DbConnectionFactory.OpenDbConnection())
{
return db.Select();
}
}
}
In the above snippet, Select() is a generic method that gets data from the table represented by the class specified with it. We enclosed the data operation inside a using block to dispose the connection object immediately after the operation is done. To apply filter while fetching data, we can pass a lambda expression to the Select() method as shown in the following methods:
public List GetMarksByStudent(int studentId)
{
using (var db = DbConnectionFactory.OpenDbConnection())
{
return db.Select(m => m.StudentId == studentId);
}
}
public Marks GetMarks(int marksId)
{
using (var db = DbConnectionFactory.OpenDbConnection())
{
return db.Select(m => m.Id == marksId).FirstOrDefault();
}
}
To add marks of a student, we can call the Insert() method on the connection object. If the Insert() method adds data to a table with an identity column in it, the identity value can be fetched using LastInsertedId() method on the same connection object. Following snippet demonstrates this while adding a new entry of marks:
public int AddMarks(Marks marks)
{
using (var db = DbConnectionFactory.OpenDbConnection())
{
db.Insert(marks);
return (int)db.LastInsertId();
}
}
The last operation that we need to perform is updating marks. It is a straight forward operation and returns the number of rows affected.
public int UpdateMarks(Marks marks)
{
using (var db = DbConnectionFactory.OpenDbConnection())
{
return db.Update(marks);
}
}
With this, the repository is completed and now we can use it in our services. As the service classes need an instance of the repository class, let’s make the instance available through the dependency injector Funq.
container.Register(c => new StudentDbRepository()).ReusedWithin(ReuseScope.Request);
The ReuseWithin() method chained with the Register() method is used to define scope of an instance registered. The repository object is scoped within the HTTP request. The object is destroyed as soon as the request ends.
Following are the modified StudentService and MarksService classes.
public class StudentService : Service
{
StudentDbRepository repository;
public StudentService(StudentDbRepository _repository)
{
repository = _repository;
}
public object Get(StudentRequestDto studentDto)
{
if (studentDto.Id == default(int))
{
return repository.GetStudents();
}
else
{
return repository.GetStudentById(studentDto.Id);
}
}
}
public class MarksService : Service
{
StudentDbRepository repository;
public MarksService(StudentDbRepository _repository)
{
repository = _repository;
}
public object Get(MarksRequestDto dto)
{
if (dto.StudentId != default(int))
{
var student = repository.GetStudentById(dto.StudentId);
var marks = repository.GetMarksByStudent(dto.StudentId);
return new MarksGetResponseDto()
{
Id = student.StudentId,
Name = student.Name,
Class = student.CurrentClass,
Marks = marks
};
}
else if (dto.MarksId != default(int))
{
var marks = repository.GetMarks(dto.MarksId);
var student = repository.GetStudentById(marks.StudentId);
return new MarksGetResponseDto()
{
Id = student.StudentId,
Name = student.Name,
Class = student.CurrentClass,
Marks = new List() { marks }
};
}
return null;
}
public object Post(MarksRequestDto dto)
{
var nextId = StaticStudentDb.studentMarks[StaticStudentDb.studentMarks.Count() - 1].Id;
var newStudentMarks = new Marks()
{
StudentId = dto.StudentId,
MarksAwarded = dto.MarksAwarded,
MaxMarks = dto.MaxMarks,
Subject = dto.Subject
};
var id = repository.AddMarks(newStudentMarks);
newStudentMarks.Id = id;
return newStudentMarks;
}
public object Put(MarksRequestDto dto)
{
return repository.UpdateMarks(new Marks()
{
Id = dto.MarksId,
Subject = dto.Subject,
StudentId = dto.StudentId,
MarksAwarded = dto.MarksAwarded,
MaxMarks = dto.MaxMarks
});
}
}
Here is the MarksGetResponseDto used in the above snippet:
public class MarksGetResponseDto
{
public int Id { get; set; }
public string Name { get; set; }
public int Class { get; set; }
public IEnumerable Marks { get; set; }
}
Using HTTP Response
In the services we wrote till now, we are returning plain objects. ServiceStack internally wraps this data inside an HTTP response before sending it to the user. But you may want to get control over the HTTP response and send data along with a status code of your choice to the client. This can be done using IHttpResult.
Let’s refactor the Get method of the StudentService to use IHttpResult:
public IHttpResult Get(StudentRequestDto studentDto)
{
if (studentDto.Id == default(int))
{
var result = new HttpResult(repository.GetStudents());
return result;
}
else
{
var student = repository.GetStudentById(studentDto.Id);
if (student != null)
{
return new HttpResult(student);
}
else
{
return new HttpError(HttpStatusCode.NotFound,"Student with id "+studentDto.Id + " doesn't exist.");
}
}
}
Both HttpResult and HttpResult have a number of overloaded constructors offering flexibility to set status code, response type, message and a number of other HTTP parameters of our choice.
Razor Views
Till now, we used the Service and Data access features of ServiceStack. Let’s complete the demo application by adding some views. ServiceStack supports Razor and markdown razor views. If you are already familiar with the Razor views in ASP.NET MVC, you don’t need to learn anything new to use the view engine of ServiceStack.
The difference between ServiceStack and MVC appears when we see the way views are rendered in these frameworks. Unlike ASP.NET MVC, ServiceStack doesn’t need a controller. Data for the view is passed from the corresponding Service method. This data is available to the view in the Model object and the view can use it for model binding. Views are rendered on the same endpoint where the service is exposed. But we can still get the data served from these endpoints by specifying format of the data in the URL.
We have already added assembly required for Razor views while installing the NuGet packages. We can start building the views now. As a first step, let’s configure Razor as a plugin on start of the application.
Plugins.Add(new RazorFormat());
By default, an application doesn’t know about the razor views. We must add some configurations in Web.config to be able to use the view engine seamlessly. Luckily, the NuGet package ServiceStack adds all the required configurations to Web.config. You can check your Web.config file to see the new configurations.
By convention, ServiceStack looks for its views under a folder named Views. So create a new folder and change its name to Views. To keep the UI consistent, let’s create a layout file. Add a new file to the Views folder and name it _Layout.cshtml. Add the following code to this file:
@ViewBag.Title
Student Marks Reports of XYZ School
@RenderSection("Scripts", required: false)
Like in case of MVC, the views in ServiceStack get the dynamic object ViewBag. Here we are using it to set title of the page dynamically.
By convention, names of the Views should be same as the name of the corresponding request DTO classes. As we have two DTO classes, add two files named StudentRequestDto.cshtml and MarksRequestDto.cshtml to the Views folder. Both these files automatically extend the layout file, we don’t need to declare it anywhere.
Razor mark-up in the StudentRequestDto.cshtml view is going to be very simple, as it has to loop through the student objects and display their details along with a link to the marks page. Following is the Razor mark-up in this view:
@using StudentReports.Models
@inherits ViewPage>
@{
ViewBag.Title = "Student List";
}
Name |
City |
Current Class |
View Marks |
@{
foreach (var item in Model)
{
@item.Name |
@item.City |
@item.CurrentClass |
View Marks
|
}
}
Run the application and change the address in the browser to:
http://localhost:/students
It should display the following page:
The marks page is going to be more functional than the Students list page as it has to perform fetch, add and update marks operations. On load, the page gets list of marks of the student from Get method of MarksService and this data is available in the Model object. For adding and updating marks, we will invoke the corresponding REST APIs using jQuery AJAX. Following is the mark-up in the page:
@using StudentReports.Models
@inherits ViewPage
@{
ViewBag.Title = "Marks of " + Model.Name + " studying in class " + Model.Class;
}
@{
if (Model.Marks == null || Model.Marks.Count() == 0)
{
No marks added for the student yet.
}
else
{
Subject |
Marks Awarded |
Max Marks |
Update |
@{
foreach (var item in Model.Marks)
{
@item.Subject |
@item.MarksAwarded |
@item.MaxMarks |
|
}
}
}
}
Note: The markup has been truncated here to save some space. Please download the source code to view the complete markup.
In the layout page, we have defined an optional script section that can be used in the child pages to include custom scripts. Before executing the custom script, we would have all the libraries loaded.
Let’s write some code to add new marks for a student. By default, the add marks form is invisible to the user. On click of the Add Marks button, we need to show the form and accept inputs. When the data is successfully posted to the server, we refresh the page to see all the marks of the student. Following is the script for adding new marks within the scripts section:
Alternatively, we can bind data to the table manually to avoid refreshing the page. I used this approach to keep things simple.
Similarly, we need to write script to send a PUT request when marks are modified. I am leaving this part as an assignment. The solution is available in the downloadable code for this article.
I hope this article helped you to get started with ServiceStack and also got your hands dirty with it. Using ServiceStack, it is easier to build services and views and get them running on any platform of your choice. The good thing is, it doesn’t depend on any other third parties to make any of its component work. At the same time, the components in the framework are built with a vision of easier usability, speed and modularity in mind. ServiceStack is not limited to the set of features discussed in this article. We will have some more articles in future focusing on more capabilities of this great framework. I encourage you to check out the GitHub projects (github.com/ServiceStack/ ) and their official wiki (https://github.com/ServiceStack/ServiceStack/wiki) to learn more about the framework.