주말 아침 - 주간 닷넷 #22

한 주 동안 .NET 생태계에서 있었던 주요 이슈와 아티클, 기술 트렌드를 정리해 소개합니다.


:pushpin: .NET을 위한 새로운 Microsoft Testing Platform

https://medium.com/@benjaminabt/the-new-microsoft-testing-platform-for-net-8a487a1cad5c

  • 저자: BEN ABT
  • 태그: #testing #mtp #vstest #migration dotnet10

주요 내용

  • Microsoft Testing Platform(MTP)과 VSTest의 아키텍처 차이: MTP는 테스트 러너가 프로젝트에 내장되어 실행 파일처럼 동작
  • 컴파일 타임 확장 등록, 결정론적 실행 모델, Native AOT/트리밍 호환성
  • MSTest.Sdk, EnableMSTestRunner, global.json 등 실무 마이그레이션 샘플 6가지 제시
  • VSTest와의 명령어 매핑(–logger trx → --report-trx 등)과 CI 파이프라인 업데이트 가이드
  • 마이그레이션 실패 패턴: 플랫폼 혼재, dotnet test 동작 차이, 필터 호환성, exit code 8 변경

:pushpin: Aspire 13.2 발표

  • 저자: Maddy Montaquila, David Fowler
  • 태그: aspire dotnet #cli ai #distributed

주요 내용

  • AI 에이전트 네이티브 CLI 도입: aspire start --detach, aspire wait, aspire doctor 등 구조화된 명령어
  • TypeScript AppHost 작성 지원(프리뷰): C# 외에 TypeScript로도 분산 앱 오케스트레이션 구성 가능
  • 대시보드 개선: 트레이스/로그/설정을 JSON/.env로 내보내기, GenAI 시각화 개선, 리소스 그래프 레이아웃
  • 새 통합: Certbot, AI Foundry 개편, Bun JavaScript 지원
  • aspire export로 디버그 스냅샷 생성, 쿼리 문자열 민감 데이터 마스킹

:pushpin: C#에서 비동기 스트림 병합: IAsyncEnumerable의 누락된 기본 요소

https://medium.com/@nuthim/merging-async-streams-in-c-a-missing-primitive-in-iasyncenumerable-8ded378107ce

  • 저자: Mithun Basak
  • 태그: csharp async #iasyncenumerable #concurrency

주요 내용

  • FX 환율 캐시 서비스에서 ~1000개 HTTP 요청을 제어된 동시성으로 처리하는 실제 문제 정의
  • 각 API 호출을 IAsyncEnumerable로 모델링하는 설계
  • MergedAsyncEnumerable 구현: Task.WhenAny로 완료 순서대로 결과 yield
  • IndexedIterator로 각 스트림을 추적하고 완료된 스트림을 제거하는 메커니즘
  • LINQ Chunk()로 동시 실행 수를 제한하고, 대규모 프로듀서에는 Channel 기반 대안 언급

:pushpin: .NET의 SOH vs LOH: 모든 C# 개발자가 알아야 할 메모리

https://medium.com/@granthgharewal/soh-vs-loh-in-net-what-every-c-developer-should-know-about-memory-9abaee21876b

  • 저자: Granth Gharewal
  • 태그: #memory #gc #performance dotnet

주요 내용

  • SOH는 세대별(Gen 0/1/2) GC로 관리되며 컬렉션 시 압축 수행, LOH는 Gen 2 수집 시에만 수거되고 기본 비압축
  • LOH의 85KB 임계값은 대형 객체 이동 비용 회피를 위한 의도적 트레이드오프
  • LOH 단편화로 전체 메모리는 충분해도 연속 블록 부족으로 OutOfMemoryException 발생 가능
  • ArrayPool, 청크 단위 처리(64KB 이하), RecyclableMemoryStream으로 LOH 할당 회피
  • GCSettings.LargeObjectHeapCompactionMode = CompactOnce로 수동 LOH 압축(제한적 사용 권장)

:pushpin: Pure.DI: 컨테이너 없이, 리플렉션 없이, 컴파일 타임 유효성 검사와 함께하는 DI

https://medium.com/@nikolay.pyanikov/pure-di-di-without-container-without-net-type-reflection-and-with-compile-time-validation-0572a3a07737

  • 저자: Nikolay Pyanikov
  • 태그: #dependency-injection #source-generator #aot #pure-di

주요 내용

  • C# 소스 제너레이터 기반 DI로 컴파일 타임에 의존성 그래프를 분석하고 순수 C# 코드 생성
  • 런타임 컨테이너/리플렉션/서비스 로케이터 없이 new 체인으로 객체 생성
  • Binding, Tag, Lifetime(Transient/Singleton/Scoped), Factory, Generic 마커 타입 등 API 제공
  • Composition Root를 프로퍼티/메서드로 노출하여 Service Locator 안티패턴 회피
  • AOT, Unity, .NET Framework 2.0+ 등 리플렉션 제한 환경에서 활용 가능

:pushpin: 재시도 로직을 추가했더니 프로덕션에서 중복 주문이 발생하기 시작했다

https://medium.com/@iamrks/i-added-resilience-to-my-net-app-it-started-sending-duplicate-orders-2af09abffaea

  • 저자: Ravi Kant Sharma
  • 태그: #resilience #polly #efcore #distributed-systems #idempotency

주요 내용

  • Polly 재시도 정책과 EF Core Execution Strategy를 중첩 사용할 때 발생하는 중복 실행 문제
  • Polly가 전체 오퍼레이션을 재시도하면서 HTTP 호출이 중복 실행되는 메커니즘
  • HTTP 재시도(Polly)와 DB 재시도(EF Core)를 분리하는 올바른 아키텍처 패턴
  • Idempotency Key 헤더와 Outbox Pattern을 통한 분산 트랜잭션 문제 해결
  • HttpClientFactory에 Polly 정책을 등록하는 프로덕션 구성 코드

:pushpin: 하나의 Blazor 코드를 6개 플랫폼에서 #if 없이 사용하는 방법

https://medium.com/@jinjinov/how-i-use-the-same-blazor-code-for-wasm-windows-linux-macos-ios-android-without-a-single-if-0432962ac4c2

  • 저자: Urban (jinjinov)
  • 태그: blazor #crossplatform maui #architecture di

주요 내용

  • OpenHabitTracker 오픈소스 앱을 6개 플랫폼(WASM, MAUI, Photino, WPF 등)에서 단일 Razor 컴포넌트 라이브러리로 공유
  • 플랫폼 차이를 인터페이스로 추상화하고 DI로 구현체를 주입하는 패턴(IOpenFile, ISaveFile 등)
  • 파일 열기의 플랫폼별 구현(WASM InputFile, WinForms OpenFileDialog, MAUI FilePicker, Photino ShowOpenFile) 비교
  • 공유 라이브러리에 #if 전처리기 지시문을 하나도 사용하지 않는 아키텍처

:pushpin: IOptions vs IOptionsSnapshot vs IOptionsMonitor – 올바른 선택

https://medium.com/@fatihgurdal/ioptions-vs-ioptionssnapshot-vs-ioptionsmonitor-in-net-pick-the-right-one-4070120543dc

주요 내용

  • IOptions는 Singleton으로 앱 시작 시 한 번만 읽고 캐시, 런타임 변경 반영 불가
  • IOptionsSnapshot는 Scoped로 HTTP 요청마다 설정값 재읽기, Singleton에 주입 불가(captive dependency)
  • IOptionsMonitor는 Singleton이면서 실시간 변경 감지, OnChange 콜백 지원, 백그라운드 서비스에 적합
  • OnChange 콜백은 파일 워처 특성상 중복 발화 가능, 디바운싱 고려 필요

:pushpin: 스레드 안전성: volatile vs ConcurrentDictionary

https://medium.com/@akhilgite/mastering-thread-safety-in-net-volatile-vs-concurrentdictionary-f601f12e1238

  • 저자: Akhil Gite
  • 태그: #concurrency #threading #volatile #concurrent-collections

주요 내용

  • volatile 키워드의 메모리 가시성 보장 원리: acquire/release fence로 CPU/컴파일러 재정렬 방지
  • volatile이 원자성을 보장하지 않는다는 점과 Interlocked 사용 필요성
  • ConcurrentDictionary의 lock striping 내부 구조와 읽기의 lock-free 특성
  • GetOrAdd/AddOrUpdate의 팩토리 중복 실행 주의점과 volatile 플래그 조합 패턴

:pushpin: AutoMapper 마지막 무료 버전에 보안 취약점 존재

  • 저자: David Grace
  • 태그: #automapper #security #cve dotnet

주요 내용

  • AutoMapper v14(마지막 무료 버전)에 CVSS 7.5 고위험도 DoS 취약점 존재
  • 동일 타입의 중첩 객체를 재귀적으로 매핑할 때 기본 깊이 제한 없이 스택 메모리 소진
  • ~25,000-30,000 레벨의 중첩으로 StackOverflowException 발생
  • JSON MaxDepth 기본값 64가 먼저 차단하므로 실제 재현은 수동 객체 구성 필요
  • 수정 방법: 유료 버전 업그레이드, MaxDepth(64) 설정, ForAllMaps로 전체 맵에 일괄 적용

:bookmark_tabs: 가벼운 읽을거리

후보 항목 중 이슈로 선정되지 않은 가벼운 읽을거리들


EF Core 10 성능 마스터리: 7가지 실전 기법

  • ExecuteUpdate/ExecuteDelete 벌크 업데이트, 네이티브 벡터/JSON 타입으로 시맨틱 검색
  • Compiled Model + DbContext Pooling, AsNoTracking + Projection + SplitQuery 조합

빠른 .NET CLI 다운로더

  • dotnet run app.cs 스타일로 HTTP Range 요청 기반 파일 분할 병렬 다운로드(기본 8 청크)
  • 이어받기, 재시도 로직(최대 5회), 진행률 표시를 단일 파일로 구현

.NET에서 분산 락 구현하기

  • 단일 프로세스 lock이 다중 인스턴스에서 무효화되는 원인과 DB/Redis 기반 락 트레이드오프
  • TTL 기반 자동 만료로 데드락 방지하는 자가 치유 메커니즘
6개의 좋아요