In general, client-side browser applications need to store some of their data. In some cases, such as games, the application can store its data in the browser itself, using browser local storage. But in most cases, storage will happen on the server, which has access to database engines such as SQL Server. In this chapter, you will learn the basics of storing data using Entity Framework Core and exposing that data using REST and microservices built on top of ASP.NET Core.
What Is REST?
Storing data on the Web is ubiquitous. But how can applications communicate with one another? Representational State Transfer (REST) is a protocol built on top of the HTTP protocol for invoking functionality on servers, such as retrieving and storing data from/in a database.
Understanding HTTP
Before talking about REST, you should have a good understanding of the Hypertext Transfer Protocol , better known as HTTP. HTTP was created by Tim Berners-Lee at CERN in 1989. CERN is a center for elementary physics research, and what do researchers do when they have completed their research? They publish papers with their research findings. Before the Internet, publishing a paper was done literally on paper (hence the name), and it took a lot of time between writing the paper and getting it published in a research magazine. Instead, Tim Berners-Lee devised a way to put papers on a server and allow users to read these papers using a browser.
Also, scientific papers contain a lot of references, and when you want to read a paper like this, it helps to be able to access the referenced papers. The Internet facilitates reading papers through the use of Hypertext Markup Language (HTML). Hypertext is an electronic document format that can contain links to other documents. You simply click the link to read the other paper and you can go back to the first paper simply by clicking the back button in your browser.
Universal Resource Identifiers and Methods
Each time you click a hyperlink in the HTML document, the browser repeats this process with another URI.
But there are other methods. If you want to publish a new paper, you can use the POST method to send the paper to the server, supplying it with a URI. In this case, the server will store the paper at the requested URI. If you want to make a change to your paper, for example, to correct a spelling mistake, you can use the PUT method. Now the server will overwrite the URI contents. And finally, you can delete the paper using the DELETE method and its URI.
HTTP Status Codes
What happens when you ask a server about something it doesn’t have? What should the server return? Servers not only return HTML, but they also return a status code about the result. When the server can process the request successfully, it will in general return status code 200 (other successful status codes exist). When the server can’t find the resource, it will return a status code 404. Status code 404 simply means not found. The client will receive this status code and can react appropriately. When the browser receives a status code 200, it displays the HTML; when it receives a 404, it displays a not found screen, and so on.
A full list of all HTTP status codes can be found at https://en.wikipedia.org/wiki/List_of_HTTP_status_codes.
Invoking Server Functionality Using REST
Think about these methods we just talked about. With POST, you can CREATE something on a server; with GET, you can READ it back; with PUT, you can UPDATE something on the server, and with DELETE, you can DELETE things on the server. They are also known as CRUD operations (CREATE-READ-UPDATE-DELETE). Roy Fielding , the inventor of REST, realized that using the HTTP protocol you can also use HTTP to work with data stored in a database. For example, if you use the GET method with a URI http://someserver/categories, the server can execute some code to retrieve data from the categories relational table and return it. Of course, the server would use a format more appropriate for transferring data, such as XML or JSON. Because there are many different formats for data, the server also needs a way to convey which format it is sending. (At the beginning of the Web, only HTML was used as the format.) This is done through HTTP headers.
HTTP Headers
HTTP headers are instructions exchanged between the client and the server. Headers are key-value pairs, where the client and server agree on the key. Many standard HTTP headers exist. For example, a server can use the Content-Type header to tell the client to expect a specific format. Another header is the Accept header , which is sent by the client to the server to politely ask the server to send the content in that format; this is also known as content negotiation . Currently, the most popular format is JavaScript Object Notation (JSON). And this is the exchange format you will use with Blazor.
JavaScript Object Notation
An example of JSON
This JSON format describes a book, an object in memory. Objects are denoted using curly braces. Inside the book are two properties; each property uses a key : value notation. The book’s title is "Blazor Revealed". Note that the property name is also transferred as a string. And finally, the “chapters” property is an array of strings, where you use square brackets to indicate an array.
The JSON format is used for transferring data between two machines, but today is also heavily used for configuring tools such as ASP.NET Core. JSON today is way more popular on the Web than XML, probably because of its simplicity.
Some Examples of REST Calls
Building a Simple Microservice Using ASP.NET Core
So, how do you build a REST service? Your Blazor project uses ASP.NET Core for hosting the Blazor client, and adding a service to your project is easy. But first, let’s do a little intro to microservices.
Services and Single Responsibility
A service is a piece of software that listens for requests; when it receives a request, the service handles the request and returns with a response. In real life, you also encounter services and they are very similar. Consider a bank. You step into a bank and you give the teller your account number and some ID and request $100. The teller will check your account; if you have enough money in your account, the teller will deduct the money and give you the cash. Should your account be too low, the teller will refuse. In both cases, you got a response.
Services should also adhere to the principle of single responsibility . They should do one thing very well, and that’s it. For example, the pizza service will allow clients to retrieve pizzas, add, update, and delete pizzas. That’s it. A single responsibility, in this case, PIZZAS.
You can have other services too, each with their own responsibility. Services that take care of one thing are known as microservices .
The Pizza Service
The only role this project currently has is to host your Blazor client application, but now you will enhance this role by adding some microservices.
The Startup class’s Configure method
The last line with the endpoints.MapFallbackToFile("index.html") method takes care of your Blazor client project. But right before it, you see the endpoints.MapControllers() method that is used for hosting your services.
How the MapControllers method works is not the topic of this book, but I will cover what you need to know. If you want to learn more about ASP.NET Core, there are many good books about this topic, such as Pro ASP.NET Core MVC by Adam Freeman.
If you are using Code, simply right-click the Controllers folder and select Add File. Name it PizzasController.cs.
The empty PizzasController
Adding a method to the PizzaController to retrieve a list of pizzas
Let’s walk through this implementation. First, you declare a hard-coded static list of pizzas. Next is the GetPizzas method, which has an attribute of HttpGet("pizzas"). This attribute says that when you perform a GET on the server with the pizzas URI, the server should call the GetPizzas method.
The GetPizzas method returns an IQueryable<Pizza>, and ASP.NET Core will send this result back to the client with the requested format. The IQueryable<Pizza> interface is used in .NET to represent data that can be queried, such as database data, and is returned by LINQ queries.
Note that the GetPizzas method contains nothing about HOW the data will be transferred to the client. This is all taken care of for you by ASP.NET Core! By default, your implementation in ASP.NET Core will use JSON, which is what you want. ASP.NET Core allows you to pick other formats, including your custom format. This is not the scope of this book.
Time to see if it works. First, ensure that the PizzaPlace.Server project is the startup project. Right-click the PizzaPlace.Server project and select Set as Startup Project from the drop-down menu. The PizzaPlace.Server project should be shown as bold, as in Figure 5-5.
Now run your project and wait for the browser to open because you will perform a GET; you can use the browser, but for other methods, you will later use a nice tool called Postman.
A JSON-encoded list of pizzas! It works!
Now you are ready to retrieve the data from a real database using Entity Framework Core.
What Is Entity Framework Core?
Entity Framework Core is the framework Microsoft recommends for working with databases. It allows you to write classes as normal C# classes and then store and retrieve .NET objects from a database without having to be an SQL expert. It will take care of this for you. This is also known as persistence ignorance , where your code does not need to know how and where data gets stored!
Using the Code First Approach
But of course, you need to explain to Entity Framework Core what kind of data you want to store. Entity Framework Core uses a technique called code first , where you write code to describe the data and how it should be stored in the database. Then, you can use this to generate the database, the tables, and the constraints. If you want to make changes to the database, you can update the database schema with code first migrations .
If you already have a database, you can also generate the code from the database, also known as EF Database First, but this is not the target of this book.
In the code first approach, you describe the classes (also known as entities) that will map to database tables. You already have the Pizza class (which you can find in the PizzaPlace.Shared project) to describe the Pizza table in the database. But you need to do more.
In this part, you will be using SQL Server. If you installed Visual Studio on your Windows machine, SQL Server was installed too. If you don’t have SQL Server on your machine, you can install a free version of SQL Server, or use a SQL Server instance in the cloud, for example, SQL Server on Azure (https://azure.microsoft.com/en-us/get-started/). You can even install SQL Server on OSX! There are some nice articles on the Web that explain how.
The NuGet window will open in Visual Studio. NuGet is a very practical way for installing dependencies such as Entity Framework Core to your project. It will not only install the Microsoft.EntityFrameworkCore.SqlServer library but also all its dependencies.
By the time you read this book, Microsoft might have deployed a more recent version, so although Figure 5-10 shows version 3.1.1, you should select the latest stable version.
Modifying the Pizza class for Entity Framework Core
The PizzaPlaceDbContext class
First, you need to create a constructor for the PizzaPlaceDbContext class taking an DbContextOptions<PizzaPlaceDbContext> argument. This is used to pass the connection to the server, which you will do later in this section.
Next, you add a table to the database to represent your pizzas using a public property of type DbSet<Pizza>. DbSet<T> is the collection class used by Entity Framework Core, but you can think of it as a List<T>. Entity Framework Core will use the DbSet<T> to map this collection to a table, in this case, the Pizzas table.
Finally, you override the OnModelCreating method, which takes a modelBuilder argument. In the OnModelCreating method, you can describe how each DbSet<T> should be mapped to the database; for example, you can tell it which table to use, how each column should be called, which type to use, and so on. This modelBuilder has a bunch of methods that allow you to describe how the classes should be mapped to your database. In this case, you tell the modelBuilder that the Pizza table should have a primary key, the Id property of the Pizza class. You also need to tell how the Pizza.Price property should be mapped to SQL Server. You will use the SQL Server MONEY type for that. For the moment, this is enough for your current implementation.
Preparing Your Project for Code First Migrations
The Startup.ConfigureServices method
Remember IServiceCollection from the chapter on dependency injection? Here dependencies for ASP.NET Core are added, such as dependencies for Mvc and Razor pages, which are required for your service.
The Startup class’s constructor
You need this constructor to have access to the project's configuration file. The configuration will contain the connection string for the database to talk to.
Adding Entity Framework dependencies
This single statement tells ASP.NET Core that you will be using the PizzaPlaceDbContext and that you will be storing it in SQL Server. This code also looks up the connection string for the database in configuration, which you still need to add.
The appsettings.json configuration file
Finding Your Database Server’s Connection String
If you are not sure which connection string to use, you can find the connection string in Visual Studio by selecting View ➤ SQL Server Object Explorer.
Next, expand SQL Server from Figure 5-13 and select your server. Right-click it and select Properties. Now copy the connection string from the properties window and change the database name to PizzaDb.
Creating Your Code First Migration
You are almost ready to generate the database from the code. Start by adding the Microsoft.EntityFrameworkCore.Design NuGet package to the PizzaPlace.Server project.
Now you need to create a migration. A migration is a C# class that contains the changes that need to be made to the database to bring it up (or down) to the schema your application needs. This is done through a tool.
Make sure that the default project is set to PizzaPlace.Server. This will make your commands target the selected project.
If you are using Code, use the integrated terminal or open a command prompt.
You might need to install a command-line tool as well. Run the following command to install the migration tool. You only need to install this tool once.
dotnet tool install --global dotnet-ef
Should you get an error or warnings, please review the code for the Pizza and the PizzaPlaceDbContext classes and try again.
The CreatingPizzaDb.cs file
A migration class has two methods: Up and Down. The Up method will upgrade the database schema. In this case, it will create a new table called Pizzas with Id, Name, Price, and Spiciness columns.
The Down method downgrades the database schema, in this case, by dropping the column.
Generating the Database
An extract from the database generation tool’s output
This just created the database for you!
Enhancing the Pizza Microservice
Let’s add some functionality to the Pizza microservice so it uses the database instead of hard-coded data and add a method to insert a pizza in your database.
Injecting a PizzaPlaceDbContext instance into the controller
To talk to the database, the PizzasController needs a PizzaPlaceDbContext instance, and as you learned in the chapter on dependency injection, you can use a constructor to do this. The constructor only needs to save the reference in a local field (for now).
Retrieving the pizzas from the database
The InsertPizza method
This is an introduction to REST services. Building real services with all the different approaches and best practices can take up a whole book. The idea of this chapter is to get you up and running.
Testing Your Microservice Using Postman
So now, you have your first microservice. But how do you test it? Previously, you used the browser to test the GetPizzas method, which uses the GET method. For other methods such as POST, PUT, and DELETE, you need a better tool. Here you will use Postman, which is a tool specifically for testing REST services.
Installing Postman
By the time you read this book, the installation procedure may have changed a bit, so please follow the instructions from the installer.
After it has installed, run Postman.
Making REST Calls with Postman
Making a GET Request
Inserting Pizzas with POST
Ensure your PizzaPlace application is still running.
Summary
In this chapter, you had a look at how to store data on the server using Entity Framework Core and how to expose that data using REST and microservices. You added a pizza service to the PizzaPlace application and then went on testing it with Postman.
In the next chapter, you will learn how to talk to your service(s) from Blazor.