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/

Install RabbitMQ on Ubuntu 20.04

Install Erlang

wget -O- https://packages.erlang-solutions.com/ubuntu/erlang_solutions.asc | sudo apt-key add -
echo "deb https://packages.erlang-solutions.com/ubuntu focal contrib" | sudo tee /etc/apt/sources.list.d/rabbitmq.list
sudo apt update
sudo apt install erlang

Install RabbitMQ

sudo apt update && sudo apt install wget -y
sudo apt install apt-transport-https -y
wget -O- https://dl.bintray.com/rabbitmq/Keys/rabbitmq-release-signing-key.asc | sudo apt-key add -
wget -O- https://www.rabbitmq.com/rabbitmq-release-signing-key.asc | sudo apt-key add -
echo "deb https://dl.bintray.com/rabbitmq-erlang/debian focal erlang-22.x" | sudo tee /etc/apt/sources.list.d/rabbitmq.list
sudo apt update
sudo apt install rabbitmq-server
sudo systemctl enable rabbitmq-server

RabbitMQ Management Dashboard

sudo rabbitmq-plugins enable rabbitmq_management

To be able to login on the network, create an admin user like below:

rabbitmqctl add_user admin StrongPassword
rabbitmqctl set_user_tags admin administrator

References
https://computingforgeeks.com/how-to-install-latest-erlang-on-ubuntu-linux/
https://computingforgeeks.com/how-to-install-latest-rabbitmq-server-on-ubuntu-linux/

Set executable file permission on Windows for using in Linux

with Windows Subsystem for Linux

git update-index --chmod=+x myfile.sh

If you frequently work with .sh files and want to ensure they are always marked as executable, you can configure Git to automatically handle this. For example, you can use a .gitattributes file to define rules for specific file types.

*.sh text eol=lf
*.sh executable

a .bat script for Windows that searches for all .sh files in a folder and its subfolders, and then runs the git update-index --chmod=+x command for each file:

@echo off
:: Get the current directory
set "ROOT_DIR=%cd%"

:: Navigate to the current directory
cd /d "%ROOT_DIR%"

:: Loop through all .sh files in the folder and subfolders
for /r %%f in (*.sh) do (
    echo Processing file: %%f

    :: Add the file to the Git index if it's not already tracked
    git add "%%f" 2>nul

    :: Mark the file as executable
    git update-index --chmod=+x "%%f"
)

echo All .sh files in the current directory and subfolders have been marked as executable.
pause

References
https://www.scivision.dev/git-windows-chmod-executable/

Switch statement in Go

package main

import (
    "fmt"
    "time"
)

func main() {

    i := 2
    fmt.Print("Write ", i, " as ")
    switch i {
    case 1:
        fmt.Println("one")
    case 2:
        fmt.Println("two")
    case 3:
        fmt.Println("three")
    }

    switch time.Now().Weekday() {
    case time.Saturday, time.Sunday:
        fmt.Println("It's the weekend")
    default:
        fmt.Println("It's a weekday")
    }

    t := time.Now()
    switch {
    case t.Hour() < 12:
        fmt.Println("It's before noon")
    default:
        fmt.Println("It's after noon")
    }

    whatAmI := func(i interface{}) {
        switch t := i.(type) {
        case bool:
            fmt.Println("I'm a bool")
        case int:
            fmt.Println("I'm an int")
        default:
            fmt.Printf("Don't know type %T\n", t)
        }
    }
    whatAmI(true)
    whatAmI(1)
    whatAmI("hey")
}

References
https://gobyexample.com/switch

If Statement in Go

package main

import "fmt"

func main() {

    if 7%2 == 0 {
        fmt.Println("7 is even")
    } else {
        fmt.Println("7 is odd")
    }

    if 8%4 == 0 {
        fmt.Println("8 is divisible by 4")
    }

    if num := 9; num < 0 {
        fmt.Println(num, "is negative")
    } else if num < 10 {
        fmt.Println(num, "has 1 digit")
    } else {
        fmt.Println(num, "has multiple digits")
    }
}

References
https://gobyexample.com/if-else

For Loop in Go

package main

import "fmt"

func main() {

    i := 1
    for i <= 3 {
        fmt.Println(i)
        i = i + 1
    }

    for j := 7; j <= 9; j++ {
        fmt.Println(j)
    }

    for {
        fmt.Println("loop")
        break
    }

    for n := 0; n <= 5; n++ {
        if n%2 == 0 {
            continue
        }
        fmt.Println(n)
    }
}

References
https://gobyexample.com/for