한 주 동안 .NET 생태계에서 있었던 주요 이슈와 아티클, 기술 트렌드를 정리해 소개합니다.
.NET 8·9 지원 종료 임박 — 2026년 11월 10일
- 저자: Mitchel Sellers
- 태그: #dotnet8 dotnet9 #eol
주요 내용
- .NET 8과 .NET 9의 지원 종료일은 2026년 11월 10일이며 후속 LTS는 .NET 10
- 종료 후에도 앱은 동작하지만 보안 패치 중단, 기술지원 종료, 서드파티 패키지의 호환성 테스트 중단이 뒤따름
- csproj의 TargetFramework를 net10.0으로 변경하는 것이 시작점
- 빌드 성공만으로는 검증이 끝나지 않으며 인증 리다이렉트 등 프로덕션 핵심 동작을 재검증해야 함
- Breaking Changes 가이드 확인과 EF Core·ASP.NET Core 인증처럼 프레임워크에 결합된 패키지의 우선 점검을 실행 항목으로 제시
.NET 11의 자동 CSRF 보호가 OAuth 흐름을 끊는다
- 저자: Khalid Abuhakmeh
- 태그: #dotnet11 #csrf #security
주요 내용
- .NET 11은 Sec-Fetch-Site와 Origin 헤더를 검사해 POST/PUT/DELETE/PATCH에 기본으로 CSRF 방어를 적용
- Minimal API, MVC, Razor Pages, Blazor 전반에 적용되며 Blazor Web App 템플릿은 UseAntiforgery() 호출을 더 이상 포함하지 않음
- PKCE 토큰 교환, form_post 콜백, front-channel logout iframe 등 cross-origin OAuth 흐름이 차단될 수 있음
- CORS 정책은 이 보호와 별개로 동작해 CORS 허용만으로는 우회되지 않음
- 결제·ID 공급자 웹훅은 DisableAntiforgery(), [IgnoreAntiforgeryToken]으로 엔드포인트별 예외 처리가 필요하며 BFF 패턴이 우회책으로 제시됨
C# 15 프리뷰 신기능 살펴보기
- 저자: Bill Wagner
- 태그: #csharp15 #dotnet11 #uniontypes
주요 내용
- union 키워드로 상속 관계가 없는 타입 집합을 하나의 값으로 표현하고 switch에서 컴파일러가 완전성을 검사
- closed 한정자로 파생 타입을 같은 어셈블리로 제한하는 닫힌 계층 구조
- 메모리 안전성 재설계(프리뷰): 포인터 선언·&·fixed·sizeof는 unsafe가 불필요해지고 역참조·멤버 접근·함수 포인터 호출은 여전히 필요하며, unsafe 메서드 호출자에 안전성 전파가 강제되는 브레이킹 체인지
- 컬렉션 표현식의 with(…) 요소로
List<string> names = [with(capacity: n), .. values]형태의 생성자 인자 전달 - 확장 인덱서와 레이블 붙은 break/continue로 플래그 변수 없이 다중 루프를 탈출
System.Text.Json으로 유니온을 직렬화할 때 겪는 고충
- 저자: Andrew Lock
- 태그: #dotnet11 #systemtextjson #csharp15
주요 내용
- closed 계층을 기본 설정으로 직렬화하면 파생 타입 정보가 소실되고, InferClosedTypePolymorphism은 접근 제한자 불일치나 abstract 다단계 계층에서 실패
- union은 JSON 프리미티브 타입(Number/String/Bool/Object)이 겹치면 역직렬화가 불가능하며, 모든 case가 Object로 직렬화되는 SupportedOS 사례로 시연
- JsonTypeClassifierFactory<T> 기반 커스텀 구조적 분류기 구현으로 우회
- RC1에 포함될 JsonUnionTypeStructuralClassifier도 중첩 union이나 POCO 아닌 타입이 섞이면 실패한다는 점을 미리 검증
- TypeScript 상호운용성을 우선한 API 리뷰 결정 때문에 실사용 라운드트립 시나리오 대부분이 지원되지 않는 상태
마이크로소프트, WinUI·Windows App SDK 개발을 깃허브로 이전
- 저자: Paul Thurrott
- 태그: #winui #windowsappsdk opensource
주요 내용
- WinUI와 Windows App SDK의 메인라인 개발이 GitHub으로 이전되었으며 2025년 8월 발표된 현대화 이니셔티브의 4단계에 해당
- 일상적인 엔지니어링 작업이 공개적으로 진행된다는 마이크로소프트 엔지니어의 발언 인용
- 현재는 브랜치·PR·리뷰·머지 등 저장소 작업을 마이크로소프트 엔지니어가 직접 수행하며 커뮤니티 기여는 이후 단계에서 활성화 예정
- 과거 WPF·WinForms·WinUI XAML 라이브러리 오픈소스화의 연장선이며 최종 목표는 완전 오픈소스 전환
Akka.NET으로 만드는 분산 작업 스케줄러
- 저자: Aaron Stannard
- 태그: #akkadotnet #distributedsystems #scheduling
주요 내용
- 수 분에서 수십 시간짜리 작업을 클러스터에 분산하되 실행 중인 작업은 중단하지 않고 스케일링해야 하는 요구사항
- Akka.Cluster.Sharding은 스케일 시 샤드를 재분배해 60% 진행된 작업을 중단·재시작시키고, 클러스터 라우터는 작업 크기 인식과 복구 메커니즘이 없어 부적합
- JobTracker(클러스터 싱글톤), JobReceiver(노드별 진행 추적), JobExecutor(실행), JobSubmitter(테넌트별 진행상황)로 역할 분리
- 작업마다 오디오 분량·파일 크기·행 수 같은 O(1) 크기 지표를 부여하고 노드별 총 부하 기준으로 최소 부하 노드에 배치
- 입력을 Command·Fact·Event로 3분류하고 Akka.Persistence 저널 재생 후 실제 워커 상태와 대조하는 재조정 복구 절차
ASP.NET Core 분산 추적 — HTTP는 자동, 큐는 수동
- 저자: Adrian Bailador
- 태그: aspnetcore #opentelemetry #distributedtracing
주요 내용
- OrdersApi가 PricingApi를 HTTP로 호출하고 SQLite에 저장한 뒤 알림을 큐에 넣는 구조를 Channel<T> 기반 BackgroundService로 구성
- AspNetCore·HttpClient·EntityFrameworkCore 계측과 OTLP(gRPC 4317)로 Jaeger 전송
- W3C Trace Context 덕분에 HTTP 호출 간에는 트레이스가 자동 전파되지만 큐를 통한 비동기 핸드오프는 전파되지 않음
- Activity.Current?.Context를 메시지와 함께 저장했다가 컨슈머 측 StartActivity()의 parentContext로 넘겨 수동 전파
- ActivitySource 이름과 SDK 구독 이름이 어긋나면 에러 없이 계측이 누락되며, SQLite가 EF Core 스팬에서 main 데이터베이스로 표기되는 세부사항을 Jaeger 캡처로 제시
C# 처리 파이프라인을 결정론적으로 유닛 테스트하기
- 저자: Nick Cosentino
- 태그: csharp #unittesting #channels
주요 내용
- 임의의 딜레이 대신 진입·계속 진행·취소 요청·큐 여유 같은 인과관계 신호를 제어해 결정론적 테스트를 작성
- 스테이지의 성공·거부·예외·취소 네 결과를 구분하며 거부와 예외는 서로 다른 단락과 재시도 동작을 가짐
- TaskCompletionSource<T>로 진입 신호를 기다린 뒤 취소를 실행하고, Channel의 바운드 큐를 시간 가정 없이 검증
- Completion(신규 수락 중단)·Drain(수락분 처리)·Shutdown(자원 정리)을 별개 생명주기 단계로 구분
- PipelineRunner, ScriptedStage, ManualTimeProvider 등 의존성 없는 테스트 더블 구현과 함께, 정합성 검증과 성능 벤치마크를 같은 테스트에 섞지 말라는 경고
모듈러 모놀리스에서 스키마를 넘나드는 쿼리와 트랜잭션
- 저자: Anton Martyniuk
- 태그: #modularmonolith #cqrs #efcore
주요 내용
- 모듈별로 DbContext를 분리하면 스키마 간 직접 조인이 불가능하고 트랜잭션도 모듈 경계를 넘지 못함
- 모듈 간 API 호출, 도메인 이벤트 기반 데이터 복제, DB 뷰 조인, YARP 기반 BFF 합성 뷰, 별도 리포팅 모듈 등 다섯 가지 조회 방식을 비교
- 각 방식의 대가로 N+1, 데이터 중복과 지연 일관성, DB 레벨 결합, 배포 복잡도, 모듈 격리 원칙 위반을 정리
- 트랜잭션은 도메인 이벤트 기반 최종 일관성과 공유 TransactionManager 기반 강한 일관성 두 접근을 코드로 대비
- 이벤트 발행·구독, DbContext 공유 트랜잭션 설정, EF Core 뷰 매핑, HttpClientFactory 기반 BFF 구현 코드 포함
OpenTelemetry에서 ActivitySource가 실제로 하는 일
- 저자: Bart Wullems
- 태그: #opentelemetry dotnet #tracing
주요 내용
- ActivitySource는 OpenTelemetry가 아니라 System.Diagnostics(BCL) 소속이며 리스너가 없으면 아무것도 기록되지 않음
- 동일한 이름의 ActivitySource 인스턴스를 여러 클래스와 어셈블리에서 생성해도 문제가 없다는 점을 팀 내 검증으로 확인
- TracerProviderBuilder.AddSource()는 이름과 선택적 버전으로 구독하며, 이름이 어긋나면 에러 없이 조용히 드롭되는 것이 계측 누락의 주된 원인
- ActivitySource를 DI 싱글톤으로 등록하는 대신 private static readonly 필드로 두는 방식을 권장
- Company.Product.Component 형태의 명명 규칙과 AddSource(“OrderProcessing.*”) 와일드카드 매칭
ConfuserEx로 보호된 .NET/Godot CTF 챌린지 수동 언패킹
- 저자: Oscar404
- 태그: #reverseengineering #confuserex #ctf
주요 내용
- ConfuserEx 1.6.0으로 보호된 어셈블리를 de4dot 같은 자동 도구 없이 dnSpyEx, monodis, dnfile, .NET 리플렉션만으로 분석
- 투명 유니코드 문자를 이용한 이름 난독화, 스위치 기반 상태 머신의 제어흐름 평탄화, 호출자 종속 문자열 암호화, 의도된 로직 버그 네 가지에 각각 대응
- 6-케이스 스위치를 XOR·곱셈 롤링 상태값으로 역추적해 CryptoUtil.Xor를 단순 XOR 루프로 복원
- 문자열 복호화 키가 StackFrame과 MethodBase로 호출자 신원에 종속되어 외부 리플렉션 호출 시 실패하며, 원래 호출 경로를 보존한 공개 메서드를 통해 우회
- EscalateHeat()의 상한이 5인데 TryOpen()이 6을 요구하는 로직 버그를 리플렉션으로 속성을 직접 조작해 해결
가벼운 읽을거리
후보 항목 중 이슈로 선정되지 않은 가벼운 읽을거리들
C# 14 확장 멤버로 기존 타입에 프로퍼티 추가하기
- C# 14 확장 멤버가 상태를 가진 프로퍼티를 지원하지 않는 한계에서 출발해 ConditionalWeakTable로 객체별 데이터를 연결
- StrongBox<T>로 미설정 값과 null을 구분하고, Unsafe.As 기반 대안과 정적 생성자 레이아웃 검증도 제시
- 두 기법 모두 실무 적용에는 부적합하다는 것이 저자의 결론
ASP.NET Core 엔드포인트에는 타임아웃이 없다
- 애플리케이션 레벨 기본 타임아웃이 없어 .NET 8+ 미들웨어로 직접 설정해야 하며, 강제 종료가 아닌 협조적 취소로 동작
- AddRequestTimeouts() → UseRequestTimeouts() → WithRequestTimeout() 3단계 구성과 스트리밍용 DisableRequestTimeout()
- 토큰이 EF Core와 HttpClient까지 전파되어야 실제로 취소되며 디버거가 붙어 있으면 동작하지 않음
ASP.NET Core 10의 패스키
- .NET 10 Identity에 네이티브 WebAuthn/FIDO2 지원이 들어와 서드파티 라이브러리 없이 패스워드리스 인증 구현
- 등록은 MakePasskeyCreationOptionsAsync → navigator.credentials.create() → PerformPasskeyAttestationAsync 흐름
- 기본 attestation 검증과 하드웨어 allowlist는 아직 지원되지 않음
EF 사용 시 ValueGeneratedOnAdd를 주의하라
- 신규 엔티티인데도 변경 추적기가 Added가 아닌 Modified로 표시해 저장되지 않던 문제의 원인 추적
- Guid.CreateVersion7()으로 ID를 직접 생성하면서 EF에는 알리지 않아 기본값 ValueGeneratedOnAdd가 적용된 것이 원인
- builder.Property(x => x.Id).ValueGeneratedNever() 한 줄로 해결
모듈형 CMS를 만들며 모듈을 플러그인으로 만들지 않은 이유
- 13개 선택 모듈을 런타임 플러그인이 아닌 컴파일 타임 NuGet 의존성으로 구성한 설계 근거
- 플러그인 폴더에 파일을 놓는 것은 임의 코드 실행이라는 위협 모델과, AssemblyLoadContext 로딩이 Native AOT·트리밍을 차단한다는 제약
- 설치 시 개발자 개입 필요와 단일 의존성 그래프의 버전 충돌 가능성은 한계로 인정
.NET 오픈소스 지속가능성을 위한 오픈 코어 모델
- Marten·Wolverine 핵심은 MIT로 유지하고 컨설팅·지원 계약과 상용 도구로 수익을 얻는 3단계 사업 모델
- Wolverine의 리더 선출 같은 기능은 전업 개발 없이는 불가능했다며 DB 장애·커넥션 드롭·쿠버네티스 이슈를 근거로 제시
- Polly의 OSMF 라이선스 채택에 공감하면서도 고객 반발 시 의존성을 교체할 수 있다는 입장도 함께 밝힘
Postie — Minimal API를 커맨드·쿼리 핸들러에 직접 매핑
- MapQuery, MapPostCreate, MapPutCommand, MapDeleteCommand로 Minimal API를 핸들러에 연결하고 200/404, 201+Location, 204를 자동 반환
- [FromRoute] 오탐지 같은 설정 실수를 시작 시점에 예외로 즉시 실패시키며, IEndpointDispatcher로 MediatR 등 다른 미디에이터 교체 가능
.NET bin·obj 디렉터리 정리 도구
- .csproj를 재귀 탐색해 각 프로젝트의 bin·obj 폴더를 찾고 PowerShell/Bash 환경에 맞는 삭제 명령을 생성
- 명령을 자동 실행하지 않고 검토용으로만 출력하며 현재 디렉터리 탐색 시에는 확인 프롬프트를 표시
