๐Ÿš€ .NET Core ์ฝ˜์†” ์•ฑ์—์„œ ์˜์กด์„ฑ ์ฃผ์ž… ์‚ฌ์šฉํ•˜๊ธฐ

์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿš€ .NET Core ์ฝ˜์†” ์•ฑ์—์„œ ์˜์กด์„ฑ ์ฃผ์ž… ์‚ฌ์šฉํ•˜๊ธฐ

 

 

์•ˆ๋…•ํ•˜์„ธ์š”, ์žฌ๋Šฅ๋„ท ๋…์ž ์—ฌ๋Ÿฌ๋ถ„! ์˜ค๋Š˜์€ .NET Core ์ฝ˜์†” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์˜์กด์„ฑ ์ฃผ์ž…(Dependency Injection, DI)์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ๊ธ€์„ ํ†ตํ•ด ์—ฌ๋Ÿฌ๋ถ„์€ ์ฝ˜์†” ์•ฑ์—์„œ๋„ ์˜์กด์„ฑ ์ฃผ์ž…์˜ ๊ฐ•๋ ฅํ•œ ์ด์ ์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๐ŸŽ‰

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

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

์ž, ๊ทธ๋Ÿผ ์ง€๊ธˆ๋ถ€ํ„ฐ .NET Core ์ฝ˜์†” ์•ฑ์˜ ์„ธ๊ณ„์— ์˜์กด์„ฑ ์ฃผ์ž…์ด๋ผ๋Š” ๋งˆ๋ฒ•์„ ๋ถˆ์–ด๋„ฃ์–ด ๋ณผ๊นŒ์š”? ๐Ÿ’ซ

๐Ÿ“š ๋ชฉ์ฐจ

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

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

์˜์กด์„ฑ ์ฃผ์ž…์€ ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ์ค‘์š”ํ•œ ๋””์ž์ธ ํŒจํ„ด ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ์ด ๊ฐœ๋…์„ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด, ๋จผ์ € '์˜์กด์„ฑ'์ด ๋ฌด์—‡์ธ์ง€ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

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

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


public class EmailService
{
    public void SendEmail(string to, string subject, string body)
    {
        // ์ด๋ฉ”์ผ ์ „์†ก ๋กœ์ง
    }
}

public class UserService
{
    private EmailService _emailService = new EmailService();

    public void RegisterUser(string email)
    {
        // ์‚ฌ์šฉ์ž ๋“ฑ๋ก ๋กœ์ง
        _emailService.SendEmail(email, "Welcome!", "Welcome to our service!");
    }
}
  

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

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

์˜์กด์„ฑ ์ฃผ์ž…์€ ์ด๋Ÿฌํ•œ ์˜์กด ๊ด€๊ณ„๋ฅผ ์™ธ๋ถ€์—์„œ ์ฃผ์ž…ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์ฆ‰, ํด๋ž˜์Šค๊ฐ€ ์˜์กดํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•˜๋Š” ๋Œ€์‹ , ์™ธ๋ถ€์—์„œ ์ƒ์„ฑ๋œ ๊ฐ์ฒด๋ฅผ ๋ฐ›์•„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์œ„์˜ ์˜ˆ์ œ๋ฅผ ์˜์กด์„ฑ ์ฃผ์ž… ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:


public class UserService
{
    private readonly IEmailService _emailService;

    public UserService(IEmailService emailService)
    {
        _emailService = emailService;
    }

    public void RegisterUser(string email)
    {
        // ์‚ฌ์šฉ์ž ๋“ฑ๋ก ๋กœ์ง
        _emailService.SendEmail(email, "Welcome!", "Welcome to our service!");
    }
}
  

์ด์ œ UserService๋Š” IEmailService ์ธํ„ฐํŽ˜์ด์Šค์— ์˜์กดํ•˜๋ฉฐ, ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์ด ์˜์กด์„ฑ์„ ์ฃผ์ž…๋ฐ›์Šต๋‹ˆ๋‹ค.

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

  1. ๋Š์Šจํ•œ ๊ฒฐํ•ฉ: ํด๋ž˜์Šค ๊ฐ„์˜ ์˜์กด์„ฑ์ด ์ค„์–ด๋“ค์–ด ์ฝ”๋“œ์˜ ์œ ์—ฐ์„ฑ์ด ์ฆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  2. ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ: ๋ชฉ(mock) ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์‰ฝ๊ฒŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ์œ ์ง€๋ณด์ˆ˜์„ฑ: ์˜์กดํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์‰ฝ๊ฒŒ ๊ต์ฒดํ•  ์ˆ˜ ์žˆ์–ด ์ฝ”๋“œ ์ˆ˜์ •์ด ์šฉ์ดํ•ฉ๋‹ˆ๋‹ค.
  4. ์žฌ์‚ฌ์šฉ์„ฑ: ๋™์ผํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋‹ค์–‘ํ•œ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

์˜์กด์„ฑ ์ฃผ์ž…์€ ์ฃผ๋กœ ์„ธ ๊ฐ€์ง€ ๋ฐฉ์‹์œผ๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค:

  1. ์ƒ์„ฑ์ž ์ฃผ์ž…: ๊ฐ€์žฅ ํ”ํžˆ ์‚ฌ์šฉ๋˜๋Š” ๋ฐฉ์‹์œผ๋กœ, ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์˜์กด์„ฑ์„ ์ฃผ์ž…๋ฐ›์Šต๋‹ˆ๋‹ค.
  2. ์†์„ฑ ์ฃผ์ž…: ๊ณต๊ฐœ ์†์„ฑ์„ ํ†ตํ•ด ์˜์กด์„ฑ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ฉ”์„œ๋“œ ์ฃผ์ž…: ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์„ ํ†ตํ•ด ์˜์กด์„ฑ์„ ์ „๋‹ฌ๋ฐ›์Šต๋‹ˆ๋‹ค.

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

์˜์กด์„ฑ ์ฃผ์ž…์˜ ์œ ํ˜• ์ƒ์„ฑ์ž ์ฃผ์ž… ๊ฐ€์žฅ ํ”ํžˆ ์‚ฌ์šฉ๋จ ๊ฐ์ฒด ์ƒ์„ฑ ์‹œ ์˜์กด์„ฑ ์ œ๊ณต ํ•ญ์ƒ ์œ ํšจํ•œ ์ƒํƒœ ๋ณด์žฅ ์†์„ฑ ์ฃผ์ž… ๊ณต๊ฐœ ์†์„ฑ์œผ๋กœ ์„ค์ • ์„ ํƒ์  ์˜์กด์„ฑ์— ์œ ์šฉ ๋Ÿฐํƒ€์ž„ ์‹œ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ ๋ฉ”์„œ๋“œ ์ฃผ์ž… ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ๋กœ ์ „๋‹ฌ ๋™์ ์ธ ์˜์กด์„ฑ์— ์ ํ•ฉ ๋ฉ”์„œ๋“œ๋ณ„ ์˜์กด์„ฑ ์ง€์ •

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

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

2. .NET Core์˜ ์˜์กด์„ฑ ์ฃผ์ž… ์ปจํ…Œ์ด๋„ˆ ์†Œ๊ฐœ ๐Ÿงฐ

.NET Core๋Š” ๊ฐ•๋ ฅํ•˜๊ณ  ์œ ์—ฐํ•œ ๋‚ด์žฅ ์˜์กด์„ฑ ์ฃผ์ž… ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด ์ปจํ…Œ์ด๋„ˆ๋Š” Microsoft.Extensions.DependencyInjection ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉฐ, ASP.NET Core ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ฝ˜์†” ์•ฑ์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

DI ์ปจํ…Œ์ด๋„ˆ์˜ ์ฃผ์š” ๊ตฌ์„ฑ ์š”์†Œ

  1. IServiceCollection: ์„œ๋น„์Šค ๋“ฑ๋ก์„ ์œ„ํ•œ ์ธํ„ฐํŽ˜์ด์Šค
  2. ServiceProvider: ๋“ฑ๋ก๋œ ์„œ๋น„์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ํŒฉํ† ๋ฆฌ
  3. ServiceDescriptor: ์„œ๋น„์Šค ๋“ฑ๋ก ์ •๋ณด๋ฅผ ๋‹ด๋Š” ํด๋ž˜์Šค

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

์„œ๋น„์Šค๋ฅผ ๋“ฑ๋กํ•˜๋Š” ์ฃผ์š” ๋ฉ”์„œ๋“œ๋“ค์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • AddTransient<TService, TImplementation>(): ์š”์ฒญํ•  ๋•Œ๋งˆ๋‹ค ์ƒˆ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
  • AddScoped<TService, TImplementation>(): ๋ฒ”์œ„(์ฃผ๋กœ ์›น ์š”์ฒญ) ๋‹น ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
  • AddSingleton<TService, TImplementation>(): ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด์—์„œ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋งŒ ์‚ฌ์šฉ

์ด๋Ÿฌํ•œ ๋ฉ”์„œ๋“œ๋“ค์€ IServiceCollection ์ธํ„ฐํŽ˜์ด์Šค์˜ ํ™•์žฅ ๋ฉ”์„œ๋“œ๋กœ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ์‚ฌ์šฉ ์˜ˆ์ œ

๋‹ค์Œ์€ .NET Core์˜ DI ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋ณธ์ ์ธ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค:


using Microsoft.Extensions.DependencyInjection;

public class Program
{
    public static void Main(string[] args)
    {
        // ์„œ๋น„์Šค ์ปฌ๋ ‰์…˜ ์ƒ์„ฑ
        var services = new ServiceCollection();

        // ์„œ๋น„์Šค ๋“ฑ๋ก
        services.AddTransient<IMyService, MyService>();

        // ์„œ๋น„์Šค ํ”„๋กœ๋ฐ”์ด๋” ์ƒ์„ฑ
        var serviceProvider = services.BuildServiceProvider();

        // ์„œ๋น„์Šค ์‚ฌ์šฉ
        var myService = serviceProvider.GetService<IMyService>();
        myService.DoSomething();
    }
}

public interface IMyService
{
    void DoSomething();
}

public class MyService : IMyService
{
    public void DoSomething()
    {
        Console.WriteLine("Doing something...");
    }
}
  

DI ์ปจํ…Œ์ด๋„ˆ์˜ ์ž‘๋™ ์›๋ฆฌ

.NET Core์˜ DI ์ปจํ…Œ์ด๋„ˆ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ณผ์ •์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค:

  1. ์„œ๋น„์Šค ๋“ฑ๋ก: IServiceCollection์— ์„œ๋น„์Šค์™€ ๊ทธ ๊ตฌํ˜„์„ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.
  2. ์„œ๋น„์Šค ํ”„๋กœ๋ฐ”์ด๋” ์ƒ์„ฑ: BuildServiceProvider() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ IServiceProvider ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  3. ์„œ๋น„์Šค ํ•ด๊ฒฐ: GetService<T>() ๋˜๋Š” GetRequiredService<T>() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•„์š”ํ•œ ์„œ๋น„์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค.
DI ์ปจํ…Œ์ด๋„ˆ ์ž‘๋™ ์›๋ฆฌ ์„œ๋น„์Šค ๋“ฑ๋ก ์„œ๋น„์Šค ํ”„๋กœ๋ฐ”์ด๋” ์ƒ์„ฑ ์„œ๋น„์Šค ํ•ด๊ฒฐ ์„œ๋น„์Šค ์ˆ˜๋ช… ๊ด€๋ฆฌ Transient: ๋งค๋ฒˆ ์ƒˆ ์ธ์Šคํ„ด์Šค Scoped: ๋ฒ”์œ„ ๋‚ด ๋‹จ์ผ ์ธ์Šคํ„ด์Šค Singleton: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด ๋‹จ์ผ ์ธ์Šคํ„ด์Šค

DI ์ปจํ…Œ์ด๋„ˆ์˜ ์žฅ์ 

  • ์ž๋™ ์˜์กด์„ฑ ํ•ด๊ฒฐ: ๋ณต์žกํ•œ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„๋„ ์ž๋™์œผ๋กœ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
  • ์ˆ˜๋ช… ๊ด€๋ฆฌ: ์„œ๋น„์Šค์˜ ์ˆ˜๋ช…์„ ์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ: ๋ชฉ(mock) ๊ฐ์ฒด๋ฅผ ์‰ฝ๊ฒŒ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ์–ด ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ์šฉ์ดํ•ฉ๋‹ˆ๋‹ค.
  • ๊ตฌ์„ฑ์˜ ์ค‘์•™ํ™”: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์˜์กด์„ฑ ๊ตฌ์„ฑ์„ ํ•œ ๊ณณ์—์„œ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

DI ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค:

  • ์ˆœํ™˜ ์˜์กด์„ฑ์„ ํ”ผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์„œ๋น„์Šค์˜ ์ˆ˜๋ช…์„ ์ ์ ˆํžˆ ์„ ํƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์ปจํ…Œ์ด๋„ˆ์— ๋„ˆ๋ฌด ๋งŽ์€ ์ฑ…์ž„์„ ๋ถ€์—ฌํ•˜์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

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

์žฌ๋Šฅ๋„ท์—์„œ ์ œ๊ณตํ•˜๋Š” ์ด ๊ธ€์„ ํ†ตํ•ด, ์—ฌ๋Ÿฌ๋ถ„์€ .NET Core์˜ ๊ฐ•๋ ฅํ•œ DI ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜์—ฌ ๋” ์œ ์—ฐํ•˜๊ณ  ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์‰ฌ์šด ์ฝ˜์†” ์•ฑ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ณ„์†ํ•ด์„œ ๋‹ค์Œ ๋‚ด์šฉ์„ ์‚ดํŽด๋ณด์‹œ์ฃ !

3. ์ฝ˜์†” ์•ฑ์—์„œ ์˜์กด์„ฑ ์ฃผ์ž… ์„ค์ •ํ•˜๊ธฐ ๐Ÿ”ง

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

1. ํ”„๋กœ์ ํŠธ ์„ค์ •

๋จผ์ €, ์ƒˆ๋กœ์šด .NET Core ์ฝ˜์†” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ•„์š”ํ•œ NuGet ํŒจํ‚ค์ง€๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค:


dotnet new console -n MyConsoleApp
cd MyConsoleApp
dotnet add package Microsoft.Extensions.DependencyInjection
dotnet add package Microsoft.Extensions.Hosting
  

Microsoft.Extensions.Hosting ํŒจํ‚ค์ง€๋Š” ์˜์กด์„ฑ ์ฃผ์ž… ์„ค์ •์„ ๋” ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” IHost ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

2. ํ”„๋กœ๊ทธ๋žจ ๊ตฌ์กฐ ์„ค์ •

์ด์ œ Program.cs ํŒŒ์ผ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค:


using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

class Program
{
    static async Task Main(string[] args)
    {
        var host = CreateHostBuilder(args).Build();
        await host.RunAsync();
    }

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

public interface IMyService
{
    void DoWork();
}

public class MyService : IMyService
{
    public void DoWork()
    {
        Console.WriteLine("Doing some work!");
    }
}

public class MyHostedService : IHostedService
{
    private readonly IMyService _myService;

    public MyHostedService(IMyService myService)
    {
        _myService = myService;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _myService.DoWork();
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }
}
  

3. ์ฝ”๋“œ ์„ค๋ช…

  • CreateHostBuilder ๋ฉ”์„œ๋“œ๋Š” IHostBuilder๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ตฌ์„ฑ, ๋กœ๊น…, DI ์ปจํ…Œ์ด๋„ˆ ์„ค์ • ๋“ฑ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค.
  • ConfigureServices ๋ฉ”์„œ๋“œ ๋‚ด์—์„œ ์„œ๋น„์Šค๋ฅผ DI ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.
  • AddHostedService๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ MyHostedService๋ฅผ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์„œ๋น„์Šค๋กœ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค. ์ด ์„œ๋น„์Šค๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹œ์ž‘๋  ๋•Œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
  • MyHostedService๋Š” ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด IMyService๋ฅผ ์ฃผ์ž…๋ฐ›์Šต๋‹ˆ๋‹ค.

4. ์˜์กด์„ฑ ์ฃผ์ž… ์ž‘๋™ ์›๋ฆฌ

์ฝ˜์†” ์•ฑ์—์„œ์˜ ์˜์กด์„ฑ ์ฃผ์ž… ํ๋ฆ„ CreateHostBuilder ConfigureServices Build Host Run Host MyHostedService.StartAsync

์ด ๋‹ค์ด์–ด๊ทธ๋žจ์€ ์ฝ˜์†” ์•ฑ์—์„œ ์˜์กด์„ฑ ์ฃผ์ž…์ด ์–ด๋–ป๊ฒŒ ์„ค์ •๋˜๊ณ  ์‹คํ–‰๋˜๋Š”์ง€๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

5. ์‹คํ–‰ ๋ฐ ํ…Œ์ŠคํŠธ

์ด์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•˜๋ฉด, MyHostedService๊ฐ€ ์‹œ์ž‘๋˜๊ณ  IMyService์˜ DoWork ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.


dotnet run
  

์ถœ๋ ฅ:


Doing some work!
  

6. ์žฅ์  ๋ฐ ์ฃผ์˜์‚ฌํ•ญ

์žฅ์ :

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

์ฃผ์˜์‚ฌํ•ญ:

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

์ด์ œ ์—ฌ๋Ÿฌ๋ถ„์€ .NET Core ์ฝ˜์†” ์•ฑ์—์„œ ์˜์กด์„ฑ ์ฃผ์ž…์„ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์› ์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ์ˆ ์„ ํ™œ์šฉํ•˜๋ฉด, ์žฌ๋Šฅ๋„ท๊ณผ ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ ์ œ๊ณตํ•˜๋Š” ๋‹ค์–‘ํ•œ ์„œ๋น„์Šค๋“ค์„ ๋” ํšจ์œจ์ ์œผ๋กœ ํ†ตํ•ฉํ•˜๊ณ  ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ์„œ๋น„์Šค ๋“ฑ๋ก๊ณผ ์ˆ˜๋ช… ๊ด€๋ฆฌ์— ๋Œ€ํ•ด ๋” ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๐Ÿš€

4. ์„œ๋น„์Šค ๋“ฑ๋ก๊ณผ ์ˆ˜๋ช… ๊ด€๋ฆฌ โณ

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

์„œ๋น„์Šค ์ˆ˜๋ช… ์œ ํ˜•

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

1. Transient (์ผ์‹œ์ ) ์„œ๋น„์Šค

Transient ์„œ๋น„์Šค๋Š” ์š”์ฒญ๋  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.


services.AddTransient<IMyTransientService, MyTransientService>();
  

์‚ฌ์šฉ ์‚ฌ๋ก€: ๊ฐ€๋ฒผ์šด ์ƒํƒœ ๋น„์ €์žฅ ์„œ๋น„์Šค

2. Scoped (๋ฒ”์œ„) ์„œ๋น„์Šค

Scoped ์„œ๋น„์Šค๋Š” ์ฃผ์–ด์ง„ ๋ฒ”์œ„ ๋‚ด์—์„œ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋งŒ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐ HTTP ์š”์ฒญ์ด ํ•˜๋‚˜์˜ ๋ฒ”์œ„๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.


services.AddScoped<IMyScopedService, MyScopedService>();
  

์‚ฌ์šฉ ์‚ฌ๋ก€: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปจํ…์ŠคํŠธ, ์š”์ฒญ๋ณ„ ์บ์‹ฑ

3. Singleton (๋‹จ์ผ) ์„œ๋น„์Šค

Singleton ์„œ๋น„์Šค๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ˆ˜๋ช… ๋™์•ˆ ๋‹จ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋งŒ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.


services.AddSingleton<IMySingletonService, MySingletonService>();
  

์‚ฌ์šฉ ์‚ฌ๋ก€: ์ „์—ญ ์ƒํƒœ, ์บ์‹ฑ, ๋กœ๊น… ์„œ๋น„์Šค

์„œ๋น„์Šค ์ˆ˜๋ช… ์„ ํƒ ๊ฐ€์ด๋“œ

์„œ๋น„์Šค ์ˆ˜๋ช… ์„ ํƒ ๊ฐ€์ด๋“œ Transient - ๊ฐ€๋ฒผ์šด ์„œ๋น„์Šค - ์ƒํƒœ ๋น„์ €์žฅ - ์ž์ฃผ ๋ณ€๊ฒฝ๋˜๋Š” ๋ฐ์ดํ„ฐ Scoped - ์š”์ฒญ๋ณ„ ์„œ๋น„์Šค - ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปจํ…์ŠคํŠธ - ์š”์ฒญ ๋‚ด ์บ์‹ฑ Singleton - ์ „์—ญ ์ƒํƒœ - ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด ์บ์‹ฑ - ๋กœ๊น… ์„œ๋น„์Šค

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

์„œ๋น„์Šค๋ฅผ ๋“ฑ๋กํ•˜๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค:

1. ์ธํ„ฐํŽ˜์ด์Šค์™€ ๊ตฌํ˜„ ํด๋ž˜์Šค ๋“ฑ๋ก


services.AddTransient<IMyService, MyService>();
  

2. ๊ตฌ์ฒด ํด๋ž˜์Šค ์ง์ ‘ ๋“ฑ๋ก


services.AddTransient<MyService>();
  

3. ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ ๋“ฑ๋ก


services.AddTransient<IMyService>(sp => new MyService());
  

4. ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ์ธ์Šคํ„ด์Šค ๋“ฑ๋ก


var myService = new MyService();
services.AddSingleton<IMyService>(myService);
  

์ฃผ์˜์‚ฌํ•ญ ๋ฐ ๋ชจ๋ฒ” ์‚ฌ๋ก€

  1. ์ˆ˜๋ช… ๋ถˆ์ผ์น˜ ์ฃผ์˜: Singleton ์„œ๋น„์Šค์—์„œ Scoped ๋˜๋Š” Transient ์„œ๋น„์Šค๋ฅผ ์ฃผ์ž…๋ฐ›์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•˜์„ธ์š”.
  2. ์ˆœํ™˜ ์˜์กด์„ฑ ํ”ผํ•˜๊ธฐ: A๊ฐ€ B๋ฅผ ์˜์กดํ•˜๊ณ  B๊ฐ€ ๋‹ค์‹œ A๋ฅผ ์˜์กดํ•˜๋Š” ์ˆœํ™˜ ์˜์กด์„ฑ์„ ๋งŒ๋“ค์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•˜์„ธ์š”.
  3. ์ธํ„ฐํŽ˜์ด์Šค ์‚ฌ์šฉ: ๊ฐ€๋Šฅํ•œ ํ•œ ๊ตฌ์ฒด ํด๋ž˜์Šค ๋Œ€์‹  ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด ์˜์กด์„ฑ์„ ์ฃผ์ž…๋ฐ›์œผ์„ธ์š”.
  4. ์ ์ ˆํ•œ ์ˆ˜๋ช… ์„ ํƒ: ์„œ๋น„์Šค์˜ ํŠน์„ฑ๊ณผ ์‚ฌ์šฉ ํŒจํ„ด์„ ๊ณ ๋ คํ•˜์—ฌ ์ ์ ˆํ•œ ์ˆ˜๋ช…์„ ์„ ํƒํ•˜์„ธ์š”.
  5. ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉ: ๋ชจ๋“  ํด๋ž˜์Šค๋ฅผ ์„œ๋น„์Šค๋กœ ๋“ฑ๋กํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ์˜์กด์„ฑ ์ฃผ์ž…์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•˜์„ธ์š”.

์‹ค์ œ ์˜ˆ์ œ: ๋‚ ์”จ ์ •๋ณด ์„œ๋น„์Šค

๊ฐ„๋‹จํ•œ ๋‚ ์”จ ์ •๋ณด ์„œ๋น„์Šค๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ๊ฐ ์ˆ˜๋ช… ์œ ํ˜•์„ ์‹ค์ œ๋กœ ์ ์šฉํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


public interface IWeatherService
{
    string GetCurrentWeather();
}

public class WeatherService : IWeatherService
{
    private readonly string _weather;

    public WeatherService()
    {
        // ์‹ค์ œ๋กœ๋Š” API ํ˜ธ์ถœ ๋“ฑ์„ ํ†ตํ•ด ๋‚ ์”จ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
        _weather = new[] { "Sunny", "Cloudy", "Rainy" }[new Random().Next(3)];
    }

    public string GetCurrentWeather() => _weather;
}

public class WeatherReporter
{
    private readonly IWeatherService _weatherService;

    public WeatherReporter(IWeatherService weatherService)
    {
        _weatherService = weatherService;
    }

    public void ReportWeather()
    {
        Console.WriteLine($"Current weather: {_weatherService.GetCurrentWeather()}");
    }
}

// ์„œ๋น„์Šค ๋“ฑ๋ก
services.AddTransient<IWeatherService, WeatherService>();
services.AddTransient<WeatherReporter>();

// ์‚ฌ์šฉ
var reporter1 = serviceProvider.GetService<WeatherReporter>();
var reporter2 = serviceProvider.GetService<WeatherReporter>();

reporter1.ReportWeather();
reporter2.ReportWeather();
  

์ด ์˜ˆ์ œ์—์„œ WeatherService๋ฅผ Transient๋กœ ๋“ฑ๋กํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—, reporter1๊ณผ reporter2๋Š” ๊ฐ๊ฐ ๋‹ค๋ฅธ ๋‚ ์”จ ์ •๋ณด๋ฅผ ๋ณด๊ณ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

5. ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ™œ์šฉํ•œ ์ฝ˜์†” ์•ฑ ๊ตฌ์กฐํ™” ๐Ÿ—๏ธ

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

๊ธฐ๋ณธ ๊ตฌ์กฐ ์„ค๊ณ„

์˜์กด์„ฑ ์ฃผ์ž…์„ ํ™œ์šฉํ•œ ์ฝ˜์†” ์•ฑ์˜ ๊ธฐ๋ณธ ๊ตฌ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. ์ง„์ž…์  (Program.cs)
  2. ์˜์กด์„ฑ ์„ค์ • (Startup.cs)
  3. ์„œ๋น„์Šค ์ธํ„ฐํŽ˜์ด์Šค
  4. ์„œ๋น„์Šค ๊ตฌํ˜„
  5. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ์ง (AppLogic.cs)

์˜ˆ์ œ: ๊ฐ„๋‹จํ•œ ํ•  ์ผ ๊ด€๋ฆฌ ์ฝ˜์†” ์•ฑ

๊ฐ„๋‹จํ•œ ํ•  ์ผ ๊ด€๋ฆฌ ์ฝ˜์†” ์•ฑ์„ ๋งŒ๋“ค์–ด ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ™œ์šฉํ•œ ๊ตฌ์กฐํ™”๋ฅผ ์‹ค์Šตํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

1. Program.cs


using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

class Program
{
    static async Task Main(string[] args)
    {
        var host = CreateHostBuilder(args).Build();
        await host.Services.GetRequiredService<AppLogic>().RunAsync();
    }

    static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices((hostContext, services) =>
            {
                Startup.ConfigureServices(services);
            });
}
  

2. Startup.cs


using Microsoft.Extensions.DependencyInjection;

public static class Startup
{
    public static void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<ITaskRepository, InMemoryTaskRepository>();
        services.AddTransient<ITaskService, TaskService>();
        services.AddTransient<AppLogic>();
    }
}
  

3. ์„œ๋น„์Šค ์ธํ„ฐํŽ˜์ด์Šค


public interface ITaskRepository
{
    List<string> GetTasks();
    void AddTask(string task);
}

public interface ITaskService
{
    List<string> GetAllTasks();
    void AddNewTask(string task);
}
  

4. ์„œ๋น„์Šค ๊ตฌํ˜„


public class InMemoryTaskRepository : ITaskRepository
{
    private readonly List<string> _tasks = new List<string>();

    public List<string> GetTasks() => _tasks;
    public void AddTask(string task) => _tasks.Add(task);
}

public class TaskService : ITaskService
{
    private readonly ITaskRepository _taskRepository;

    public TaskService(ITaskRepository taskRepository)
    {
        _taskRepository = taskRepository;
    }

    public List<string> GetAllTasks() => _taskRepository.GetTasks();
    public void AddNewTask(string task) => _taskRepository.AddTask(task);
}
  

5. AppLogic.cs


public class AppLogic
{
    private readonly ITaskService _taskService;

    public AppLogic(ITaskService taskService)
    {
        _taskService = taskService;
    }

    public async Task RunAsync()
    {
        while (true)
        {
            Console.WriteLine("\n1. View Tasks");
            Console.WriteLine("2. Add Task");
            Console.WriteLine("3. Exit");
            Console.Write("Choose an option: ");

            var choice = Console.ReadLine();

            switch (choice)
            {
                case "1":
                    ViewTasks();
                    break;
                case "2":
                    await AddTaskAsync();
                    break;
                case "3":
                    return;
                default:
                    Console.WriteLine("Invalid option. Please try again.");
                    break;
            }
        }
    }

    private void ViewTasks()
    {
        var tasks = _taskService.GetAllTasks();
        if (tasks.Count == 0)
        {
            Console.WriteLine("No tasks found.");
        }
        else
        {
            for (int i = 0; i < tasks.Count; i++)
            {
                Console.WriteLine($"{i + 1}. {tasks[i]}");
            }
        }
    }

    private async Task AddTaskAsync()
    {
        Console.Write("Enter new task: ");
        var task = Console.ReadLine();
        if (!string.IsNullOrWhiteSpace(task))
        {
            _taskService.AddNewTask(task);
            Console.WriteLine("Task added successfully.");
        }
        else
        {
            Console.WriteLine("Task cannot be empty.");
        }
    }
}
  

๊ตฌ์กฐํ™”์˜ ์ด์ 

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

๊ตฌ์กฐํ™” ์‹œ ๊ณ ๋ ค์‚ฌํ•ญ

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

์ด๋ ‡๊ฒŒ ๊ตฌ์กฐํ™”๋œ ์ฝ˜์†” ์•ฑ์€ ์žฌ๋Šฅ๋„ท๊ณผ ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ ์ œ๊ณตํ•˜๋Š” ๋‹ค์–‘ํ•œ ์„œ๋น„์Šค๋“ค์„ ์‰ฝ๊ฒŒ ํ†ตํ•ฉํ•˜๊ณ  ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋ฐ˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ์ด๋Ÿฌํ•œ ๊ตฌ์กฐ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์‹ค์ œ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ๋” ๋ณต์žกํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋‹ค๋ฃจ์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๐Ÿš€

6. ์‹ค์ œ ์˜ˆ์ œ: ๋‚ ์”จ ์ •๋ณด ์ฝ˜์†” ์•ฑ ๋งŒ๋“ค๊ธฐ ๐ŸŒค๏ธ

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

ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ


WeatherApp/
โ”œโ”€โ”€ Program.cs
โ”œโ”€โ”€ Startup.cs
โ”œโ”€โ”€ AppLogic.cs
โ”œโ”€โ”€ Services/
โ”‚   โ”œโ”€โ”€ IWeatherService.cs
โ”‚   โ””โ”€โ”€ OpenWeatherMapService.cs
โ””โ”€โ”€ Models/
    โ””โ”€โ”€ WeatherInfo.cs
  

๊ตฌํ˜„ ๋‹จ๊ณ„

1. ๋ชจ๋ธ ์ •์˜ (WeatherInfo.cs)


public class WeatherInfo
{
    public string City { get; set; }
    public double Temperature { get; set; }
    public string Description { get; set; }
}
  

2. ์„œ๋น„์Šค ์ธํ„ฐํŽ˜์ด์Šค ์ •์˜ (IWeatherService.cs)


public interface IWeatherService
{
    Task<WeatherInfo> GetWeatherAsync(string city);
}
  

3. ์„œ๋น„์Šค ๊ตฌํ˜„ (OpenWeatherMapService.cs)


using System.Net.Http;
using System.Text.Json;

public class OpenWeatherMapService : IWeatherService
{
    private readonly HttpClient _httpClient;
    private const string ApiKey = "YOUR_API_KEY";

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

    public async Task<WeatherInfo> GetWeatherAsync(string city)
    {
        var response = await _httpClient.GetAsync($"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={ApiKey}&units=metric");
        response.EnsureSuccessStatusCode();
        var content = await response.Content.ReadAsStringAsync();
        var jsonDocument = JsonDocument.Parse(content);
        var root = jsonDocument.RootElement;

        return new WeatherInfo
        {
            City = root.GetProperty("name").GetString(),
            Temperature = root.GetProperty("main").GetProperty("temp").GetDouble(),
            Description = root.GetProperty("weather")[0].GetProperty("description").GetString()
        };
    }
}
  

4. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ์ง (AppLogic.cs)


public class AppLogic
{
    private readonly IWeatherService _weatherService;

    public AppLogic(IWeatherService weatherService)
    {
        _weatherService = weatherService;
    }

    public async Task RunAsync()
    {
        while (true)
        {
            Console.Write("Enter city name (or 'exit' to quit): ");
            var city = Console.ReadLine();

            if (city?.ToLower() == "exit")
                break;

            try
            {
                var weather = await _weatherService.GetWeatherAsync(city);
                Console.WriteLine($"Weather in {weather.City}:");
                Console.WriteLine($"Temperature: {weather.Temperature}ยฐC");
                Console.WriteLine($"Description: {weather.Description}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}");
            }

            Console.WriteLine();
        }
    }
}
  

5. ์˜์กด์„ฑ ์„ค์ • (Startup.cs)


using Microsoft.Extensions.DependencyInjection;

public static class Startup
{
    public static void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpClient<IWeatherService, OpenWeatherMapService>();
        services.AddTransient<AppLogic>();
    }
}
  

6. ํ”„๋กœ๊ทธ๋žจ ์ง„์ž…์  (Program.cs)


using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

class Program
{
    static async Task Main(string[] args)
    {
        var host = CreateHostBuilder(args).Build();
        await host.Services.GetRequiredService<AppLogic>().RunAsync();
    }

    static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices((hostContext, services) =>
            {
                Startup.ConfigureServices(services);
            });
}
  

์‹คํ–‰ ๊ฒฐ๊ณผ


Enter city name (or 'exit' to quit): Seoul
Weather in Seoul:
Temperature: 15.5ยฐC
Description: clear sky

Enter city name (or 'exit' to quit): New York
Weather in New York:
Temperature: 22.3ยฐC
Description: partly cloudy

Enter city name (or 'exit' to quit): exit
  

์ฝ”๋“œ ์„ค๋ช…

  • ์˜์กด์„ฑ ์ฃผ์ž…: IWeatherService๋ฅผ AppLogic์— ์ฃผ์ž…ํ•˜์—ฌ ๋Š์Šจํ•œ ๊ฒฐํ•ฉ์„ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ์„œ๋น„์Šค ์ˆ˜๋ช…: HttpClient๋Š” AddHttpClient๋ฅผ ํ†ตํ•ด ๊ด€๋ฆฌ๋˜๋ฉฐ, AppLogic์€ Transient๋กœ ๋“ฑ๋ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
  • ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ: ๋‚ ์”จ ์ •๋ณด ์กฐํšŒ ๋กœ์ง์€ OpenWeatherMapService์— ์บก์Šํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์˜ˆ์™ธ ์ฒ˜๋ฆฌ: ๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜ ๋“ฑ์˜ ์˜ˆ์™ธ ์ƒํ™ฉ์„ ์ ์ ˆํžˆ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐœ์„  ๊ฐ€๋Šฅํ•œ ๋ถ€๋ถ„

  1. API ํ‚ค๋ฅผ ์„ค์ • ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌ
  2. ๋กœ๊น… ๊ธฐ๋Šฅ ์ถ”๊ฐ€
  3. ์บ์‹ฑ ๊ตฌํ˜„์œผ๋กœ ๋ฐ˜๋ณต ์š”์ฒญ ์ตœ์ ํ™”
  4. ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๊ฐ•ํ™”

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

7. ํ…Œ์ŠคํŠธ์™€ ์˜์กด์„ฑ ์ฃผ์ž… ๐Ÿงช

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

ํ…Œ์ŠคํŠธ ํ”„๋กœ์ ํŠธ ์„ค์ •

๋จผ์ €, ์ƒˆ๋กœ์šด xUnit ํ…Œ์ŠคํŠธ ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค:


dotnet new xunit -n WeatherApp.Tests
  

๊ทธ๋ฆฌ๊ณ  ํ•„์š”ํ•œ NuGet ํŒจํ‚ค์ง€๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค:


dotnet add package Moq
dotnet add package Microsoft.Extensions.DependencyInjection
  

AppLogic ํ…Œ์ŠคํŠธ

AppLogic ํด๋ž˜์Šค์˜ ๋™์ž‘์„ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด IWeatherService์˜ ๋ชจ์˜ ๊ฐ์ฒด(mock)๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.


using Moq;
using Xunit;
using System.Threading.Tasks;

public class AppLogicTests
{
    [Fact]
    public async Task RunAsync_ShouldReturnCorrectWeatherInfo()
    {
        // Arrange
        var mockWeatherService = new Mock<IWeatherService>();
        mockWeatherService.Setup(service => service.GetWeatherAsync("Seoul"))
            .ReturnsAsync(new WeatherInfo
            {
                City = "Seoul",
                Temperature = 25.5,
                Description = "Sunny"
            });

        var appLogic = new AppLogic(mockWeatherService.Object);

        // Act & Assert
        using (var consoleOutput = new ConsoleOutput())
        {
            await appLogic.RunAsync();
            
            Assert.Contains("Weather in Seoul:", consoleOutput.GetOutput());
            Assert.Contains("Temperature: 25.5ยฐC", consoleOutput.GetOutput());
            Assert.Contains("Description: Sunny", consoleOutput.GetOutput());
        }
    }
}

// ์ฝ˜์†” ์ถœ๋ ฅ์„ ์บก์ฒ˜ํ•˜๊ธฐ ์œ„ํ•œ ํ—ฌํผ ํด๋ž˜์Šค
public class ConsoleOutput : IDisposable
{
    private readonly StringWriter stringWriter;
    private readonly TextWriter originalOutput;

    public ConsoleOutput()
    {
        stringWriter = new StringWriter();
        originalOutput = Console.Out;
        Console.SetOut(stringWriter);
    }

    public string GetOutput()
    {
        return stringWriter.ToString();
    }

    public void Dispose()
    {
        Console.SetOut(originalOutput);
        stringWriter.Dispose();
    }
}
  

OpenWeatherMapService ํ…Œ์ŠคํŠธ

OpenWeatherMapService๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด HttpClient์˜ ๋™์ž‘์„ ๋ชจ์˜ํ™”ํ•ฉ๋‹ˆ๋‹ค.


using Moq;  using Moq;
using Xunit;
using System.Net.Http;
using System.Threading.Tasks;
using System.Threading;
using Moq.Protected;

public class OpenWeatherMapServiceTests
{
    [Fact]
    public async Task GetWeatherAsync_ShouldReturnCorrectWeatherInfo()
    {
        // Arrange
        var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
        mockHttpMessageHandler.Protected()
            .Setup<Task<HttpResponseMessage>>(
                "SendAsync",
                ItExpr.IsAny<HttpRequestMessage>(),
                ItExpr.IsAny<CancellationToken>()
            )
            .ReturnsAsync(new HttpResponseMessage
            {
                Content = new StringContent(@"{
                    ""name"": ""Seoul"",
                    ""main"": { ""temp"": 25.5 },
                    ""weather"": [{ ""description"": ""clear sky"" }]
                }")
            });

        var client = new HttpClient(mockHttpMessageHandler.Object);
        var weatherService = new OpenWeatherMapService(client);

        // Act
        var result = await weatherService.GetWeatherAsync("Seoul");

        // Assert
        Assert.Equal("Seoul", result.City);
        Assert.Equal(25.5, result.Temperature);
        Assert.Equal("clear sky", result.Description);
    }
}
  

์˜์กด์„ฑ ์ฃผ์ž… ์ปจํ…Œ์ด๋„ˆ ํ…Œ์ŠคํŠธ

์˜์กด์„ฑ ์ฃผ์ž… ์„ค์ •์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌ์„ฑ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


using Microsoft.Extensions.DependencyInjection;
using Xunit;

public class StartupTests
{
    [Fact]
    public void ConfigureServices_ShouldRegisterAllDependencies()
    {
        // Arrange
        var services = new ServiceCollection();

        // Act
        Startup.ConfigureServices(services);

        // Assert
        var serviceProvider = services.BuildServiceProvider();

        Assert.NotNull(serviceProvider.GetService<IWeatherService>());
        Assert.NotNull(serviceProvider.GetService<AppLogic>());
    }
}
  

ํ…Œ์ŠคํŠธ ์‹คํ–‰

ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋ ค๋ฉด ๋‹ค์Œ ๋ช…๋ น์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค:


dotnet test
  

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

๋” ๋‚˜์€ ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ ์œ„ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ถ”๊ฐ€ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  • ์ž˜๋ชป๋œ ๋„์‹œ ์ด๋ฆ„์œผ๋กœ ๋‚ ์”จ ์ •๋ณด๋ฅผ ์š”์ฒญํ•  ๋•Œ์˜ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
  • ๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜ ์‹œ๋‚˜๋ฆฌ์˜ค
  • API ์‘๋‹ต ํ˜•์‹์ด ์˜ˆ์ƒ๊ณผ ๋‹ค๋ฅผ ๋•Œ์˜ ์ฒ˜๋ฆฌ
  • ์—ฌ๋Ÿฌ ๋„์‹œ์— ๋Œ€ํ•œ ์—ฐ์†์ ์ธ ๋‚ ์”จ ์ •๋ณด ์š”์ฒญ

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

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

๊ฒฐ๋ก 

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

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

8. ๊ณ ๊ธ‰ ์ฃผ์ œ: ์ปค์Šคํ…€ DI ์ปจํ…Œ์ด๋„ˆ ๋งŒ๋“ค๊ธฐ ๐Ÿ› ๏ธ

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

๊ธฐ๋ณธ ๊ตฌ์กฐ

์šฐ๋ฆฌ์˜ ์ปค์Šคํ…€ DI ์ปจํ…Œ์ด๋„ˆ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค:

  • ์„œ๋น„์Šค ๋“ฑ๋ก
  • ์„œ๋น„์Šค ํ•ด๊ฒฐ (์˜์กด์„ฑ ์ฃผ์ž…)
  • ์ˆ˜๋ช… ๊ด€๋ฆฌ (Transient, Singleton)

๊ตฌํ˜„


using System;
using System.Collections.Generic;

public class CustomContainer
{
    private Dictionary<Type, ServiceDescriptor> _services = new Dictionary<Type, ServiceDescriptor>();

    public void Register<TService, TImplementation>(ServiceLifetime lifetime = ServiceLifetime.Transient)
        where TImplementation : TService
    {
        _services[typeof(TService)] = new ServiceDescriptor(typeof(TImplementation), lifetime);
    }

    public TService Resolve<TService>()
    {
        return (TService)ResolveService(typeof(TService));
    }

    private object ResolveService(Type serviceType)
    {
        if (!_services.ContainsKey(serviceType))
        {
            throw new Exception($"Service of type {serviceType.Name} is not registered");
        }

        var descriptor = _services[serviceType];

        if (descriptor.Instance != null)
        {
            return descriptor.Instance;
        }

        var actualType = descriptor.ImplementationType;
        var constructor = actualType.GetConstructors()[0];
        var parameters = constructor.GetParameters();
        var parameterInstances = new object[parameters.Length];

        for (int i = 0; i < parameters.Length; i++)
        {
            parameterInstances[i] = ResolveService(parameters[i].ParameterType);
        }

        var implementation = Activator.CreateInstance(actualType, parameterInstances);

        if (descriptor.Lifetime == ServiceLifetime.Singleton)
        {
            descriptor.Instance = implementation;
        }

        return implementation;
    }
}

public class ServiceDescriptor
{
    public Type ServiceType { get; }
    public Type ImplementationType { get; }
    public object Instance { get; set; }
    public ServiceLifetime Lifetime { get; }

    public ServiceDescriptor(Type implementationType, ServiceLifetime lifetime)
    {
        ImplementationType = implementationType;
        Lifetime = lifetime;
    }
}

public enum ServiceLifetime
{
    Transient,
    Singleton
}
  

์‚ฌ์šฉ ์˜ˆ์ œ


// ์„œ๋น„์Šค ์ •์˜
public interface IMessageService
{
    string GetMessage();
}

public class EmailService : IMessageService
{
    public string GetMessage() => "This is an email message.";
}

public class SmsService : IMessageService
{
    public string GetMessage() => "This is an SMS message.";
}

public class NotificationService
{
    private readonly IMessageService _messageService;

    public NotificationService(IMessageService messageService)
    {
        _messageService = messageService;
    }

    public void SendNotification()
    {
        Console.WriteLine($"Sending notification: {_messageService.GetMessage()}");
    }
}

// ์ปจํ…Œ์ด๋„ˆ ์‚ฌ์šฉ
var container = new CustomContainer();

container.Register<IMessageService, EmailService>(ServiceLifetime.Singleton);
container.Register<NotificationService, NotificationService>();

var notificationService = container.Resolve<NotificationService>();
notificationService.SendNotification();

// ์„œ๋น„์Šค ๋ณ€๊ฒฝ
container.Register<IMessageService, SmsService>(ServiceLifetime.Singleton);

notificationService = container.Resolve<NotificationService>();
notificationService.SendNotification();
  

์ฝ”๋“œ ์„ค๋ช…

  1. Register ๋ฉ”์„œ๋“œ: ์„œ๋น„์Šค์™€ ๊ทธ ๊ตฌํ˜„์„ ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค. ์„œ๋น„์Šค์˜ ์ˆ˜๋ช…๋„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. Resolve ๋ฉ”์„œ๋“œ: ์š”์ฒญ๋œ ์„œ๋น„์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์—์„œ ์žฌ๊ท€์ ์œผ๋กœ ์˜์กด์„ฑ์„ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
  3. ServiceDescriptor: ์„œ๋น„์Šค์˜ ๊ตฌํ˜„ ํƒ€์ž…, ์ˆ˜๋ช…, ๊ทธ๋ฆฌ๊ณ  ์‹ฑ๊ธ€ํ†ค ์ธ์Šคํ„ด์Šค๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  4. ServiceLifetime: ์„œ๋น„์Šค์˜ ์ˆ˜๋ช…์„ ์ •์˜ํ•˜๋Š” ์—ด๊ฑฐํ˜•์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” Transient์™€ Singleton๋งŒ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•œ๊ณ„์ 

์ด ๊ฐ„๋‹จํ•œ ๊ตฌํ˜„์—๋Š” ๋ช‡ ๊ฐ€์ง€ ํ•œ๊ณ„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค:

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

๊ฐœ์„  ๋ฐฉํ–ฅ

์‹ค์ œ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•  DI ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋งŒ๋“ค๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ๋“ค์„ ์ถ”๊ฐ€๋กœ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

  1. ์ˆœํ™˜ ์˜์กด์„ฑ ๊ฐ์ง€ ๋ฐ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
  2. Scoped ์ˆ˜๋ช… ์ฃผ๊ธฐ ์ง€์›
  3. ๋‹ค์–‘ํ•œ ์ฃผ์ž… ๋ฐฉ์‹ ์ง€์› (์†์„ฑ ์ฃผ์ž…, ๋ฉ”์„œ๋“œ ์ฃผ์ž…)
  4. ์ œ๋„ค๋ฆญ ํƒ€์ž… ์ง€์›
  5. ์„ฑ๋Šฅ ์ตœ์ ํ™” (์˜ˆ: ๋ฆฌํ”Œ๋ ‰์…˜ ๊ฒฐ๊ณผ ์บ์‹ฑ)
  6. ์Šค๋ ˆ๋“œ ์•ˆ์ „์„ฑ ๋ณด์žฅ
  7. ๋‹ค์–‘ํ•œ ๋“ฑ๋ก ๋ฐฉ์‹ ์ง€์› (์˜ˆ: ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•œ ๋“ฑ๋ก)

๊ฒฐ๋ก 

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

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

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

9. ์„ฑ๋Šฅ ์ตœ์ ํ™” ํŒ ๐Ÿš€

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

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

์„œ๋น„์Šค์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ๋ฅผ ์ ์ ˆํžˆ ์„ ํƒํ•˜๋Š” ๊ฒƒ์€ ์„ฑ๋Šฅ์— ํฐ ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค.

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

// ์˜ˆ์‹œ
services.AddTransient<ILightweightService, LightweightService>();
services.AddScoped<IRequestScopedService, RequestScopedService>();
services.AddSingleton<ISharedStateService, SharedStateService>();
  

2. ์ƒ์„ฑ ๋น„์šฉ์ด ๋†’์€ ๊ฐ์ฒด๋Š” Singleton์œผ๋กœ ๋“ฑ๋ก

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ, HTTP ํด๋ผ์ด์–ธํŠธ ๋“ฑ ์ƒ์„ฑ ๋น„์šฉ์ด ๋†’์€ ๊ฐ์ฒด๋Š” Singleton์œผ๋กœ ๋“ฑ๋กํ•˜์—ฌ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.


services.AddSingleton<HttpClient>();
services.AddSingleton<IExpensiveService, ExpensiveService>();
  

3. ํŒฉํ† ๋ฆฌ ํŒจํ„ด ํ™œ์šฉ

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


services.AddSingleton<IServiceFactory>(sp =>
{
    return new ServiceFactory(sp);
});

services.AddTransient<IMyService>(sp =>
{
    var factory = sp.GetRequiredService<IServiceFactory>();
    return factory.CreateMyService();
});
  

4. ๋ ˆ์ด์ง€ ๋กœ๋”ฉ ๊ตฌํ˜„

์ผ๋ถ€ ์„œ๋น„์Šค๋Š” ์‹ค์ œ๋กœ ์‚ฌ์šฉ๋  ๋•Œ๋งŒ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๊ฒƒ์ด ์œ ๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด Lazy<T>๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


services.AddTransient<Lazy<IExpensiveService>>(sp =>
{
    return new Lazy<IExpensiveService>(() => sp.GetRequiredService<IExpensiveService>());
});
  

5. ๊ฐ์ฒด ํ’€๋ง ์‚ฌ์šฉ

์ž์ฃผ ์ƒ์„ฑ๋˜๊ณ  ํŒŒ๊ดด๋˜๋Š” ๊ฐ์ฒด์˜ ๊ฒฝ์šฐ, ๊ฐ์ฒด ํ’€๋ง์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


services.AddSingleton<ObjectPool<MyExpensiveObject>>(sp =>
{
    return new DefaultObjectPool<MyExpensiveObject>(new DefaultPooledObjectPolicy<MyExpensiveObject>());
});
  

6. ์ปจํ…Œ์ด๋„ˆ ๋นŒ๋“œ ์ตœ์ ํ™”

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ DI ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋นŒ๋“œํ•˜๋Š” ๊ณผ์ •์„ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


var services = new ServiceCollection();
// ์„œ๋น„์Šค ๋“ฑ๋ก...

var serviceProvider = services.BuildServiceProvider(new ServiceProviderOptions
{
    ValidateScopes = false,
    ValidateOnBuild = false
});
  

๋‹จ, ์ด ์˜ต์…˜๋“ค์€ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋Š” ํ™œ์„ฑํ™”ํ•˜์—ฌ ์ž ์žฌ์ ์ธ ๋ฌธ์ œ๋ฅผ ์กฐ๊ธฐ์— ๋ฐœ๊ฒฌํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

7. ๋ถˆํ•„์š”ํ•œ ์˜์กด์„ฑ ์ œ๊ฑฐ

๊ฐ ํด๋ž˜์Šค๊ฐ€ ์ •๋ง๋กœ ํ•„์š”ํ•œ ์˜์กด์„ฑ๋งŒ ์ฃผ์ž…๋ฐ›๋„๋ก ์„ค๊ณ„ํ•˜์„ธ์š”. ๋ถˆํ•„์š”ํ•œ ์˜์กด์„ฑ์€ ์„ฑ๋Šฅ ์ €ํ•˜์˜ ์›์ธ์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

8. ํ”„๋กœํŒŒ์ผ๋ง ๋ฐ ๋ฒค์น˜๋งˆํ‚น

์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด์„œ๋Š” ์‹ค์ œ ์ธก์ •์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. .NET์˜ ํ”„๋กœํŒŒ์ผ๋ง ๋„๊ตฌ์™€ BenchmarkDotNet ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ™œ์šฉํ•˜์„ธ์š”.


[Benchmark]
public void ResolveService()
{
    var service = _serviceProvider.GetService<IMyService>();
    service.DoSomething();
}
  

9. ์ปดํŒŒ์ผ ์‹œ์  DI ๊ณ ๋ ค

๊ทน๋‹จ์ ์ธ ์„ฑ๋Šฅ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ, ๋Ÿฐํƒ€์ž„ DI ๋Œ€์‹  ์ปดํŒŒ์ผ ์‹œ์  DI๋ฅผ ๊ณ ๋ คํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, Source Generators๋ฅผ ์‚ฌ์šฉํ•œ DI ๊ตฌํ˜„์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์„ฑ๋Šฅ ์ตœ์ ํ™” ์˜ˆ์ œ

๋‹ค์Œ์€ ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๋ช‡ ๊ฐ€์ง€ ์ตœ์ ํ™” ๊ธฐ๋ฒ•์„ ์ ์šฉํ•œ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค:


public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๋“ฑ๋กํ•˜์—ฌ ์žฌ์‚ฌ์šฉ
        services.AddSingleton<HttpClient>();

        // ํŒฉํ† ๋ฆฌ ํŒจํ„ด ํ™œ์šฉ
        services.AddSingleton<IServiceFactory, ServiceFactory>();
        services.AddTransient<IMyService>(sp => sp.GetRequiredService<IServiceFactory>().CreateMyService());

        // ๋ ˆ์ด์ง€ ๋กœ๋”ฉ ๊ตฌํ˜„
        services.AddTransient<Lazy<IExpensiveService>>(sp =>
            new Lazy<IExpensiveService>(() => sp.GetRequiredService<IExpensiveService>()));

        // ๊ฐ์ฒด ํ’€๋ง ์‚ฌ์šฉ
        services.AddSingleton<ObjectPool<MyExpensiveObject>>(sp =>
            new DefaultObjectPool<MyExpensiveObject>(new DefaultPooledObjectPolicy<MyExpensiveObject>()));
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌ์„ฑ...
    }
}

public class ServiceFactory : IServiceFactory
{
    private readonly IServiceProvider _serviceProvider;

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

    public IMyService CreateMyService()
    {
        // ๋ณต์žกํ•œ ์ƒ์„ฑ ๋กœ์ง...
        return new MyService(_serviceProvider.GetRequiredService<IDependency>());
    }
}

public class MyController : ControllerBase
{
    private readonly Lazy<IExpensiveService> _lazyExpensiveService;
    private readonly ObjectPool<MyExpensiveObject> _objectPool;

    public MyController(Lazy<IExpensiveService> lazyExpensiveService, ObjectPool<MyExpensiveObject> objectPool)
    {
        _lazyExpensiveService = lazyExpensiveService;
        _objectPool = objectPool;
    }

    public IActionResult DoSomething()
    {
        // ํ•„์š”ํ•  ๋•Œ๋งŒ ์ดˆ๊ธฐํ™”
        var expensiveService = _lazyExpensiveService.Value;

        // ๊ฐ์ฒด ํ’€์—์„œ ๊ฐ์ฒด ๊ฐ€์ ธ์˜ค๊ธฐ
        var expensiveObject = _objectPool.Get();
        try
        {
            // ์ž‘์—… ์ˆ˜ํ–‰...
            return Ok();
        }
        finally
        {
            // ๊ฐ์ฒด๋ฅผ ํ’€๋กœ ๋ฐ˜ํ™˜
            _objectPool.Return(expensiveObject);
        }
    }
}
  

๊ฒฐ๋ก 

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

10. ์˜์กด์„ฑ ์ฃผ์ž…์˜ ๋ชจ๋ฒ” ์‚ฌ๋ก€์™€ ์•ˆํ‹ฐ ํŒจํ„ด ๐ŸŽญ

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

๋ชจ๋ฒ” ์‚ฌ๋ก€ (Best Practices)

  1. ์ƒ์„ฑ์ž ์ฃผ์ž… ์‚ฌ์šฉ
    
    public class MyService
    {
        private readonly IDependency _dependency;
    
        public MyService(IDependency dependency)
        {
            _dependency = dependency ?? throw new ArgumentNullException(nameof(dependency));
        }
    }
          
  2. ์ธํ„ฐํŽ˜์ด์Šค์— ์˜์กด
    
    services.AddTransient<IMyService, MyService>();
          
  3. ์ ์ ˆํ•œ ์ˆ˜๋ช… ์ฃผ๊ธฐ ์„ ํƒ
    
    services.AddTransient<IShortLivedService, ShortLivedService>();
    services.AddScoped<IRequestScopedService, RequestScopedService>();
    services.AddSingleton<ILongLivedService, LongLivedService>();
          
  4. ์˜์กด์„ฑ ์ตœ์†Œํ™”
    
    public class GoodService
    {
        public GoodService(IDependency1 dep1, IDependency2 dep2)
        {
            // ํ•„์š”ํ•œ ์˜์กด์„ฑ๋งŒ ์ฃผ์ž…
        }
    }
          
  5. ์„ค์ • ์ฃผ์ž…
    
    services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
    services.AddTransient<IMyService, MyService>();
    
    public class MyService
    {
        public MyService(IOptions<MyOptions> options)
        {
            // ์„ค์ • ์‚ฌ์šฉ
        }
    }
          
  6. ํŒฉํ† ๋ฆฌ ํŒจํ„ด ํ™œ์šฉ
    
    services.AddTransient<IMyService>(sp =>
    {
        var dependency = sp.GetRequiredService<IDependency>();
        return new MyService(dependency);
    });
          
  7. ์ปดํฌ์ง€์…˜ ๋ฃจํŠธ์—์„œ๋งŒ ํ•ด๊ฒฐ
    
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();
            var myService = host.Services.GetRequiredService<IMyService>();
            // ์—ฌ๊ธฐ์„œ๋งŒ ์„œ๋น„์Šค๋ฅผ ์ง์ ‘ ํ•ด๊ฒฐ
        }
    }
          

์•ˆํ‹ฐ ํŒจํ„ด (Anti-Patterns)

  1. ์„œ๋น„์Šค ๋กœ์ผ€์ดํ„ฐ ํŒจํ„ด
    
    // ์•ˆํ‹ฐ ํŒจํ„ด
    public class BadService
    {
        private readonly IServiceProvider _serviceProvider;
    
        public BadService(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
    
        public void DoSomething()
        {
            var dependency = _serviceProvider.GetService<IDependency>();
            // ์ด๋Š” ์˜์กด์„ฑ์„ ์ˆจ๊ธฐ๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
        }
    }
          
  2. ์ˆœํ™˜ ์˜์กด์„ฑ
    
    // ์•ˆํ‹ฐ ํŒจํ„ด
    public class ServiceA
    {
        public ServiceA(ServiceB b) { }
    }
    
    public class ServiceB
    {
        public ServiceB(ServiceA a) { }
    }
          
  3. ๊ณผ๋„ํ•œ ์ถ”์ƒํ™”
    
    // ์•ˆํ‹ฐ ํŒจํ„ด
    services.AddTransient<IServiceA, ServiceA>();
    services.AddTransient<IServiceB, ServiceB>();
    services.AddTransient<IServiceC, Service  C>();
    services.AddTransient<IServiceD, ServiceD>();
    // ๋ชจ๋“  ๊ฒƒ์„ ์ถ”์ƒํ™”ํ•˜๋Š” ๊ฒƒ์€ ๊ณผ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
          
  4. ์ปจํ…Œ์ด๋„ˆ์— ๋Œ€ํ•œ ๊ณผ๋„ํ•œ ์˜์กด
    
    // ์•ˆํ‹ฐ ํŒจํ„ด
    public class OverlyDependentService
    {
        private readonly IServiceProvider _serviceProvider;
    
        public OverlyDependentService(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
    
        public void DoSomething()
        {
            var service1 = _serviceProvider.GetService<IService1>();
            var service2 = _serviceProvider.GetService<IService2>();
            var service3 = _serviceProvider.GetService<IService3>();
            // ์ด๋Š” ์˜์กด์„ฑ์„ ์ˆจ๊ธฐ๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
        }
    }
          
  5. ๋ถ€์ ์ ˆํ•œ ์ˆ˜๋ช… ์ฃผ๊ธฐ ์‚ฌ์šฉ
    
    // ์•ˆํ‹ฐ ํŒจํ„ด
    services.AddSingleton<IDataContext, DataContext>();
    // ๋ฐ์ดํ„ฐ ์ปจํ…์ŠคํŠธ๋ฅผ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๋“ฑ๋กํ•˜๋ฉด ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
          
  6. ์ •์  ํด๋ž˜์Šค ๋ฐ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด ๊ณผ๋‹ค ์‚ฌ์šฉ
    
    // ์•ˆํ‹ฐ ํŒจํ„ด
    public static class StaticHelper
    {
        public static void DoSomething() { }
    }
    
    // ๋Œ€์‹  ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  DI๋ฅผ ํ†ตํ•ด ์ฃผ์ž…๋ฐ›์œผ์„ธ์š”.
    public interface IHelper
    {
        void DoSomething();
    }
    
    services.AddTransient<IHelper, Helper>();
          
  7. ์„œ๋น„์Šค ํ•ด๊ฒฐ์„ ์œ„ํ•œ `new` ํ‚ค์›Œ๋“œ ์‚ฌ์šฉ
    
    // ์•ˆํ‹ฐ ํŒจํ„ด
    public class BadService
    {
        public void DoSomething()
        {
            var dependency = new Dependency();
            // ์ด๋Š” DI์˜ ์ด์ ์„ ๋ฌด์‹œํ•˜๊ณ  ๊ฐ•ํ•œ ๊ฒฐํ•ฉ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
        }
    }
          

๋ชจ๋ฒ” ์‚ฌ๋ก€ ์ ์šฉ ์˜ˆ์ œ

๋‹ค์Œ์€ ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋“ค์„ ์ ์šฉํ•œ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค:


public interface IUserService
{
    Task<User> GetUserAsync(int id);
}

public interface IEmailService
{
    Task SendEmailAsync(string to, string subject, string body);
}

public class UserService : IUserService
{
    private readonly IDbContext _dbContext;

    public UserService(IDbContext dbContext)
    {
        _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
    }

    public async Task<User> GetUserAsync(int id)
    {
        return await _dbContext.Users.FindAsync(id);
    }
}

public class EmailService : IEmailService
{
    private readonly IOptions<EmailSettings> _emailSettings;
    private readonly ILogger<EmailService> _logger;

    public EmailService(IOptions<EmailSettings> emailSettings, ILogger<EmailService> logger)
    {
        _emailSettings = emailSettings ?? throw new ArgumentNullException(nameof(emailSettings));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    public async Task SendEmailAsync(string to, string subject, string body)
    {
        // ์ด๋ฉ”์ผ ์ „์†ก ๋กœ์ง
        _logger.LogInformation($"Sending email to {to}");
        // ์‹ค์ œ ์ด๋ฉ”์ผ ์ „์†ก ์ฝ”๋“œ...
    }
}

public class UserController : ControllerBase
{
    private readonly IUserService _userService;
    private readonly IEmailService _emailService;

    public UserController(IUserService userService, IEmailService emailService)
    {
        _userService = userService ?? throw new ArgumentNullException(nameof(userService));
        _emailService = emailService ?? throw new ArgumentNullException(nameof(emailService));
    }

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

        await _emailService.SendEmailAsync(user.Email, "User Retrieved", "Your user information was accessed.");

        return Ok(user);
    }
}

// Startup.cs
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<IDbContext, AppDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        services.AddScoped<IUserService, UserService>();
        services.AddSingleton<IEmailService, EmailService>();

        services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));

        services.AddControllers();
    }
}
  

๊ฒฐ๋ก 

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

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

๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ์ด ๊ธ€์˜ ๋งˆ๋ฌด๋ฆฌ์™€ ํ•จ๊ป˜ ์ถ”๊ฐ€ ํ•™์Šต ์ž๋ฃŒ๋ฅผ ์ œ๊ณตํ•˜์—ฌ, ์—ฌ๋Ÿฌ๋ถ„์ด ์˜์กด์„ฑ ์ฃผ์ž…์— ๋Œ€ํ•ด ๋” ๊นŠ์ด ์žˆ๊ฒŒ ํ•™์Šตํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค. ๐ŸŽ“

11. ๋งˆ๋ฌด๋ฆฌ ๋ฐ ์ถ”๊ฐ€ ํ•™์Šต ์ž๋ฃŒ ๐Ÿ“š

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

ํ•ต์‹ฌ ์š”์•ฝ

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

์ถ”๊ฐ€ ํ•™์Šต ์ž๋ฃŒ

์˜์กด์„ฑ ์ฃผ์ž…๊ณผ .NET Core์— ๋Œ€ํ•ด ๋” ๊นŠ์ด ํ•™์Šตํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ๋‹ค์Œ ์ž๋ฃŒ๋“ค์„ ์ฐธ๊ณ ํ•˜์„ธ์š”:

  1. ๊ณต์‹ ๋ฌธ์„œ
  2. ์ฑ…
    • "Dependency Injection Principles, Practices, and Patterns" by Mark Seemann and Steven van Deursen
    • "Pro ASP.NET Core 3" by Adam Freeman
  3. ์˜จ๋ผ์ธ ์ฝ”์Šค
  4. ๋ธ”๋กœ๊ทธ ๋ฐ ์•„ํ‹ฐํด
  5. ์˜คํ”ˆ ์†Œ์Šค ํ”„๋กœ์ ํŠธ
    • dotnet/runtime - .NET Core ๋Ÿฐํƒ€์ž„์˜ ์†Œ์Šค ์ฝ”๋“œ
    • Autofac - ์ธ๊ธฐ ์žˆ๋Š” DI ์ปจํ…Œ์ด๋„ˆ

๋งˆ๋ฌด๋ฆฌ

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

์ด ๊ธ€์—์„œ ๋‹ค๋ฃฌ ๋‚ด์šฉ๋“ค์„ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•ด๋ณด๋ฉด์„œ, ์—ฌ๋Ÿฌ๋ถ„๋งŒ์˜ ๊ฒฝํ—˜๊ณผ ๋…ธํ•˜์šฐ๋ฅผ ์Œ“์•„๊ฐ€์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค. ์˜์กด์„ฑ ์ฃผ์ž…์€ ์ฒ˜์Œ์—๋Š” ๋ณต์žกํ•ด ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ๊พธ์ค€ํ•œ ์‹ค์Šต๊ณผ ํ•™์Šต์„ ํ†ตํ•ด ๋งˆ์Šคํ„ฐํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

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