Bind gRPC Service to specific port in ASP.NET Core

This works (server side) with Kestrel:

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
    webBuilder.ConfigureKestrel(options =>
    {
       options.Listen(IPAddress.Loopback, 5000);
       options.Listen(IPAddress.Loopback, 5005, configure => configure.UseHttps());
    });
    webBuilder.UseStartup<Startup>();
});

client side:

var httpHandler = new HttpClientHandler
 {
     ServerCertificateCustomValidationCallback =
     HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
 };  

AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
                
using var channel = GrpcChannel.ForAddress("https://localhost:5005", new GrpcChannelOptions { HttpHandler = httpHandler } );
            
var client = new Greeter.GreeterClient(channel);

References
https://stackoverflow.com/questions/63827667/bind-grpc-services-to-specific-port-in-aspnetcore
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel/options?view=aspnetcore-5.0
https://andrewlock.net/5-ways-to-set-the-urls-for-an-aspnetcore-app/

Call insecure gRPC services with .NET Core client

// This switch must be set before creating the GrpcChannel/HttpClient.
AppContext.SetSwitch(
    "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

// The port number(5000) must match the port of the gRPC server.
var channel = GrpcChannel.ForAddress("http://localhost:5000");
var client = new Greet.GreeterClient(channel);

The System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport switch is only required for .NET Core 3.x. It does nothing in .NET 5 and isn’t required.

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(options =>
            {
                // Setup a HTTP/2 endpoint without TLS.
                options.ListenLocalhost(5000, o => o.Protocols = 
                    HttpProtocols.Http2);
            });
            webBuilder.UseStartup<Startup>();
        });

When an HTTP/2 endpoint is configured without TLS, the endpoint’s ListenOptions.Protocols must be set to HttpProtocols.Http2

References
https://docs.microsoft.com/en-us/aspnet/core/grpc/troubleshoot?view=aspnetcore-5.0#call-insecure-grpc-services-with-net-core-client
https://docs.microsoft.com/en-us/aspnet/core/grpc/troubleshoot?view=aspnetcore-5.0#unable-to-start-aspnet-core-grpc-app-on-macos

Call a gRPC service with an untrusted/invalid certificate in C#

var httpHandler = new HttpClientHandler();
// Return `true` to allow certificates that are untrusted/invalid
httpHandler.ServerCertificateCustomValidationCallback = 
    HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

var channel = GrpcChannel.ForAddress("https://localhost:5001",
    new GrpcChannelOptions { HttpHandler = httpHandler });
var client = new Greet.GreeterClient(channel);

References
https://docs.microsoft.com/en-us/aspnet/core/grpc/troubleshoot?view=aspnetcore-5.0#call-a-grpc-service-with-an-untrustedinvalid-certificate

gRPC services with C#

Add a .proto file to a C# app

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>

C# Tooling support for .proto files

Server:

<PackageReference Include="Grpc.AspNetCore" Version="2.28.0" />

Client:

<PackageReference Include="Google.Protobuf" Version="3.11.4" />
<PackageReference Include="Grpc.Net.Client" Version="2.28.0" />
<PackageReference Include="Grpc.Tools" Version="2.28.1">

Generated C# assets

Server Side:

To ensure only the server assets are generated in a server project, the GrpcServices attribute is set to Server.

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>
public class GreeterService : Greeter.GreeterBase
{
    private readonly ILogger<GreeterService> _logger;
    public GreeterService(ILogger<GreeterService> logger)
    {
        _logger = logger;
    }

    public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
    {
        return Task.FromResult(new HelloReply
        {
            Message = "Hello " + request.Name
        });
    }
}

Client Side:

static async Task Main(string[] args)
{
    // The port number(5001) must match the port of the gRPC server.
    using var channel = GrpcChannel.ForAddress("https://localhost:5001");
    var client =  new Greeter.GreeterClient(channel);
    var reply = await client.SayHelloAsync(
                      new HelloRequest { Name = "GreeterClient" });
    Console.WriteLine("Greeting: " + reply.Message);
    Console.WriteLine("Press any key to exit...");
    Console.ReadKey();
}

References
https://docs.microsoft.com/en-us/aspnet/core/grpc/basics?view=aspnetcore-5.0

Arrays in Go

An array is a data structure that consists of a collection of elements of a single type or simply you can say a special variable, which can hold more than one value at a time. The values an array holds are called its elements or items. An array holds a specific number of elements, and it cannot grow or shrink. Different data types can be handled as elements in arrays such as Int, String, Boolean, and others. The index of the first element of any dimension of an array is 0, the index of the second element of any array dimension is 1, and so on.

import "fmt"

func main() {
    // declare an array
    var colors [3]string
    // assign values to array
    colors[0] = "Red"
    colors[1] = "Green"
    colors[2] = "Blue"
    
    // print all items in array
    fmt.Println(colors)
    // print on item of an array
    fmt.Println(colors[1])
    
    // declare and assign
    var numbers = [5]int{5, 4, 2, 1, 10}
    fmt.Println(numbers)
    
    // print length of array
    fmt.Println("Number of colors:", len(colors))
    fmt.Println("Number of numbers:", len(numbers))
}

Initialize an Array with an Array Literal

x := [5]int{10, 20, 30, 40, 50}   // Intialized with values
    var y [5]int = [5]int{10, 20, 30} // Partial assignment

 

References
https://www.golangprograms.com/go-language/arrays.html

Referencing values with pointers in Go

import (
    "fmt"
)

func main() {
    var p *int
    var v int = 42

    // put memory address of v in p
    p = &v

    // print memory address of v
    fmt.Println(p)

    // print value of v
    fmt.Println(*p)

    // change value of v by changing pointer value
    *p = 50

    // print value of p
    fmt.Println(v)
}

 

Getting input from the console in Go

import "fmt"

func main() {

    var str string
    fmt.Print("Enter a string: ")
    // scans text read from standard input, storing them space-separated
    // for example we can read Mahmood from input, but not Mahmood Ramzani
    fmt.Scanln(&str)
    fmt.Printf("String Value : %v\n",str)

    var str1,str2 string
    fmt.Print("Enter two string: ")
    fmt.Scanln(&str1,&str2)
    fmt.Printf("String Value1 : %v\n",str1)
    fmt.Printf("String Value1 : %v\n",str2)
}
import (
    "bufio"
    "fmt"
    "os"
    "strconv"
    "strings"
)

func main() {

    reader := bufio.NewReader(os.Stdin)
    fmt.Print("Enter text :")
    str, _ := reader.ReadString('\n')
    fmt.Println(str)

    fmt.Print("Enter a number : ")
    str, _ = reader.ReadString('\n')
    // trim space
    trimmedStr := strings.TrimSpace(str)
    // convert string to int
    number, err := strconv.ParseInt(trimmedStr, 10, 32)

    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Println(number)
    }
}

 

Outputting strings with the fmt package in Go

import "fmt"

func main() {

    // using the default formats
    fmt.Println("Hello Mahmood")

    // return values from Println
    n, _ := fmt.Println("Hello Mahmood 2")

    // formats according to a format specifier
    fmt.Printf("Length : %d\n", n)

    isTrue := true
    aNumber := 1400
    name := "Mahmood"

    // The verbs:

    // values in a default format
    fmt.Printf("Boolean : %v\n", isTrue)
    fmt.Printf("Number : %v\n", aNumber)
    fmt.Printf("String : %v\n", name)

    // values with specified format
    fmt.Printf("Boolean : %t\n", isTrue)
    fmt.Printf("Number : %d\n", aNumber)
    fmt.Printf("String : %s\n", name)

    // formats according to a format specifier and returns the resulting string
    myString := fmt.Sprintf("Hello %s", name)
    fmt.Println(myString)
}

References
https://golang.org/pkg/fmt/