• Featured post

C# Task async programming (TAP) and parallel code

The core for asynchronous programming are the objects Task and Task<T>. Both of them are compatible with the keywords async and await.

First of all we need to identify if the code’s I/O-bound or CPU-bound.

  • the code’s limited for external operations and waits for something a lot of time. Examples of this are DDBB calls, or a server’s response. In this case we have to use async/await to free the thread while we wait
  • the code does a CPU-intensive operation. Then we move the work to another thread using Task.Run() so we don’t block the main thread.

async code vs parallel code

(!) Asynchronous code is not the same as parallel code (!)

  • In async code you are trying to make your threads do as little work as possible. This will keep your app responsibe, capable to serve many requests at once and scale well.
  • In parallel code you do the opposite. You use and keep a hold on a thread to do CPU-intensive calculations

async code

The importante of async programming is that you choose when to wait on a task. This way, you can start other tasks concurrently

In async code, one single thread can start the next task concurrently before the previous one completes.
(!) async code doesn’t cause additional threads to be created because an async method doesn’t run on its own thread. (!) It runs on the current synchronization context and uses time on the thread only when the method is active.

parallel code

For parallelism you need multiple threads where each thread executes a task, and all of those tasks are executed at the same time

Read More

.NET launchsettings vs appsettings

launchSettings

Tiene más que ver con el despliegue. Establece los perfiles con los que ejecutaremos nuestro proyecto. Configura la forma en la que se inicia la aplicación durante el desarrollo y contiene valores que NO DEBEN EXPONERSE EN PROD.

No se utiliza en entornos de producción.

{
  "profiles": {
    "my.project.namespace": {
      "commandName": "Project",
      "launchBrowser": false,
      "applicationUrl": "https://localhost:5011;http://localhost:5010",
	  "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

ASPNETCORE_ENVIRONMENT Indica el entorno - soporta los siguientes valores

  • Development
  • Staging
  • Production valor por defecto si se omite el valor

commandName especifica el servidor web que se va a iniciar

  • IISExpress inicia IIS Express
  • Project inicia Kestrel

appsettings

Se utiliza para almacenar la configuración de la aplicación, como cadenas de conexión de BBDD.

Se utiliza tanto en entornos de desarrollo como de producción.

{
	"LocalDirectory": "/opt/data-download",
	"MyServiceConfig": {
		"Uri": "http://localhost:8800",
		"Endpoint": "/some-endpoint",
		"Timeout": 30
	}
}

Hay varias maneras de leer la configuración.

leer de la raiz

Las que se encuentran en la raiz las podemos leer inyectando la config en la clase.

public class MyService(IConfiguration _config) : IMyService
{
	public void MyMethod()
	{
		var localDirectory = _config["LocalDirectory"];
	}
}

leer de una clase de config custom

por un lado tenemos la clase de config

public class MyServiceConfig
{
	public const string Section = "MyServiceConfig";

	public string Uri { get; set; }
	public string Endpoint { get; set; }
	public int Timeout { get; set; }
}

y por otro lado la inyectamos

public class MyService(MyServiceConfig _config) : IMyService
{
	public void MyMethod()
	{
		var uri = _config.Uri;
		var endpoint = _config.Endpoint;
		var timeout = _config.Timeout;
	}
}

la tendremos que poner también en el Startup

public void ConfigureServices(IServiceCollection services)
{
	// ...
	services.Configure<MyServiceConfig>(config.GetSection(MyServiceConfig.Section));
	// ...
}

Reference(s)

https://learn.microsoft.com/es-es/aspnet/core/fundamentals/environments?view=aspnetcore-8.0
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-8.0

.NET Middleware

Middleware is software assembled into a pipeline to handle request and responses. Each component:

  • Chooses if he passes the request to the next component.
  • Can perform work before and after the next component.

Common use cases:

  • Logging
  • Authentication & Authorization
  • Request/Response processing
  • Caching
  • Error handling

.NET middleware

Implementation w. DI

We create our own custom middleware with an internal dependency, which is the class it’s going to process before/after our request.

// interface and its class, which do the processing
public interface IMiddlewareService
{
	Task ProcessRequest(string request);
}

// interface implementation
public class MiddlewareService : IMiddlewareService
{
	public async Task ProcessRequest(string request)
	{
		// do something with the request
		Console.WriteLine(request);
	}
}

Then we have our middleware class as such

public class CustomMiddleware(IMiddlewareService _service) : IMiddleware
{
	public async Task InvokeAsync(HttpContext context, RequestDelegate next)
	{
		// custom logic to be executed BEFORE next middleware
		await _service.ProcessRequest("middleware processing request");
		await next(context);
		// custom logic to be executed AFTER next middleware
	}
}

Declaration inside Startup.cs

public void ConfigureServices(IServiceCollection services)
{
	// ... whatever

	// register both: our custom middleware, and its internal dependency
	services.AddTransient<IMiddlewareService, MiddlewareService>();
	services.AddTransient<CustomMiddleware>();
	
	// ... whatever else
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
	// ... whatever

	// declaration to use middleware
	app.UseMiddleware<CustomMiddleware>();
	// if we use this, the middleware declaration has to be BEFORE or else it won't work
	app.UseEndpoints(endpoints => 
	{
		endpoints.MapControllers();
	})

	// ... whatever else
}

Reference(s)

https://medium.com/@dushyanthak/best-practices-for-writing-custom-middlewares-in-asp-net-core-97b58c50cf9c
https://learn.microsoft.com/es-es/aspnet/core/fundamentals/middleware/write?view=aspnetcore-8.0
https://sardarmudassaralikhan.medium.com/custom-middleware-in-asp-net-core-web-api-70c2ffbbc095

Test APIs with Postman - Scripting

We can set pre-request scripts (run before the request) & tests (after execution) at several levels:

  • Collection
  • Folder
  • Request

Snippets

Inside pre-request Script and Tests we have a SNIPPETS column with templates we may use for our code.

postman scripting

Get / Set variables

console.log("Hello world");

// work with local vars
let urlVar = pm.variables.get("protocol");
console.log("value for protocol: " + urlVar);

pm.variables.set("protocol", "http");
console.log(pm.variables.get("protocol"));  

// work with global vars
let globalVar = pm.globals.get("env");
console.log(globalVar);

Read More

Test APIs with Postman - GUI

To test postman I use https://reqres.in. You can use it to learn how to write Postman tests.

Collections

Collections have metadata which you can set up. This includes:

  • Authorization so you don’t need to set it for every single request.
  • Variables, for variables only for this collection (so you don’t use environment vars).
  • Collection tests.

postman gui

Read More

Error al crear imagenes en local (Minikube)

Hay un problema al intentar correr una imagen tuya propia en local con minikube. Minikube tiene su propio repositorio de imagenes y si no encuentra una imagen alli, la intenta descargar siempre del repositorio.

Solución

Set imagePullPolicy: IfNotPresent

error crear imagenes minikube en local

Run the following command:

eval $(minikube docker-env)
# build again the image
# try to run it again

Reference(s)

https://medium.com/bb-tutorials-and-thoughts/how-to-use-own-local-doker-images-with-minikube-2c1ed0b0968

K8s config commands

Config

Azure

log-in into a tenant

az login --tenant 7f2c3a6b-e849-4d6f-b65d-1c0ef8b0f41c

configure local kubectl .kube config file

az aks get-credentials --resource-group my-aks --name aksname --admin

(the –admin part is optional but useful)

Contexts & Namespaces

see all configured contexts

kubectl config get-contexts

configure a context with a default namespace

kubectl config set-context <context_here> --namespace=<namespace_here>
# example
kubectl config set-context my-aks-context --namespace=aks-dev

Read More

Docker-compose how to export volumes to another machine

Data generated and used by Docker containers does not persist after restarts. We use Docker volumes to manage data to solve this issue. We use it to persist data in a container or share data between containers.

Volumes are the preferred mechanism for persisting data generated and user by Docker containers. Volumes are easier to back up or migrate.

Volumes are often a better choice than persisting data in a container’s writable layer, because a volume does not increase the size of the containers using it. The volume’s contents exist outside the lifecycle of a given container.

We have 3 volume types:

Anonymous volumes

Helpful to persist data temporarily. If we restart our container data is still visible. It doesn’t persist when we remove the container. Not accessible by other containers. They’re created inside /var/lib/docker/volume.

Example file:

version: '3.8'  
services:  
  db:  
    image: mysql  
    restart: always  
    environment:  
      MYSQL_ROOT_PASSWORD: root  
      MYSQL_DATABASE: test_db  
    ports:  
      - "3306:3306"  
    volumes:  
      - /var/lib/mysql

Read More

Migrate docker-compose to k8s

Steps to go from a docker-compose file, to build an Image out of the file, upload it to DockerHub, and run it with Kubernetes (minikube).

Set up

Install Kompose

# linux
curl -L https://github.com/kubernetes/kompose/releases/download/v1.22.0/kompose-linux-amd64 -o kompose
chmod +x kompose
sudo mv ./kompose /usr/local/bin/kompose

Clone App and Host It into DockerHub

Clone the files, go to the directory where your Dockerfile is and run:

# mariocodes is my DockerHub username
# kubernetes-custom-java-maven-app is the name of the repo I created at DockerHub
docker build -f Dockerfile -t mariocodes/kubernetes-custom-java-maven-app .

Read More

K8s install Minikube

(Oficial Doc)

Technology to quickly set up a Kubernetes cluster locally to learn how to use Kubernetes.

Installation

How to install on a fresh Ubuntu installation:

Install prerrequisites and kubectl

sudo apt-get update && sudo apt-get install -y apt-transport-https curl

curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -

echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.list

sudo apt-get update
sudo apt-get install -y kubectl

Read More

Common errors in k8s

STATUS CrashLoopBackOff

CrashLoopBackOff and no log appears. This happens as the container has no command to run so it start up and then immediately exits.

Give your image a command.

more here

apiVersion: v1
kind: Pod
metadata:
  name: twocontainers
spec:
  containers:
  - name: container1
    image: python:3.6-alpine
	command: ['sh', '-c', 'echo cont1 > index.html && python -m http.server 8082']
  - name: container2
    image: python:3.6-alpine
	command: ['sh', '-c', 'echo cont1 > index.html && python -m http.server 8083']