Posts From Category: dotnet

C# Pattern matching

Overview of scenarios where you can use pattern matching. These techniques can improve the readability and correctness of your code.

Reduce nested if-else

We have the following class

IAnimal animal = new Cat("Fred", 12);

then with a single if we can determine if the animal is more than 10 years old and has the name of fred

if(animal is Cat { CatYears: >10, Name: "Fred"} myCat)
{
	Console.WriteLine($"{myCat.CatYears} old");
}

Null checks

One of the most common scenarios.

string? message = MaybeString();
if(message is not null) 
{
	Console.WriteLine(message);
}

Compare discrete values

You can test a varaible to find a match on specific values

public State PerformOperation(string command) =>
	command switch
	{
		"SystemTest" => RunDiagnostics(),
		"Start" => StartSystem(),
		"Stop" => StopSystem(),
		_ => throw new ArgumentException("Invalid string value", nameof(command)),
	};

_ is the discard pattern that matches all values. It handles any error conditions where the value doesn’t match one of the defined values.

Read More

C# Expression bodied members

Expression body definitions let you provide a member’s implementation in a concise, readable form.

Methods

Expression-bodied method consists of a single expression that returns:

  • a value whose type matches the return value
  • or performs an operation for void methods
public class Person(string firstName, string lastName)
{
	public override string ToString() => $"{firstName} {lastName}".Trim();
	public void DisplayName() => Console.WriteLine(ToString());
}

Read-only properties

You can use them to implement read-only property.

public class Location(string locationName)
{
	public string Name => loactionName;
}

Reference(s)

https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members

Read More

Deconstruction in ASP.NET Core

Desconstructors allows us to extract in a single expression, properties of an object or elements of a tuple, and assign them to distinct variables.

record and record struct automatically provide a Deconstruct method.

Classes

before deconstruction we had to manually extract each variable

var pat = new Person() { Name = "Patrick", BirdDate = new DateOnly(1999, 1, 18)};
var name = pat.Name;
var birthDate = pat.BirthDate;
Console.WriteLine($"Name: {name}, birthdate: {birthDate}");

class Person

public class Person
{
	public string Name { get; set; }
	public string Location { get; set; }
}

with deconstruction

var pat = new Person() { Name = "Patrick", BirdDate = new DateOnly(1999, 1, 18)};
var (name, birthDate) = pat;
Console.WriteLine($"Name: {name}, birthdate: {birthDate}");

class Person with Deconstructor

public class Person
{
	public string Name { get; set; }
	public string Location { get; set; }
	
	public void Deconstruct(out string name, out string location) 
	{
		name = Name;
		location = Location;
	}
}

if you don’t want all properties, just discard some using the discard character _

var pat = new Person() { Name = "Patrick", BirdDate = new DateOnly(1999, 1, 18)};
var (name, _) = pat;
Console.WriteLine($"Name: {name}");

Tuples

The same applies to tuples

// tuple creation
(string name, string location) person = ("mario", "spain");
// deconstructor
var (name, location) = person;

Reference(s)

https://blog.ndepend.com/deconstruction-in-c/

Read More

Cache in ASP.NET Core

ASP.NET Core offers several cache types. I’m going to explore here IMemoryCache which stores data in the memory of the web server. It’s simple but not suitable for distributed scenarios.

first of all we need to register the services

builder.Services.AddMemoryCache();

here’s how you can use it

public service(IMemoryCache cache, AppDbContext context)
{
	public Person GetPerson(string id)
	{
		if(!cache.TryGetValue(id, out Person person))
		{
			person = context.Persons.Find(id);

			var cacheEntryOptions = new MemoryCacheEntryOptions()
				.SetAbsoluteExpiration(TimeSpan.FromMinutes(10))
				.SetSlidingExpiration(TimeSpan.FromMinutes(2));

			cache.Set(id, person, cacheEntryOptions);
		}

		return person;
	}
}

Reference(s)

https://www.milanjovanovic.tech/blog/caching-in-aspnetcore-improving-application-performance

Read More

Dependency injection in .NET Core

Dependency injection is native-available in .NET Core

DI implementation

interface we want to inject

public interface IDateTime
{
	DateTime Now { get; }
}

interface’s implementation

public class SystemDateTime : IDateTime
{
	public DateTime Now
	{
		get { return DateTime.Now; }
	}
}

service we inject into

public class HomeController : Controller
{
	private readonly IDateTime _dateTime;

	public HomeController(IDateTime dateTime)
	{
		_dateTime = dateTime;
	}

	public IActionResult Index()
	{
		var serverTime = _dateTime.Now;
		return Ok(serverTime);
	}
}

Read More

C# Anonymous types objects

Anonymous types provide an easy way to encapsulate different properties in a single object. Unlike properties in a class, the properties of anonymous type objects are read-only.

Declare and use anon type objects

declaration

var loginCredentials = new { Username = "suresh", Password = "******" };
Console.WriteLine($"Username {loginCredentials.Username.ToString()}");
Console.WriteLine($"Password {loginCredentials.Password.ToString()}");

After assigning values to the Username and Password properties, they cannot be altered *(they’re readonly).

Anon objects in LINQ

Usually, anon data types are used in the select clause to return a specific subset of properties for each object in the collection.

we have the employee class

public class Employee
{
	public int ID { get; set; }
	public string Name { get; set; }
	public int Age { get; set; }
	public string Address { get; set; }
}
List<Employee> employees = // whatever ...
// we convert an Employee into an anon object type with a subset of properties
var employeeDetails = from emp in employees
	select new { Id = emp.ID, Name = emp.Name };

Reference(s)

https://www.syncfusion.com/blogs/post/understanding-csharp-anonymous-types

Read More

Dependency injection w. multiple implementations

I have the class package with a type, plus more info not relevant to the question

public class Package
{
	public string Type { get; set; }
	// ... more package properties
}

I have the following interface service to mail packages

public interface IMailService
{
	public Task<string> SendPackage(Package package);
}

Then I have several implementations for this interface

public class MailNewPackageService : IMailService
{
	public async Task<string> SendPackage(Package package)
	{
		Console.WriteLine("send package through new service");
		// implementation ...
	}
}

public class MailOldPackageService : IMailService
{
	public async Task<string> SendPackage(Package package)
	{
		Console.WriteLine("send package through old service");
		// implementation ...
	}
}

Read More

C# Streams and Files

MemoryStream

Los streams en memoria se usan sobre todo para leer de ficheros, o para almacenar información que queremos guardar en ficheros.

Si se inicializa mediante el siguiente constructor no se puede cambiar su tamaño.

MemoryStream ms = new MemoryStream(150);
ms.Capacity;
ms.Length;
ms.Position;

// 0 bits from Begin
ms.Seek(0, SeekOrigin.Begin);
// 5 bits from current position
ms.Seek(5, SeekOrigin.Current);
// go back 10 bits from current position
ms.Seek(-10, SeekOrigin.Current);

Files

Ejemplo para leer y escribir un fichero.

write file

FileStream fsEscribir = new FileStream("miArchivo.txt", FileMode.Create);

string cadena = "this is an example";

fsEscribir.Write(ASCIIEncoding.ASCII.GetBytes(cadena), 0, cadena.Length);
fsEscribir.Close();

read file

byte[] infoArchivo = new byte[100];

FileStream fs = new FileStream("miArchivo.txt", FileMode.Open);
fs.Read(infoArchivo, 0, (int) fs.Length);

Console.WriteLine(ASCIIEncoding.ASCII.GetString(infoArchivo));
Console.ReadKey();

fs.Close();

Read More

Servicebus vs queue

ServiceBus

Sistema de mensajeria COMPLEJO que permite comunicacion entre MULTIPLES SERVICIOS usando patrones publication/subscription

Permite a un mensaje ser consumido por MULTIPLES CONSUMERS Ideal para flujos de trabajo complejos

Queue

Mecanismo mas simple y directo. Permite la transmision de mensajes de un punto a otro. Un mensaje enviado a la cola es recibido y procesado por un unico consumidor Se centra en GARANTIZAR LA ENTREGA del mensaje, pero es mas limitado.

Read More

C# Events

Permite a una clase notificar a otras cuando ocurre algo de interés.

public class Publicador
{
	// Declaracion de un evento
	public event EventHandler EventoSimple;

	// trigger
	public void DispararEvento()
	{
		// verificacion de subscripcion
		if(EventoSimple != null)
		{
			EventoSimple(this, EventArgs.Empty);
		}
	}
}
public class Suscriptor
{
	public void Suscribirse(Publicador publicador)
	{
		// suscripcion al evento
		publicador.EventoSimple += ManejadorEvento;
	}

	private void ManejadorEvento(object sender, EventArgs e)
	{
		// do whatever you need to do and/or send here
	}
}
// usage
var publicador = new Publicador();
var suscriptor = new Suscriptor();
suscriptor.Suscribirse(publicador);

Read More

C# Delegates

Un delegado es un placeholder para un método. Permite pasar una función como parámetro a un método.

Hay varios tipos de delegado:

  • Action<T> consume una clase, devuelve void Ejemplo Console.WriteLine();
  • Predicate<T> consume una clase, devuelve bool Por ejemplo para abstraer condiciones
  • Func<T, K> consume una clase y devuelve otra. Por ejemplo para abstraer mappings

Usaremos el struct Book para todos los ejemplos

public struct Book
{
	public string Title;        // Title of the book.
	public string Author;       // Author of the book.
	public decimal Price;       // Price of the book.
	public bool Paperback;      // Is it paperback?

	public Book(string title, string author, decimal price, bool paperBack)
	{
		Title = title;
		Author = author;
		Price = price;
		Paperback = paperBack;
	}
}

Action (Consumer)

Tenemos el ejemplo BookDBActionService

public class BookDBActionService
{
	// List of all books in the database
	List<Book> list = new List<Book>();

	// initialize test data on constructor
	public BookDBActionService()
	{
		list.Add(new Book("title1", "author1", 10, true));
		list.Add(new Book("title2", "author2", 20, false));
	}

	// Aqui tenemos el Action<Book> donde delegamos como se procesa cada libro
	public void ProcessPaperbackBooks(Action<Book> processBook)
	{
		foreach (Book b in list)
		{
			if (b.Paperback)
			{
				// delegate call
				processBook(b);
			}
		}
	}
}

Llamada donde ejecutamos el código y llamamos al Action<Book>

public static void Main(string[] args)
{
var bookDBAction = new BookDBActionService();
bookDBAction.ProcessPaperbackBooks(book => Console.WriteLine(book.Title));
}

Read More

C# Async ops

El nucleo de la programacion asincrona son los objetos Task y Task<T>. Son compatibles con las palabras clave async y await.

Primero hay que reconocer si el codigo se usa para trabajos enlazados a I/O o si son CPU intensivos.

  • Si el codigo espera algo como una BBDD o una response de un servidor, es codigo I/O. En este caso hay que usar async y await
  • Si el codigo realiza un calculo costoso, es CPU intensivo. Use await para esperar una operacion que se ha comenzado en background con Task.run

Async / Await (Operaciones I/O)

La palabra clave importante aqui es await. Lo que hace es suspender la ejecucion del metodo actual y devolver el control hasta que está lista para seguir.

public async Task Main()
{
	string contenido = await LeerPaginaWebAsync("http://example.com");
}

private async Task<string> LeerPaginaWebAsync(string url)
{
	using (HttpClient client = new HttpClient())
	{
		return await client.GetStringAsync(url);
	}
}

Read More

C# Async await best practices

Don’t use async void

An async method may return Task, Task<T> and void. Natural return types are all but void.

Any sync method returning void becomes an async method returning Task. example:

// synchronous work
void MyMethod()
{
	Thread.sleep(1000);
}

// asynchronous work
async Task MyAsyncMethod()
{
	await Task.Delay(1000);
}

When an exception is thrown out of an async Task or async Task<T> method that exception is captured and placed on the Task object. For async void methods, exceptions aren’t caught.

Read More

Visual Studio (Code)

Shortcuts

  • prop - creates a new property for a class
  • ctor - creates a new constructor
  • cw - creates a new Console.WriteLine() statement
  • try - creates a try-catch statement

To create a new property, type prop, hit twice tab and it creates a property template which you can navegate and override

vstudio 2

Debug in VsCode

Watch a variable

En la pestaña watch se puede introducir el nombre de una variable y al hacer debug mostrará siempre el valor de esta variable.

vstudio-4

Read More

Linq examples

Retrieve a simple subset of properties for all items in list

Usually, anon data types are used in the select clause to return a specific subset of properties for each object in the collection.

we have the employee class

public class Employee
{
	public int ID { get; set; }
	public string Name { get; set; }
	public int Age { get; set; }
	public string Address { get; set; }
}
List<Employee> employees = // whatever ...
// we convert an Employee into an anon object type with a subset of properties
var employeeDetails = from emp in employees
	select new { Id = emp.ID, Name = emp.Name };

How to map List of classes

// Method to show call usage. 
public List<MappedUser> MapListOfUsers(List<User> users)
{
	// option 1
	List<MappedUser> mappedUsers = users.Select(user => MapSingleUser(user))
		.ToList();
	
	// option 2
	List<MappedUser> mappedUsers2 = 
		(from user in users select MapSingleUser(user)).ToList();
}

method to encapsulate mapping itself

private MappedUser MapSingleUser(User user)
{
 var mapped = new MappedUser
 {
	 Id = user.Id,
	 Name = user.Name,
	 Email = user.Email
 };
 return mapped;
}

This provides easier and more legible than doing a foreach to iterate everything.

How to filter list per properties (Where)

var adminUserTask = users
	.AsParallel()
	.Where(user => "admin".Equals(user.type.ToLower()))
	.Select(async user => { return await ProcessAdmin(user);});
List<UserResults> results = (await Task.WhenAll(adminUserTask)).ToList();

How to select records based on another list (ids)

This is how to select a list of items, selecting them by id, based on another list of items

List<string> idList = // ...
var profiles = _context.UserProfiles
		.Where(userProf => idList.Contains(userProf.Id));

How to order based on a dynamic parameter

// Direction is an Enum w. values ASC or DESC
private List<Person> SortPersons(Direction direction, List<Person> persons, Func<Person, string> sortBy)
{
	if(direction.DESC)
	{
		return persons.OrderByDescending(sortBy.Invoke).ToList();
	} else 
	{
		return persons.OrderBy(sortBy.Invoke).ToList();
	}
}

How to use it

var sortedPersons = SortPersons(direction, persons, person => person.Name);

How to use in async await env

We separate the linq query into Task and Execution. This executes this Task concurrently.

Single param lambda

remember that for lambdas with a single param where it comes from the same query, you don’t need to explicitely set it

this transforms

public List<int> FilterList(List<int> listToFilter, List<int> filterintList)
{
	return listToFilter.Where(number => filteringList.Contains(number)).ToList();
}

How to filter list per properties (Where)

filter by properties in a nullable list and return true if there’s any row that match. If the list is null, it returns false.

return response.results?.rows
	.Where(row => row.id == requestId && (row.owner == requestOwner || row.responsible == requestResponsible))
	.Any() ?? false;

another example

var task = response.results.rows
	.AsParallel()
	.Where(row => "specifictype".Equals(row.type.ToLower()))
	.Select(async row => {
		if(row.type.Equals("specificType"))
		{
			return await Something(row, id, log);
		} else 
		{
			return row;
		}
	});

Methods worth a mention

Remove duplicates Distinct()

var task = response.results.rows
	.AsParallel()
	.Where(row => "specificType".Equals(row.type.ToLower()))
	.Select(async row => { return await Something(row, id, log);});

Get the difference of two lists Except()

var distinctList = listToFilter
	.Except(filteringList)
	.ToList();

Read More