. Net framework and Net core for gRPC communication

I seldom write blogs, and my writing style is not very good. It is inevitable that there will be various problems, but I hope to do some personal sharing for this platform. The collaboration of this article comes from the actual project needs, and there are no realizable cases and solutions on the domestic Internet; However, by browsing stack overflow, there is a solution, so it is also shared with programmers who need it.

Preparation: the vs version used is 2019, in which the server platform is Net Core, the client is Net Framwork

I. server project: create ASP Net core grpc project, as shown in the figure:

Find the target template, select the project storage location, and then go to the next step. The default Framework version is Net core version 3.1, and then complete the creation.

Project structure:, we can see that suffixes are automatically created for us in the template proto protocol file and greeterservice CS class files, which saves us a lot of things, so we can directly enter the client.

2, Client project creation and configuration:

       1., Create in vs2019 Net standard (. Net framework) console. After creation, copy the "greet.proto" protocol file of the server to the client, and configure the configuration of the client console project csproj file, add the following code:

<ItemGroup>
    <Protobuf Include="greet.proto" GrpcServices="Client" />
  </ItemGroup>

2. Note that if the file name and file storage location are stored in the upper level directory, you can include = "XX \ XXX. Proto";

3. Install the corresponding Nuget management package: Grpc Tools,Google. Protobuf, and Grpc Net. Client or (Grpc.core, this package is currently in maintenance, but does not provide updates. Microsoft and Grpc team have developed Grpc.Net.Client), and then recompile the generated project and enter the client code writing.

        4. Client code: note that the reference plug-in here is grpc Net. Client,

var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Greeter.GreeterClient(channel);
            var reply = await client.SayHelloAsync(new HelloRequest { Name = "three delicacies" });

            Console.WriteLine("come from" + reply.Message);

            channel.ShutdownAsync().Wait();
            Console.WriteLine("Any key exit...");
            Console.ReadKey();

5. For joint commissioning, start the server project first, and then the client project. See the effect, as shown in the figure:

The general meaning is because of the server net core is http2, so the client needs to configure the http2 request or send the request with grpc web. Therefore, the Nuget package of grpc web is added and retested, but the error is still reported.

6. Try to modify the client, set http2, and the server listens to port 5001. The following code is still useless.

//client
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
//On the server side, add port listening in the startup class and CreateHostBuilder function in Program
webBuilder.ConfigureKestrel(options =>
                    {
                        options.AddServerHeader = false;
                        options.Listen(IPAddress.Loopback, 5001, listenOptions =>
                        {
                            //dlistenOptions.UseHttps(certificates);
                            listenOptions.Protocols = HttpProtocols.Http2;
                        });
                    });

7. Other attempts: https://docs.microsoft.com/zh-cn/aspnet/core/grpc/netstandard?view=aspnetcore-5.0 , tell me the reason is System.Net.Http.WinHttpHandler And win10 versions are not enough.

8. The user-defined certificate is successfully opened. The specific client code and server code are as follows:

//client
//server.pem creates the certificate through pwoershell, and then generates it through openssl pem file
SslCredentials secureCredentials = new SslCredentials(File.ReadAllText("server.pem"));
            var channel = new Channel("localhost", 5001, secureCredentials);
            Console.WriteLine("Link complete");

            var client = new Greeter.GreeterClient(channel);
            Console.WriteLine("Connect server");
            var reply = await client.SayHelloAsync(new HelloRequest { Name = "three delicacies" });

            Console.WriteLine("come from" + reply.Message);

            channel.ShutdownAsync().Wait();
            Console.WriteLine("Any key exit...");
            Console.ReadKey();
//Server: startup class, Main function in Program class
public static void Main(string[] args)
        {
            //Load Certificate profile,
            var config = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddEnvironmentVariables()
                .AddJsonFile("Certificate.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"certificate.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json",optional:true,reloadOnChange:true)
                .Build();
            //Read the content under the node in the configuration file
            var certificateSettings = config.GetSection("certificateSettings");
            string certificateFileName = certificateSettings.GetValue<string>("fileName");
            string certificatePassword = certificateSettings.GetValue<string>("password");
            //Extract the private key and verify the client's request to ensure that it is a secure and reliable request
            var certificates = new X509Certificate2(certificateFileName, certificatePassword);

            var host = new WebHostBuilder().UseKestrel(options =>
            {
                options.AddServerHeader = false;
                options.Listen(IPAddress.Loopback, 5001, listenOptions =>
                  {
                      //This is very important. It monitors whether the request on port 5001 is secure and carries the public key
                      listenOptions.UseHttps(certificates);
                      listenOptions.Protocols = HttpProtocols.Http2;
                  });
            })
            .UseConfiguration(config)
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseStartup<Startup>()
            .UseUrls("http://localhost:5001")
            .Build();
            host.Run();
            //CreateHostBuilder(args).Build().Run();
        }

In addition, the server needs to add certificate source file and certificate configuration json, as shown in the figure:

Certificate.json configuration

pwoershell generates a certificate. Source code:

//Change the place in Chinese to what you need
//The location of the generated certificate is c:\tmp
# setup certificate properties including the commonName (DNSName) property for Chrome 58+
$certificate = New-SelfSignedCertificate `
     -Subject Change the title to what you want, and don't take messy symbols (this will be displayed when installing the certificate))`
     -DnsName Friendly domain name(for example:localhost) `
     -KeyAlgorithm RSA `
     -KeyLength 2048 `
     -NotBefore (Get-Date) `
     -NotAfter (Get-Date).AddYears(2) `
     -CertStoreLocation  "cert:CurrentUser\My"  `
     -FriendlyName  "Friendly name of the certificate, in IIS Display when specified Certificate for .NET Core(Localhost Certificate for .Net Core)"  `
     -HashAlgorithm SHA256 `
     -KeyUsage DigitalSignature, KeyEncipherment, DataEncipherment `
     -TextExtension @( "2.5.29.37={text}1.3.6.1.5.5.7.3.1" )
$certificatePath = 'Cert:\CurrentUser\My\' + ($certificate.ThumbPrint) 
 
# create temporary certificate path
$tmpPath =  "C:\tmp"
If(!(test-path $tmpPath))
{
New-Item -ItemType Directory -Force -Path $tmpPath
}
 
# set certificate password here
$pfxPassword = ConvertTo-SecureString -String  "Password for your certificate"  -Force -AsPlainText
$pfxFilePath =  "c:\tmp\Name of your certificate.pfx"
$cerFilePath =  "c:\tmp\Name of your certificate.cer"
 
# create pfx certificate
Export-PfxCertificate -Cert $certificatePath -FilePath $pfxFilePath -Password $pfxPassword
Export-Certificate -Cert $certificatePath -FilePath $cerFilePath
 
# import the pfx certificate
Import-PfxCertificate -FilePath $pfxFilePath Cert:\LocalMachine\My -Password $pfxPassword -Exportable
 
# trust the certificate by importing the pfx certificate into your trusted root
Import-Certificate -FilePath $cerFilePath -CertStoreLocation Cert:\CurrentUser\Root
 
# optionally delete the physical certificates (don't delete the pfx file as you need to copy this to your app directory)
# Remove-Item $pfxFilePath
Remove-Item $cerFilePath

9. Recompile the code of the server and client, run the server first, and then run the client. Digression: for the first time, I don't know why, the server received the request, but the client didn't receive the return, so I decided to try the next day. Later, I thought it might be affected by the openssl window. The next day, I tried and succeeded, as shown in the figure:

 

Added by lordfrikk on Fri, 31 Dec 2021 19:29:03 +0200