๐Ÿš€ .NET Core์˜ ์˜์กด์„ฑ ์ฃผ์ž… ์ปจํ…Œ์ด๋„ˆ ํ™œ์šฉ

์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿš€ .NET Core์˜ ์˜์กด์„ฑ ์ฃผ์ž… ์ปจํ…Œ์ด๋„ˆ ํ™œ์šฉ

 

 

์•ˆ๋…•ํ•˜์„ธ์š”, ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ์ž ์—ฌ๋Ÿฌ๋ถ„! ์˜ค๋Š˜์€ .NET Core์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜์ธ ์˜์กด์„ฑ ์ฃผ์ž…(Dependency Injection, DI) ์ปจํ…Œ์ด๋„ˆ์— ๋Œ€ํ•ด ๊นŠ์ด ์žˆ๊ฒŒ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ๊ธ€์„ ํ†ตํ•ด ์—ฌ๋Ÿฌ๋ถ„์€ ์˜์กด์„ฑ ์ฃผ์ž…์˜ ๊ฐœ๋…๋ถ€ํ„ฐ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ์˜ ํ™œ์šฉ๊นŒ์ง€ ์ „๋ฌธ์ ์ธ ์ง€์‹์„ ์Œ“์„ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜์กด์„ฑ ์ฃผ์ž…์€ ํ˜„๋Œ€ ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ์—์„œ ํ•„์ˆ˜์ ์ธ ๋””์ž์ธ ํŒจํ„ด์œผ๋กœ, ์ฝ”๋“œ์˜ ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. .NET Core๋Š” ์ด๋Ÿฌํ•œ ์˜์กด์„ฑ ์ฃผ์ž…์„ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ง€์›ํ•˜๋ฉฐ, ๊ฐ•๋ ฅํ•œ DI ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

ย 

์ด ๊ธ€์—์„œ๋Š” .NET Core์˜ DI ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ƒ์„ธํžˆ ๋‹ค๋ฃฐ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ๊ฐœ๋…๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด ๊ณ ๊ธ‰ ๊ธฐ์ˆ ๊นŒ์ง€, ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ ๋ฐ”๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์‹ค์šฉ์ ์ธ ์ง€์‹์„ ์ œ๊ณตํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ, ์ตœ๊ทผ ํŠธ๋ Œ๋“œ์ธ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜์™€ ํด๋ผ์šฐ๋“œ ๋„ค์ดํ‹ฐ๋ธŒ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์—์„œ DI์˜ ์ค‘์š”์„ฑ์ด ๋”์šฑ ๋ถ€๊ฐ๋˜๊ณ  ์žˆ๋Š” ๋งŒํผ, ์ด์— ๋Œ€ํ•œ ๋‚ด์šฉ๋„ ํฌํ•จํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

ย 

์ž, ๊ทธ๋Ÿผ .NET Core์˜ ์˜์กด์„ฑ ์ฃผ์ž… ์„ธ๊ณ„๋กœ ํ•จ๊ป˜ ๋– ๋‚˜๋ณผ๊นŒ์š”? ๐ŸŒŸ

๐Ÿ“š ๋ชฉ์ฐจ

  1. ์˜์กด์„ฑ ์ฃผ์ž…์˜ ๊ธฐ๋ณธ ๊ฐœ๋…
  2. .NET Core DI ์ปจํ…Œ์ด๋„ˆ ์†Œ๊ฐœ
  3. ์„œ๋น„์Šค ์ˆ˜๋ช… ๊ด€๋ฆฌ
  4. ์˜์กด์„ฑ ์ฃผ์ž… ๊ตฌํ˜„ ๋ฐฉ๋ฒ•
  5. ๊ณ ๊ธ‰ DI ํ…Œํฌ๋‹‰
  6. ์„ฑ๋Šฅ ์ตœ์ ํ™”์™€ ๋ชจ๋ฒ” ์‚ฌ๋ก€
  7. ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ์˜ DI ํ™œ์šฉ
  8. ํ…Œ์ŠคํŒ…๊ณผ DI
  9. ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค์™€ DI
  10. ๊ฒฐ๋ก  ๋ฐ ํ–ฅํ›„ ์ „๋ง

1. ์˜์กด์„ฑ ์ฃผ์ž…์˜ ๊ธฐ๋ณธ ๊ฐœ๋… ๐Ÿงฉ

์˜์กด์„ฑ ์ฃผ์ž…(Dependency Injection, DI)์€ ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ์ค‘์š”ํ•œ ๋””์ž์ธ ํŒจํ„ด ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ์ด ๊ฐœ๋…์„ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์€ .NET Core์˜ DI ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ํ™œ์šฉํ•˜๋Š” ๋ฐ ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค.

1.1 ์˜์กด์„ฑ์ด๋ž€?

์˜์กด์„ฑ์€ ํ•œ ํด๋ž˜์Šค๊ฐ€ ๋‹ค๋ฅธ ํด๋ž˜์Šค์˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, OrderService ํด๋ž˜์Šค๊ฐ€ PaymentProcessor ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค๋ฉด, OrderService๋Š” PaymentProcessor์— ์˜์กดํ•œ๋‹ค๊ณ  ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ย 

์ „ํ†ต์ ์ธ ๋ฐฉ์‹์—์„œ๋Š” ์˜์กด์„ฑ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฒ˜๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค:


public class OrderService
{
    private PaymentProcessor _paymentProcessor;

    public OrderService()
    {
        _paymentProcessor = new PaymentProcessor();
    }

    public void ProcessOrder(Order order)
    {
        // ์ฃผ๋ฌธ ์ฒ˜๋ฆฌ ๋กœ์ง
        _paymentProcessor.ProcessPayment(order.TotalAmount);
    }
}

์ด ๋ฐฉ์‹์˜ ๋ฌธ์ œ์ ์€ OrderService๊ฐ€ PaymentProcessor์˜ ๊ตฌ์ฒด์ ์ธ ๊ตฌํ˜„์— ๊ฐ•ํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ์ฝ”๋“œ์˜ ์œ ์—ฐ์„ฑ์„ ๋–จ์–ด๋œจ๋ฆฌ๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

1.2 ์˜์กด์„ฑ ์ฃผ์ž…์˜ ์ •์˜

์˜์กด์„ฑ ์ฃผ์ž…์€ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ํด๋ž˜์Šค๊ฐ€ ์ž์‹ ์˜ ์˜์กด์„ฑ์„ ์ง์ ‘ ์ƒ์„ฑํ•˜๋Š” ๋Œ€์‹ , ์™ธ๋ถ€์—์„œ ์˜์กด์„ฑ์„ ์ œ๊ณต๋ฐ›์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋Š์Šจํ•œ ๊ฒฐํ•ฉ(Loose Coupling)์„ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ย 

์˜์กด์„ฑ ์ฃผ์ž…์„ ์ ์šฉํ•œ ์˜ˆ์‹œ:


public interface IPaymentProcessor
{
    void ProcessPayment(decimal amount);
}

public class OrderService
{
    private readonly IPaymentProcessor _paymentProcessor;

    public OrderService(IPaymentProcessor paymentProcessor)
    {
        _paymentProcessor = paymentProcessor;
    }

    public void ProcessOrder(Order order)
    {
        // ์ฃผ๋ฌธ ์ฒ˜๋ฆฌ ๋กœ์ง
        _paymentProcessor.ProcessPayment(order.TotalAmount);
    }
}

์ด์ œ OrderService๋Š” ๊ตฌ์ฒด์ ์ธ PaymentProcessor ๊ตฌํ˜„์— ์˜์กดํ•˜์ง€ ์•Š๊ณ , ์ถ”์ƒํ™”๋œ IPaymentProcessor ์ธํ„ฐํŽ˜์ด์Šค์— ์˜์กดํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋‹ค์–‘ํ•œ ๊ฒฐ์ œ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์„ ์‰ฝ๊ฒŒ ๊ต์ฒดํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

1.3 ์˜์กด์„ฑ ์ฃผ์ž…์˜ ์ด์ 

  • ์œ ์—ฐ์„ฑ ํ–ฅ์ƒ: ๊ตฌํ˜„์ฒด๋ฅผ ์‰ฝ๊ฒŒ ๊ต์ฒดํ•  ์ˆ˜ ์žˆ์–ด ์‹œ์Šคํ…œ์˜ ์œ ์—ฐ์„ฑ์ด ์ฆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  • ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ: ๋ชฉ(Mock) ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค.
  • ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ: ๋™์ผํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ์—ฌ๋Ÿฌ ํด๋ž˜์Šค๋ฅผ ์‰ฝ๊ฒŒ ๊ต์ฒดํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ด€์‹ฌ์‚ฌ์˜ ๋ถ„๋ฆฌ: ๊ฐ์ฒด ์ƒ์„ฑ๊ณผ ์‚ฌ์šฉ์„ ๋ถ„๋ฆฌํ•˜์—ฌ ๋‹จ์ผ ์ฑ…์ž„ ์›์น™์„ ์ง€ํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์œ ์ง€๋ณด์ˆ˜์„ฑ ํ–ฅ์ƒ: ์ฝ”๋“œ ๊ฐ„์˜ ๊ฒฐํ•ฉ๋„๊ฐ€ ๋‚ฎ์•„์ ธ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค.

1.4 ์˜์กด์„ฑ ์ฃผ์ž…์˜ ์œ ํ˜•

์˜์กด์„ฑ ์ฃผ์ž…์€ ์ฃผ๋กœ ์„ธ ๊ฐ€์ง€ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค:

  1. ์ƒ์„ฑ์ž ์ฃผ์ž…(Constructor Injection): ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ๋ฐฉ์‹์œผ๋กœ, ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค.
  2. ์†์„ฑ ์ฃผ์ž…(Property Injection): ๊ณต๊ฐœ ์†์„ฑ์„ ํ†ตํ•ด ์˜์กด์„ฑ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ฉ”์„œ๋“œ ์ฃผ์ž…(Method Injection): ๋ฉ”์„œ๋“œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•ด ์˜์กด์„ฑ์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

.NET Core์˜ DI ์ปจํ…Œ์ด๋„ˆ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ƒ์„ฑ์ž ์ฃผ์ž…์„ ์ง€์›ํ•˜๋ฉฐ, ์ด๋Š” ๊ฐ€์žฅ ๊ถŒ์žฅ๋˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

1.5 IoC (Inversion of Control)

์˜์กด์„ฑ ์ฃผ์ž…์€ IoC(์ œ์–ด์˜ ์—ญ์ „) ์›์น™์˜ ํ•œ ํ˜•ํƒœ์ž…๋‹ˆ๋‹ค. IoC๋Š” ํ”„๋กœ๊ทธ๋žจ์˜ ์ œ์–ด ํ๋ฆ„์„ ์—ญ์ „์‹œํ‚ค๋Š” ์†Œํ”„ํŠธ์›จ์–ด ๋””์ž์ธ ์›์น™์ž…๋‹ˆ๋‹ค. ์ „ํ†ต์ ์ธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ๋Š” ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ํ”„๋กœ๊ทธ๋žจ์˜ ํ๋ฆ„์„ ์ œ์–ดํ–ˆ์ง€๋งŒ, IoC์—์„œ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๊ทธ ์—ญํ• ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

ย 

DI๋Š” IoC๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋กœ, ๊ฐ์ฒด์˜ ์ƒ์„ฑ๊ณผ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ฐœ๋ฐœ์ž๊ฐ€ ์•„๋‹Œ DI ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ฐœ๋ฐœ์ž๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ๋” ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

IoC ์ปจํ…Œ์ด๋„ˆ ์„œ๋น„์Šค A ์„œ๋น„์Šค B ์„œ๋น„์Šค C ์˜์กด์„ฑ ๊ด€๋ฆฌ ๋ฐ ์ฃผ์ž…

์œ„ ๋‹ค์ด์–ด๊ทธ๋žจ์€ IoC ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์–ด๋–ป๊ฒŒ ์„œ๋น„์Šค๋“ค์˜ ์˜์กด์„ฑ์„ ๊ด€๋ฆฌํ•˜๊ณ  ์ฃผ์ž…ํ•˜๋Š”์ง€๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ์ปจํ…Œ์ด๋„ˆ๋Š” ๊ฐ ์„œ๋น„์Šค์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ , ํ•„์š”ํ•  ๋•Œ ์ ์ ˆํ•œ ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค.

1.6 SOLID ์›์น™๊ณผ ์˜์กด์„ฑ ์ฃผ์ž…

์˜์กด์„ฑ ์ฃผ์ž…์€ SOLID ์›์น™, ํŠนํžˆ ์˜์กด์„ฑ ์—ญ์ „ ์›์น™(Dependency Inversion Principle, DIP)๊ณผ ๋ฐ€์ ‘ํ•œ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค. DIP๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์˜๋ฉ๋‹ˆ๋‹ค:

  1. ์ƒ์œ„ ์ˆ˜์ค€ ๋ชจ๋“ˆ์€ ํ•˜์œ„ ์ˆ˜์ค€ ๋ชจ๋“ˆ์— ์˜์กดํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ๋‘˜ ๋‹ค ์ถ”์ƒํ™”์— ์˜์กดํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  2. ์ถ”์ƒํ™”๋Š” ์„ธ๋ถ€ ์‚ฌํ•ญ์— ์˜์กดํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ์„ธ๋ถ€ ์‚ฌํ•ญ์ด ์ถ”์ƒํ™”์— ์˜์กดํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์˜์กด์„ฑ ์ฃผ์ž…์€ ์ด ์›์น™์„ ์‹คํ˜„ํ•˜๋Š” ํšจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค๋‚˜ ์ถ”์ƒ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์˜์กด์„ฑ์„ ์ •์˜ํ•จ์œผ๋กœ์จ, ๊ณ ์ˆ˜์ค€ ๋ชจ๋“ˆ๊ณผ ์ €์ˆ˜์ค€ ๋ชจ๋“ˆ ์‚ฌ์ด์˜ ์ง์ ‘์ ์ธ ์˜์กด์„ฑ์„ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1.7 ์˜์กด์„ฑ ์ฃผ์ž…์˜ ํ•œ๊ณ„์™€ ์ฃผ์˜์ 

์˜์กด์„ฑ ์ฃผ์ž…์ด ๋งŽ์€ ์ด์ ์„ ์ œ๊ณตํ•˜์ง€๋งŒ, ๋ช‡ ๊ฐ€์ง€ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ๋„ ์žˆ์Šต๋‹ˆ๋‹ค:

  • ๋ณต์žก์„ฑ ์ฆ๊ฐ€: ํฐ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” DI ์„ค์ •์ด ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜: ์ปดํŒŒ์ผ ์‹œ์ ์ด ์•„๋‹Œ ๋Ÿฐํƒ€์ž„์— ์˜์กด์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ๊ฒฌ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ณผ๋„ํ•œ ์ถ”์ƒํ™”: ๋ถˆํ•„์š”ํ•œ ์ถ”์ƒํ™”๋กœ ์ธํ•ด ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์„ฑ๋Šฅ ์˜ํ–ฅ: ์˜์กด์„ฑ ํ•ด๊ฒฐ ๊ณผ์ •์ด ์•ฝ๊ฐ„์˜ ์„ฑ๋Šฅ ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ํ•œ๊ณ„์ ๋“ค์€ ์ ์ ˆํ•œ ์„ค๊ณ„์™€ .NET Core์˜ ๊ฐ•๋ ฅํ•œ DI ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ™œ์šฉํ•จ์œผ๋กœ์จ ๋Œ€๋ถ€๋ถ„ ๊ทน๋ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ’ก Pro Tip: ์˜์กด์„ฑ ์ฃผ์ž…์„ ์ฒ˜์Œ ์ ์šฉํ•  ๋•Œ๋Š” ์ž‘์€ ๋ฒ”์œ„๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์„ธ์š”. ํ•ต์‹ฌ ์„œ๋น„์Šค๋‚˜ ์ž์ฃผ ๋ณ€๊ฒฝ๋˜๋Š” ์ปดํฌ๋„ŒํŠธ์— ๋จผ์ € ์ ์šฉํ•˜๊ณ , ์ ์ง„์ ์œผ๋กœ ํ™•์žฅํ•ด ๋‚˜๊ฐ€๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด DI์˜ ์ด์ ์„ ์ตœ๋Œ€ํ•œ ํ™œ์šฉํ•˜๋ฉด์„œ๋„ ๋ณต์žก์„ฑ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ ์˜์กด์„ฑ ์ฃผ์ž…์˜ ๊ธฐ๋ณธ ๊ฐœ๋…์„ ์ž˜ ์ดํ•ดํ•˜์…จ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ ์„น์…˜์—์„œ๋Š” .NET Core์˜ DI ์ปจํ…Œ์ด๋„ˆ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. .NET Core๊ฐ€ ์–ด๋–ป๊ฒŒ ์ด๋Ÿฌํ•œ ๊ฐœ๋…๋“ค์„ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ๊ฐœ๋ฐœ์ž๋“ค์ด ์–ด๋–ป๊ฒŒ ์ด๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

2. .NET Core DI ์ปจํ…Œ์ด๋„ˆ ์†Œ๊ฐœ ๐Ÿงฐ

.NET Core์˜ ์˜์กด์„ฑ ์ฃผ์ž…(DI) ์ปจํ…Œ์ด๋„ˆ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์˜ ํ•ต์‹ฌ ๊ตฌ์„ฑ ์š”์†Œ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ์ด ์ปจํ…Œ์ด๋„ˆ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์˜์กด์„ฑ์„ ๊ด€๋ฆฌํ•˜๊ณ , ํ•„์š”ํ•œ ์‹œ์ ์— ์ ์ ˆํ•œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ฃผ์ž…ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. .NET Core์˜ DI ์ปจํ…Œ์ด๋„ˆ๋Š” ๊ฐ€๋ณ๊ณ  ์œ ์—ฐํ•˜๋ฉฐ, ํ™•์žฅ์„ฑ์ด ๋›ฐ์–ด๋‚˜ ๋‹ค์–‘ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์— ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

2.1 .NET Core DI ์ปจํ…Œ์ด๋„ˆ์˜ ํŠน์ง•

.NET Core์˜ DI ์ปจํ…Œ์ด๋„ˆ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฃผ์š” ํŠน์ง•์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค:

  • ๋‚ด์žฅํ˜•: ๋ณ„๋„์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜ ์—†์ด .NET Core์— ๊ธฐ๋ณธ์œผ๋กœ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ฒฝ๋Ÿ‰ํ™”: ์ตœ์†Œํ•œ์˜ ์˜ค๋ฒ„ํ—ค๋“œ๋กœ ๋น ๋ฅธ ์„ฑ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  • ํ™•์žฅ์„ฑ: ์‚ฌ์šฉ์ž ์ •์˜ ๊ธฐ๋Šฅ์„ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ƒ๋ช…์ฃผ๊ธฐ ๊ด€๋ฆฌ: ๊ฐ์ฒด์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ์„ธ๋ฐ€ํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ปจ๋ฒค์…˜ ๊ธฐ๋ฐ˜: ๋ช…์‹œ์ ์ธ ๊ตฌ์„ฑ ์—†์ด๋„ ๋งŽ์€ ๊ฒฝ์šฐ ์ž๋™์œผ๋กœ ์˜์กด์„ฑ์„ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

2.2 DI ์ปจํ…Œ์ด๋„ˆ ์„ค์ •

.NET Core ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ DI ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ณผ์ •์€ ๋งค์šฐ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ์ฃผ๋กœ Program.cs ๋˜๋Š” Startup.cs ํŒŒ์ผ์—์„œ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.


public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices((hostContext, services) =>
            {
                // ์—ฌ๊ธฐ์—์„œ ์„œ๋น„์Šค๋ฅผ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค
                services.AddTransient<IMyService, MyService>();
            });
}

์œ„ ์ฝ”๋“œ์—์„œ ConfigureServices ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์— ์„œ๋น„์Šค๋ฅผ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๋“ฑ๋ก๋œ ์„œ๋น„์Šค๋“ค์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

2.3 ์„œ๋น„์Šค ๋“ฑ๋ก ๋ฐฉ๋ฒ•

.NET Core DI ์ปจํ…Œ์ด๋„ˆ๋Š” ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์œผ๋กœ ์„œ๋น„์Šค๋ฅผ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  1. ์ธํ„ฐํŽ˜์ด์Šค์™€ ๊ตฌํ˜„์ฒด ๋“ฑ๋ก:
    services.AddTransient<IMyService, MyService>();
  2. ๊ตฌ์ฒด ํด๋ž˜์Šค ๋“ฑ๋ก:
    services.AddTransient<MyService>();
  3. ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ ๋“ฑ๋ก:
    services.AddTransient<IMyService>(sp => new MyService());
  4. ์ธ์Šคํ„ด์Šค ๋“ฑ๋ก:
    services.AddSingleton<IMyService>(new MyService());

2.4 ์„œ๋น„์Šค ํ•ด๊ฒฐ(Resolving)

๋“ฑ๋ก๋œ ์„œ๋น„์Šค๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ํ•ด๊ฒฐ(resolve)ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  1. ์ƒ์„ฑ์ž ์ฃผ์ž…: ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ๋ฐฉ๋ฒ•์œผ๋กœ, ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž์—์„œ ์˜์กด์„ฑ์„ ์ฃผ์ž…๋ฐ›์Šต๋‹ˆ๋‹ค.
    
    public class MyController
    {
        private readonly IMyService _myService;
    
        public MyController(IMyService myService)
        {
            _myService = myService;
        }
    }
        
  2. ์•ก์…˜ ์ฃผ์ž… (ASP.NET Core MVC): ์ปจํŠธ๋กค๋Ÿฌ ์•ก์…˜ ๋ฉ”์„œ๋“œ์—์„œ ์ง์ ‘ ์„œ๋น„์Šค๋ฅผ ์ฃผ์ž…๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    
    public IActionResult Index([FromServices] IMyService myService)
    {
        // myService ์‚ฌ์šฉ
    }
        
  3. HttpContext๋ฅผ ํ†ตํ•œ ํ•ด๊ฒฐ: HttpContext๋ฅผ ํ†ตํ•ด ์„œ๋น„์Šค๋ฅผ ์š”์ฒญํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    
    var myService = HttpContext.RequestServices.GetService<IMyService>();
        
  4. IServiceProvider๋ฅผ ํ†ตํ•œ ์ˆ˜๋™ ํ•ด๊ฒฐ: ํ•„์š”ํ•œ ๊ฒฝ์šฐ IServiceProvider๋ฅผ ํ†ตํ•ด ์ˆ˜๋™์œผ๋กœ ์„œ๋น„์Šค๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    
    public class MyClass
    {
        public MyClass(IServiceProvider serviceProvider)
        {
            var myService = serviceProvider.GetService<IMyService>();
        }
    }
        

2.5 ์Šค์ฝ”ํ”„์™€ ์ƒ๋ช…์ฃผ๊ธฐ

.NET Core DI ์ปจํ…Œ์ด๋„ˆ๋Š” ์„ธ ๊ฐ€์ง€ ์ฃผ์š” ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค:

  • Transient: ์„œ๋น„์Šค๊ฐ€ ์š”์ฒญ๋  ๋•Œ๋งˆ๋‹ค ์ƒˆ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • Scoped: ์š”์ฒญ(HTTP ์š”์ฒญ ๋“ฑ) ๋ฒ”์œ„ ๋‚ด์—์„œ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค.
  • Singleton: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒ๋ช…์ฃผ๊ธฐ ๋™์•ˆ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋งŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ฐ ์ƒ๋ช…์ฃผ๊ธฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:


services.AddTransient<ITransientService, TransientService>();
services.AddScoped<IScopedService, ScopedService>();
services.AddSingleton<ISingletonService, SingletonService>();

2.6 DI ์ปจํ…Œ์ด๋„ˆ์˜ ๋‚ด๋ถ€ ๋™์ž‘

.NET Core์˜ DI ์ปจํ…Œ์ด๋„ˆ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ๋ณต์žกํ•œ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์„œ๋น„์Šค๊ฐ€ ์š”์ฒญ๋˜๋ฉด, ์ปจํ…Œ์ด๋„ˆ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ณผ์ •์„ ๊ฑฐ์นฉ๋‹ˆ๋‹ค:

  1. ์š”์ฒญ๋œ ์„œ๋น„์Šค์˜ ๋“ฑ๋ก ์ •๋ณด๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  2. ์„œ๋น„์Šค์˜ ์ƒ๋ช…์ฃผ๊ธฐ์— ๋”ฐ๋ผ ์ƒˆ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ๊ธฐ์กด ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  3. ์„œ๋น„์Šค๊ฐ€ ๋‹ค๋ฅธ ์˜์กด์„ฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด, ์žฌ๊ท€์ ์œผ๋กœ ์ด ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•˜์—ฌ ๋ชจ๋“  ์˜์กด์„ฑ์„ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
  4. ์™„์ „ํžˆ ๊ตฌ์„ฑ๋œ ์„œ๋น„์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
DI ์ปจํ…Œ์ด๋„ˆ ๋™์ž‘ ๊ณผ์ • ์„œ๋น„์Šค ์š”์ฒญ ๋“ฑ๋ก ์ •๋ณด ํ™•์ธ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ/๋ฐ˜ํ™˜ ์˜์กด์„ฑ ํ•ด๊ฒฐ

2.7 ์„ฑ๋Šฅ ๊ณ ๋ ค์‚ฌํ•ญ

.NET Core์˜ DI ์ปจํ…Œ์ด๋„ˆ๋Š” ๋งค์šฐ ํšจ์œจ์ ์œผ๋กœ ์„ค๊ณ„๋˜์—ˆ์ง€๋งŒ, ๋Œ€๊ทœ๋ชจ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ์š”์†Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค:

  • ์„œ๋น„์Šค ํ•ด๊ฒฐ ์‹œ๊ฐ„: ๋ณต์žกํ•œ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„๋Š” ์„œ๋น„์Šค ํ•ด๊ฒฐ ์‹œ๊ฐ„์„ ์ฆ๊ฐ€์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ: ํŠนํžˆ Singleton ์„œ๋น„์Šค์˜ ๊ฒฝ์šฐ, ๋งŽ์€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Scoped ์„œ๋น„์Šค์˜ ๊ด€๋ฆฌ: ๋งŽ์€ ์ˆ˜์˜ Scoped ์„œ๋น„์Šค๋Š” ์š”์ฒญ ์ฒ˜๋ฆฌ ์‹œ๊ฐ„์„ ๋Š˜๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์„ฑ๋Šฅ ์ด์Šˆ๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ๋ฌด์‹œํ•  ๋งŒํ•œ ์ˆ˜์ค€์ด์ง€๋งŒ, ๋Œ€๊ทœ๋ชจ ์‹œ์Šคํ…œ์—์„œ๋Š” ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

2.8 DI ์ปจํ…Œ์ด๋„ˆ ํ™•์žฅ

.NET Core์˜ DI ์ปจํ…Œ์ด๋„ˆ๋Š” ํ™•์žฅ์„ฑ์ด ๋›ฐ์–ด๋‚˜ ์‚ฌ์šฉ์ž ์ •์˜ ๊ธฐ๋Šฅ์„ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

  • ์‚ฌ์šฉ์ž ์ •์˜ ์ƒ๋ช…์ฃผ๊ธฐ ๊ด€๋ฆฌ
  • ์กฐ๊ฑด๋ถ€ ์„œ๋น„์Šค ๋“ฑ๋ก
  • ์„œ๋น„์Šค ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด ๊ตฌํ˜„
  • ์„œ๋น„์Šค ํŒฉํ† ๋ฆฌ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•

์ด๋Ÿฌํ•œ ํ™•์žฅ์€ IServiceCollection์— ํ™•์žฅ ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜, ์‚ฌ์šฉ์ž ์ •์˜ IServiceProvider๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ์‹คํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ’ก Pro Tip: .NET Core์˜ DI ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ตœ๋Œ€ํ•œ ํ™œ์šฉํ•˜๋ ค๋ฉด , ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ๋ฒ•์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”:
  • ์„œ๋น„์Šค ๋“ฑ๋ก ์‹œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋Š์Šจํ•œ ๊ฒฐํ•ฉ์„ ์œ ์ง€ํ•˜์„ธ์š”.
  • ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ์‹ ์ค‘ํžˆ ์„ ํƒํ•˜์—ฌ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๊ณผ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜์„ธ์š”.
  • ๋ณต์žกํ•œ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„๋Š” ํŒฉํ† ๋ฆฌ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ด€๋ฆฌํ•˜์„ธ์š”.
  • ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์‹œ Mock ๊ฐ์ฒด๋ฅผ ์‰ฝ๊ฒŒ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„ํ•˜์„ธ์š”.

.NET Core์˜ DI ์ปจํ…Œ์ด๋„ˆ๋Š” ๊ฐ•๋ ฅํ•˜๋ฉด์„œ๋„ ์œ ์—ฐํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ํ™œ์šฉํ•˜๋ฉด ๋” ๋ชจ๋“ˆํ™”๋˜๊ณ , ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์‰ฌ์šฐ๋ฉฐ, ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์šฉ์ดํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3. ์„œ๋น„์Šค ์ˆ˜๋ช… ๊ด€๋ฆฌ โณ

.NET Core์˜ DI ์ปจํ…Œ์ด๋„ˆ์—์„œ ์„œ๋น„์Šค ์ˆ˜๋ช… ๊ด€๋ฆฌ๋Š” ๋งค์šฐ ์ค‘์š”ํ•œ ๊ฐœ๋…์ž…๋‹ˆ๋‹ค. ์ ์ ˆํ•œ ์ˆ˜๋ช… ์ฃผ๊ธฐ๋ฅผ ์„ ํƒํ•˜๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๊ณ  ๋ฆฌ์†Œ์Šค๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์„น์…˜์—์„œ๋Š” ๊ฐ ์„œ๋น„์Šค ์ˆ˜๋ช… ์˜ต์…˜์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ณ , ์–ธ์ œ ์–ด๋–ค ์˜ต์…˜์„ ์„ ํƒํ•ด์•ผ ํ•˜๋Š”์ง€ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

3.1 ์„œ๋น„์Šค ์ˆ˜๋ช… ์˜ต์…˜

.NET Core DI ์ปจํ…Œ์ด๋„ˆ๋Š” ์„ธ ๊ฐ€์ง€ ์ฃผ์š” ์„œ๋น„์Šค ์ˆ˜๋ช… ์˜ต์…˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค:

  1. Transient (์ผ์‹œ์ )
  2. Scoped (๋ฒ”์œ„)
  3. Singleton (๋‹จ์ผ)

๊ฐ ์˜ต์…˜์€ ์„œ๋น„์Šค ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ์žฌ์‚ฌ์šฉ๋˜๋Š” ๋ฐฉ์‹์„ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

3.2 Transient ์„œ๋น„์Šค

ํŠน์ง•:

  • ์„œ๋น„์Šค๊ฐ€ ์š”์ฒญ๋  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.
  • ๊ฐ€์žฅ ์งง์€ ์ˆ˜๋ช…์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค.
  • ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜์ง€ ์•Š๋Š” ๊ฐ€๋ฒผ์šด ์„œ๋น„์Šค์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ ์˜ˆ:

services.AddTransient<IDataProcessor, DataProcessor>();

์ ํ•ฉํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค:

  • ๊ฐ€๋ฒผ์šด ์ƒํƒœ ๋น„์ €์žฅ ์„œ๋น„์Šค
  • ๋งค๋ฒˆ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ
  • ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ ํ™˜๊ฒฝ์—์„œ ์Šค๋ ˆ๋“œ ์•ˆ์ „์„ฑ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ

3.3 Scoped ์„œ๋น„์Šค

ํŠน์ง•:

  • ์š”์ฒญ ๋ฒ”์œ„(์ผ๋ฐ˜์ ์œผ๋กœ HTTP ์š”์ฒญ) ๋‚ด์—์„œ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ณต์œ ๋ฉ๋‹ˆ๋‹ค.
  • ๊ฐ™์€ ์š”์ฒญ ๋‚ด์—์„œ๋Š” ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • ์š”์ฒญ์ด ์™„๋ฃŒ๋˜๋ฉด ์ธ์Šคํ„ด์Šค๊ฐ€ ํ๊ธฐ๋ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ ์˜ˆ:

services.AddScoped<IRepository, Repository>();

์ ํ•ฉํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค:

  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปจํ…์ŠคํŠธ
  • ์š”์ฒญ๋ณ„ ์บ์‹ฑ
  • ์‚ฌ์šฉ์ž ์„ธ์…˜ ๊ด€๋ จ ์„œ๋น„์Šค

3.4 Singleton ์„œ๋น„์Šค

ํŠน์ง•:

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ˆ˜๋ช… ๋™์•ˆ ๋‹จ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋งŒ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.
  • ๋ชจ๋“  ์š”์ฒญ์—์„œ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ณต์œ ๋ฉ๋‹ˆ๋‹ค.
  • ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ์ค„์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ์Šค๋ ˆ๋“œ ์•ˆ์ „์„ฑ์— ์ฃผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ ์˜ˆ:

services.AddSingleton<IConfiguration, Configuration>();

์ ํ•ฉํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค:

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค์ •
  • ๋กœ๊น… ์„œ๋น„์Šค
  • ์ธ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ

3.5 ์ˆ˜๋ช… ์ฃผ๊ธฐ ๋น„๊ต

์„œ๋น„์Šค ์ˆ˜๋ช… ์ฃผ๊ธฐ ๋น„๊ต Transient Scoped Singleton ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ˆ˜๋ช…

3.6 ์ˆ˜๋ช… ์ฃผ๊ธฐ ์„ ํƒ ์‹œ ๊ณ ๋ ค์‚ฌํ•ญ

์ ์ ˆํ•œ ์„œ๋น„์Šค ์ˆ˜๋ช…์„ ์„ ํƒํ•  ๋•Œ ๋‹ค์Œ ์‚ฌํ•ญ์„ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

  1. ์ƒํƒœ ๊ด€๋ฆฌ: ์„œ๋น„์Šค๊ฐ€ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•ด์•ผ ํ•˜๋Š”์ง€, ์•„๋‹ˆ๋ฉด ์ƒํƒœ ๋น„์ €์žฅ์ด์–ด์•ผ ํ•˜๋Š”์ง€ ๊ณ ๋ คํ•ฉ๋‹ˆ๋‹ค.
  2. ์„ฑ๋Šฅ: ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ๋น„์šฉ๊ณผ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ๊ณ ๋ คํ•ฉ๋‹ˆ๋‹ค.
  3. ๋™์‹œ์„ฑ: ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ์˜ ์•ˆ์ „์„ฑ์„ ๊ณ ๋ คํ•ฉ๋‹ˆ๋‹ค.
  4. ์˜์กด์„ฑ: ์„œ๋น„์Šค๊ฐ€ ์˜์กดํ•˜๋Š” ๋‹ค๋ฅธ ์„œ๋น„์Šค์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ๋ฅผ ๊ณ ๋ คํ•ฉ๋‹ˆ๋‹ค.
  5. ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ์ด๋‚˜ ํŒŒ์ผ ํ•ธ๋“ค๊ณผ ๊ฐ™์€ ๋ฆฌ์†Œ์Šค์˜ ์ ์ ˆํ•œ ๊ด€๋ฆฌ๋ฅผ ๊ณ ๋ คํ•ฉ๋‹ˆ๋‹ค.

3.7 ์ˆ˜๋ช… ์ฃผ๊ธฐ ๊ด€๋ จ ์ฃผ์˜์‚ฌํ•ญ

Captive Dependency: ๋” ๊ธด ์ˆ˜๋ช…์„ ๊ฐ€์ง„ ์„œ๋น„์Šค๊ฐ€ ๋” ์งง์€ ์ˆ˜๋ช…์˜ ์„œ๋น„์Šค์— ์˜์กดํ•˜๋Š” ๊ฒฝ์šฐ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.


// ์ž˜๋ชป๋œ ์˜ˆ:
services.AddSingleton<IService, Service>(); // Service๋Š” IRepository์— ์˜์กด
services.AddScoped<IRepository, Repository>();

// ์˜ฌ๋ฐ”๋ฅธ ์˜ˆ:
services.AddScoped<IService, Service>();
services.AddScoped<IRepository, Repository>();

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•:

  • ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„๋ฅผ ์‹ ์ค‘ํžˆ ์„ค๊ณ„ํ•ฉ๋‹ˆ๋‹ค.
  • ํŒฉํ† ๋ฆฌ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ ์˜์กด์„ฑ์„ ๋™์ ์œผ๋กœ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
  • IServiceProvider๋ฅผ ์ฃผ์ž…๋ฐ›์•„ ํ•„์š”ํ•  ๋•Œ ์„œ๋น„์Šค๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

3.8 ์‚ฌ์šฉ์ž ์ •์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ

.NET Core DI ์ปจํ…Œ์ด๋„ˆ๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ๋„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ํŠน๋ณ„ํ•œ ์š”๊ตฌ์‚ฌํ•ญ์ด ์žˆ๋Š” ๊ฒฝ์šฐ IServiceProviderFactory<TContainerBuilder>๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ •์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


public class CustomLifetimeManager : IServiceProviderFactory<CustomBuilder>
{
    // ๊ตฌํ˜„ ๋‚ด์šฉ
}

// ์‚ฌ์šฉ
services.AddSingleton<IServiceProviderFactory<CustomBuilder>, CustomLifetimeManager>();
๐Ÿ’ก Pro Tip: ์„œ๋น„์Šค ์ˆ˜๋ช… ์ฃผ๊ธฐ๋ฅผ ๊ฒฐ์ •ํ•  ๋•Œ๋Š” ํ•ญ์ƒ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์š”๊ตฌ์‚ฌํ•ญ๊ณผ ์„ฑ๋Šฅ์„ ๊ท ํ˜•์žˆ๊ฒŒ ๊ณ ๋ คํ•˜์„ธ์š”. ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ Scoped ์„œ๋น„์Šค๋กœ ์‹œ์ž‘ํ•˜์—ฌ ํ•„์š”์— ๋”ฐ๋ผ Transient๋‚˜ Singleton์œผ๋กœ ์กฐ์ •ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, ์ •๊ธฐ์ ์œผ๋กœ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„๋ฅผ ๊ฒ€ํ† ํ•˜์—ฌ Captive Dependency ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€ํ•˜์„ธ์š”.

์„œ๋น„์Šค ์ˆ˜๋ช… ๊ด€๋ฆฌ๋Š” .NET Core ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์„ฑ๋Šฅ๊ณผ ์•ˆ์ •์„ฑ์— ํฐ ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค. ๊ฐ ์ˆ˜๋ช… ์ฃผ๊ธฐ ์˜ต์…˜์˜ ํŠน์„ฑ์„ ์ž˜ ์ดํ•ดํ•˜๊ณ , ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๊ฒŒ ์ ์ ˆํžˆ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ์‹ค์ œ๋กœ ์˜์กด์„ฑ ์ฃผ์ž…์„ ๊ตฌํ˜„ํ•˜๋Š” ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

4. ์˜์กด์„ฑ ์ฃผ์ž… ๊ตฌํ˜„ ๋ฐฉ๋ฒ• ๐Ÿ› ๏ธ

์˜์กด์„ฑ ์ฃผ์ž…(DI)์„ ํšจ๊ณผ์ ์œผ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์€ ๊น”๋”ํ•˜๊ณ  ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์šฉ์ดํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ํ•ต์‹ฌ์ ์ž…๋‹ˆ๋‹ค. ์ด ์„น์…˜์—์„œ๋Š” .NET Core์—์„œ ์˜์กด์„ฑ ์ฃผ์ž…์„ ๊ตฌํ˜„ํ•˜๋Š” ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•๊ณผ ๊ฐ ๋ฐฉ๋ฒ•์˜ ์žฅ๋‹จ์ , ๊ทธ๋ฆฌ๊ณ  ์ ์ ˆํ•œ ์‚ฌ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค์— ๋Œ€ํ•ด ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

4.1 ์ƒ์„ฑ์ž ์ฃผ์ž… (Constructor Injection)

์ƒ์„ฑ์ž ์ฃผ์ž…์€ ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ด๊ณ  ๊ถŒ์žฅ๋˜๋Š” DI ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์˜ˆ์‹œ:


public class OrderService
{
    private readonly IRepository _repository;
    private readonly ILogger _logger;

    public OrderService(IRepository repository, ILogger logger)
    {
        _repository = repository ?? throw new ArgumentNullException(nameof(repository));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    public void ProcessOrder(Order order)
    {
        _logger.Log("Processing order...");
        _repository.Save(order);
    }
}

์žฅ์ :

  • ์˜์กด์„ฑ์ด ๋ช…ํ™•ํ•˜๊ฒŒ ๋“œ๋Ÿฌ๋‚ฉ๋‹ˆ๋‹ค.
  • ๊ฐ์ฒด ์ƒ์„ฑ ์‹œ์ ์— ๋ชจ๋“  ์˜์กด์„ฑ์ด ํ•ด๊ฒฐ๋ฉ๋‹ˆ๋‹ค.
  • ๋ถˆ๋ณ€์„ฑ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.
  • ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ์šฉ์ดํ•ฉ๋‹ˆ๋‹ค.

๋‹จ์ :

  • ๋งŽ์€ ์˜์กด์„ฑ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์ƒ์„ฑ์ž๊ฐ€ ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

4.2 ์†์„ฑ ์ฃผ์ž… (Property Injection)

์†์„ฑ ์ฃผ์ž…์€ ์„ ํƒ์ ์ธ ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•  ๋•Œ ์œ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์˜ˆ์‹œ:


public class EmailService
{
    public ILogger Logger { get; set; }

    public void SendEmail(string to, string subject, string body)
    {
        Logger?.Log($"Sending email to {to}");
        // ์ด๋ฉ”์ผ ์ „์†ก ๋กœ์ง
    }
}

์žฅ์ :

  • ์„ ํƒ์  ์˜์กด์„ฑ์„ ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋Ÿฐํƒ€์ž„์— ์˜์กด์„ฑ์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹จ์ :

  • ์˜์กด์„ฑ์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • null ์ฒดํฌ๊ฐ€ ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ถˆ๋ณ€์„ฑ์„ ๋ณด์žฅํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

4.3 ๋ฉ”์„œ๋“œ ์ฃผ์ž… (Method Injection)

๋ฉ”์„œ๋“œ ์ฃผ์ž…์€ ์˜์กด์„ฑ์ด ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์‹œ์—๋งŒ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์˜ˆ์‹œ:


public class ReportGenerator
{
    public void GenerateReport(IDataSource dataSource)
    {
        var data = dataSource.GetData();
        // ๋ณด๊ณ ์„œ ์ƒ์„ฑ ๋กœ์ง
    }
}

์žฅ์ :

  • ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์‹œ์—๋งŒ ์˜์กด์„ฑ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ๋‹ค์–‘ํ•œ ์˜์กด์„ฑ์„ ๋™์ ์œผ๋กœ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹จ์ :

  • ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ๋งˆ๋‹ค ์˜์กด์„ฑ์„ ์ „๋‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ํด๋ž˜์Šค์˜ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ธฐ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

4.4 ์„œ๋น„์Šค ๋กœ์ผ€์ดํ„ฐ ํŒจํ„ด (Service Locator Pattern)

์„œ๋น„์Šค ๋กœ์ผ€์ดํ„ฐ ํŒจํ„ด์€ DI์˜ ๋Œ€์•ˆ์œผ๋กœ ์‚ฌ์šฉ๋˜์ง€๋งŒ, ์ผ๋ฐ˜์ ์œผ๋กœ ๊ถŒ์žฅ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์˜ˆ์‹œ:


public class OrderProcessor
{
    public void ProcessOrder(Order order)
    {
        var logger = ServiceLocator.Current.GetInstance<ILogger>();
        var repository = ServiceLocator.Current.GetInstance<IRepository>();

        logger.Log("Processing order...");
        repository.Save(order);
    }
}

์žฅ์ :

  • ์˜์กด์„ฑ์„ ๋™์ ์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ ˆ๊ฑฐ์‹œ ์‹œ์Šคํ…œ์—์„œ DI๋กœ ์ „ํ™˜ํ•  ๋•Œ ์ž„์‹œ ๋ฐฉํŽธ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹จ์ :

  • ์˜์กด์„ฑ์ด ์ˆจ๊ฒจ์ ธ ์žˆ์–ด ์ฝ”๋“œ์˜ ์˜๋„๋ฅผ ํŒŒ์•…ํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
  • ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ์–ด๋ ค์›Œ์ง‘๋‹ˆ๋‹ค.
  • ์„œ๋น„์Šค ๋กœ์ผ€์ดํ„ฐ์— ๋Œ€ํ•œ ์˜์กด์„ฑ์ด ์ƒ๊น๋‹ˆ๋‹ค.

4.5 ํŒฉํ† ๋ฆฌ ํŒจํ„ด์„ ํ™œ์šฉํ•œ DI

๋ณต์žกํ•œ ๊ฐ์ฒด ์ƒ์„ฑ ๋กœ์ง์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ํŒฉํ† ๋ฆฌ ํŒจํ„ด์„ DI์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์˜ˆ์‹œ:


public interface IServiceFactory
{
    IService CreateService(ServiceType type);
}

public class ServiceFactory : IServiceFactory
{
    private readonly IServiceProvider _serviceProvider;

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

    public IService CreateService(ServiceType type)
    {
        switch (type)
        {
            case ServiceType.TypeA:
                return _serviceProvider.GetService<ServiceA>();
            case ServiceType.TypeB:
                return _serviceProvider.GetService<ServiceB>();
            default:
                throw new ArgumentOutOfRangeException(nameof(type));
        }
    }
}

public class ComplexService
{
    private readonly IServiceFactory _factory;

    public ComplexService(IServiceFactory factory)
    {
        _factory = factory;
    }

    public void DoSomething(ServiceType type)
    {
        var service = _factory.CreateService(type);
        service.Execute();
    }
}

์žฅ์ :

  • ๋ณต์žกํ•œ ๊ฐ์ฒด ์ƒ์„ฑ ๋กœ์ง์„ ์บก์Šํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋Ÿฐํƒ€์ž„์— ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐฉ์‹์„ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • DI ์ปจํ…Œ์ด๋„ˆ์™€ ์ž˜ ํ†ตํ•ฉ๋ฉ๋‹ˆ๋‹ค.

๋‹จ์ :

  • ์ถ”๊ฐ€์ ์ธ ์ถ”์ƒํ™” ๊ณ„์ธต์œผ๋กœ ์ธํ•ด ๋ณต์žก์„ฑ์ด ์ฆ๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

4.6 ๋‹ค์ค‘ ๊ตฌํ˜„ ์ฃผ์ž…

ํ•˜๋‚˜์˜ ์ธํ„ฐํŽ˜์ด์Šค์— ๋Œ€ํ•ด ์—ฌ๋Ÿฌ ๊ตฌํ˜„์ฒด๋ฅผ ์ฃผ์ž…ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์˜ˆ์‹œ:


public interface IValidator<T>
{
    bool Validate(T entity);
}

public class CompositeValidator<T> : IValidator<T>
{
    private readonly IEnumerable<IValidator<T>> _validators;

    public CompositeValidator(IEnumerable<IValidator<T>> validators)
    {
        _validators = validators;
    }

    public bool Validate(T entity)
    {
        return _validators.All(v => v.Validate(entity));
    }
}

// ์„œ๋น„์Šค ๋“ฑ๋ก
services.AddTransient<IValidator<User>, EmailValidator>();
services.AddTransient<IValidator<User>, AgeValidator>();
services.AddTransient<IValidator<User>, CompositeValidator<User>>();

์žฅ์ :

  • ๋™์ผํ•œ ์ธํ„ฐํŽ˜์ด์Šค์˜ ์—ฌ๋Ÿฌ ๊ตฌํ˜„์„ ์œ ์—ฐํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ƒˆ๋กœ์šด ๊ตฌํ˜„์„ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹จ์ :

  • ๊ตฌํ˜„์ด ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

4.7 ์กฐ๊ฑด๋ถ€ DI

๋Ÿฐํƒ€์ž„ ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๊ตฌํ˜„์„ ์ฃผ์ž…ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์˜ˆ์‹œ:


public interface IDataStore { }
public class SqlDataStore : IDataStore { }
public class InMemoryDataStore : IDataStore { }

services.AddTransient<IDataStore>(serviceProvider =>
{
    var configuration = serviceProvider.GetService<IConfiguration>();
    return configuration["UseInMemoryStore"] == "true"
        ? new InMemoryDataStore()
        : new SqlDataStore();
});

์žฅ์ :

  • ๋Ÿฐํƒ€์ž„ ์กฐ๊ฑด์— ๋”ฐ๋ผ ์œ ์—ฐํ•˜๊ฒŒ ๊ตฌํ˜„์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์„ค์ • ๋ณ€๊ฒฝ๋งŒ์œผ๋กœ ๋™์ž‘์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹จ์ :

  • ์กฐ๊ฑด ๋กœ์ง์ด ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํ…Œ์ŠคํŠธ๊ฐ€ ๋” ์–ด๋ ค์›Œ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๐Ÿ’ก Pro Tip: ์˜์กด์„ฑ ์ฃผ์ž… ๊ตฌํ˜„ ์‹œ ๋‹ค์Œ ์‚ฌํ•ญ์„ ๊ณ ๋ คํ•˜์„ธ์š”:
  • ๊ฐ€๋Šฅํ•œ ํ•œ ์ƒ์„ฑ์ž ์ฃผ์ž…์„ ์‚ฌ์šฉํ•˜์„ธ์š”. ์ด๋Š” ๊ฐ€์žฅ ๋ช…ํ™•ํ•˜๊ณ  ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์‰ฌ์šด ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
  • ์†์„ฑ ์ฃผ์ž…์€ ์„ ํƒ์  ์˜์กด์„ฑ์—๋งŒ ์‚ฌ์šฉํ•˜์„ธ์š”.
  • ๋ฉ”์„œ๋“œ ์ฃผ์ž…์€ ์˜์กด์„ฑ์ด ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์‹œ์—๋งŒ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•˜์„ธ์š”.
  • ์„œ๋น„์Šค ๋กœ์ผ€์ดํ„ฐ ํŒจํ„ด์€ ๊ฐ€๋Šฅํ•œ ํ”ผํ•˜์„ธ์š”. ํ•„์š”ํ•œ ๊ฒฝ์šฐ ํŒฉํ† ๋ฆฌ ํŒจํ„ด์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”.
  • ๋ณต์žกํ•œ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„๋Š” ํŒฉํ† ๋ฆฌ ํŒจํ„ด์ด๋‚˜ ๋นŒ๋” ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ด€๋ฆฌํ•˜์„ธ์š”.
  • ํ•ญ์ƒ SOLID ์›์น™, ํŠนํžˆ ๋‹จ์ผ ์ฑ…์ž„ ์›์น™(SRP)๊ณผ ์˜์กด์„ฑ ์—ญ์ „ ์›์น™(DIP)์„ ์—ผ๋‘์— ๋‘์„ธ์š”.

์˜์กด์„ฑ ์ฃผ์ž…์„ ํšจ๊ณผ์ ์œผ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์€ ํด๋ฆฐ ์ฝ”๋“œ ์ž‘์„ฑ์˜ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. ๊ฐ ์ƒํ™ฉ์— ๋งž๋Š” ์ ์ ˆํ•œ DI ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•˜๊ณ , ์ฝ”๋“œ์˜ ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ์„ ํ•ญ์ƒ ๊ณ ๋ คํ•˜์„ธ์š”. ๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ๋” ๊ณ ๊ธ‰ DI ํ…Œํฌ๋‹‰์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

5. ๊ณ ๊ธ‰ DI ํ…Œํฌ๋‹‰ ๐Ÿš€

๊ธฐ๋ณธ์ ์ธ ์˜์กด์„ฑ ์ฃผ์ž… ๊ตฌํ˜„์„ ๋„˜์–ด์„œ, ๋” ๋ณต์žกํ•˜๊ณ  ํŠน์ˆ˜ํ•œ ์ƒํ™ฉ์—์„œ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ณ ๊ธ‰ DI ํ…Œํฌ๋‹‰๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํ…Œํฌ๋‹‰๋“ค์€ ๋Œ€๊ทœ๋ชจ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด๋‚˜ ํŠน๋ณ„ํ•œ ์š”๊ตฌ์‚ฌํ•ญ์ด ์žˆ๋Š” ํ”„๋กœ์ ํŠธ์—์„œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

5.1 ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด (Decorator Pattern)

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด์€ ๊ธฐ์กด ์„œ๋น„์Šค์— ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์„ ๋™์ ์œผ๋กœ ๋ถ™์ด๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. .NET Core DI์—์„œ๋Š” ์ด๋ฅผ ์šฐ์•„ํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์˜ˆ์‹œ:


public interface INotificationService
{
    void SendNotification(string message);
}

public class EmailNotificationService : INotificationService
{
    public void SendNotification(string message)
    {
        Console.WriteLine($"Sending email: {message}");
    }
}

public class LoggingDecorator : INotificationService
{
    private readonly INotificationService _inner;
    private readonly ILogger _logger;

    public LoggingDecorator(INotificationService inner, ILogger logger)
    {
        _inner = inner;
        _logger = logger;
    }

    public void SendNotification(string message)
    {
        _logger.Log($"Sending notification: {message}");
        _inner.SendNotification(message);
    }
}

// ์„œ๋น„์Šค ๋“ฑ๋ก
services.AddTransient<INotificationService, EmailNotificationService>();
services.Decorate<INotificationService, LoggingDecorator>();

์žฅ์ :

  • ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์—ฌ๋Ÿฌ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์กฐํ•ฉํ•˜์—ฌ ๋ณต์žกํ•œ ๋™์ž‘์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ด€์‹ฌ์‚ฌ์˜ ๋ถ„๋ฆฌ๋ฅผ ์ด‰์ง„ํ•ฉ๋‹ˆ๋‹ค.

5.2 ์ปจํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ ์˜์กด์„ฑ ํ•ด๊ฒฐ (Context-based Resolution)

๋Ÿฐํƒ€์ž„ ์ปจํ…์ŠคํŠธ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๊ตฌํ˜„์„ ์ œ๊ณตํ•ด์•ผ ํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์˜ˆ์‹œ:


public interface IUserRepository { }
public class SqlUserRepository : IUserRepository { }
public class MongoUserRepository : IUserRepository { }

public class RepositoryFactory
{
    private readonly IServiceProvider _serviceProvider;

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

    public IUserRepository GetRepository(string context)
    {
        return context switch
        {
            "SQL" => _serviceProvider.GetService<SqlUserRepository  >(),
            "Mongo" => _serviceProvider.GetService<MongoUserRepository>(),
            _ => throw new ArgumentException("Unknown context", nameof(context))
        };
    }
}

// ์„œ๋น„์Šค ๋“ฑ๋ก
services.AddTransient<SqlUserRepository>();
services.AddTransient<MongoUserRepository>();
services.AddTransient<RepositoryFactory>();

์žฅ์ :

  • ๋Ÿฐํƒ€์ž„์— ์œ ์—ฐํ•˜๊ฒŒ ๊ตฌํ˜„์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋‹ค์ค‘ ํ…Œ๋„ŒํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

5.3 ๋ ˆ์ด์ง€ ์˜์กด์„ฑ (Lazy Dependencies)

์˜์กด์„ฑ์ด ์‹ค์ œ๋กœ ์‚ฌ์šฉ๋  ๋•Œ๊นŒ์ง€ ๊ทธ ์ƒ์„ฑ์„ ์ง€์—ฐ์‹œํ‚ค๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์˜ˆ์‹œ:


public class ExpensiveService
{
    public void DoSomething() { /* ๋น„์šฉ์ด ๋งŽ์ด ๋“œ๋Š” ์ž‘์—… */ }
}

public class Client
{
    private readonly Lazy<ExpensiveService> _expensiveService;

    public Client(Lazy<ExpensiveService> expensiveService)
    {
        _expensiveService = expensiveService;
    }

    public void DoWork()
    {
        // ExpensiveService๋Š” ์ด ์‹œ์ ์— ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค
        _expensiveService.Value.DoSomething();
    }
}

// ์„œ๋น„์Šค ๋“ฑ๋ก
services.AddTransient<ExpensiveService>();
services.AddTransient(sp => new Lazy<ExpensiveService>(sp.GetRequiredService<ExpensiveService>));

์žฅ์ :

  • ๋ฆฌ์†Œ์Šค๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ดˆ๊ธฐํ™” ์‹œ๊ฐ„์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

5.4 ๋ช…๋ช…๋œ ์˜์กด์„ฑ (Named Dependencies)

๊ฐ™์€ ์ธํ„ฐํŽ˜์ด์Šค์˜ ์—ฌ๋Ÿฌ ๊ตฌํ˜„์„ ๊ตฌ๋ถ„ํ•ด์•ผ ํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์˜ˆ์‹œ:


public interface IPaymentGateway { }
public class StripeGateway : IPaymentGateway { }
public class PayPalGateway : IPaymentGateway { }

public class PaymentService
{
    private readonly IPaymentGateway _stripeGateway;
    private readonly IPaymentGateway _paypalGateway;

    public PaymentService(
        [FromKeyedServices("Stripe")] IPaymentGateway stripeGateway,
        [FromKeyedServices("PayPal")] IPaymentGateway paypalGateway)
    {
        _stripeGateway = stripeGateway;
        _paypalGateway = paypalGateway;
    }
}

// ์„œ๋น„์Šค ๋“ฑ๋ก
services.AddKeyedTransient<IPaymentGateway, StripeGateway>("Stripe");
services.AddKeyedTransient<IPaymentGateway, PayPalGateway>("PayPal");

์žฅ์ :

  • ๋™์ผํ•œ ์ธํ„ฐํŽ˜์ด์Šค์˜ ์—ฌ๋Ÿฌ ๊ตฌํ˜„์„ ๋ช…ํ™•ํ•˜๊ฒŒ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์„ค์ •์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๊ตฌํ˜„์„ ์‰ฝ๊ฒŒ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

5.5 ํ”„๋ก์‹œ ํŒจํ„ด (Proxy Pattern)

์„œ๋น„์Šค์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์ œ์–ดํ•˜๊ฑฐ๋‚˜ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์˜ˆ์‹œ:


public interface IDatabase
{
    void SaveData(string data);
}

public class Database : IDatabase
{
    public void SaveData(string data)
    {
        Console.WriteLine($"Saving data: {data}");
    }
}

public class DatabaseProxy : IDatabase
{
    private readonly IDatabase _database;
    private readonly ILogger _logger;

    public DatabaseProxy(IDatabase database, ILogger logger)
    {
        _database = database;
        _logger = logger;
    }

    public void SaveData(string data)
    {
        _logger.Log("Before saving data");
        _database.SaveData(data);
        _logger.Log("After saving data");
    }
}

// ์„œ๋น„์Šค ๋“ฑ๋ก
services.AddTransient<IDatabase, Database>();
services.Decorate<IDatabase, DatabaseProxy>();

์žฅ์ :

  • ์›๋ณธ ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋กœ๊น…, ์บ์‹ฑ ๋“ฑ์˜ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

5.6 ์ปดํฌ์ง€ํŠธ ํŒจํ„ด (Composite Pattern)

์—ฌ๋Ÿฌ ๊ตฌํ˜„์„ ํ•˜๋‚˜์˜ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ํ†ตํ•ฉํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์˜ˆ์‹œ:


public interface IValidator
{
    bool Validate(object data);
}

public class CompositeValidator : IValidator
{
    private readonly IEnumerable<IValidator> _validators;

    public CompositeValidator(IEnumerable<IValidator> validators)
    {
        _validators = validators;
    }

    public bool Validate(object data)
    {
        return _validators.All(v => v.Validate(data));
    }
}

// ์„œ๋น„์Šค ๋“ฑ๋ก
services.AddTransient<IValidator, EmailValidator>();
services.AddTransient<IValidator, PhoneValidator>();
services.AddTransient<IValidator, CompositeValidator>();

์žฅ์ :

  • ๋ณต์žกํ•œ ๊ฒ€์ฆ ๋กœ์ง์„ ๋‹จ์ˆœํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ƒˆ๋กœ์šด ๊ฒ€์ฆ ๊ทœ์น™์„ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

5.7 ํŒฉํ† ๋ฆฌ ํŒจํ„ด๊ณผ DI์˜ ๊ฒฐํ•ฉ

๋ณต์žกํ•œ ๊ฐ์ฒด ์ƒ์„ฑ ๋กœ์ง์„ ์บก์Šํ™”ํ•˜๋ฉด์„œ DI์˜ ์ด์ ์„ ํ™œ์šฉํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์˜ˆ์‹œ:


public interface IConnectionFactory
{
    IDbConnection CreateConnection();
}

public class SqlConnectionFactory : IConnectionFactory
{
    private readonly string _connectionString;

    public SqlConnectionFactory(IConfiguration configuration)
    {
        _connectionString = configuration.GetConnectionString("DefaultConnection");
    }

    public IDbConnection CreateConnection()
    {
        return new SqlConnection(_connectionString);
    }
}

public class Repository
{
    private readonly IConnectionFactory _connectionFactory;

    public Repository(IConnectionFactory connectionFactory)
    {
        _connectionFactory = connectionFactory;
    }

    public void SaveData(string data)
    {
        using var connection = _connectionFactory.CreateConnection();
        // ๋ฐ์ดํ„ฐ ์ €์žฅ ๋กœ์ง
    }
}

// ์„œ๋น„์Šค ๋“ฑ๋ก
services.AddSingleton<IConnectionFactory, SqlConnectionFactory>();
services.AddTransient<Repository>();

์žฅ์ :

  • ๊ฐ์ฒด ์ƒ์„ฑ ๋กœ์ง์„ ์ค‘์•™ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํ…Œ์ŠคํŠธ์™€ ๋ชจ์˜ ๊ฐ์ฒด ์ƒ์„ฑ์ด ์šฉ์ดํ•ด์ง‘๋‹ˆ๋‹ค.
๐Ÿ’ก Pro Tip: ๊ณ ๊ธ‰ DI ํ…Œํฌ๋‹‰์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ๋‹ค์Œ ์‚ฌํ•ญ์„ ๊ณ ๋ คํ•˜์„ธ์š”:
  • ๋ณต์žก์„ฑ๊ณผ ์œ ์—ฐ์„ฑ ์‚ฌ์ด์˜ ๊ท ํ˜•์„ ์œ ์ง€ํ•˜์„ธ์š”. ๋•Œ๋กœ๋Š” ๊ฐ„๋‹จํ•œ ํ•ด๊ฒฐ์ฑ…์ด ๋” ๋‚˜์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํŒ€ ๋ฉค๋ฒ„๋“ค๊ณผ ์‚ฌ์šฉ๋œ ํŒจํ„ด์— ๋Œ€ํ•ด ์ถฉ๋ถ„ํžˆ ์†Œํ†ตํ•˜์„ธ์š”. ๋ฌธ์„œํ™”์™€ ์ฝ”๋“œ ์ฃผ์„์„ ์ž˜ ์ž‘์„ฑํ•˜์„ธ์š”.
  • ์„ฑ๋Šฅ์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ์„ ํ•ญ์ƒ ๊ณ ๋ คํ•˜์„ธ์š”. ํŠนํžˆ ๋Ÿฐํƒ€์ž„์— ์˜์กด์„ฑ์„ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒฝ์šฐ ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
  • ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ๋ณต์žกํ•œ DI ์„ค์ •์ด ์˜๋„๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.
  • ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ๊ณ ๊ธ‰ ํ…Œํฌ๋‹‰์„ ์‚ฌ์šฉํ•˜์„ธ์š”. ๊ณผ๋„ํ•œ ์ถ”์ƒํ™”๋Š” ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๊ณ ๊ธ‰ DI ํ…Œํฌ๋‹‰๋“ค์€ ๋ณต์žกํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ์ฝ”๋“œ์˜ ์œ ์—ฐ์„ฑ๊ณผ ํ™•์žฅ์„ฑ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ฐ ํ…Œํฌ๋‹‰์˜ ์žฅ๋‹จ์ ์„ ์ž˜ ์ดํ•ดํ•˜๊ณ , ํ”„๋กœ์ ํŠธ์˜ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๊ฒŒ ์ ์ ˆํžˆ ์„ ํƒํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ์„น์…˜์—์„œ๋Š” DI๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์˜ ์„ฑ๋Šฅ ์ตœ์ ํ™”์™€ ๋ชจ๋ฒ” ์‚ฌ๋ก€์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

6. ์„ฑ๋Šฅ ์ตœ์ ํ™”์™€ ๋ชจ๋ฒ” ์‚ฌ๋ก€ ๐Ÿš€

์˜์กด์„ฑ ์ฃผ์ž…(DI)์€ ์ฝ”๋“œ์˜ ์œ ์—ฐ์„ฑ๊ณผ ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ค์ง€๋งŒ, ์ž˜๋ชป ์‚ฌ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ ์ €ํ•˜๋ฅผ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์„น์…˜์—์„œ๋Š” .NET Core DI๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ์ผ๋ฐ˜์ ์ธ ๋ชจ๋ฒ” ์‚ฌ๋ก€์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

6.1 ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ธฐ๋ฒ•

6.1.1 ์ ์ ˆํ•œ ์ƒ๋ช…์ฃผ๊ธฐ ์„ ํƒ

์„œ๋น„์Šค์˜ ์ƒ๋ช…์ฃผ๊ธฐ(Transient, Scoped, Singleton)๋ฅผ ์‹ ์ค‘ํžˆ ์„ ํƒํ•˜์„ธ์š”. ๋ถˆํ•„์š”ํ•˜๊ฒŒ Transient๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ์ฒด ์ƒ์„ฑ ๋น„์šฉ์ด ์ฆ๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


// ์ข‹์€ ์˜ˆ
services.AddSingleton<IConfiguration, Configuration>();
services.AddScoped<IDbContext, AppDbContext>();
services.AddTransient<IEmailSender, EmailSender>();

6.1.2 ๋ ˆ์ด์ง€ ๋กœ๋”ฉ ํ™œ์šฉ

๋ฌด๊ฑฐ์šด ์˜์กด์„ฑ์˜ ๊ฒฝ์šฐ, Lazy<T>๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•„์š”ํ•  ๋•Œ๋งŒ ์ดˆ๊ธฐํ™”ํ•˜์„ธ์š”.


public class HeavyService
{
    private readonly Lazy<IExpensiveResource> _expensiveResource;

    public HeavyService(Lazy<IExpensiveResource> expensiveResource)
    {
        _expensiveResource = expensiveResource;
    }

    public void DoWork()
    {
        // ํ•„์š”ํ•œ ์‹œ์ ์— ์ดˆ๊ธฐํ™”
        var resource = _expensiveResource.Value;
        // ์ž‘์—… ์ˆ˜ํ–‰
    }
}

6.1.3 ๊ฐ์ฒด ํ’€๋ง ๊ณ ๋ ค

์ž์ฃผ ์ƒ์„ฑ๋˜๊ณ  ํŒŒ๊ดด๋˜๋Š” ๊ฐ์ฒด์˜ ๊ฒฝ์šฐ, ๊ฐ์ฒด ํ’€๋ง์„ ๊ณ ๋ คํ•˜์„ธ์š”.


services.AddTransient<IObjectPool<ExpensiveObject>, DefaultObjectPool<ExpensiveObject>>();
services.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();

6.1.4 ์ปดํŒŒ์ผ ์‹œ์  DI ์‚ฌ์šฉ

์„ฑ๋Šฅ์ด ์ค‘์š”ํ•œ ๊ฒฝ์šฐ, Source Generators๋ฅผ ์‚ฌ์šฉํ•œ ์ปดํŒŒ์ผ ์‹œ์  DI๋ฅผ ๊ณ ๋ คํ•˜์„ธ์š”.


[assembly: InjectableAssembly]

public partial class MyService
{
    [Inject] private readonly IRepository _repository;

    [Inject]
    public MyService() { }

    public void DoSomething()
    {
        _repository.SaveData();
    }
}

6.2 ๋ชจ๋ฒ” ์‚ฌ๋ก€

6.2.1 ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜ ์„ค๊ณ„

๊ตฌ์ฒด์ ์ธ ํด๋ž˜์Šค ๋Œ€์‹  ์ธํ„ฐํŽ˜์ด์Šค์— ์˜์กดํ•˜์„ธ์š”. ์ด๋Š” ์œ ์—ฐ์„ฑ๊ณผ ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.


public class OrderService
{
    private readonly IRepository _repository;
    private readonly ILogger _logger;

    public OrderService(IRepository repository, ILogger logger)
    {
        _repository = repository;
        _logger = logger;
    }
}

6.2.2 ์ƒ์„ฑ์ž ์ฃผ์ž… ์„ ํ˜ธ

๊ฐ€๋Šฅํ•œ ํ•œ ์ƒ์„ฑ์ž ์ฃผ์ž…์„ ์‚ฌ์šฉํ•˜์„ธ์š”. ์ด๋Š” ์˜์กด์„ฑ์„ ๋ช…ํ™•ํžˆ ํ•˜๊ณ  ๋ถˆ๋ณ€์„ฑ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.


public class UserService
{
    private readonly IUserRepository _userRepository;
    private readonly IEmailService _emailService;

    public UserService(IUserRepository userRepository, IEmailService emailService)
    {
        _userRepository = userRepository;
        _emailService = emailService;
    }
}

6.2.3 ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„ ์ตœ์†Œํ™”

์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„๋ฅผ ๊ฐ€๋Šฅํ•œ ํ•œ ์–•๊ฒŒ ์œ ์ง€ํ•˜์„ธ์š”. ๊นŠ์€ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„๋Š” ์„ฑ๋Šฅ ์ €ํ•˜์™€ ๋ณต์žก์„ฑ ์ฆ๊ฐ€๋ฅผ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


// ํ”ผํ•ด์•ผ ํ•  ์˜ˆ
public class DeepService
{
    public DeepService(IDependency1 dep1, IDependency2 dep2, IDependency3 dep3, IDependency4 dep4, IDependency5 dep5)
    {
        // ๋„ˆ๋ฌด ๋งŽ์€ ์˜์กด์„ฑ
    }
}

// ๋” ๋‚˜์€ ์˜ˆ
public class CompositeService
{
    public CompositeService(IServiceGroup serviceGroup)
    {
        // ์˜์กด์„ฑ ๊ทธ๋ฃนํ™”
    }
}

6.2.4 ์„œ๋น„์Šค ๋กœ์ผ€์ดํ„ฐ ํŒจํ„ด ํ”ผํ•˜๊ธฐ

์„œ๋น„์Šค ๋กœ์ผ€์ดํ„ฐ ํŒจํ„ด์€ ์˜์กด์„ฑ์„ ์ˆจ๊ธฐ๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๊ฐ€๋Šฅํ•œ ํ”ผํ•˜์„ธ์š”.


// ํ”ผํ•ด์•ผ ํ•  ์˜ˆ
public class BadExample
{
    public void DoSomething(IServiceProvider serviceProvider)
    {
        var service = serviceProvider.GetService<IMyService>();
        service.Execute();
    }
}

// ๋” ๋‚˜์€ ์˜ˆ
public class GoodExample
{
    private readonly IMyService _service;

    public GoodExample(IMyService service)
    {
        _service = service;
    }

    public void DoSomething()
    {
        _service.Execute();
    }
}

6.2.5 ์ ์ ˆํ•œ ์ถ”์ƒํ™” ์ˆ˜์ค€ ์œ ์ง€

๊ณผ๋„ํ•œ ์ถ”์ƒํ™”๋Š” ์ฝ”๋“œ๋ฅผ ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ ์ ˆํ•œ ์ˆ˜์ค€์˜ ์ถ”์ƒํ™”๋ฅผ ์œ ์ง€ํ•˜์„ธ์š”.


// ๊ณผ๋„ํ•œ ์ถ”์ƒํ™”์˜ ์˜ˆ
public interface IStringManipulator
{
    string Manipulate(string input);
}

public class UpperCaseManipulator : IStringManipulator
{
    public string Manipulate(string input) => input.ToUpper();
}

// ๋” ๊ฐ„๋‹จํ•˜๊ณ  ๋ช…ํ™•ํ•œ ์˜ˆ
public static class StringExtensions
{
    public static string ToUpperCase(this string input) => input.ToUpper();
}

6.2.6 ์„ค์ • ์ค‘์•™ํ™”

DI ์„ค์ •์„ ์ค‘์•™ํ™”ํ•˜์—ฌ ๊ด€๋ฆฌํ•˜์„ธ์š”. ์ด๋Š” ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.


public static class DependencyInjectionConfig
{
    public static IServiceCollection AddApplicationServices(this IServiceCollection services)
    {
        services.AddScoped<IUserService, UserService>();
        services.AddScoped<IOrderService, OrderService>();
        // ๊ธฐํƒ€ ์„œ๋น„์Šค ๋“ฑ๋ก
        return services;
    }
}

// Startup.cs ๋˜๋Š” Program.cs์—์„œ
services.AddApplicationServices();

6.2.7 ์ˆœํ™˜ ์˜์กด์„ฑ ํ”ผํ•˜๊ธฐ

์ˆœํ™˜ ์˜์กด์„ฑ์€ ๋ณต์žก์„ฑ์„ ์ฆ๊ฐ€์‹œํ‚ค๊ณ  ๋””๋ฒ„๊น…์„ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์„ค๊ณ„๋ฅผ ์žฌ๊ณ ํ•˜์—ฌ ์ˆœํ™˜ ์˜์กด์„ฑ์„ ์ œ๊ฑฐํ•˜์„ธ์š”.


// ํ”ผํ•ด์•ผ ํ•  ์˜ˆ (์ˆœํ™˜ ์˜์กด์„ฑ)
public class A
{
    public A(B b) { }
}

public class B
{
    public B(A a) { }
}

// ๋” ๋‚˜์€ ์˜ˆ
public class A
{
    public A(IB b) { }
}

public class B : IB
{
    public B() { }
}

public interface IB { }
๐Ÿ’ก Pro Tip: ์„ฑ๋Šฅ ์ตœ์ ํ™”์™€ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ์ ์šฉํ•  ๋•Œ๋Š” ๋‹ค์Œ ์‚ฌํ•ญ์„ ๊ณ ๋ คํ•˜์„ธ์š”:
  • ์„ฑ๋Šฅ ์ตœ์ ํ™”๋Š” ์ธก์ • ๊ฐ€๋Šฅํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์„ ๋•Œ๋งŒ ์ˆ˜ํ–‰ํ•˜์„ธ์š”. premature optimization์€ ํ”ผํ•˜์„ธ์š”.
  • ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ๋งน๋ชฉ์ ์œผ๋กœ ๋”ฐ๋ฅด์ง€ ๋ง๊ณ , ํ”„๋กœ์ ํŠธ์˜ ํŠน์„ฑ๊ณผ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๊ฒŒ ์ ์šฉํ•˜์„ธ์š”.
  • ํŒ€ ๋‚ด์—์„œ ์ผ๊ด€๋œ DI ํŒจํ„ด๊ณผ ๊ทœ์น™์„ ์ •ํ•˜๊ณ  ๋ฌธ์„œํ™”ํ•˜์„ธ์š”.
  • ์ •๊ธฐ์ ์œผ๋กœ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„๋ฅผ ๊ฒ€ํ† ํ•˜๊ณ  ์ตœ์ ํ™”ํ•˜์„ธ์š”.
  • ์ƒˆ๋กœ์šด .NET Core ๋ฒ„์ „์ด ์ถœ์‹œ๋  ๋•Œ๋งˆ๋‹ค DI ๊ด€๋ จ ๊ฐœ์„ ์‚ฌํ•ญ์„ ํ™•์ธํ•˜๊ณ  ์ ์šฉ์„ ๊ณ ๋ คํ•˜์„ธ์š”.

์ด๋Ÿฌํ•œ ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ธฐ๋ฒ•๊ณผ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ์ ์šฉํ•˜๋ฉด, .NET Core DI๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์„ฑ๋Šฅ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ DI๋ฅผ ํ™œ์šฉํ•˜๋Š” ๊ตฌ์ฒด์ ์ธ ์˜ˆ์‹œ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

7. ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ์˜ DI ํ™œ์šฉ ๐Ÿ—๏ธ

์ด๋ก ์ ์ธ ๊ฐœ๋…์„ ๋„˜์–ด, ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ ์˜์กด์„ฑ ์ฃผ์ž…(DI)์„ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ์„น์…˜์—์„œ๋Š” ๋‹ค์–‘ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์™€ ์˜ˆ์‹œ๋ฅผ ํ†ตํ•ด DI์˜ ์‹ค์ œ ์ ์šฉ ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

7.1 ์›น API ํ”„๋กœ์ ํŠธ์—์„œ์˜ DI ํ™œ์šฉ

ASP.NET Core Web API ํ”„๋กœ์ ํŠธ์—์„œ DI๋ฅผ ํ™œ์šฉํ•˜๋Š” ์˜ˆ์‹œ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


// Startup.cs
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddScoped<IUserRepository, UserRepository>();
        services.AddScoped<IUserService, UserService>();
        services.AddSingleton<IEmailService, EmailService>();
        services.AddHttpClient<IExternalApiClient, ExternalApiClient>();
    }
}

// UserController.cs
[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
    private readonly IUserService _userService;

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

    [HttpGet("{id}")]
    public async Task<IActionResult> GetUser(int id)
    {
        var user = await _userService.GetUserByIdAsync(id);
        if (user == null)
            return NotFound();
        return Ok(user);
    }
}

// UserService.cs
public class UserService : IUserService
{
    private readonly IUserRepository _userRepository;
    private readonly IEmailService _emailService;

    public UserService(IUserRepository userRepository, IEmailService emailService)
    {
        _userRepository = userRepository;
        _emailService = emailService;
    }

    public async Task<User> GetUserByIdAsync(int id)
    {
        var user = await _userRepository.GetByIdAsync(id);
        if (user != null)
        {
            await _emailService.SendEmailAsync(user.Email, "User Retrieved", "Your user information was accessed.");
        }
        return user;
    }
}

7.2 ๋ฏธ๋“ค์›จ์–ด์—์„œ์˜ DI ํ™œ์šฉ

ASP.NET Core ๋ฏธ๋“ค์›จ์–ด์—์„œ DI๋ฅผ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


public class CustomMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;

    public CustomMiddleware(RequestDelegate next, ILogger<CustomMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context, IUserService userService)
    {
        _logger.LogInformation("Executing CustomMiddleware");
        
        if (context.Request.Headers.TryGetValue("User-Id", out var userId))
        {
            var user = await userService.GetUserByIdAsync(int.Parse(userId));
            if (user != null)
            {
                context.Items["CurrentUser"] = user;
            }
        }

        await _next(context);
    }
}

// Startup.cs์—์„œ ๋ฏธ๋“ค์›จ์–ด ๋“ฑ๋ก
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseMiddleware<CustomMiddleware>();
    // ๊ธฐํƒ€ ๋ฏธ๋“ค์›จ์–ด ์„ค์ •
}

7.3 ๋ฐฐ๊ฒฝ ์ž‘์—…์—์„œ์˜ DI ํ™œ์šฉ

IHostedService๋ฅผ ์‚ฌ์šฉํ•œ ๋ฐฐ๊ฒฝ ์ž‘์—…์—์„œ DI๋ฅผ ํ™œ์šฉํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


public class DataCleanupService : BackgroundService
{
    private readonly IServiceProvider _serviceProvider;
    private readonly ILogger<DataCleanupService> _logger;

    public DataCleanupService(IServiceProvider serviceProvider, ILogger<DataCleanupService> logger)
    {
        _serviceProvider = serviceProvider;
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            using (var scope = _serviceProvider.CreateScope())
            {
                var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
                var dateTimeProvider = scope.ServiceProvider.GetRequiredService<IDateTimeProvider>();

                var oldData = await dbContext.TemporaryData
                    .Where(d => d.CreatedAt < dateTimeProvider.Now.AddDays(-30))
                    .ToListAsync(stoppingToken);

                dbContext.TemporaryData.RemoveRange(oldData);
                await dbContext.SaveChangesAsync(stoppingToken);

                _logger.LogInformation($"Cleaned up {oldData.Count} old records");
            }

            await Task.Delay(TimeSpan.FromHours(24), stoppingToken);
        }
    }
}

// Startup.cs์—์„œ ํ˜ธ์Šคํ‹ฐ๋“œ ์„œ๋น„์Šค ๋“ฑ๋ก
services.AddHostedService<DataCleanupService>();

7.4 ํ…Œ์ŠคํŠธ์—์„œ์˜ DI ํ™œ์šฉ

๋‹จ์œ„ ํ…Œ์ŠคํŠธ์—์„œ DI๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์˜์กด์„ฑ์„ ๋ชจ์˜(Mock)ํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


public class UserServiceTests
{
    [Fact]
    public async Task GetUserByIdAsync_ShouldReturnUser_WhenUserExists()
    {
        // Arrange
        var mockRepository = new Mock<IUserRepository>();
        var mockEmailService = new Mock<IEmailService>();
        var expectedUser = new User { Id = 1, Name = "John Doe", Email = "john@example.com" };

        mockRepository.Setup(repo => repo.GetByIdAsync(1))
            .ReturnsAsync(expectedUser);

        var userService = new UserService(mockRepository.Object, mockEmailService.Object);

        // Act
        var result = await userService.GetUserByIdAsync(1);

        // Assert
        Assert.Equal(expectedUser, result);
        mockEmailService.Verify(email => email.SendEmailAsync(
            expectedUser.Email,
            It.IsAny<string>(),
            It.IsAny<string>()
        ), Times.Once);
    }
}

7.5 ์„ค์ • ์ฃผ์ž…

IOptions ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ค์ •์„ ์ฃผ์ž…ํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


public class EmailSettings
{
    public string SmtpServer { get; set; }
    public int Port { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
}

public class EmailService : IEmailService
{
    private readonly EmailSettings _settings;

    public EmailService(IOptions<EmailSettings> settings)
    {
        _settings = settings.Value;
    }

    public async Task SendEmailAsync(string to, string subject, string body)
    {
        using var client = new SmtpClient(_settings.SmtpServer, _settings.Port)
        {
            Credentials = new NetworkCredential(_settings.Username, _settings.Password),
            EnableSsl = true
        };

        await client.SendMailAsync(new MailMessage(_settings.Username, to, subject, body));
    }
}

// Startup.cs์—์„œ ์„ค์ • ๋“ฑ๋ก
services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));
services.AddSingleton<IEmailService, EmailService>();

7.6 ๋‹ค์ค‘ ๊ตฌํ˜„ ์ฃผ์ž…

ํ•˜๋‚˜์˜ ์ธํ„ฐํŽ˜์ด์Šค์— ๋Œ€ํ•ด ์—ฌ๋Ÿฌ ๊ตฌํ˜„์„ ์ฃผ์ž…ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


public interface INotificationChannel
{
    Task SendNotificationAsync(string message);
}

public class EmailNotificationChannel : INotificationChannel { /* ๊ตฌํ˜„ */ }
public class SmsNotificationChannel : INotificationChannel { /* ๊ตฌํ˜„ */ }
public class PushNotificationChannel : INotificationChannel { /* ๊ตฌํ˜„ */ }

public class NotificationService
{
    private readonly IEnumerable<INotificationChannel> _channels;

    public NotificationService(IEnumerable<INotificationChannel> channels)
    {
        _channels = channels;
    }

    public async Task BroadcastNotificationAsync(string message)
    {
        foreach (var channel in _channels)
        {
            await channel.SendNotificationAsync(message  );
        }
    }
}

// Startup.cs์—์„œ ๋“ฑ๋ก
services.AddTransient<INotificationChannel, EmailNotificationChannel>();
services.AddTransient<INotificationChannel, SmsNotificationChannel>();
services.AddTransient<INotificationChannel, PushNotificationChannel>();
services.AddTransient<NotificationService>();

7.7 ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด ํ™œ์šฉ

Scrutor ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด์„ ๊ตฌํ˜„ํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


public interface ICacheService
{
    Task<T> GetOrSetAsync<T>(string key, Func<Task<T>> factory);
}

public class RedisCacheService : ICacheService { /* Redis ๊ตฌํ˜„ */ }

public class CacheDecorator<T> : ICacheService where T : ICacheService
{
    private readonly T _inner;
    private readonly ILogger _logger;

    public CacheDecorator(T inner, ILogger<CacheDecorator<T>> logger)
    {
        _inner = inner;
        _logger = logger;
    }

    public async Task<T> GetOrSetAsync<T>(string key, Func<Task<T>> factory)
    {
        _logger.LogInformation($"Cache operation for key: {key}");
        return await _inner.GetOrSetAsync(key, factory);
    }
}

// Startup.cs์—์„œ ๋“ฑ๋ก
services.AddTransient<ICacheService, RedisCacheService>();
services.Decorate<ICacheService, CacheDecorator<ICacheService>>();

7.8 Factory ํŒจํ„ด ํ™œ์šฉ

๋Ÿฐํƒ€์ž„์— ์ ์ ˆํ•œ ๊ตฌํ˜„์„ ์„ ํƒํ•˜๋Š” Factory ํŒจํ„ด์˜ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


public interface IPaymentProcessor
{
    Task ProcessPaymentAsync(decimal amount);
}

public class StripePaymentProcessor : IPaymentProcessor { /* Stripe ๊ตฌํ˜„ */ }
public class PayPalPaymentProcessor : IPaymentProcessor { /* PayPal ๊ตฌํ˜„ */ }

public interface IPaymentProcessorFactory
{
    IPaymentProcessor CreateProcessor(string paymentMethod);
}

public class PaymentProcessorFactory : IPaymentProcessorFactory
{
    private readonly IServiceProvider _serviceProvider;

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

    public IPaymentProcessor CreateProcessor(string paymentMethod)
    {
        return paymentMethod.ToLower() switch
        {
            "stripe" => _serviceProvider.GetRequiredService<StripePaymentProcessor>(),
            "paypal" => _serviceProvider.GetRequiredService<PayPalPaymentProcessor>(),
            _ => throw new ArgumentException($"Unsupported payment method: {paymentMethod}")
        };
    }
}

// Startup.cs์—์„œ ๋“ฑ๋ก
services.AddTransient<StripePaymentProcessor>();
services.AddTransient<PayPalPaymentProcessor>();
services.AddSingleton<IPaymentProcessorFactory, PaymentProcessorFactory>();

7.9 Lazy ์˜์กด์„ฑ ํ™œ์šฉ

๋ฌด๊ฑฐ์šด ์˜์กด์„ฑ์„ ์ง€์—ฐ ๋กœ๋”ฉํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


public class HeavyService
{
    public HeavyService()
    {
        // ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ์ดˆ๊ธฐํ™” ์ž‘์—…
        Thread.Sleep(5000);
    }

    public void DoWork() { /* ์ž‘์—… ์ˆ˜ํ–‰ */ }
}

public class LightweightService
{
    private readonly Lazy<HeavyService> _heavyService;

    public LightweightService(Lazy<HeavyService> heavyService)
    {
        _heavyService = heavyService;
    }

    public void DoSomething()
    {
        // HeavyService๊ฐ€ ์‹ค์ œ๋กœ ํ•„์š”ํ•œ ์‹œ์ ์— ์ดˆ๊ธฐํ™”
        _heavyService.Value.DoWork();
    }
}

// Startup.cs์—์„œ ๋“ฑ๋ก
services.AddTransient<HeavyService>();
services.AddTransient(sp => new Lazy<HeavyService>(sp.GetRequiredService<HeavyService>));
services.AddTransient<LightweightService>();

7.10 ์Šค์ฝ”ํ”„ ๊ด€๋ฆฌ

์ˆ˜๋™์œผ๋กœ ์Šค์ฝ”ํ”„๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


public class ScopedOperationService
{
    private readonly IServiceScopeFactory _scopeFactory;

    public ScopedOperationService(IServiceScopeFactory scopeFactory)
    {
        _scopeFactory = scopeFactory;
    }

    public async Task PerformScopedOperationAsync()
    {
        using var scope = _scopeFactory.CreateScope();
        var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
        var logger = scope.ServiceProvider.GetRequiredService<ILogger<ScopedOperationService>>();

        // ์Šค์ฝ”ํ”„ ๋‚ด์—์„œ ์ž‘์—… ์ˆ˜ํ–‰
        var entities = await dbContext.Entities.ToListAsync();
        foreach (var entity in entities)
        {
            // ์—”ํ‹ฐํ‹ฐ ์ฒ˜๋ฆฌ
            logger.LogInformation($"Processing entity: {entity.Id}");
        }

        await dbContext.SaveChangesAsync();
    }
}

// Startup.cs์—์„œ ๋“ฑ๋ก
services.AddTransient<ScopedOperationService>();
๐Ÿ’ก Pro Tip: ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ DI๋ฅผ ํ™œ์šฉํ•  ๋•Œ ๋‹ค์Œ ์‚ฌํ•ญ์„ ๊ณ ๋ คํ•˜์„ธ์š”:
  • ํ”„๋กœ์ ํŠธ์˜ ๊ตฌ์กฐ์™€ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๊ฒŒ DI ํŒจํ„ด์„ ์„ ํƒํ•˜์„ธ์š”.
  • ์„ฑ๋Šฅ์— ๋ฏผ๊ฐํ•œ ๋ถ€๋ถ„์—์„œ๋Š” Lazy ๋กœ๋”ฉ์ด๋‚˜ Factory ํŒจํ„ด์„ ๊ณ ๋ คํ•˜์„ธ์š”.
  • ๋ณต์žกํ•œ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„๋Š” ์ฃผ๊ธฐ์ ์œผ๋กœ ๊ฒ€ํ† ํ•˜๊ณ  ์ตœ์ ํ™”ํ•˜์„ธ์š”.
  • ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ์„ ํ•ญ์ƒ ์—ผ๋‘์— ๋‘๊ณ  ์„ค๊ณ„ํ•˜์„ธ์š”.
  • ์ƒˆ๋กœ์šด ํŒ€ ๋ฉค๋ฒ„๋ฅผ ์œ„ํ•ด DI ์„ค์ •๊ณผ ํŒจํ„ด์— ๋Œ€ํ•œ ๋ฌธ์„œ๋ฅผ ์œ ์ง€๋ณด์ˆ˜ํ•˜์„ธ์š”.

์ด๋Ÿฌํ•œ ์‹ค์ œ ์˜ˆ์‹œ๋“ค์„ ํ†ตํ•ด .NET Core์˜ DI ์‹œ์Šคํ…œ์ด ์–ผ๋งˆ๋‚˜ ๊ฐ•๋ ฅํ•˜๊ณ  ์œ ์—ฐํ•œ์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ์˜ ์š”๊ตฌ์‚ฌํ•ญ๊ณผ ๋ณต์žก์„ฑ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ํŒจํ„ด๊ณผ ๊ธฐ๋ฒ•์„ ์„ ํƒํ•˜์—ฌ ์ ์šฉํ•˜๋ฉด, ์œ ์ง€๋ณด์ˆ˜์„ฑ์ด ๋†’๊ณ  ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์‰ฌ์šด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ์„น์…˜์—์„œ๋Š” DI์™€ ๊ด€๋ จ๋œ ํ…Œ์ŠคํŒ… ์ „๋žต์— ๋Œ€ํ•ด ๋” ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

8. ํ…Œ์ŠคํŒ…๊ณผ DI ๐Ÿงช

์˜์กด์„ฑ ์ฃผ์ž…(DI)์€ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์™€ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ๋” ์‰ฝ๊ณ  ํšจ๊ณผ์ ์œผ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ด ์„น์…˜์—์„œ๋Š” DI๋ฅผ ํ™œ์šฉํ•œ ๋‹ค์–‘ํ•œ ํ…Œ์ŠคํŒ… ์ „๋žต๊ณผ ๊ธฐ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

8.1 ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์™€ DI

DI๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์˜์กด์„ฑ์„ ์‰ฝ๊ฒŒ ๋ชจ์˜(Mock)ํ•  ์ˆ˜ ์žˆ์–ด, ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ํ›จ์”ฌ ๊ฐ„๋‹จํ•ด์ง‘๋‹ˆ๋‹ค.


public class OrderService
{
    private readonly IRepository<Order> _orderRepository;
    private readonly IPaymentService _paymentService;

    public OrderService(IRepository<Order> orderRepository, IPaymentService paymentService)
    {
        _orderRepository = orderRepository;
        _paymentService = paymentService;
    }

    public async Task<bool> PlaceOrderAsync(Order order)
    {
        if (await _paymentService.ProcessPaymentAsync(order.TotalAmount))
        {
            await _orderRepository.AddAsync(order);
            return true;
        }
        return false;
    }
}

[Fact]
public async Task PlaceOrderAsync_ShouldReturnTrue_WhenPaymentIsSuccessful()
{
    // Arrange
    var mockOrderRepository = new Mock<IRepository<Order>>();
    var mockPaymentService = new Mock<IPaymentService>();
    var order = new Order { TotalAmount = 100 };

    mockPaymentService.Setup(s => s.ProcessPaymentAsync(It.IsAny<decimal>()))
        .ReturnsAsync(true);

    var orderService = new OrderService(mockOrderRepository.Object, mockPaymentService.Object);

    // Act
    var result = await orderService.PlaceOrderAsync(order);

    // Assert
    Assert.True(result);
    mockOrderRepository.Verify(r => r.AddAsync(order), Times.Once);
}

8.2 ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ์™€ DI

ASP.NET Core์˜ TestServer๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ DI ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์„ค์ •๋œ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


public class OrderControllerIntegrationTests : IClassFixture<WebApplicationFactory<Startup>>
{
    private readonly WebApplicationFactory<Startup> _factory;

    public OrderControllerIntegrationTests(WebApplicationFactory<Startup> factory)
    {
        _factory = factory;
    }

    [Fact]
    public async Task PlaceOrder_ReturnsSuccessStatusCode()
    {
        // Arrange
        var client = _factory.CreateClient();
        var order = new OrderDto { TotalAmount = 100 };

        // Act
        var response = await client.PostAsJsonAsync("/api/orders", order);

        // Assert
        response.EnsureSuccessStatusCode();
        Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType.ToString());
    }
}

8.3 ํ…Œ์ŠคํŠธ์šฉ DI ์ปจํ…Œ์ด๋„ˆ ๊ตฌ์„ฑ

ํ…Œ์ŠคํŠธ์—์„œ ์‹ค์ œ ๊ตฌํ˜„ ๋Œ€์‹  ๋ชจ์˜ ๊ฐ์ฒด๋‚˜ ์ธ๋ฉ”๋ชจ๋ฆฌ ๊ตฌํ˜„์„ ์‚ฌ์šฉํ•˜๋„๋ก DI ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์žฌ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureServices(services =>
        {
            // ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปจํ…์ŠคํŠธ ๋Œ€์‹  ์ธ๋ฉ”๋ชจ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‚ฌ์šฉ
            var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<ApplicationDbContext>));
            if (descriptor != null)
            {
                services.Remove(descriptor);
            }
            services.AddDbContext<ApplicationDbContext>(options =>
            {
                options.UseInMemoryDatabase("InMemoryDbForTesting");
            });

            // ์‹ค์ œ ์„œ๋น„์Šค ๋Œ€์‹  ๋ชจ์˜ ์„œ๋น„์Šค ์‚ฌ์šฉ
            services.AddTransient<IPaymentService, MockPaymentService>();

            // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‹œ๋“œ
            var sp = services.BuildServiceProvider();
            using var scope = sp.CreateScope();
            var scopedServices = scope.ServiceProvider;
            var db = scopedServices.GetRequiredService<ApplicationDbContext>();
            db.Database.EnsureCreated();
            SeedTestData(db);
        });
    }

    private void SeedTestData(ApplicationDbContext context)
    {
        // ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€
    }
}

8.4 ํ…Œ์ŠคํŠธ ๋”๋ธ” ํ™œ์šฉ

DI๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค์–‘ํ•œ ํ…Œ์ŠคํŠธ ๋”๋ธ”(Test Double)์„ ์‰ฝ๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

8.4.1 Stub


public class StubPaymentService : IPaymentService
{
    public Task<bool> ProcessPaymentAsync(decimal amount)
    {
        return Task.FromResult(true); // ํ•ญ์ƒ ์„ฑ๊ณต ๋ฐ˜ํ™˜
    }
}

8.4.2 Mock


var mockPaymentService = new Mock<IPaymentService>();
mockPaymentService.Setup(s => s.ProcessPaymentAsync(It.IsAny<decimal>()))
    .ReturnsAsync(true);

8.4.3 Fake


public class FakeRepository<T> : IRepository<T> where T : class
{
    private readonly List<T> _entities = new List<T>();

    public Task<T> GetByIdAsync(int id)
    {
        return Task.FromResult(_entities.FirstOrDefault());
    }

    public Task AddAsync(T entity)
    {
        _entities.Add(entity);
        return Task.CompletedTask;
    }

    // ๊ธฐํƒ€ IRepository ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
}

8.5 ํ…Œ์ŠคํŠธ ์ปจํ…Œ์ด๋„ˆ ํ™œ์šฉ

์‹ค์ œ ํ™˜๊ฒฝ๊ณผ ์œ ์‚ฌํ•œ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด Docker ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


public class DatabaseFixture : IAsyncLifetime
{
    private const string ConnectionString = "Server=localhost;Database=TestDb;User=sa;Password=YourStrong!Passw0rd;";
    private readonly TestcontainersContainer _dbContainer;

    public DatabaseFixture()
    {
        _dbContainer = new TestcontainersBuilder<TestcontainersContainer>()
            .WithImage("mcr.microsoft.com/mssql/server:2019-latest")
            .WithEnvironment("ACCEPT_EULA", "Y")
            .WithEnvironment("SA_PASSWORD", "YourStrong!Passw0rd")
            .WithPortBinding(1433, true)
            .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(1433))
            .Build();
    }

    public async Task InitializeAsync()
    {
        await _dbContainer.StartAsync();
        // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ ์ƒ์„ฑ ๋ฐ ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ์‚ฝ์ž…
    }

    public async Task DisposeAsync()
    {
        await _dbContainer.StopAsync();
    }

    public string GetConnectionString()
    {
        return ConnectionString.Replace("localhost", _dbContainer.Hostname);
    }
}

public class IntegrationTests : IClassFixture<DatabaseFixture>
{
    private readonly DatabaseFixture _fixture;

    public IntegrationTests(DatabaseFixture fixture)
    {
        _fixture = fixture;
    }

    [Fact]
    public async Task TestWithRealDatabase()
    {
        var connectionString = _fixture.GetConnectionString();
        // connectionString์„ ์‚ฌ์šฉํ•˜์—ฌ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ํ†ต์‹ ํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ˆ˜ํ–‰
    }
}

8.6 ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ์™€ DI

DI ์„ค์ •์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ฑ๋Šฅ์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ์„ ์ธก์ •ํ•˜๋Š” ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


[Benchmark]
public async Task ResolveAndUseService()
{
    using var scope = _serviceProvider.CreateScope();
    var service = scope.ServiceProvider.GetRequiredService<IMyService>();
    await service.DoWorkAsync();
}

8.7 ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€ ํ–ฅ์ƒ

DI๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์˜์กด์„ฑ์„ ์‰ฝ๊ฒŒ ๊ต์ฒดํ•  ์ˆ˜ ์žˆ์–ด, ๋‹ค์–‘ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ ๋†’์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


[Theory]
[InlineData(true, true)]
[InlineData(false, false)]
public async Task PlaceOrderAsync_ShouldReturnExpectedResult(bool paymentSuccess, bool expectedResult)
{
    // Arrange
    var mockOrderRepository = new Mock<IRepository<Order>>();
    var mockPaymentService = new Mock<IPaymentService>();
    var order = new Order { TotalAmount = 100 };

    mockPaymentService.Setup(s => s.ProcessPaymentAsync(It.IsAny<decimal>()))
        .ReturnsAsync(paymentSuccess);

    var orderService = new OrderService(mockOrderRepository.Object, mockPaymentService.Object);

    // Act
    var result = await orderService.PlaceOrderAsync(order);

    // Assert
    Assert.Equal(expectedResult, result);
    mockOrderRepository.Verify(r => r.AddAsync(order), Times.Exactly(paymentSuccess ? 1 : 0));
}
๐Ÿ’ก Pro Tip: DI๋ฅผ ํ™œ์šฉํ•œ ํ…Œ์ŠคํŒ… ์ „๋žต์„ ์ˆ˜๋ฆฝํ•  ๋•Œ ๋‹ค์Œ ์‚ฌํ•ญ์„ ๊ณ ๋ คํ•˜์„ธ์š”:
  • ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์™€ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ์˜ ์ ์ ˆํ•œ ๊ท ํ˜•์„ ์œ ์ง€ํ•˜์„ธ์š”.
  • ํ…Œ์ŠคํŠธ ๋”๋ธ”์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์‹ค์ œ ๊ตฌํ˜„์ฒด์™€์˜ ์ฐจ์ด๋ฅผ ์ตœ์†Œํ™”ํ•˜์„ธ์š”.
  • ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•˜๋Š” DI ์„ค์ •์ด ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ๊ณผ ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•˜์„ธ์š”.
  • ์„ฑ๋Šฅ์— ๋ฏผ๊ฐํ•œ ๋ถ€๋ถ„์— ๋Œ€ํ•ด์„œ๋Š” ๋ฒค์น˜๋งˆํฌ ํ…Œ์ŠคํŠธ๋ฅผ ์ •๊ธฐ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•˜์„ธ์š”.
  • ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ DI ๊ด€๋ จ ์ฝ”๋“œ์˜ ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜์„ธ์š”.

DI๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ํ™œ์šฉํ•œ ํ…Œ์ŠคํŒ… ์ „๋žต์€ ์ฝ”๋“œ์˜ ํ’ˆ์งˆ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ค๊ณ , ๋ฆฌํŒฉํ† ๋ง๊ณผ ๊ธฐ๋Šฅ ์ถ”๊ฐ€๋ฅผ ๋” ์•ˆ์ „ํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜์—์„œ DI๋ฅผ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

9. ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค์™€ DI ๐ŸŒ

๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜์—์„œ ์˜์กด์„ฑ ์ฃผ์ž…(DI)์€ ๋”์šฑ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ์ด ์„น์…˜์—์„œ๋Š” ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ํ™˜๊ฒฝ์—์„œ DI๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ๊ณ ๋ คํ•ด์•ผ ํ•  ์‚ฌํ•ญ๋“ค์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

9.1 ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค์—์„œ์˜ DI ์ค‘์š”์„ฑ

๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜์—์„œ DI๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์œ ๋กœ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค:

  • ์„œ๋น„์Šค ๊ฐ„ ๋Š์Šจํ•œ ๊ฒฐํ•ฉ ์œ ์ง€
  • ์„œ๋น„์Šค ๋…๋ฆฝ์„ฑ ๋ฐ ๊ต์ฒด ์šฉ์ด์„ฑ ํ™•๋ณด
  • ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ ํ–ฅ์ƒ
  • ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ ์ฆ๊ฐ€
  • ํ™•์žฅ์„ฑ ๋ฐ ์œ ์ง€๋ณด์ˆ˜์„ฑ ๊ฐœ์„ 

9.2 ์„œ๋น„์Šค ๊ฐ„ ํ†ต์‹ ๊ณผ DI

๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ๊ฐ„ ํ†ต์‹ ์—์„œ DI๋ฅผ ํ™œ์šฉํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


public interface IUserService
{
    Task<UserDto> GetUserAsync(int userId);
}

public class HttpUserService : IUserService
{
    private readonly HttpClient _httpClient;

    public HttpUserService(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task<UserDto> GetUserAsync(int userId)
    {
        var response = await _httpClient.GetAsync($"/api/users/{userId}");
        response.EnsureSuccessStatusCode();
        return await response.Content.ReadFromJsonAsync<UserDto>();
    }
}

// Startup.cs
services.AddHttpClient<IUserService, HttpUserService>(client =>
{
    client.BaseAddress = new Uri("https://user-service.example.com");
});

9.3 ์„œ๋น„์Šค ๋””์Šค์ปค๋ฒ„๋ฆฌ์™€ DI

๋™์  ์„œ๋น„์Šค ๋””์Šค์ปค๋ฒ„๋ฆฌ๋ฅผ DI์™€ ๊ฒฐํ•ฉํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


public interface IServiceDiscovery
{
    Task<Uri> GetServiceUriAsync(string serviceName);
}

public class ConsulServiceDiscovery : IServiceDiscovery
{
    private readonly IConsulClient _consulClient;

    public ConsulServiceDiscovery(IConsulClient consulClient)
    {
        _consulClient = consulClient;
    }

    public async Task<Uri> GetServiceUriAsync(string serviceName)
    {
        var response = await _consulClient.Health.Service(serviceName, tag: "production");
        var service = response.Response.FirstOrDefault(s => s.Service.Service == serviceName);
        return service != null ? new Uri($"http://{service.Service.Address}:{service.Service.Port}") : null;
    }
}

public class DynamicHttpClientFactory
{
    private readonly IServiceDiscovery _serviceDiscovery;
    private readonly IHttpClientFactory _httpClientFactory;

    public DynamicHttpClientFactory(IServiceDiscovery serviceDiscovery, IHttpClientFactory httpClientFactory)
    {
        _serviceDiscovery = serviceDiscovery;
        _httpClientFactory = httpClientFactory;
    }

    public async Task<HttpClient> CreateClientAsync(string serviceName)
    {
        var serviceUri = await _serviceDiscovery.GetServiceUriAsync(serviceName);
        var client = _httpClientFactory.CreateClient();
        client.BaseAddress = serviceUri;
        return client;
    }
}

// Startup.cs
services.AddSingleton<IServiceDiscovery, ConsulServiceDiscovery>();
services.AddSingleton<DynamicHttpClientFactory>();

9.4 ๊ตฌ์„ฑ ๊ด€๋ฆฌ์™€ DI

์ค‘์•™ ์ง‘์ค‘์‹ ๊ตฌ์„ฑ ๊ด€๋ฆฌ๋ฅผ DI์™€ ํ†ตํ•ฉํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


public interface IConfigurationService
{
    Task<T> GetConfigurationAsync<T>(string key);
}

public class ConsulConfigurationService : IConfigurationService
{
    private readonly IConsulClient _consulClient;

    public ConsulConfigurationService(IConsulClient consulClient)
    {
        _consulClient = consulClient;
    }

    public async Task<T> GetConfigurationAsync<T>(string key)
    {
        var pair = await _consulClient.KV.Get(key);
        if (pair.Response == null)
            throw new KeyNotFoundException($"Configuration key '{key}' not found.");

        var value = Encoding.UTF8.GetString(pair.Response.Value);
        return JsonSerializer.Deserialize<T>(value);
    }
}

public class EmailService
{
    private readonly IConfigurationService _configService;

    public EmailService(IConfigurationService configService)
    {
        _configService = configService;
    }

    public async Task SendEmailAsync(string to, string subject, string body)
    {
        var smtpConfig = await _configService.GetConfigurationAsync<SmtpConfiguration>("email/smtp");
        // smtpConfig๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฉ”์ผ ์ „์†ก
    }
}

// Startup.cs
services.AddSingleton<IConfigurationService, ConsulConfigurationService>();
services.AddTransient<EmailService>();

9.5 ํšŒ๋ณต์„ฑ๊ณผ DI

Polly ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํšŒ๋ณต์„ฑ ํŒจํ„ด์„ DI์™€ ํ†ตํ•ฉํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


public interface IResillientHttpClientFactory
{
    HttpClient CreateClient(string name);
}

public class ResillientHttpClientFactory : IResillientHttpClientFactory
{
    private readonly IHttpClientFactory _httpClientFactory;

    public ResillientHttpClientFactory(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }

    public HttpClient CreateClient(string name)
    {
        var client = _httpClientFactory.CreateClient(name);
        
        var retryPolicy = Policy<HttpResponseMessage>
            .Handle<HttpRequestException>()
            .OrResult(msg => !msg.IsSuccessStatusCode)
            .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));

        var circuitBreakerPolicy = Policy<HttpResponseMessage>
            .Handle<HttpRequestException>()
            .OrResult(msg => !msg.IsSuccessStatusCode)
            .CircuitBreakerAsync(5, TimeSpan.FromMinutes(1));

        var policyWrap = Policy.WrapAsync(retryPolicy, circuitBreakerPolicy);

        client.SendAsync = (request, cancellationToken) => 
            policyWrap.ExecuteAsync(() => client.SendAsync(request, cancellationToken));

        return client;
    }
}

// Startup.cs
services.AddHttpClient();
services.AddSingleton<IResillientHttpClientFactory, ResillientHttpClientFactory>();

9.6 ๋กœ๊น…๊ณผ ๋ชจ๋‹ˆํ„ฐ๋ง

๋ถ„์‚ฐ ๋กœ๊น… ๋ฐ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ์„ DI์™€ ํ†ตํ•ฉํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


public interface IDistributedLogger
{
    Task LogAsync(LogLevel level, string message, params object[] args);
}

public class ElasticSearchLogger : IDistributedLogger
{
    private readonly IElasticClient _elasticClient;

    public ElasticSearchLogger(IElasticClient elasticClient)
    {
        _elasticClient = elasticClient;
    }

    public async Task LogAsync(LogLevel level, string message, params object[] args)
    {
        var logEntry = new LogEntry
        {
            Timestamp = DateTime.UtcNow,
            Level = level,
            Message = string.Format(message, args),
            ServiceName = "MyMicroservice"
        };

        await _elasticClient.IndexDocumentAsync(logEntry);
    }
}

public class OrderService
{
    private readonly IDistributedLogger _logger;

    public OrderService(IDistributedLogger logger)
    {
        _logger = logger;
    }

    public async Task ProcessOrderAsync(Order order)
    {
        await _logger.LogAsync(LogLevel.Information, "Processing order {OrderId}", order.Id);
        // ์ฃผ๋ฌธ ์ฒ˜๋ฆฌ ๋กœ์ง
    }
}

// Startup.cs
services.AddSingleton<IElasticClient>(sp =>
{
    var settings = new ConnectionSettings(new Uri("http://elasticsearch:9200"))
        .DefaultIndex("logs");
    return new ElasticClient(settings);
});
services.AddSingleton<IDistributedLogger, ElasticSearchLogger>();

9.7 ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ

๋ถ„์‚ฐ ํŠธ๋žœ์žญ์…˜์„ DI์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


public interface IDistributedTransactionManager
{
    Task<IDisposable> Be  ginTransactionAsync();
    Task CommitAsync(IDisposable transactionScope);
    Task RollbackAsync(IDisposable transactionScope);
}

public class DistributedTransactionManager : IDistributedTransactionManager
{
    private readonly IServiceProvider _serviceProvider;

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

    public async Task<idisposable> BeginTransactionAsync()
    {
        // ๋ถ„์‚ฐ ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘ ๋กœ์ง
        return new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);
    }

    public async Task CommitAsync(IDisposable transactionScope)
    {
        var scope = transactionScope as TransactionScope;
        scope?.Complete();
        await Task.CompletedTask;
    }

    public async Task RollbackAsync(IDisposable transactionScope)
    {
        var scope = transactionScope as TransactionScope;
        scope?.Dispose();
        await Task.CompletedTask;
    }
}

public class OrderProcessingService
{
    private readonly IDistributedTransactionManager _transactionManager;
    private readonly IOrderRepository _orderRepository;
    private readonly IPaymentService _paymentService;

    public OrderProcessingService(
        IDistributedTransactionManager transactionManager,
        IOrderRepository orderRepository,
        IPaymentService paymentService)
    {
        _transactionManager = transactionManager;
        _orderRepository = orderRepository;
        _paymentService = paymentService;
    }

    public async Task ProcessOrderAsync(Order order)
    {
        using var transaction = await _transactionManager.BeginTransactionAsync();
        try
        {
            await _orderRepository.SaveAsync(order);
            await _paymentService.ProcessPaymentAsync(order.TotalAmount);
            await _transactionManager.CommitAsync(transaction);
        }
        catch
        {
            await _transactionManager.RollbackAsync(transaction);
            throw;
        }
    }
}

// Startup.cs
services.AddSingleton<idistributedtransactionmanager distributedtransactionmanager>();
</idistributedtransactionmanager></idisposable>

9.8 ์„œ๋น„์Šค ๋ฉ”์‹œ์™€ DI

์„œ๋น„์Šค ๋ฉ”์‹œ(์˜ˆ: Istio)์™€ DI๋ฅผ ํ†ตํ•ฉํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


public interface IServiceMesh
{
    Task<string> GetServiceEndpointAsync(string serviceName);
}

public class IstioServiceMesh : IServiceMesh
{
    private readonly HttpClient _httpClient;

    public IstioServiceMesh(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task<string> GetServiceEndpointAsync(string serviceName)
    {
        var response = await _httpClient.GetAsync($"http://istio-pilot.istio-system:8080/v1/registration/{serviceName}");
        response.EnsureSuccessStatusCode();
        var content = await response.Content.ReadAsStringAsync();
        // Istio ์‘๋‹ต ํŒŒ์‹ฑ ๋ฐ ์—”๋“œํฌ์ธํŠธ ๋ฐ˜ํ™˜
        return "http://service-endpoint";
    }
}

public class ServiceClient
{
    private readonly IServiceMesh _serviceMesh;
    private readonly IHttpClientFactory _httpClientFactory;

    public ServiceClient(IServiceMesh serviceMesh, IHttpClientFactory httpClientFactory)
    {
        _serviceMesh = serviceMesh;
        _httpClientFactory = httpClientFactory;
    }

    public async Task<string> CallServiceAsync(string serviceName, string endpoint)
    {
        var serviceEndpoint = await _serviceMesh.GetServiceEndpointAsync(serviceName);
        var client = _httpClientFactory.CreateClient();
        var response = await client.GetAsync($"{serviceEndpoint}/{endpoint}");
        response.EnsureSuccessStatusCode();
        return await response.Content.ReadAsStringAsync();
    }
}

// Startup.cs
services.AddHttpClient<iservicemesh istioservicemesh>();
services.AddTransient<serviceclient>();
</serviceclient></iservicemesh></string></string></string>

9.9 ํ™•์žฅ์„ฑ๊ณผ DI

๋™์  ์Šค์ผ€์ผ๋ง์„ ์ง€์›ํ•˜๋Š” ์„œ๋น„์Šค๋ฅผ DI์™€ ํ•จ๊ป˜ ๊ตฌํ˜„ํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


public interface ILoadBalancer
{
    Task<string> GetNextEndpointAsync(string serviceName);
}

public class RoundRobinLoadBalancer : ILoadBalancer
{
    private readonly IServiceDiscovery _serviceDiscovery;
    private readonly ConcurrentDictionary<string list>> _serviceEndpoints = new();
    private readonly ConcurrentDictionary<string int> _currentIndex = new();

    public RoundRobinLoadBalancer(IServiceDiscovery serviceDiscovery)
    {
        _serviceDiscovery = serviceDiscovery;
    }

    public async Task<string> GetNextEndpointAsync(string serviceName)
    {
        if (!_serviceEndpoints.TryGetValue(serviceName, out var endpoints))
        {
            endpoints = await _serviceDiscovery.GetServiceEndpointsAsync(serviceName);
            _serviceEndpoints[serviceName] = endpoints;
        }

        if (endpoints.Count == 0)
        {
            throw new InvalidOperationException($"No endpoints available for service {serviceName}");
        }

        var index = _currentIndex.AddOrUpdate(serviceName, 0, (_, oldValue) => (oldValue + 1) % endpoints.Count);
        return endpoints[index];
    }
}

public class ScalableServiceClient
{
    private readonly ILoadBalancer _loadBalancer;
    private readonly IHttpClientFactory _httpClientFactory;

    public ScalableServiceClient(ILoadBalancer loadBalancer, IHttpClientFactory httpClientFactory)
    {
        _loadBalancer = loadBalancer;
        _httpClientFactory = httpClientFactory;
    }

    public async Task<string> CallServiceAsync(string serviceName, string endpoint)
    {
        var serviceEndpoint = await _loadBalancer.GetNextEndpointAsync(serviceName);
        var client = _httpClientFactory.CreateClient();
        var response = await client.GetAsync($"{serviceEndpoint}/{endpoint}");
        response.EnsureSuccessStatusCode();
        return await response.Content.ReadAsStringAsync();
    }
}

// Startup.cs
services.AddSingleton<iloadbalancer roundrobinloadbalancer>();
services.AddTransient<scalableserviceclient>();
</scalableserviceclient></iloadbalancer></string></string></string></string></string>

9.10 ๋ณด์•ˆ๊ณผ DI

๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ํ™˜๊ฒฝ์—์„œ ๋ณด์•ˆ์„ DI์™€ ํ†ตํ•ฉํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


public interface ITokenService
{
    Task<string> GetServiceTokenAsync();
}

public class JwtTokenService : ITokenService
{
    private readonly HttpClient _httpClient;
    private readonly IOptions<authsettings> _authSettings;

    public JwtTokenService(HttpClient httpClient, IOptions<authsettings> authSettings)
    {
        _httpClient = httpClient;
        _authSettings = authSettings;
    }

    public async Task<string> GetServiceTokenAsync()
    {
        var response = await _httpClient.PostAsJsonAsync(_authSettings.Value.TokenEndpoint, new
        {
            client_id = _authSettings.Value.ClientId,
            client_secret = _authSettings.Value.ClientSecret,
            grant_type = "client_credentials"
        });

        response.EnsureSuccessStatusCode();
        var tokenResponse = await response.Content.ReadFromJsonAsync<tokenresponse>();
        return tokenResponse.AccessToken;
    }
}

public class SecureServiceClient
{
    private readonly ITokenService _tokenService;
    private readonly IHttpClientFactory _httpClientFactory;

    public SecureServiceClient(ITokenService tokenService, IHttpClientFactory httpClientFactory)
    {
        _tokenService = tokenService;
        _httpClientFactory = httpClientFactory;
    }

    public async Task<string> CallSecureServiceAsync(string serviceUrl, string endpoint)
    {
        var token = await _tokenService.GetServiceTokenAsync();
        var client = _httpClientFactory.CreateClient();
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
        var response = await client.GetAsync($"{serviceUrl}/{endpoint}");
        response.EnsureSuccessStatusCode();
        return await response.Content.ReadAsStringAsync();
    }
}

// Startup.cs
services.AddHttpClient<itokenservice jwttokenservice>();
services.AddTransient<secureserviceclient>();
services.Configure<authsettings>(Configuration.GetSection("AuthSettings"));
</authsettings></secureserviceclient></itokenservice></string></tokenresponse></string></authsettings></authsettings></string>
๐Ÿ’ก Pro Tip: ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ํ™˜๊ฒฝ์—์„œ DI๋ฅผ ํ™œ์šฉํ•  ๋•Œ ๋‹ค์Œ ์‚ฌํ•ญ์„ ๊ณ ๋ คํ•˜์„ธ์š”:
  • ์„œ๋น„์Šค ๊ฐ„ ํ†ต์‹ ์— ์‚ฌ์šฉ๋˜๋Š” ํด๋ผ์ด์–ธํŠธ๋ฅผ ์ถ”์ƒํ™”ํ•˜๊ณ  DI๋ฅผ ํ†ตํ•ด ์ฃผ์ž…ํ•˜์„ธ์š”.
  • ์„œ๋น„์Šค ๋””์Šค์ปค๋ฒ„๋ฆฌ, ๋กœ๋“œ ๋ฐธ๋Ÿฐ์‹ฑ, ํšŒ๋ณต์„ฑ ํŒจํ„ด ๋“ฑ์„ DI ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ†ตํ•ด ์ค‘์•™์—์„œ ๊ด€๋ฆฌํ•˜์„ธ์š”.
  • ๊ตฌ์„ฑ, ๋กœ๊น…, ๋ชจ๋‹ˆํ„ฐ๋ง ๋“ฑ์˜ ํฌ๋กœ์Šค์ปคํŒ… ๊ด€์‹ฌ์‚ฌ๋ฅผ DI๋ฅผ ํ†ตํ•ด ์ผ๊ด€๋˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜์„ธ์š”.
  • ๋ณด์•ˆ ๊ด€๋ จ ๋กœ์ง์„ DI๋ฅผ ํ†ตํ•ด ์ถ”์ƒํ™”ํ•˜์—ฌ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ๋†’์ด์„ธ์š”.
  • ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ๊ฐ„์˜ ์˜์กด์„ฑ์„ ์ตœ์†Œํ™”ํ•˜๊ณ , ํ•„์š”ํ•œ ๊ฒฝ์šฐ DI๋ฅผ ํ†ตํ•ด ๋Š์Šจํ•˜๊ฒŒ ๊ฒฐํ•ฉํ•˜์„ธ์š”.

๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜์—์„œ DI๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ํ™œ์šฉํ•˜๋ฉด, ์„œ๋น„์Šค ๊ฐ„์˜ ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ”๊ณ  ํ™•์žฅ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ ์„œ๋น„์Šค์˜ ๋…๋ฆฝ์„ฑ์„ ์œ ์ง€ํ•˜๋ฉด์„œ๋„ ๊ณตํ†ต ๊ด€์‹ฌ์‚ฌ๋ฅผ ์ผ๊ด€๋˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

10. ๊ฒฐ๋ก  ๋ฐ ํ–ฅํ›„ ์ „๋ง ๐Ÿ”ฎ

์ง€๊ธˆ๊นŒ์ง€ .NET Core์˜ ์˜์กด์„ฑ ์ฃผ์ž…(DI) ์ปจํ…Œ์ด๋„ˆ์— ๋Œ€ํ•ด ๊นŠ์ด ์žˆ๊ฒŒ ์‚ดํŽด๋ณด์•˜์Šต๋‹ˆ๋‹ค. DI๋Š” ํ˜„๋Œ€ ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ์—์„œ ํ•„์ˆ˜์ ์ธ ๊ธฐ์ˆ ์ด๋ฉฐ, .NET Core๋Š” ๊ฐ•๋ ฅํ•˜๊ณ  ์œ ์—ฐํ•œ DI ์‹œ์Šคํ…œ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด์ œ ์šฐ๋ฆฌ๊ฐ€ ํ•™์Šตํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜๊ณ , ์•ž์œผ๋กœ์˜ ์ „๋ง์— ๋Œ€ํ•ด ๋…ผ์˜ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

10.1 ์ฃผ์š” ๋‚ด์šฉ ์š”์•ฝ

  1. DI์˜ ๊ธฐ๋ณธ ๊ฐœ๋…: ์˜์กด์„ฑ ์ฃผ์ž…์˜ ํ•ต์‹ฌ ์›๋ฆฌ์™€ ์ด์ ์— ๋Œ€ํ•ด ํ•™์Šตํ–ˆ์Šต๋‹ˆ๋‹ค.
  2. .NET Core DI ์ปจํ…Œ์ด๋„ˆ: .NET Core์—์„œ ์ œ๊ณตํ•˜๋Š” DI ์ปจํ…Œ์ด๋„ˆ์˜ ํŠน์ง•๊ณผ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด์•˜์Šต๋‹ˆ๋‹ค.
  3. ์„œ๋น„์Šค ์ˆ˜๋ช… ๊ด€๋ฆฌ: Transient, Scoped, Singleton ๋“ฑ ๋‹ค์–‘ํ•œ ์„œ๋น„์Šค ์ˆ˜๋ช… ์˜ต์…˜๊ณผ ๊ทธ ํ™œ์šฉ๋ฒ•์„ ์ดํ•ดํ–ˆ์Šต๋‹ˆ๋‹ค.
  4. DI ๊ตฌํ˜„ ๋ฐฉ๋ฒ•: ์ƒ์„ฑ์ž ์ฃผ์ž…, ์†์„ฑ ์ฃผ์ž…, ๋ฉ”์„œ๋“œ ์ฃผ์ž… ๋“ฑ ๋‹ค์–‘ํ•œ DI ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์„ ํ•™์Šตํ–ˆ์Šต๋‹ˆ๋‹ค.
  5. ๊ณ ๊ธ‰ DI ํ…Œํฌ๋‹‰: ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด, ํŒฉํ† ๋ฆฌ ํŒจํ„ด ๋“ฑ ๊ณ ๊ธ‰ DI ๊ธฐ๋ฒ•์„ ํƒ๊ตฌํ–ˆ์Šต๋‹ˆ๋‹ค.
  6. ์„ฑ๋Šฅ ์ตœ์ ํ™”์™€ ๋ชจ๋ฒ” ์‚ฌ๋ก€: DI ์‚ฌ์šฉ ์‹œ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค.
  7. ์‹ค์ œ ํ”„๋กœ์ ํŠธ ์ ์šฉ: ๋‹ค์–‘ํ•œ ์‹ค์ œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ DI๋ฅผ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์‚ดํŽด๋ณด์•˜์Šต๋‹ˆ๋‹ค.
  8. ํ…Œ์ŠคํŒ…๊ณผ DI: DI๋ฅผ ํ™œ์šฉํ•œ ํšจ๊ณผ์ ์ธ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์™€ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ•์„ ํ•™์Šตํ–ˆ์Šต๋‹ˆ๋‹ค.
  9. ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค์™€ DI: ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜์—์„œ DI๋ฅผ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ํƒ๊ตฌํ–ˆ์Šต๋‹ˆ๋‹ค.

10.2 DI์˜ ์ค‘์š”์„ฑ

์˜์กด์„ฑ ์ฃผ์ž…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์œ ๋กœ ํ˜„๋Œ€ ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ์—์„œ ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค:

  • ์ฝ”๋“œ์˜ ์œ ์—ฐ์„ฑ ํ–ฅ์ƒ: DI๋ฅผ ํ†ตํ•ด ๊ตฌ์ฒด์ ์ธ ๊ตฌํ˜„์— ์˜์กดํ•˜์ง€ ์•Š๊ณ  ์ถ”์ƒํ™”์— ์˜์กดํ•  ์ˆ˜ ์žˆ์–ด, ์ฝ”๋“œ์˜ ์œ ์—ฐ์„ฑ์ด ํฌ๊ฒŒ ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.
  • ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ: ์˜์กด์„ฑ์„ ์‰ฝ๊ฒŒ ๋ชจ์˜(Mock)ํ•  ์ˆ˜ ์žˆ์–ด, ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ํ›จ์”ฌ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค.
  • ๊ด€์‹ฌ์‚ฌ์˜ ๋ถ„๋ฆฌ: DI๋Š” ๊ฐ์ฒด ์ƒ์„ฑ๊ณผ ์‚ฌ์šฉ์„ ๋ถ„๋ฆฌํ•˜์—ฌ ๋‹จ์ผ ์ฑ…์ž„ ์›์น™์„ ์ง€ํ‚ค๋Š” ๋ฐ ๋„์›€์„ ์ค๋‹ˆ๋‹ค.
  • ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ: ์˜์กด์„ฑ์„ ์ถ”์ƒํ™”ํ•จ์œผ๋กœ์จ ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋†’์•„์ง‘๋‹ˆ๋‹ค.
  • ์œ ์ง€๋ณด์ˆ˜์„ฑ ํ–ฅ์ƒ: ๋Š์Šจํ•œ ๊ฒฐํ•ฉ์„ ํ†ตํ•ด ์ฝ”๋“œ์˜ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค.

10.3 .NET Core DI์˜ ๊ฐ•์ 

.NET Core์˜ DI ์‹œ์Šคํ…œ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฐ•์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค:

  • ๋‚ด์žฅํ˜• ์†”๋ฃจ์…˜: ๋ณ„๋„์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—†์ด ํ”„๋ ˆ์ž„์›Œํฌ์— ๊ธฐ๋ณธ์œผ๋กœ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์„ฑ๋Šฅ ์ตœ์ ํ™”: Microsoft์— ์˜ํ•ด ์ง€์†์ ์œผ๋กœ ์ตœ์ ํ™”๋˜์–ด ๋†’์€ ์„ฑ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  • ํ™•์žฅ์„ฑ: ์‚ฌ์šฉ์ž ์ •์˜ ๊ธฐ๋Šฅ์„ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ํ™•์žฅ ํฌ์ธํŠธ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  • ํ†ตํ•ฉ์„ฑ: ASP.NET Core ๋ฐ ๋‹ค๋ฅธ .NET ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค๊ณผ ๊ธด๋ฐ€ํ•˜๊ฒŒ ํ†ตํ•ฉ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ง€์†์ ์ธ ๊ฐœ์„ : ๊ฐ .NET ๋ฒ„์ „๋งˆ๋‹ค ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ๊ณผ ๊ฐœ์„ ์‚ฌํ•ญ์ด ์ถ”๊ฐ€๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

10.4 ํ–ฅํ›„ ์ „๋ง

์˜์กด์„ฑ ์ฃผ์ž…๊ณผ .NET Core DI ์‹œ์Šคํ…œ์˜ ๋ฏธ๋ž˜๋Š” ๋งค์šฐ ๋ฐ์•„ ๋ณด์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŠธ๋ Œ๋“œ์™€ ๋ฐœ์ „์ด ์˜ˆ์ƒ๋ฉ๋‹ˆ๋‹ค:

  1. ์ปดํŒŒ์ผ ์‹œ์  ์ตœ์ ํ™”: ์†Œ์Šค ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋ฅผ ํ™œ์šฉํ•œ ์ปดํŒŒ์ผ ์‹œ์  DI ์ตœ์ ํ™”๊ฐ€ ๋”์šฑ ๋ฐœ์ „ํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋ฉ๋‹ˆ๋‹ค.
  2. ํด๋ผ์šฐ๋“œ ๋„ค์ดํ‹ฐ๋ธŒ ํ†ตํ•ฉ: ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค, ์„œ๋น„์Šค ๋ฉ”์‹œ ๋“ฑ ํด๋ผ์šฐ๋“œ ๋„ค์ดํ‹ฐ๋ธŒ ๊ธฐ์ˆ ๊ณผ์˜ ๋” ๊นŠ์€ ํ†ตํ•ฉ์ด ์ด๋ฃจ์–ด์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  3. AI/ML ํ†ตํ•ฉ: ์ธ๊ณต์ง€๋Šฅ๊ณผ ๋จธ์‹ ๋Ÿฌ๋‹ ์„œ๋น„์Šค๋ฅผ ๋” ์‰ฝ๊ฒŒ ์ฃผ์ž…ํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ๊ฐœ๋ฐœ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  4. ํฌ๋กœ์Šค ํ”Œ๋žซํผ ์ง€์› ๊ฐ•ํ™”: .NET์˜ ํฌ๋กœ์Šค ํ”Œ๋žซํผ ํŠน์„ฑ์— ๋งž์ถฐ ๋‹ค์–‘ํ•œ ํ™˜๊ฒฝ์—์„œ์˜ DI ์ง€์›์ด ๊ฐ•ํ™”๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  5. ์„ฑ๋Šฅ ํ–ฅ์ƒ: ์ง€์†์ ์ธ ์ตœ์ ํ™”๋ฅผ ํ†ตํ•ด DI ์‹œ์Šคํ…œ์˜ ์„ฑ๋Šฅ์ด ๋”์šฑ ํ–ฅ์ƒ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  6. ๋ณด์•ˆ ๊ฐ•ํ™”: ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ†ตํ•œ ๋ณด์•ˆ ๊ธฐ๋Šฅ ํ†ตํ•ฉ์ด ๋”์šฑ ๊ฐ•ํ™”๋  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋ฉ๋‹ˆ๋‹ค.
  7. ๊ฐœ๋ฐœ์ž ๊ฒฝํ—˜ ๊ฐœ์„ : DI ์„ค์ •๊ณผ ์‚ฌ์šฉ์„ ๋”์šฑ ์ง๊ด€์ ์ด๊ณ  ์‰ฝ๊ฒŒ ๋งŒ๋“œ๋Š” ๋„๊ตฌ์™€ ๊ธฐ๋Šฅ์ด ๊ฐœ๋ฐœ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

10.5 ๊ฐœ๋ฐœ์ž๋ฅผ ์œ„ํ•œ ์กฐ์–ธ

์˜์กด์„ฑ ์ฃผ์ž…๊ณผ .NET Core DI๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ํ™œ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์กฐ์–ธ์„ ๋“œ๋ฆฝ๋‹ˆ๋‹ค:

  • ์ง€์†์ ์ธ ํ•™์Šต: DI ํŒจํ„ด๊ณผ .NET Core์˜ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด ์ง€์†์ ์œผ๋กœ ํ•™์Šตํ•˜์„ธ์š”.
  • ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ์šฉ: ์ด๋ก ์  ์ง€์‹์„ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ๊ทน์ ์œผ๋กœ ์ ์šฉํ•ด ๋ณด์„ธ์š”.
  • ์ปค๋ฎค๋‹ˆํ‹ฐ ์ฐธ์—ฌ: .NET ์ปค๋ฎค๋‹ˆํ‹ฐ์— ์ฐธ์—ฌํ•˜์—ฌ ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค๊ณผ ๊ฒฝํ—˜์„ ๊ณต์œ ํ•˜์„ธ์š”.
  • ์ฝ”๋“œ ๋ฆฌ๋ทฐ: ๋™๋ฃŒ๋“ค๊ณผ DI ๊ด€๋ จ ์ฝ”๋“œ ๋ฆฌ๋ทฐ๋ฅผ ์ž์ฃผ ํ•˜์—ฌ ์ตœ์„ ์˜ ๋ฐฉ๋ฒ•์„ ์ฐพ์•„๊ฐ€์„ธ์š”.
  • ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง: DI ์‚ฌ์šฉ์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ฑ๋Šฅ์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ์„ ์ฃผ๊ธฐ์ ์œผ๋กœ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜์„ธ์š”.
  • ์„ค๊ณ„ ์›์น™ ์ค€์ˆ˜: SOLID ์›์น™ ๋“ฑ ๊ฐ์ฒด ์ง€ํ–ฅ ์„ค๊ณ„ ์›์น™์„ ํ•ญ์ƒ ์—ผ๋‘์— ๋‘์„ธ์š”.
  • ํ…Œ์ŠคํŠธ ์ฃผ๋„ ๊ฐœ๋ฐœ: DI๋ฅผ ํ™œ์šฉํ•œ ํ…Œ์ŠคํŠธ ์ฃผ๋„ ๊ฐœ๋ฐœ(TDD)์„ ์‹ค์ฒœํ•ด ๋ณด์„ธ์š”.
๐Ÿ’ก Final Thought: ์˜์กด์„ฑ ์ฃผ์ž…์€ ๋‹จ์ˆœํ•œ ๊ธฐ์ˆ ์ด ์•„๋‹Œ ์„ค๊ณ„ ์ฒ ํ•™์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ๊นŠ์ด ์ดํ•ดํ•˜๊ณ  ์ ์ ˆํžˆ ํ™œ์šฉํ•จ์œผ๋กœ์จ, ์šฐ๋ฆฌ๋Š” ๋” ์œ ์—ฐํ•˜๊ณ , ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์‰ฌ์šด ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. .NET Core์˜ DI ์‹œ์Šคํ…œ์€ ์ด๋Ÿฌํ•œ ๋ชฉํ‘œ๋ฅผ ๋‹ฌ์„ฑํ•˜๋Š” ๋ฐ ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ์•ž์œผ๋กœ๋„ ๊ณ„์†ํ•ด์„œ ๋ฐœ์ „ํ•˜๋Š” ์ด ๊ธฐ์ˆ ์„ ์ฃผ์‹œํ•˜๊ณ , ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ์— ์ ๊ทน์ ์œผ๋กœ ์ ์šฉํ•ด ๋ณด์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์˜์กด์„ฑ ์ฃผ์ž…๊ณผ .NET Core DI์— ๋Œ€ํ•œ ์šฐ๋ฆฌ์˜ ์—ฌ์ •์ด ์—ฌ๊ธฐ์„œ ๋๋‚ฉ๋‹ˆ๋‹ค. ์ด ์ง€์‹์ด ์—ฌ๋Ÿฌ๋ถ„์˜ ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ ์—ฌ์ •์— ํฐ ๋„์›€์ด ๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ํ•ญ์ƒ ํ•™์Šตํ•˜๊ณ , ์‹คํ—˜ํ•˜๊ณ , ๊ฐœ์„ ํ•˜๋Š” ์ž์„ธ๋ฅผ ์žƒ์ง€ ๋งˆ์„ธ์š”. ํ–‰์šด์„ ๋น•๋‹ˆ๋‹ค!