asp.net - tutorial - build an asp net app in azure with sql database




DI in Funzioni di Azure (6)

AzureFunctions.Autofac è molto facile da usare.

Basta aggiungere un file di configurazione:

public class DIConfig
{
    public DIConfig(string functionName)
    {
        DependencyInjection.Initialize(builder =>
        {
            builder.RegisterType<Sample>().As<ISample>();
            ...
        }, functionName);
    }
}

Aggiungere l'attributo DependencyInjectionConfig quindi iniettare:

[DependencyInjectionConfig(typeof(DIConfig))]
public class MyFunction
{
    [FunctionName("MyFunction")]
    public static HttpResponseMessage Run([HttpTrigger(AuthorizationLevel.Function, "get", Route = null)]HttpRequestMessage request, 
                                          TraceWriter log, 
                                          [Inject]ISample sample)
    {

https://github.com/introtocomputerscience/azure-function-autofac-dependency-injection

Ho alcune librerie di classi che uso nella mia app API Web ASP.NET che gestiscono tutte le mie operazioni di back-end, ad esempio le operazioni CRUD su più database come database SQL di Azure, DB Cosmos, ecc.

Non voglio re-inventare la ruota e riuscire ad usarli in una nuova funzione di Azure che sto creando in Visual Studio 2017. Tutti i miei metodi di repository utilizzano un'interfaccia. Quindi, come implementerò l'integrazione delle dipendenze nella mia nuova funzione di Azure?

Non vedo alcun supporto per DI ma sono un po 'confuso. Sembra che le funzioni di Azure siano basate sullo stesso SDK di WebJobs e penso che l'anno scorso Microsoft abbia iniziato a supportare DI in WebJobs, lo so per certo perché l'ho implementato usando Ninject.

Esiste un modo per utilizzare le mie librerie esistenti nel mio nuovo progetto di Azure Functions?


C'è una richiesta di funzione aperta sulle pagine di GitHub per le funzioni di Azure relative a questo argomento.

Tuttavia, il modo in cui mi sto avvicinando a questo sta usando un qualche tipo di entry point 'wrapper', risolvolo usando il localizzatore di servizi e avviando la funzione da lì.

Questo sembra un po 'come questo (semplificato)

var builder = new ContainerBuilder();
//register my types

var container = builder.Build();

using(var scope = container.BeginLifetimeScope())
{
  var functionLogic = scope.Resolve<IMyFunctionLogic>();

  functionLogic.Execute();
}

Questo è un po 'hacky, ovviamente, ma è il meglio che ci sia fino a quando non ci sia al momento (per quanto ne so).


Ho visto il blog di zona willie menzionato molto quando si tratta di questo argomento, ma non è necessario seguire questa strada per usare DI con le funzioni di Azure.

Se si utilizza Version2, è possibile rendere le funzioni di Azure non statiche. Quindi puoi aggiungere un costruttore pubblico per l'iniezione delle tue dipendenze. Il prossimo passo è aggiungere una classe IWebJobsStartup. Nella tua classe di avvio sarai in grado di registrare i tuoi servizi come faresti per qualsiasi altro progetto .Net Core.

Ho un repository pubblico che sta usando questo approccio qui: https://github.com/jedi91/MovieSearch/tree/master/MovieSearch

Ecco un link diretto alla classe di avvio: https://github.com/jedi91/MovieSearch/blob/master/MovieSearch/Startup.cs

Ed ecco la funzione: https://github.com/jedi91/MovieSearch/blob/master/MovieSearch/Functions/Search.cs

Spero che questo approccio aiuti. Se si desidera mantenere le funzioni di Azure statiche, l'approccio willie-zone dovrebbe funzionare, ma mi piace molto questo approccio e non richiede alcuna libreria di terze parti.

Una cosa da notare è il file Directory.Build.target. Questo file copierà le estensioni nel file host in modo che DI funzioni quando la funzione viene distribuita in Azure. L'esecuzione locale della funzione non richiede questo file.


In realtà c'è un modo molto più semplice e semplice fornito fuori dalla scatola da Microsoft. È un po 'difficile da trovare però. È sufficiente creare una classe di avvio e aggiungere qui tutti i servizi richiesti, quindi è possibile utilizzare l'iniezione del costruttore come nelle normali applicazioni Web e web apis.

Questo è tutto ciò che devi fare.

Per prima cosa creo la mia classe di avvio, che chiamo la mia Startup.cs per essere coerente con le app Razor, anche se questo è per le funzioni di Azure, ma è ancora il modo Microsoft.

using System;
using com.paypal;
using dk.commentor.bl.command;
using dk.commentor.logger;
using dk.commentor.sl;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using org.openerp;

[assembly:Microsoft.Azure.WebJobs.Hosting.WebJobsStartup(typeof(dk.commentor.starterproject.api.Startup))]
namespace dk.commentor.starterproject.api
{

    public class Startup : IWebJobsStartup
    {

        public void Configure(IWebJobsBuilder builder)
        {
            builder.Services.AddSingleton<ILogger, CommentorLogger>();
            builder.Services.AddSingleton<IPaymentService, PayPalService>();
            builder.Services.AddSingleton<IOrderService, OpenERPService>();
            builder.Services.AddSingleton<ProcessOrderCommand>();
            Console.WriteLine("Host started!");
        }
    }
}

Successivamente cambio la chiamata del metodo nella funzione da statica a non statica e aggiungo un costruttore alla classe (che ora è anche non statica). In questo costruttore aggiungo semplicemente i servizi che richiedo come parametri del costruttore.

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using dk.commentor.bl.command;

namespace dk.commentor.starterproject.api
{
    public class ProcessOrder
    {
        private ProcessOrderCommand processOrderCommand;

        public ProcessOrder(ProcessOrderCommand processOrderCommand) {
            this.processOrderCommand = processOrderCommand;
        }

        [FunctionName("ProcessOrder")]
        public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, ILogger log)
        {
            log.LogInformation("C# HTTP trigger ProcessOrder called!");
            log.LogInformation(System.Environment.StackTrace);

            string jsonRequestData = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic requestData = JsonConvert.DeserializeObject(jsonRequestData);

            if(requestData?.orderId != null)
                return (ActionResult)new OkObjectResult($"Processing order with id {requestData.orderId}");
            else
                return new BadRequestObjectResult("Please pass an orderId in the request body");
        }
    }
}

Spero che questo aiuti.



Vorrei aggiungere i miei 2 centesimi. Ho usato la tecnica che è usata da Host per iniettare ILogger. Se guardi il progetto Startup ho creato GenericBindingProvider che implementa IBindingProvider. Quindi per ogni tipo che voglio essere iniettato lo registro come segue:

builder.Services.AddTransient<IWelcomeService, WelcomeService>();
builder.Services.AddSingleton<IBindingProvider, GenericBindingProvider<IWelcomeService>>();

Lo svantaggio è che è necessario registrare il tipo che si desidera iniettare nella funzione due volte.

Codice di esempio:

Esempio di iniezione delle dipendenze V2 delle funzioni di Azure





azure-functions