Utilizzare .NET Framework con le Azure Function in modalità isolata

di Cristian Civera, in Azure Functions,

Le Azure Function rappresentano sulla piattaforma cloud di Microsoft l'implementazione FaaS che possiamo utilizzare per concentrarci sulle nostre logiche e dimenticarci di server e protocolli godendo al massimo della scalabilità.

Ormai giunti alla versione 4 del runtine e del modello di host, quando sviluppiamo una function di fatto stiamo usando dotnet 6 per la gestione dei trigger e dei binding, ed il nostro codice gira all'interno dello stesso processo. Questo garantisce massima velocità, perché il nostro codice si avvia insieme all'hosting stesso, ma al tempo stesso ci limita ad utilizzare le stesse librerie che l'SDK sfrutta (per esempio di serializzazione JSON) e lo stesso runtime, di conseguenza la stessa versione del linguaggio. Non possiamo quindi utilizzare dotnet 7 o dotnet 3.1 o versioni diversi di un pacchetto NuGet del quale necessitiamo. Se questo in molti casi non è un problema, perché possiamo rinunciare all'ultima versione di dotnet oppure allineare vecchio codice dotnet core alla versione più recente, non è altrettanto facile fare lo stesso se disponiamo codice scritto per il .NET Framework.

Sebbene la versione 1 di hosting sia ancora utilizzabile, oltre ad usare una versione di hosting vecchia ci ritroviamo con i vincoli sui pacchetti NuGet indicati in precedenza. Per ovviare a questo possiamo sfruttare la modalità con processo isolato, con la quale lanciare il runtime in versione 4, basato su dotnet 6, ma avviare un ulteriore processo con il runtime che vogliamo. Di fatto sviluppiamo una console app indipendente che mediante appositi pacchetti NuGet ci permette di dialogare con l'hosting delle function per gestire binding e trigger.

Per imbastire questa nuova modalità possiamo usare Visual Studio 2022 che nella creazione di una function ci permette di indicare questa nuova modalità, come mostrato in figura.

Non importa se è specificato .NET 6, perché otteniamo così un progetto con tutto il necessario. Quello che dobbiamo fare è alterare il csproj rimuovendo implicit using e il supporto ai nullable. Successivamente aggiorniamo i pacchetti NuGet all'ultima versione e cambiamo il target framework su net48, ottenendo un progetto simile al seguente.

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net48</TargetFramework>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
    <OutputType>Exe</OutputType>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.10.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.0.13" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.7.0" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
</Project>

Alteriamo inoltre Program.cs includendo anche il nome della classe e l'entry point, implicito in dotnet 6, ma non con il .NET Framework.

public class Program
{
    public static void Main()
    {
#if DEBUG
        FunctionsDebugger.Enable();
#endif

        var host = new HostBuilder()
            .ConfigureFunctionsWorkerDefaults()
            .Build();

        host.Run();
    }
}

Il codice di startup che troviamo già pronto è del tutto simile ad una applicazione ASP.NET Core, con la differenza che viene invocato ConfigureFunctionsWorkerDefaults, il quale configura e instaura il dialogo gRPC verso l'hosting e registra le dipendenze necessarie. Possiamo sfruttare lo stesso per registrare servizi o middleware (in maniera del tutto simile a ASP.NET Core).

A questo punto possiamo procedere a sviluppare la nostra function o ad aggiungerne delle altre in modo del tutto simile a quanto effettuiamo già con la modalità in process, con l'unica differenza che gli attributi stanno in un nuovo namespace Microsoft.Azure.Functions.Worker, presentando inoltre alcune limitazioni nelle possibilità.
Possiamo a questo punto compilare e avviare la function. Purtroppo, non possiamo usare direttamente Visual Studio per farlo, ma dobbiamo ricorrere alla seguente linea di comando, posizionandoci nella cartella del progetto.

func.exe host start --dotnet-isolated-debug

Questo comando avvia l'hosting e la nostra console app, mostrandoci l'id del processo lanciato.

In questo modo possiamo tornare in Visual Studio ed effettuare l'attach manuale dal menu debugging. A questo punto l'esperienza di debug è del tutto simile a quando già facciamo.
Per maggiori informazioni sulle limitazioni rimandiamo alla documentazione ufficiale https://learn.microsoft.com/en-us/azure/azure-functions/dotnet-isolated-process-guide

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi