주말 아침 - 주간 닷넷 #31


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


:pushpin: C# 15의 조용한 확장 — collection expression with(...)와 union 키워드

https://medium.com/@Rajdip27/c-15-quietly-expanded-and-its-a-bigger-deal-than-you-think-73c7c32d253f

  • 저자: Santanu Chandra
  • 태그: #csharp15 #collectionexpressions #uniontypes

주요 내용

  • 컬렉션 표현식 인자(with(...) 절): 생성자 인자(capacity, comparer 등)를 컬렉션 표현식 안에서 직접 전달
  • with(...)는 표현식의 첫 요소 위치에 와야 한다는 제약
  • union 키워드 도입으로 합 타입(sum type) 선언, 패턴 매칭 시 컴파일러가 망라성(exhaustiveness) 강제
  • 값 타입의 union 사용 시 박싱 오버헤드 트레이드오프
  • 짧은 코드 샘플(List with capacity, Pet union/switch) 시연

:pushpin: EF Core 페이지네이션 후속편 — Keyset, 정렬 그리드, htmx, 인덱싱 비용

  • 저자: Chris Woodruff
  • 태그: #efcore #pagination #htmx

주요 내용

  • Keyset 페이지네이션 채택 조건을 “큰 테이블 AND 쓰기 빈도 높음 AND 사용자 노출” 세 가지로 좁힘
  • 고정 정렬은 (CreatedAt, Id) 복합 커서/인덱스로 단순하지만, 동적 정렬은 SortColumn/Direction/KeyValue/Id 커서와 switch 디스패치(4컬럼 기준 약 80줄)로 비용 증가
  • 모든 keyset 정렬 컬럼은 PK로 끝나는 커버링 복합 인덱스 필요. 1천만 행·8컬럼 시나리오에서 4개 인덱스가 약 1GB 차지, 쓰기 증폭 발생
  • htmx의 hx-trigger="revealed" 센티넬 행과 ?handler=Sort 핸들러로 무한 스크롤·정렬 변경 구현, 커서는 불투명 토큰으로 인코딩
  • ~5만 행 미만, 관리자 UI의 “N페이지로 점프”, 정적 데이터, 12개 이상 동적 정렬 컬럼에서는 offset이 더 적합

:pushpin: Dapper at Scale — 저장 프로시저로 오후를 날린 5가지 교훈

https://levelup.gitconnected.com/dapper-at-scale-the-stored-procedure-lessons-that-cost-me-an-afternoon-e3b1bc9cfa25

  • 저자: Tim Turner
  • 태그: #dapper #storedprocedures #datalayer

주요 내용

  • 인라인 SQL과 SP 혼용보다 SP로 완전 통일 권장 (반쪽짜리 마이그레이션의 위험성)
  • 시드 데이터 멱등 배포: 고정 데이터셋은 블록 단위 가드, 증가 데이터셋은 행 단위 가드
  • 모든 SP가 출력 파라미터(@ErrorMessage, @ErrorFound)로 에러 보고하는 표준화된 규약
  • IDapperBase 추상화로 파라미터 바인딩/출력 파라미터 처리 보일러플레이트 제거
  • 패턴 이식 시 암묵적 전제(예: SP의 NULL 기본값 vs DBNull 명시 전달) 확인의 중요성

:pushpin: C# 구조체에서 강타입 제로카피 뷰까지

https://medium.com/@zabavnov/from-structs-to-strongly-typed-zero-copy-views-in-c-2119a8dab661

  • 저자: Vadim Zabavnov
  • 태그: csharp #refstruct #zerocopy

주요 내용

  • 값 의미론 관점에서 ref, in, ref readonly 매개변수의 차이를 정리
  • ref struct가 스택에만 존재하도록 강제되는 제약이 안전성을 보장하는 핵심 이유
  • ref 기반 추상화는 상속이 아니라 provider/cursor/projection/bounds/driver로 분리한 컴포지션 권장
  • Sudoku 풀이(행/열/블록 통합 로직), 다차원 디바이스 메모리 검사(5차원 커서를 flat 버퍼에 매핑)를 사례로 사용
  • API 복잡도 증가, 수명 제약, 힙 기반 다형성 상실, 인지 부담 등 트레이드오프 명시

:pushpin: 팬아웃 동시성 포스트모템 — Task.WhenAll이 1,400 RPS를 5,600 RPS로 증폭시킨 사례

https://bhautikk.medium.com/when-parallel-became-a-problem-a-backend-engineering-postmortem-on-fan-out-concurrency-729deb5a19d9

  • 저자: Bhautik Kapadiya
  • 태그: #concurrency #postmortem #resilience

주요 내용

  • 음식 배달 플랫폼 주문 집계 서비스가 트래픽 피크에서 120ms → 4,800ms 레이턴시로 악화된 사례
  • 요청당 4개 다운스트림 병렬 호출(Task.WhenAll)이 1,400 RPS를 5,600 RPS로 증폭시켜 커넥션 풀 고갈
  • 근본 원인 4가지: 무제한 트래픽 증폭, bounded concurrency 부재, 글로벌 deadline 부재, async/await의 자동 scalable 오해
  • 해결책: SemaphoreSlim으로 동시 호출 제한, CancellationToken 글로벌 deadline, Polly로 retry/circuit breaker, 비핵심 호출 graceful degradation

:pushpin: AutoStack.Identity — 무의존성 .NET 10 SAML 2.0 / JWT / XML 서명 라이브러리 만들기

https://medium.com/@mishraabhishek.2899/building-autostack-identity-a-zero-dependency-net-10-library-for-saml-2-0-jwt-and-xml-signing-0a8b58a2c97b

주요 내용

  • 헬스케어 SSO 통합 시 Microsoft.Identity.Web의 SAML 미지원, 서드파티 SAML의 미들웨어 결합·테스트 난이도, 보안 감사에서 발견된 토큰 리플레이 취약성이 자체 구현 동기
  • JWT(RS/ES/HS 256·384·512), SAML 2.0 SP/IdP 플로우, 임의 XML 디지털 서명 검증 세 가지 핵심 기능
  • IJwtSigner/IJwtVerifier 인터페이스로 프로토콜과 암호 연산 분리, TimeProvider 주입으로 만료 테스트 결정성 확보
  • 표준 충실 구현(RFC 7518 ECDSA의 IEEE P1363 포맷, HMAC 타이밍 안전 비교)과 자체 구현 유틸(Base64URL) 트레이드오프
  • XML 정규화에서 공백·네임스페이스 처리가 서명 검증에 미치는 민감성

:pushpin: .NET 백엔드의 멱등성 설계 — 키, 해시, DB 제약, Outbox까지

https://medium.com/@oshadhaj/idempotency-in-net-backend-systems-how-to-prevent-duplicate-processing-fd8a60b8ddd4

  • 저자: Oshadha Thrimavithana
  • 태그: dotnet #idempotency #backend

주요 내용

  • 재시도, 메시지 재전송 등으로 발생하는 중복 처리 문제와 멱등성 정의
  • Idempotency-Key 헤더 + 요청 페이로드의 SHA-256 해시 저장으로 오용 감지
  • 애플리케이션 레벨 체크만으로는 동시성에서 부족 — DB에 (Key, Operation) 유니크 제약 권장
  • 비즈니스 변경과 멱등성 레코드를 단일 트랜잭션 안에서 원자적으로 커밋
  • Inbox/Outbox 패턴을 결합해 at-least-once 메시지 전달 환경에서 안전성 확보

:pushpin: Task를 ValueTask로 교체했더니 — 핫패스에서 0 byte 할당 경험

https://serkanozbeykurucu.medium.com/i-replaced-task-with-valuetask-in-my-data-layer-heres-what-actually-happened-283f2e4afc9e

  • 저자: Serkan Özbey Kurucu
  • 태그: #valuetask #performance async

주요 내용

  • Task<T>는 동기 완료 경우에도 힙 할당, 고처리량 시 GC 압박
  • ValueTask<T>는 struct로 동기 완료 시 스택 보관, 진짜 비동기일 때만 Task 래핑
  • 95% 캐시 적중 메서드 벤치마크에서 ValueTask는 0 byte 할당, Task는 지속적 할당
  • 적합: 캐시 조회, 커넥션 풀, 프로듀서-컨슈머 같은 동기 완료 빈도 높은 핫패스 / 부적합: 공개 API, 다중 await, 네트워크/디스크 I/O
  • ValueTask<T>는 단 한 번만 await 가능

:pushpin: OpenTelemetry 로그에 Serilog 스타일 destructuring 도입하기

https://medium.com/@sebastien.desalvador/bringing-serilog-style-destructuring-to-opentelemetry-logs-b9bac0ae905a

  • 저자: Sébastien de Salvador
  • 태그: #opentelemetry #serilog #logging

주요 내용

  • Serilog → OpenTelemetry 마이그레이션 시 잃게 되는 자동 객체 destructuring(중첩 속성을 쿼리 가능한 필드로 평탄화) 문제 제기
  • Serilog의 @ prefix 구문이 OpenTelemetry에는 기본 미제공
  • SerilogLikeDestructuringProcessor를 파이프라인에 끼워 @ 접두 attribute를 감지해 JSON(camelCase) 직렬화 후 교체
  • 실패 시 ToString()으로 fallback
  • 기존 Serilog 코드 패턴과 관측성 투자를 보존하면서 OpenTelemetry로 점진 전환 가능

:pushpin: .NET 현대화 Part 26 — ASP.NET Core Rate Limiting 미들웨어로 40초 → 1초

https://medium.com/@michael.kopt/️-modernizing-net-part-26-implementing-rate-limiting-middleware-in-asp-net-core-29eb8451d762

  • 저자: Michael Kopt
  • 태그: aspnetcore #ratelimiting #middleware

주요 내용

  • 무제한 동시 요청 시 40초+ 응답 스파이크가 PermitLimit 25 적용 후 1초 미만으로 감소한 사례
  • 시간 윈도우가 아닌 Concurrency Limiter 전략을 채택해 스레드풀 고갈 방지
  • PartitionedRateLimiter.Create<HttpContext, string> 기반 구체 코드 — PermitLimit, QueueLimit, FIFO 큐 설정
  • UseRateLimiter()를 라우팅 뒤, 인가 앞에 배치하라는 파이프라인 가이드
  • PermitLimit 10~25에서 시작, 피크 시 CPU 70% 미만 유지 권장

:pushpin: Shiny.DocumentDb v6 — 벡터 검색과 전역 쿼리 필터

  • 저자: Allan Ritchie
  • 태그: #documentdb #vectorsearch dotnet

주요 내용

  • 벡터/ANN 검색 추가: pgvector, SQL Server 2025 VECTOR_DISTANCE, Cosmos DiskANN, MongoDB Atlas $vectorSearch, DuckDB vss로 네이티브 변환
  • ReadOnlyMemory<float>Microsoft.Extensions.AI.Embedding 통합
  • EF Core HasQueryFilter 형식의 전역 쿼리 필터 — 읽기·단건·대량·체인지 스트림에 일괄 적용, 명명 필터는 선택적 비활성화 가능
  • CreateIndexAsync<T>(ctx.User, u => u.LastName, u => u.FirstName) 형태의 복합 JSON 인덱스 지원
  • PostgreSQL/MySQL/SQL Server에서 세마포어 직렬화를 제거하고 ADO.NET 드라이버 풀링 사용, AOT 호환 유지

:bookmark_tabs: 가벼운 읽을거리

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


.NET 개발자를 위한 Python — 타입, 클래스, 레코드, 인터페이스 매핑

  • Python의 동적 타이핑과 C# 정적 타이핑, self/__init__ 명시, new 키워드 부재 같은 차이를 한쪽씩 매핑
  • C# record ↔ Python @dataclass, 인터페이스의 ABC(명목) vs Protocol(구조) 두 접근 비교

Dapper로 EF Core 없이 낙관적 동시성 구현하기

  • LastUpdated DateTime 컬럼을 동시성 토큰으로 사용, UPDATE의 WHERE 절에 타임스탬프 비교 추가
  • 영향 행 수 0이면 충돌로 판정해 HTTP 409 반환, 클라이언트에 LastUpdated를 함께 반환하는 읽기-수정-쓰기 3단계 패턴

ConsoleLogStreaming — SSE로 분산 앱 콘솔 실시간 스트리밍

  • AddConsoleLogStreaming() + UseConsoleLogStreaming() 미들웨어 등록만으로 콘솔 출력을 REST API로 노출
  • 브라우저는 EventSource(SSE)로 /console-logs 구독, 워크플로 디자이너·디버깅 UI 같은 라이브 출력 대시보드용

ToLookup() — 가장 저평가된 LINQ 기능

  • 1:N 관계에서 Dictionary<TKey, List<TValue>> 대신 ILookup<TKey, TValue> 활용, 즉시 실행 후 메모리 캐싱
  • 반복 조회 시 Where() 재스캔(O(n))을 O(1) 인덱스로 대체, 존재하지 않는 키 접근 시 빈 컬렉션 반환

ToList()의 숨겨진 비용

  • 1000만행 운영 환경에서 ToList()가 즉시 메모리 할당과 GC 압박을 유발, Where()로 메모리 필터링하는 안티패턴
  • SQL 단에서 미리 필터링하고 Select()로 필요한 컬럼만 가져오는 패턴 권장, lazy loading과 결합 시 N+1 위험

JetBrains Rider 2026.2의 WPF Hot Reload

  • Rider 2026.2 EAP 2부터 디버거 실행 중 XAML 편집을 실시간 반영, 대상 TFM은 .NET 9.0-windows / .NET 10.0-windows / .NET Framework
  • NuGet 추가, 새 컨트롤/윈도/페이지 추가, x:Class·루트 타입 변경, 런타임 리소스/테마 사전 변경 시는 재시작 필요

ReflectionIT.PropertyThrowGenerator — partial property에 가드 절 자동 주입

  • [ThrowIfNull], [ThrowIfGreaterThan(...)], [ThrowIfNegative] 등 속성 부착만으로 setter 검증 코드를 Roslyn 소스 생성기가 생성
  • 내부적으로 .NET 8의 ArgumentException.ThrowIf... 헬퍼 호출, C# 14 / .NET 8 이상 필요

Windows 11 WinUI 전략 변화 — 네이티브 앱 권장과 셸 재작성

  • "WinUI 3"에서 버전 표기를 제거하고 그냥 "WinUI"로 리브랜딩, 향후 대규모 breaking change 없음을 시사
  • Windows 11 셸과 시작 메뉴를 React Native에서 네이티브 WinUI로 재작성, 엔터프라이즈용 DataGrid·Charting 컨트롤 추가 예정
4개의 좋아요

"망라성"이라는 단어는 직접 생각해낸 것인가요?
번역이나 책을 쓰시면 잘 쓰실 듯 합니다.

1개의 좋아요

오… 굳은 의지 좋네요. WPF 개발자는 어차피 WPF에서 WPF-UI 쓰면서 필요한 Windows 기능에 대해서만 Windows App SDK 사용하면 개발 스탠스는 거의 비슷하겠지만요…

WinUI도 Microsoft.UI.Xaml 사용하는 것처럼 어차피 WPF와 유사하게 개발하다보니 아직은 넘어가야하나 라는 생각이 크게 안드는데 WPF랑 WinUI 둘다 사용해보신 분들이 어떤 차이를 느끼셨을지 궁금하네요.

1개의 좋아요

헙!!! 클로드의 번역입니다 ㅋㅋㅋㅋ

1개의 좋아요