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

In Part -1 of this
article you created EmployeeCRUD service definition using Protocol Buffer
language. The EmployeeCRUD.proto file and EF Core model is now ready. In this
part you will create the EmployeeCRUD service based on the structure defined in
the .proto file.
To begin, open the project created in
Part -1 and expand the
Services folder. Rename the service file to EmployeeCRUDService.cs. At this
point the Solutions Explorer will look like this:

Now open the EmployeeCRUDService.cs file and modify the class to resemble
this:
...
using DataAccess = GrpcService1.DataAccess;
public class EmployeeCRUDService :
EmployeeCRUD.EmployeeCRUDBase
{
private DataAccess.AppDbContext db = null;
public EmployeeCRUDService(
DataAccess.AppDbContext db)
{
this.db = db;
}
}
As you can see, EmployeeCRUDService class inherits from
EmployeeCRUD.EmployeeCRUDBase. This base class is automatically generated for
you based on the .proto file you created earlier. The EmployeeCRUDService class
needs to override the service methods such as SelectAll() and SelectByID(). You
will do that shortly.
Since the service method implementation requires access to EF Core data
context and entity classes, AppDbContext is injected in the constructor of the
service class. Note that in my case there are two Employee classes - one
obtained from the Employee message type and the other is Employee entity class.
Here in the service you need to use both Employee classes. Therefore, DataAccess
namespace alias is used to correctly identify both.
Next, add SelectAll() method to the service class as shown below:
public override Task<Employees> SelectAll
(Empty requestData, ServerCallContext context)
{
Employees responseData = new Employees();
var query = from emp in db.Employees
select new Employee()
{
EmployeeID = emp.EmployeeID,
FirstName = emp.FirstName,
LastName = emp.LastName
};
responseData.Items.AddRange(query.ToArray());
return Task.FromResult(responseData);
}
The SelectAll() method is an async method and takes two parameters. The first
requestData parameter contains data received along with the request. In this
case it's an Empty object. The second parameter is ServerCallContext object that
represents server-side context for the RPC call being made. The
ServerCallContext is automatically made available to all the service methods. In
this case we don't use it in our processing.
Inside, we create Employees object. Recollect that Employees message type is
a collection of Employee objects. A LINQ query then projects DataAccess.Employee
into Employee. Actual Employee data is added to Employees object using its Items
collection and AddRange() method.
The Employees object thus created is returned to the caller.
Now add SelectByID() method as shown below:
public override Task<Employee> SelectByID
(EmployeeFilter requestData,
ServerCallContext context)
{
var data = db.Employees.Find
(requestData.EmployeeID);
Employee emp = new Employee()
{
EmployeeID = data.EmployeeID,
FirstName = data.FirstName,
LastName = data.LastName
};
return Task.FromResult(emp);
}
The SelectByID() method receives EmployeeFilter object containing EmployeeID.
Inside, it fetches the matching Employee object using Find() method and returns
it to the caller.
Then add Insert() method as shown below:
public override Task<Empty> Insert
(Employee requestData,
ServerCallContext context)
{
db.Employees.Add(new DataAccess.Employee()
{
EmployeeID = requestData.EmployeeID,
FirstName = requestData.FirstName,
LastName = requestData.LastName
});
db.SaveChanges();
return Task.FromResult(new Empty());
}
The Insert() method receives an Employee object containing details of the new
employee to be added. Inside, it adds it to the Employees DbSet using Add()
method. The data is saved to the database using SaveChanges() method. Recollect
that Insert(), Update(), and Delete() actions return Empty object to the caller.
So, an Empty object is returned to the caller.
Similarly, add the Update() method as shown below:
public override Task<Empty>
Update(Employee requestData,
ServerCallContext context)
{
db.Employees.Update(new DataAccess.Employee()
{
EmployeeID = requestData.EmployeeID,
FirstName = requestData.FirstName,
LastName = requestData.LastName
});
db.SaveChanges();
return Task.FromResult(new Empty());
}
Update() method is similar to Insert() in that it also receives Employee
object. Inside, it updates an existing Employee using Update() method and saves
the changes using SaveChanges() method.
Finally, add the Delete() method as shown below:
public override Task<Empty>
Delete(EmployeeFilter requestData,
ServerCallContext context)
{
var data = db.Employees.Find(requestData.EmployeeID);
db.Employees.Remove(new DataAccess.Employee()
{
EmployeeID = data.EmployeeID,
FirstName = data.FirstName,
LastName = data.LastName
});
db.SaveChanges();
return Task.FromResult(new Empty());
}
The Delete() method receives an EmployeeFilter object containing EmployeeID
of an employee to be deleted. Inside, it finds that Employee using Find() method
and then removes it from Employee DbSet using Remove() method. The changes are
persisted in the database by calling SaveChanges() method.
This complete the EmployeeCRUDService. One final step is to modify
Configure() in the Startup class as shown below:
public void Configure(IApplicationBuilder app,
IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<EmployeeCRUDService>();
...
});
}
Change the type mentioned in the MapGrpcService() method call to
EmployeeCRUDService. You can now compile the project to ensure that there are no
compilation errors. If you run the application at this
stage, you will see a console window opened as shown below:

As you can see, the service is available at https://localhost:5001. You can
now consume it in a client application. You will build a client application in
the next part of this article.
That's it for now! Keep coding!!
"Taming the mind by the goad of Prana -- that wonderful game called
meditation."
#AjapaYogaByBipinJoshi