mirror of https://github.com/abpframework/abp.git
4 changed files with 178 additions and 0 deletions
@ -0,0 +1,178 @@ |
|||
# Using gRPC with the ABP Framework |
|||
|
|||
[gRPC](https://grpc.io/) defines itself as an open source, language agnostic, universal, high-performance **Remote Procedure Call (RPC)** framework. |
|||
|
|||
In this article, I will show you how to create a gRPC service and consume it from a console application with the ABP Framework. While the client application is console in this article, it can easily be a service consuming another service in a microservice system. |
|||
|
|||
> **This article will be a step by step tutorial.** I wrote the article based on Microsoft's [Code-first gRPC services and clients with .NET](https://docs.microsoft.com/en-us/aspnet/core/grpc/code-first) document. You can read that document for more details about gRPC and the code-first approach. |
|||
|
|||
## Creating the Application |
|||
|
|||
> I will use the ABP version 6.0 for this article. I am using the 6.0.0-rc.4 version since the stable version hasn't been published at the time I am writing this article. If it is released while you're reading this, do not specify the `--version` and `--preview` parameters in the following commands. |
|||
|
|||
Install the [ABP CLI](https://docs.abp.io/en/abp/latest/CLI) if you haven't installed it yet: |
|||
|
|||
````bash |
|||
dotnet tool install -g Volo.Abp.Cli --version 6.0.0-rc.4 |
|||
```` |
|||
|
|||
or update to the version 6.0.0-rc.4 if you've already installed a previous version: |
|||
|
|||
````bash |
|||
dotnet tool update Volo.Abp.Cli -g --version 6.0.0-rc.4 |
|||
```` |
|||
|
|||
Create an empty folder, open a command-line terminal and type the following command in the terminal window to create a new ABP solution using the ABP CLI: |
|||
|
|||
````bash |
|||
abp new ProductManagement -u blazor -t app --preview |
|||
```` |
|||
|
|||
I've created an application with the Blazor UI, but the UI is not important for this tutorial, you can select your favorite UI option. |
|||
|
|||
## Open the Solution |
|||
|
|||
Open the solution in your favorite IDE. I like [Rider](https://www.jetbrains.com/rider/), but Visual Studio, VS Code or any other IDE perfectly works. The following figure shows the solution structure in Rider: |
|||
|
|||
 |
|||
|
|||
Run the `ProductManagement.DbMigrator` project (a console application) to create the database and seed the initial data. |
|||
|
|||
## Defining the Service Contract |
|||
|
|||
We are starting by defining the service contract and DTO classes those will be shared between the server and the client applications. |
|||
|
|||
Create a `Products` folder in the `ProductManagement.Application.Contracts` project and add a new interface named `IProductAppService`: |
|||
|
|||
````csharp |
|||
using System.Collections.Generic; |
|||
using System.ServiceModel; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Services; |
|||
|
|||
namespace ProductManagement.Products; |
|||
|
|||
[ServiceContract] |
|||
public interface IProductAppService : IApplicationService |
|||
{ |
|||
Task<List<ProductDto>> GetListAsync(); |
|||
} |
|||
```` |
|||
|
|||
Your IDE will complain about the `[ServiceContract]` attribute, but it is necessary for the contract-first gRPC library we will be using later. So, add the [System.ServiceModel.Primitives](https://www.nuget.org/packages/System.ServiceModel.Primitives) NuGet package to the `ProductManagement.Application.Contracts` project, and it should be fixed. You can simply edit the `ProductManagement.Application.Contracts.csproj` file and add the following line in an `ItemGroup` tag: |
|||
|
|||
````xml |
|||
<PackageReference Include="System.ServiceModel.Primitives" Version="4.7.0" /> |
|||
```` |
|||
|
|||
Or you can use your IDE to find and add that NuGet package, it is up to you. |
|||
|
|||
I've also used `ProductDto` class, but not defined yet. Create a new class in the same folder with the `IProductAppService` file: |
|||
|
|||
````csharp |
|||
using System; |
|||
using System.Runtime.Serialization; |
|||
|
|||
namespace ProductManagement.Products; |
|||
|
|||
[DataContract] |
|||
public class ProductDto |
|||
{ |
|||
[DataMember(Order = 1)] |
|||
public Guid Id { get; set; } |
|||
|
|||
[DataMember(Order = 2)] |
|||
public string Name { get; set; } |
|||
} |
|||
```` |
|||
|
|||
`[DataContract]` and `[DataMember]` properties are needed for serialization. In gRPC, property serialization orders are important, because property names are not transferred to the target application, to keep the serialized data small. |
|||
|
|||
After adding these classes, `ProductManagement.Application.Contracts` project should look like in the following figure: |
|||
|
|||
 |
|||
|
|||
Contracts part is over. We actually didn't have any dependency to gRPC at that point. Our service and DTOs are pretty plain classes, except a few standard attributes, which are already defined in the .NET Core framework. Now, we can implement the `IProductAppService`. |
|||
|
|||
## Implementing the Service |
|||
|
|||
We are implementing the application services in the `ProductManagement.Application` project. So, add a new `Products` folder to that project and define a `ProductAppService` class inside it: |
|||
|
|||
````csharp |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace ProductManagement.Products; |
|||
|
|||
public class ProductAppService : ProductManagementAppService, IProductAppService |
|||
{ |
|||
public async Task<List<ProductDto>> GetListAsync() |
|||
{ |
|||
return new List<ProductDto> |
|||
{ |
|||
new ProductDto { Id = Guid.NewGuid(), Name = "Product 1" }, |
|||
new ProductDto { Id = Guid.NewGuid(), Name = "Product 2" }, |
|||
}; |
|||
} |
|||
} |
|||
```` |
|||
|
|||
This is a pretty standard, plain [application service ](https://docs.abp.io/en/abp/latest/Application-Services)class. All the ABP application service features (validation, audit logging, unit of work, etc.) are available. You can inject [repositories](https://docs.abp.io/en/abp/latest/Repositories) and perform database queries. To keep this article simple, I am returning a hard-coded data from here. |
|||
|
|||
> `ProductManagementAppService` is a base class coming in the ABP startup template. While you don't have to inherit from it, it provides useful base properties and methods you typically need in an application service. |
|||
|
|||
Application service part is over. Again, we didn't write any gRPC specific code. Don't worry, we will write in the next section. |
|||
|
|||
## Configuring the gRPC Server |
|||
|
|||
In this solution, `ProductManagement.HttpApi.Host` is the project that configures and runs the server-side application. So, we will make changes in that project. |
|||
|
|||
First, add the [protobuf-net.Grpc.AspNetCore](https://www.nuget.org/packages/protobuf-net.Grpc.AspNetCore) NuGet package to the `ProductManagement.HttpApi.Host` project: |
|||
|
|||
````xml |
|||
<PackageReference Include="protobuf-net.Grpc.AspNetCore" Version="1.0.177" /> |
|||
```` |
|||
|
|||
Then open the `ProductManagementHttpApiHostModule.cs` file, find the `ConfigureServices` method and add the following line into this method: |
|||
|
|||
````csharp |
|||
context.Services.AddCodeFirstGrpc(); |
|||
```` |
|||
|
|||
This will register code-first gRPC services to the [dependency injection](https://docs.abp.io/en/abp/latest/Dependency-Injection) system. Then find the `app.UseConfiguredEndpoints()` line in the `OnApplicationInitialization` method and change it as shown below: |
|||
|
|||
````csharp |
|||
app.UseConfiguredEndpoints(endpoints => |
|||
{ |
|||
endpoints.MapGrpcService<IProductAppService>(); |
|||
}); |
|||
```` |
|||
|
|||
We've configured the `IProductAppService` to handle gRPC requests to that service. The following figure shows the whole change done in the `ProductManagementHttpApiHostModule` class: |
|||
|
|||
 |
|||
|
|||
gRPC handles request with the HTTP/2 protocol and should listen an endpoint other than the default HTTP endpoint used by the application. We can easily configure the Kestrel server to listen two endpoints, one for our HTTP APIs, the other one for gRPC services. Add the following configuration inside the `appsettings.json` file of the `ProductManagement.HttpApi.Host` project: |
|||
|
|||
````json |
|||
"Kestrel": { |
|||
"Endpoints": { |
|||
"Https": { |
|||
"Url": "https://localhost:44388", |
|||
"Protocols": "Http1AndHttp2" |
|||
}, |
|||
"gRPC": { |
|||
"Url": "https://localhost:10042", |
|||
"Protocols": "Http2" |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
The server-side configuration is done. It is ready to receive gRPC requests. Now, we can change the client to consume the gRPC service we've created. |
|||
|
|||
## Implementing the Client Side |
|||
|
|||
TODO |
|||
|
|||
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 85 KiB |
Loading…
Reference in new issue