
Experimental.System.Messaging을 대대적으로 정비했습니다.net8.0으로 업그레이드하고, GitHub Actions CI/CD를 구축했습니다.2018년, .NET Core가 한창 성장하던 시기에 MSMQ(Microsoft Message Queuing)를 .NET Core에서 사용해야 하는 상황이 생겼습니다. 당시 Microsoft는 System.Messaging을 .NET Core로 포팅할 계획이 없었고, 저는 Microsoft Reference Source에서 소스 코드를 가져와 직접 포팅한 뒤 NuGet 패키지로 배포했습니다.
그렇게 만들어진 Experimental.System.Messaging 패키지는 누적 다운로드 수만 봐도 꽤 많은 분들이 사용해주셨습니다. 하지만 정작 저는 1.1.0 버전 이후로 거의 6년간 이 패키지를 방치해두었습니다.
2025년 11월, 커뮤니티에서 제보된 이슈들과 PR을 검토하다가, 이 패키지에 심각한 문제가 있다는 것을 깨달았습니다.
가장 큰 문제는 라이선스였습니다.
원본 소스 코드는 Microsoft Reference Source에서 가져온 것으로, Ms-RL (Microsoft Reciprocal License) 하에 배포되었습니다. 그런데 저는 당시 라이선스에 대한 이해가 부족해서, 이 패키지를 MIT 라이선스로 잘못 배포했습니다.
Ms-RL은 파생 저작물도 동일한 라이선스로 배포해야 한다는 조건이 있습니다. 즉, 처음부터 Ms-RL로 배포했어야 했습니다. 오픈소스 생태계에서 라이선스 준수는 기본 중의 기본인데, 이런 기본적인 부분을 놓쳤다는 것이 정말 부끄럽습니다.
v1.2.0에서 이 문제를 수정하고, README에 다음과 같은 설명을 추가했습니다:
The original source code was obtained from Microsoft Reference Source when it was available under the Ms-RL license. Due to insufficient understanding at the time, this package was mistakenly distributed under the MIT License from its initial release until version 1.1.0. We sincerely apologize for this error and have corrected the license to Ms-RL starting from version 1.2.0.
이번 릴리스에서 가장 중요한 버그 수정은 StringToBytes 메서드의 Unicode 문자열 null 종료 처리 문제입니다.
이 버그는 MessageQueue.Label, Message.Label, MessageQueue.MulticastAddress, 그리고 큐 포맷 이름 관련 속성들에 영향을 주고 있었습니다. 문자열 끝에 null terminator가 제대로 처리되지 않아서, 특정 상황에서 문자열이 잘리거나 예상치 못한 문자가 포함되는 문제가 있었습니다. 실제 운영 환경에서 이 문제를 겪고 제보해주신 분들께 감사드립니다.
이번 릴리스의 하이라이트는 큐 접근 제어(ACL) 설정 기능입니다. GitHub 사용자 @j0hnth0m 님이 PR #5를 통해 기여해주셨습니다.
이 기능을 위해 다음 클래스들이 새로 포팅되었습니다:
AccessControlEntry, AccessControlEntryType, AccessControlListMessageQueueAccessControlEntryMessageQueuePermission, MessageQueuePermissionAccessMessageQueuePermissionEntry, MessageQueuePermissionEntryCollection이제 프로그래밍 방식으로 MSMQ 큐에 대한 접근 권한을 설정할 수 있습니다. 엔터프라이즈 환경에서 보안 요구사항을 충족하는 데 유용한 기능입니다.
라이선스 문제 외에도, 문서에서 사용하던 "counterfeit(위조품)"라는 표현을 "unofficial port(비공식 포트)"로 변경했습니다.
"counterfeit"라는 단어에 대해 조금 변명을 하자면, 당시 저는 영어가 익숙하지 않아서 이 단어가 가진 무게를 제대로 이해하지 못했습니다. 단순히 "공식이 아닌 것", "원본을 흉내 낸 것" 정도의 가벼운 뉘앙스로 생각하고 사용했는데, 최근에야 이 단어가 "위조품", "가짜", 심지어 불법적인 복제물을 의미하는 상당히 강한 부정적 표현이라는 것을 알게 되었습니다. 합법적으로 공개된 소스 코드를 기반으로 만든 파생 저작물을 스스로 "위조품"이라고 부른 셈이니, 지금 생각하면 정말 부끄러운 표현 선택이었습니다. "unofficial port(비공식 포트)"가 이 프로젝트의 성격을 훨씬 정확하게 설명하는 표현입니다.
또한, MSMQ를 처음 접하는 분들을 위해 원격 큐 경로 포맷에 대한 문서도 추가했습니다. TCP, OS, HTTP, HTTPS 프로토콜별 포맷 이름 구문과 예제를 README에 정리해두었습니다.
6년이라는 시간 동안 .NET 생태계는 엄청나게 변했습니다. 이번 기회에 빌드 환경을 전면적으로 현대화했습니다.
netstandard2.0 → net8.0처음에는 크로스플랫폼 호환성을 위해 .NET Standard 2.0을 타겟으로 했습니다. 하지만 MSMQ는 Windows 전용 기술입니다. Mono는 WineHQ로 전환되었고, .NET Framework는 이미 네이티브 System.Messaging을 가지고 있으며, Silverlight, UWP, Unity 등은 이 라이브러리의 대상이 아닙니다. 결국 .NET Standard 타겟팅은 불필요한 복잡성만 추가하고 있었습니다.
.NET 8.0으로 전환하면서 최신 C# 기능과 성능 개선의 혜택을 받을 수 있게 되었습니다.
이제 코드를 푸시하면 자동으로 빌드와 테스트가 실행됩니다. 워크플로우에서는 Windows 러너에 MSMQ를 자동으로 설치하고, 테스트용 큐를 생성한 뒤 단위 테스트를 실행합니다. 릴리스 태그를 푸시하면 NuGet 패키지가 자동으로 발행됩니다.
테스트 프로젝트도 .NET Core 2.0에서 .NET 8.0으로 업그레이드했습니다. 테스트 관련 패키지들도 모두 최신 버전으로 업데이트했고, 테스트가 큐의 존재 여부를 확인하고 필요시 자동 생성하도록 개선하여 테스트 독립성을 높였습니다.
BinaryMessageFormatter에서 사용하는 BinaryFormatter는 보안상의 이유로 .NET 5부터 deprecated 되었습니다. 하지만 MSMQ와의 호환성을 위해 이 코드를 유지해야 하므로, #pragma warning disable SYSLIB0011을 추가하여 경고를 억제했습니다. 원본 코드의 동작을 최대한 유지하면서도 빌드 경고 없이 컴파일되도록 했습니다.
NuGet 패키지 자체의 품질도 개선했습니다.
사실 이 패키지를 계속 방치한 데에는 변명의 여지가 없습니다. 하지만 몇 가지 계기가 있었습니다:
커뮤니티 기여: @j0hnth0m 님이 접근 제어 기능을 추가하는 PR을 보내주셨습니다. 누군가 이 패키지를 실제로 사용하고 있고, 심지어 기능을 추가해주려 한다는 사실이 저를 움직이게 했습니다.
버그 리포트: Unicode 처리 버그가 실제 운영 환경에서 문제를 일으키고 있다는 제보를 받았습니다. 제 패키지 때문에 누군가 고생하고 있다는 것을 알게 되니 더 이상 방치할 수 없었습니다.
라이선스 인식: 오픈소스 라이선스에 대해 더 공부하면서, 과거의 실수를 깨달았습니다. MIT 라이선스로 배포한 것이 단순한 실수가 아니라 원 저작자의 의도를 훼손한 것일 수 있다는 점에서 책임감을 느꼈습니다.
Microsoft가 공식 MSMQ 클라이언트를 .NET Core/.NET 8+용으로 출시할 가능성은 낮아 보입니다. MSMQ 자체가 레거시 기술로 분류되고 있고, Microsoft는 Azure Service Bus나 다른 현대적인 메시징 솔루션으로의 마이그레이션을 권장하고 있으니까요.
하지만 현실에서는 여전히 MSMQ를 사용하는 시스템이 많습니다. 당장 마이그레이션할 수 없는 상황에서 .NET 8+로 업그레이드해야 하는 분들에게 이 패키지가 도움이 될 수 있습니다. 그렇다면 이 비공식 패키지라도 제대로 관리하는 것이 이 패키지를 사용하는 분들에 대한 최소한의 책임이라고 생각했습니다.
오래된 프로젝트를 다시 들여다보는 것은 과거의 미숙함과 마주하는 일이기도 합니다. 라이선스 실수, 방치된 이슈들, 업데이트되지 않은 의존성, 부적절한 용어 선택...
그래도 늦었다고 생각할 때가 가장 빠른 때라고 하죠. 이번 v1.2.0 릴리스를 계기로, 앞으로는 좀 더 책임감 있게 이 패키지를 관리하려고 합니다.
만약 이 패키지를 사용하고 계시다면, v1.2.0으로 업그레이드해 주세요. 그리고 언제든 이슈나 PR은 환영합니다!