Azure 기능의 DI
ASP에서 사용하는 클래스 라이브러리가 몇 개 있습니다.Azure SQL Database, Cosmos DB 등의 여러 데이터베이스에 대한 CRUD 작업 등 모든 백엔드 작업을 처리하는 NET Web API 앱
Visual Studio 2017에서 만들고 있는 새로운 Azure Functions에서 휠을 재발명하여 사용할 수 있는 것은 아닙니다.모든 저장소 메서드는 인터페이스를 사용합니다.그렇다면 새로운 Azure 기능에 의존성 주입을 어떻게 구현해야 할까요?
DI에 대한 지원은 보이지 않지만 조금 혼란스럽습니다.Azure Functions는 WebJobs와 같은 SDK를 기반으로 하고 있는 것 같습니다.Microsoft는 작년에 WebJobs에서 DI를 지원하기 시작했다고 생각합니다.Ninject를 사용하여 구현했기 때문에 확실히 알고 있습니다.
새로운 Azure Functions 프로젝트에서 기존 라이브러리를 사용할 수 있는 방법이 있습니까?
서비스 로케이터(안티) 패턴에 덧붙여, 이러한 2개의 테크닉이 표시됩니다.Azure Functions 팀에도 코멘트를 부탁했습니다.
https://blog.wille-zone.de/post/azure-functions-dependency-injection/
https://blog.wille-zone.de/post/azure-functions-proper-dependency-injection/
Azure Functions의 GitHub 페이지에 이 건에 관한 오픈 기능 요청이 있습니다.
그러나 제가 접근하려는 방법은 일종의 '랩퍼' 진입점을 사용하는 것입니다. 서비스 로케이터를 사용하여 이 문제를 해결하고 거기서부터 기능을 시작합니다.
이것은 약간 이와 같습니다(간소화).
var builder = new ContainerBuilder();
//register my types
var container = builder.Build();
using(var scope = container.BeginLifetimeScope())
{
var functionLogic = scope.Resolve<IMyFunctionLogic>();
functionLogic.Execute();
}
이것은 물론 좀 진부하지만, 내가 아는 바로는 그것이 최선이다.
willi-zone 블로그에서 이 토픽에 대해 많이 언급하고 있습니다만, Azure 기능과 함께 DI를 사용하기 위해 그 루트를 사용할 필요는 없습니다.
버전 2 를 사용하고 있는 경우는, Azure 기능을 정적으로 할 수 있습니다.그런 다음 종속성을 주입하는 공용 생성자를 추가할 수 있습니다.다음 단계에서는 IWebJobsStartup 클래스를 추가합니다.스타트업 클래스에서는 다른 클래스와 마찬가지로 서비스를 등록할 수 있습니다.넷코어 프로젝트
여기에서는, 다음의 어프로치를 채용하고 있는 퍼블릭 리포트가 있습니다.https://github.com/jedi91/MovieSearch/tree/master/MovieSearch
다음은 스타트업 클래스에 대한 직접 링크입니다.https://github.com/jedi91/MovieSearch/blob/master/MovieSearch/Startup.cs
다음은 https://github.com/jedi91/MovieSearch/blob/master/MovieSearch/Functions/Search.cs의 기능입니다.
이 접근방식이 도움이 되길 바랍니다.Azure 함수를 정적인 상태로 유지하고 싶다면 willi-zone 접근법이 효과적일 것입니다만, 저는 이 접근법이 매우 마음에 들어 서드파티 라이브러리가 필요 없습니다.
한 가지 주의할 점은 디렉토리입니다.Build.target 파일.이 파일은 호스트 파일에 확장자를 복사하여 함수를 Azure에 배포한 후 DI가 작동하도록 합니다.함수를 로컬로 실행할 때는 이 파일이 필요하지 않습니다.
Azure Functions Dependency Injection은 MSBuild 2019에서 발표되었습니다.다음은 그 방법의 예입니다.
[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]
namespace MyNamespace
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddHttpClient();
builder.Services.AddSingleton((s) => {
return new CosmosClient(Environment.GetEnvironmentVariable("COSMOSDB_CONNECTIONSTRING"));
});
builder.Services.AddSingleton<ILoggerProvider, MyLoggerProvider>();
}
}
}
위와 같이 방금 Build 2019에서 발표되었습니다.ASP와 거의 동일하게 셋업할 수 있게 되었습니다.넷코어 앱
실제로 마이크로소프트가 바로 사용할 수 있는 훨씬 더 좋고 간단한 방법이 있습니다.찾기가 좀 어렵긴 한데.스타트업 클래스를 만들고 필요한 모든 서비스를 여기에 추가하면 일반 웹 앱이나 웹 아피스와 같이 컨스트럭터 주입을 사용할 수 있습니다.
이것만 하면 돼요.
처음에 스타트업 클래스를 만들 때는 Razor 웹 앱과 일관성을 유지하기 위해 Startup.cs이라고 불렀습니다.이것은 Azure Functions용이지만, 여전히 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!");
}
}
}
다음으로 함수의 메서드 호출을 스태틱에서 비 스태틱으로 변경하고 클래스에 컨스트럭터를 추가합니다(이것도 비 스태틱입니다).이 컨스트럭터에서는 필요한 서비스를 컨스트럭터 파라미터로 추가합니다.
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");
}
}
}
도움이 됐으면 좋겠다.
여기에 제 2센트를 더하고 싶습니다.호스트가 ILogger를 주입할 때 사용하는 기술을 사용했습니다.스타트업 프로젝트를 보시면 IBinding Provider를 구현하는 Generic Binding Provider를 만들었습니다.그런 다음 주입을 원하는 유형별로 다음과 같이 등록합니다.
builder.Services.AddTransient<IWelcomeService, WelcomeService>();
builder.Services.AddSingleton<IBindingProvider, GenericBindingProvider<IWelcomeService>>();
단점은 함수에 삽입할 유형을 두 번 등록해야 한다는 것입니다.
샘플 코드:
Simple을 사용하고 있습니다.Azure Functions(Azure 기능)에서 인젝터가 완벽하게 미세합니다.등록이 있는 클래스(IoCConfig라고 부릅니다)를 만들고 각 인스턴스가 기존 인스턴스를 사용하도록 함수 클래스에 해당 클래스의 정적 인스턴스를 만듭니다.
public interface IIoCConfig
{
T GetInstance<T>() where T : class;
}
public class IoCConfig : IIoCConfig
{
internal Container Container;
public IoCConfig(ExecutionContext executionContext, ILogger logger)
{
var configurationRoot = new ConfigurationBuilder()
.SetBasePath(executionContext.FunctionAppDirectory)
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
Container = new Container();
Configure(configurationRoot, logger);
}
public IoCConfig(IConfigurationRoot configurationRoot, ILogger logger)
{
Container = new Container();
Configure(configurationRoot, logger);
}
private void Configure(IConfigurationRoot configurationRoot, ILogger logger)
{
Container.RegisterInstance(typeof(IConfigurationRoot), configurationRoot);
Container.Register<ISomeType, SomeType>();
}
public T GetInstance<T>() where T : class
{
return Container.GetInstance<T>();
}
}
그 후 루트:
public static class SomeFunction
{
public static IIoCConfig IoCConfig;
[FunctionName("SomeFunction")]
public static async Task Run(
[ServiceBusTrigger("some-topic", "%SUBSCRIPTION_NAME%", Connection = "AZURE_SERVICEBUS_CONNECTIONSTRING")]
SomeEvent msg,
ILogger log,
ExecutionContext executionContext)
{
Ensure.That(msg).IsNotNull();
if (IoCConfig == null)
{
IoCConfig = new IoCConfig(executionContext, log);
}
var someType = IoCConfig.GetInstance<ISomeType>();
await someType.Handle(msg);
}
}
Azure Functions (Azure Functions)오토팩은 매우 사용하기 쉽다.
구성 파일을 추가합니다.
public class DIConfig
{
public DIConfig(string functionName)
{
DependencyInjection.Initialize(builder =>
{
builder.RegisterType<Sample>().As<ISample>();
...
}, functionName);
}
}
의존 관계 추가Injection Config Atribute를 다음에 injection합니다.
[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
저는 이것이 더 나은 해결책이라고 생각합니다.
https://github.com/junalmeida/autofac-azurefunctions https://www.nuget.org/packages/Autofac.Extensions.DependencyInjection.AzureFunctions
프로젝트에 NuGet을 설치한 후 Startup.cs을 만들고 다음 내용을 추가합니다.
[assembly: FunctionsStartup(typeof(Startup))]
public class Startup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder
.UseAppSettings() // this is optional, this will bind IConfiguration in the container.
.UseAutofacServiceProviderFactory(ConfigureContainer);
}
private void ConfigureContainer(ContainerBuilder builder)
{
// do DI registration against Autofac like normal! (builder is just the normal ContainerBuilder from Autofac)
}
...
그런 다음 함수 코드에서 DI를 통해 일반 생성자 주입을 수행할 수 있습니다.
public class Function1 : Disposable
{
public Function1(IService1 service1, ILogger logger)
{
// logger and service1 injected via autofac like normal
// ...
}
[FunctionName(nameof(Function1))]
public async Task Run([QueueTrigger("myqueue-items", Connection = "AzureWebJobsStorage")]string myQueueItem)
{
//...
종속성 주입 지원은 Azure Functions 2.x부터 시작됩니다. 즉, 이제 종속성 주입은 Azure 함수를 활용할 수 있습니다.NET 코어 의존성 주입 기능.
종속성 주입을 사용하려면 먼저 다음 NuGet 패키지를 설치해야 합니다.
- 마이크로소프트(MS.애저, 기능.내선번호
- 마이크로소프트(MS.NET.Sdk기능들
의존성 주입을 사용하면 DBContext, Http 클라이언트 사용률(Httpclienfactory), Ilogger factory, 캐시 지원 등이 쉬워집니다.
먼저 아래와 같이 스타트업 클래스를 업데이트합니다.
namespace DemoApp
{
public class Startup: FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddScoped<IHelloWorld, HelloWorld>();
// Registering Serilog provider
var logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
builder.Services.AddLogging(lb => lb.AddSerilog(logger));
//Reading configuration section can be added here etc.
}
}
}
둘째, 함수 클래스 및 메서드레벨에서의 Static 키워드 삭제
public class DemoFunction
{
private readonly IHelloWorld _helloWorld;
public DemoFunction(IHelloWorld helloWorld)
{
_helloWorld = helloWorld;
}
[FunctionName("HttpDemoFunction")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
}
예를 들어 위의 내용을 살펴보면IHello World는 를 사용하여 주입됩니다.NET 코어 DI
**주의:**의존성 주입용 Azure 함수 v3의 최신 버전을 사용하여 몇 가지 절차를 수행할 수 있도록 하는 것은 위와 같이 수동입니다.
github의 샘플 코드는 여기에서 찾을 수 있습니다.
언급URL : https://stackoverflow.com/questions/45912224/di-in-azure-functions
'prosource' 카테고리의 다른 글
KVO(Key-Value Observation)는 Swift에서 사용할 수 있습니까? (0) | 2023.04.23 |
---|---|
로컬 변경 내용이 병합에 의해 덮어쓰기된다는 'git pull' 오류를 무시하려면 어떻게 해야 합니까? (0) | 2023.04.23 |
노업과 앰퍼샌드의 차이점은 무엇입니까? (0) | 2023.04.23 |
현재 화면의 WPF 창 최대화 (0) | 2023.04.23 |
C# 어플리케이션의 리소스와 임베디드 자원의 차이점은 무엇입니까? (0) | 2023.04.23 |