Claude Code Plugins

Community-maintained marketplace

Feedback

dependency-injection

@christian289/wpf-tutorials
0
0

Microsoft.Extensions.DependencyInjection과 GenericHost를 사용한 의존성 주입 패턴

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name dependency-injection
description Microsoft.Extensions.DependencyInjection과 GenericHost를 사용한 의존성 주입 패턴

Dependency Injection 및 GenericHost 사용

.NET 프로젝트에서 Dependency Injection과 GenericHost를 사용하는 방법에 대한 가이드입니다.

핵심 원칙

  • Microsoft.Extensions.DependencyInjection을 사용하여 의존성 주입 구현
  • GenericHost (Microsoft.Extensions.Hosting)를 기본으로 사용
  • Constructor Injection을 통한 서비스 주입 방식 적용

Console 및 일반 프로젝트 - Program.cs

// Program.cs
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

// GenericHost를 사용한 DI 설정
// Configure DI using GenericHost
var host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((context, services) =>
    {
        // 서비스 등록
        // Register services
        services.AddSingleton<IUserRepository, UserRepository>();
        services.AddScoped<IUserService, UserService>();
        services.AddTransient<IEmailService, EmailService>();

        // 메인 애플리케이션 서비스 등록
        // Register main application service
        services.AddSingleton<App>();
    })
    .Build();

// ServiceProvider를 통해 서비스 가져오기
// Get service through ServiceProvider
var app = host.Services.GetRequiredService<App>();
await app.RunAsync();

// 애플리케이션 클래스 - Constructor Injection
// Application class - Constructor Injection
public sealed class App(IUserService userService, IEmailService emailService)
{
    private readonly IUserService _userService = userService;
    private readonly IEmailService _emailService = emailService;

    public async Task RunAsync()
    {
        // 주입된 서비스 사용
        // Use injected services
        var users = await _userService.GetAllUsersAsync();

        foreach (var user in users)
        {
            await _emailService.SendWelcomeEmailAsync(user.Email);
        }
    }
}

WPF 프로젝트 - App.xaml.cs

// App.xaml.cs
namespace MyApp;

using System.Windows;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

public partial class App : Application
{
    private readonly IHost _host;

    public App()
    {
        // GenericHost 생성 및 서비스 등록
        // Create GenericHost and register services
        _host = Host.CreateDefaultBuilder()
            .ConfigureServices((context, services) =>
            {
                // Services 등록
                // Register services
                services.AddSingleton<IUserRepository, UserRepository>();
                services.AddSingleton<IUserService, UserService>();
                services.AddTransient<IDialogService, DialogService>();

                // ViewModels 등록
                // Register ViewModels
                services.AddTransient<MainViewModel>();
                services.AddTransient<SettingsViewModel>();

                // Views 등록
                // Register Views
                services.AddSingleton<MainWindow>();
            })
            .Build();
    }

    protected override async void OnStartup(StartupEventArgs e)
    {
        await _host.StartAsync();

        // MainWindow를 ServiceProvider로부터 가져오기
        // Get MainWindow from ServiceProvider
        var mainWindow = _host.Services.GetRequiredService<MainWindow>();
        mainWindow.Show();

        base.OnStartup(e);
    }

    protected override async void OnExit(ExitEventArgs e)
    {
        using (_host)
        {
            await _host.StopAsync();
        }

        base.OnExit(e);
    }
}

MainWindow.xaml.cs - Constructor Injection

// MainWindow.xaml.cs
namespace MyApp;

using System.Windows;

public partial class MainWindow : Window
{
    // Constructor Injection을 통한 ViewModel 주입
    // ViewModel injection through Constructor Injection
    public MainWindow(MainViewModel viewModel)
    {
        InitializeComponent();
        DataContext = viewModel;
    }
}

ViewModel - Constructor Injection

// ViewModels/MainViewModel.cs
namespace MyApp.ViewModels;

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;

public sealed partial class MainViewModel : ObservableObject
{
    private readonly IUserService _userService;
    private readonly IDialogService _dialogService;

    // Constructor Injection
    public MainViewModel(IUserService userService, IDialogService dialogService)
    {
        _userService = userService;
        _dialogService = dialogService;

        LoadDataAsync();
    }

    [ObservableProperty]
    private ObservableCollection<User> users = [];

    [RelayCommand]
    private async Task LoadDataAsync()
    {
        try
        {
            var userList = await _userService.GetAllUsersAsync();
            Users = new ObservableCollection<User>(userList);
        }
        catch (Exception ex)
        {
            await _dialogService.ShowErrorAsync("오류 발생", ex.Message);
            // Error occurred
        }
    }
}

서비스 Lifetime 규칙

Singleton

애플리케이션 전체에서 하나의 인스턴스만 생성

  • Repository, 전역 상태 관리 서비스
  • services.AddSingleton<IUserRepository, UserRepository>()

Scoped

요청(Scope)당 하나의 인스턴스 생성

  • DbContext, 트랜잭션 단위 서비스
  • services.AddScoped<IUserService, UserService>()
  • ⚠️ WPF에서는 일반적으로 사용하지 않음 (Web 애플리케이션에서 주로 사용)

Transient

요청할 때마다 새 인스턴스 생성

  • ViewModel, 일회성 서비스
  • services.AddTransient<MainViewModel>()

ServiceProvider 직접 사용 (권장하지 않음)

안티패턴: Service Locator

// Service Locator 패턴 (안티패턴)
// Service Locator pattern (anti-pattern)
public sealed class SomeClass
{
    private readonly IServiceProvider _serviceProvider;

    public SomeClass(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public void DoSomething()
    {
        // ⚠️ 권장하지 않음: ServiceProvider를 직접 사용
        // Not recommended: Using ServiceProvider directly
        var service = _serviceProvider.GetRequiredService<IUserService>();
    }
}

권장: Constructor Injection

// 올바른 방법: Constructor Injection 사용
// Correct way: Use Constructor Injection
public sealed class SomeClass
{
    private readonly IUserService _userService;

    public SomeClass(IUserService userService)
    {
        _userService = userService;
    }

    public void DoSomething()
    {
        // ✅ 권장: Constructor Injection으로 주입받은 서비스 사용
        // Recommended: Use service injected through Constructor Injection
        _userService.GetAllUsersAsync();
    }
}

필수 NuGet 패키지

<ItemGroup>
  <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
  <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
</ItemGroup>