Learn ASP.NET Core 3.0 : MVC, Razor Pages, Web API, Entity Framework Core, and Blazor.
Microsoft's official documentation can be found here. Looking for professional online training courses? Next weekend batches are starting in November 2019. More details here.

CRUD using gRPC, EF Core, and ASP.NET Core (Part - 1)

If you have read about the new features of ASP.NET core 3.0, you are probably aware that it supports gRPC, a framework for building services using Remote Procedure Call (RPC). I won't go into the dry information about what gRPC is and how it can help you solve software problems in this article. This multipart article creates a simple yet complete example that performs CRUD operations on the Employees table of Northwind database. As you develop this example you will get chance to familiarize yourself with the basics of gRPC as implemented in .NET Core 3.0.

Let's get going.

Begin by creating a new Visual Studio project based on gRPC project template.

Once the project gets created your Solution Explorer should look similar to this:

Notice the Ptotos folder that contains a .proto file. Rename the default fine to EmployeeCRUD.proto. This file contains instructions of Protocol Buffer language. The primary purpose of this file is to define the structure of a service you wish to create. Structure of a service includes its methods, method signatures, and types needed  by the service.

At the top of EmployeeCRUD.proto file write (or modify) these lines:

syntax = "proto3";
package Northwind;
option csharp_namespace = "GrpcService1";

The first line tells that this file uses proto3 syntax (there is also proto2). So, simply put it's the protocol buffer language version that this file is using. The next two lines control the C# namespaces once this file is compiled. I won't go into the details of package and csharp_namespace option here but you can read more in the documentation.

Next, you need to define the structure of your service. In this case you want to create a service that performs CRUD operations on the Employees table. Here is the structure of EmployeeCRUD service that we will be using for this example.

service EmployeeCRUD {
  rpc SelectAll (Empty) returns (Employees);
  rpc SelectByID (EmployeeFilter) returns (Employee);
  rpc Insert (Employee) returns (Empty);
  rpc Update (Employee) returns (Empty);
  rpc Delete (EmployeeFilter) returns (Empty);
}

The above code defines structure for a service called EmployeeCRUD. There are five "rpc" methods - SelectAll(), SelectByID(), Insert(), Update(), and Delete(). Each method accepts a message and returns a message. These messages are types that you have to define in the .proto file. For example, SelectAll() method accepts a message of type Empty and returns a message of type Employees. As the name suggests Empty message type doesn't pass anything to the method and looks like this:

message Empty {

}

You can give any name of your choice to the message type. Here, we are using Empty as the name.

The SelectAll() method returns a list of Employee objects in the form of Employees type. So, there are two messages types to be defined - Employee and Employees. They are shown below:

message Employee {
  int32 employeeID = 1;
  string firstName = 2;
  string lastName = 3;
}


message Employees
{
   repeated Employee items = 1;
}

Notice that Employee message type defines three fields - employeeID, firstName, and lastName. Each field has a data type such as int32 or string, and also a field number. A field number is a numeric value between 1 to 536870911. Numbers between 19000 and 19999 are reserved and hence can't be used.

The Employees message type is supposed to be a collection of Employee type. The repeated keyword marks the items field to be a collection of Employee items.

The SelectByID() message type accepts an EmployeeFilter and returns a single Employee object. The EmployeeFilter contains filtering criteria for an Employee and looks like this:

message EmployeeFilter
{
   int32 employeeID = 1;
}

As you can see, the EmployeeFilter type contains a single field named employeeID and its data type is int32. The SelectByID() returns a single Employee matching the specified employeeID value.

The Insert(), Update(), and Delete() methods are similar in that they all return Empty message. The Insert(), and Update() methods accept an Employee to be added and Employee to be modified respectively. The Delete() method accepts an EmployeeFilter containing an EmployeeID of an Employee to be deleted.

This completes the EmployeeCRUD.proto file. This .proto file gets converted to a C# class upon compilation. I would suggest that you go through the Prototype Buffer documentation to familiarize the terminology and syntax of the .proto file.

Now open the appsettings.json file and add the database connection string to the Northwind database as shown below:

"ConnectionStrings": {
  "AppDb": "data source=.;initial catalog=Northwind;
            integrated security=true"
}

Then add NuGet package for Microsoft.EntityFrameworkCore.SqlServer and add a custom DbContext class as shown below:

public class AppDbContext:DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) 
: base(options)
    {

    }
    public DbSet<Employee> Employees { get; set; }
}

The AppDbContext class defines the Employees DbSet. The Employee entity class used by the AppDbContext is shown below:

public class Employee
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int EmployeeID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Note that there are now two Employee types - Employee from EmployeeCRUD.proto file and Employee entity class. Arrange them in meaningful namespaces or give different names to them if this seems to be confusing to you.

Finally, register the AppDbContext with the DI container This is done in the ConfigureServices() as shown below:

public void ConfigureServices(IServiceCollection services)
{
    services.AddGrpc();

    services.AddDbContext<AppDbContext>(options => 
options.UseSqlServer(this.config.
GetConnectionString("AppDb")));
}

At this point your project may not compile successfully because you haven't implemented the service yet. You will do that in the next part of this article.

That's it for now! Keep coding!!


"As you magnetize an iron rod by rubbing it with a magnet again and again, a flickering mind too becomes one pointed by practicing meditation again and again."
#AjapaYogaByBipinJoshi

Bipin Joshi is an independent software consultant, trainer, author, yoga mentor, and meditation teacher. He has been programming, meditating, and teaching for 24+ years. He conducts instructor-led online training courses in ASP.NET family of technologies for individuals and small groups. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced the Yoga way of life he also teaches Ajapa Yoga to interested individuals. To know more about him click here.

Get article updates : Facebook  Twitter  LinkedIn

Posted On : 21 October 2019


Tags : ASP.NET ASP.NET Core Data Access SQL Server C# Visual Studio


Subscribe to our newsletter

Get monthly email updates about new articles, tutorials, code samples, and how-tos getting added to our knowledge base.

  

Receive Weekly Updates