Memòria compartida entre processos

Problema:

  • Es requereix afegir una interconnexió amb una aplicació que els seus mètodes públics estan en un format antic, en aquest cas, ActiveX.
  • Aquests controls són exclusivament en 32-bits.
  • La aplicació que els ha de consumir és multi-plataforma i no pot ser condicionada per connectar-se amb aquesta aplicació, el qual és accessòria.

Possibles solucions d’arquitectura:

  • Crear diferents compilacions (no desitjable, complica el codi i obliga a publicar-ne diferents versions)
  • Crear una aplicació en servei del sistema operatiu (malauradament en aquest cas queda descartat ja que el control de ActiveX ens obliga a tenir accés al System.Windows.Forms)
  • Crear una aplicació instanciada des la aplicació principal

Al final he triat la última solució a la qual ens trobem doncs que la intercomunicació entre els processos la podem fer amb diferents mètodes12:

  • Utilitzar un fitxer d’entrada i un altre de sortida entre les aplicacions: potser un mètode eficaç i ràpid, fàcil de transmetre a través de parametrització i lectura de sortida estàndard.
  • Pipes/Canonades(anònims i anomenats)34: ens obligaria a establir un protocol degut a les poques dimensions dels missatges capaços de ser retransmesos per canonades/pipes.
  • Sockets (a través de WCF o Remoting5): complica el codi i ens obliga a establir protocol de funcionament.
  • Per la consola: és el mètode més a pic i pala però el que podem garantir una prova de concepte. El problema és que a major quantitat de dades més lent es torna, mètode lent ja de per si.
  • Memòria compartida67: aquesta es pot fer a través de fitxers mapejats en memòria, el qual també ens facilita la interconnexió i a més a més amb mutex podem establir un nivell de seguretat bastant alta de orde de processament.

La transmissió de dades es pot fer per classes (després fer marshalling) o per serialització (tant JSON com XML). He triat JSON perquè és la que menys ocuparà i en part, perquè si es fan registres d’entrada i sortida ja disposem d’eines per llegir-los i analitzar-los.

Un punt clau són els mutex. Encara que l’ordre de execució dels processos és seqüencial, això ens donarà possibilitat de que evitar que es llegeixin posicions abans de que s’hagin acabat de escriure.

Tant els fitxers com els pipes serà essencial què siguin creats per la aplicació principal: això ens donarà l’avantatge de controlar quan la memòria ha de ser creada i netejada.

La crida a la aplicació que contindrà els accessos a ActiveX es fa mitjançant System.Diagnostics8 aquesta API ens permet a través de StartInfo de aportar paràmetres a la aplicació (propietat arguments), com redirigir el input i output estàndard (propietat StandardOutput.ReadToEnd() per a obtenir el string de sortida).

Codi:

  1. https://stackoverflow.com/a/65731962/2219577 ↩︎
  2. https://stackoverflow.com/a/14140726/2219577 ↩︎
  3. https://learn.microsoft.com/en-us/dotnet/standard/io/pipe-operations ↩︎
  4. https://learn.microsoft.com/en-us/dotnet/api/system.io.pipes.anonymouspipeserverstream ↩︎
  5. https://learn.microsoft.com/en-us/dotnet/api/system.runtime.remoting.channels.ipc.ipcchannel ↩︎
  6. https://learn.microsoft.com/en-us/dotnet/standard/io/memory-mapped-files ↩︎
  7. https://learn.microsoft.com/en-us/dotnet/api/system.io.memorymappedfiles.memorymappedfile.createnew ↩︎
  8. https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.process ↩︎

Refresh token in a NSwag C# Client

I use NSwag also to generate the API Clients in VS (using the VS extension REST API Code Generator for VS).

My approach was to override SendAsync using DelegatingHandler. In this handle is possible to catch the response of SendAsync and then manage to refresh the token. I found a kind of implementation in the docs, but in this answer you can find the source of my approach to implement the handle:

I used a global/static variable to store the refresh tokens and other authentication data required.

In my case I had no chance to use dependency injection (DI) as the answer I linked before. Then, before using the service, I create a HttpClient and I assign the CustomDelegatingHandler to this HttpClient.

Primers passos de NET6, C# i Linux

Crides a llibreries

Les crides fins ara es feien des PInvoke a la llibreria de ghostscript de windows. Amb linux no farà falta en si descarregar-afegir la llibreria. També el PInvoke amb linux hi ha unes particularitats 1.

Directoris

Els directoris també canvien. Per a tenir una generació de noms de directoris neta sense directoris a mà, hem de revisar les carpetes especials que fem ús a la API de Path de NET2

Llibreries d’imatges

El fet de no comptar amb System.Drawing dificulta molts dels procesaments de imatge dels que es feia us d’aquesta llibreria de sistema. Cal utilitzar alternatives com Imagesharp o Skiasharp3

Dependències terceres

L’entorn és amb docker/debian per a poder fer el PInvoke a Ghostscript correctament cal instal·lar totes les llibreries següents des el dockerfile:

RUN apt update -y && apt install -y -qq ghostscript && apt install -y -qq libgs9 && apt install -y -qq libgs9-common && apt install -y -qq libgs-dev

  1. https://developers.redhat.com/blog/2016/09/14/pinvoke-in-net-core-rhel ↩︎
  2. https://developers.redhat.com/blog/2018/11/07/dotnet-special-folder-api-linux ↩︎
  3. https://devblogs.microsoft.com/dotnet/net-core-image-processing/ ↩︎

Entity Framework Core i transaccions

Punts claus que cal tenir en compte abans de començar amb las transaccions amb EFCore

Hi ha alguna política activa de reintents (EnableRetryOnFailure):

  • En transaccions estaràs obligat a llançar-les com estratègies d’execució 1
  • Aquestes estratègies estan lligades a la base de dades i al seu proveïdor 2

Tinc MARS (Mutiple Active Results Sets) actius:

  • En transaccions no podràs fer servir punts de retorn (CreateSavePoint, Rollback to SavePoint) 3
  • Per això caldrà reduir els blocs que es fan canvis i evitar les indeterminacions que es poden vaure al fer SaveChanges sobre punts de retorn

  1. https://learn.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency#execution-strategies-and-transactions ↩︎
  2. https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.executionstrategyextensions.execute?view=efcore-7.0#microsoft-entityframeworkcore-executionstrategyextensions-execute(microsoft-entityframeworkcore-storage-iexecutionstrategy-system-action) ↩︎
  3. https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.executionstrategyextensions.execute?view=efcore-7.0#microsoft-entityframeworkcore-executionstrategyextensions-execute(microsoft-entityframeworkcore-storage-iexecutionstrategy-system-action) ↩︎

C# i async

Poques ganes:

bool method(){
   var result = classasync.method().Result;
   return result;
}

Venga va, una oportunitat:

async bool method(){
   var result = await classasync.method();
   return result;
}

Però es que no vull fer-lo asíncron:

bool method(){
   var resultTask = Task.Run(async () => await classasync.method());
   resultTask.Wait();
   return resultTask.Result;
}

Va, donem-li una oportunitat a l’asíncron:

async bool method(){
   var resultTask = Task.Run(async () => await classasync.method());
   resultTask.WaitAsync();
   return resultTask.Result;
}

Ajuda: https://ianvink.wordpress.com/2021/12/12/c-running-an-async-await-task-inside-a-non-async-method-code-block/