Add System.ServiceModel.Msmq — client-side MSMQ transport#5958
Open
afifi-ins wants to merge 1 commit into
Open
Add System.ServiceModel.Msmq — client-side MSMQ transport#5958afifi-ins wants to merge 1 commit into
afifi-ins wants to merge 1 commit into
Conversation
afifi-ins
added a commit
to afifi-ins/wcf
that referenced
this pull request
Jun 8, 2026
The Helix Linux and macOS legs were failing on three theory cases:
MsmqConditionsTest.ImplicitDtcEnabled_HonorsEnvVar("true"|"TRUE"|"True")
Symptom:
Assert.True() Failure
Expected: True
Actual: False
Root cause: ConditionalTestDetectors.IsImplicitDtcEnabled() is
Windows-only by design (MSMQ itself is Windows-only) and returns
false on non-Windows hosts regardless of the env var. The
[SupportedOSPlatform("windows")] attribute on the test class is an
analyzer hint only — xunit still ran the tests on Linux / macOS Helix
queues and the Assert.True expectation no longer held.
Fix: assert the actual contract — true on Windows, false elsewhere —
so the test passes on every platform the dispatch runs on.
Verified locally on Windows: 150/150 unit tests pass.
Port the WCF MSMQ client transport (NetMsmqBinding and MsmqIntegrationBinding) from .NET Framework into a new, shippable System.ServiceModel.Msmq NuGet package. Enables modern .NET clients to send SOAP and raw-body messages to MSMQ queues, with optional DTC transaction enlistment. The package is Windows-only and self-contained on the managed side (depends only on System.ServiceModel.Primitives). Features - NetMsmqBinding: SOAP-over-MSMQ with the full binding-element graph (MsmqTransportBindingElement, MsmqBindingElementBase, MsmqBindingBase). - MsmqIntegrationBinding: interop with legacy MSMQ applications via MsmqMessage<T> and MsmqIntegrationMessageProperty (raw body, no SOAP envelope). - Channel shapes: IOutputChannel and IOutputSessionChannel with their channel factories; MsmqUri address translators (net.msmq://, FormatName, private/direct). - Native interop: a hand-rolled P/Invoke layer over mqrt.dll (UnsafeNativeMethods, SafeMsmqQueueHandle, NativeMsmqMessage, MsmqQueue) with no third-party runtime dependency. - Transactions: MessageQueueTransactionType None/Single/Automatic; Automatic enlists the ambient System.Transactions transaction into MSMQ's native DTC via DtcTransactionBridge (no custom IEnlistmentNotification required). - Error handling: MsmqException maps native MQ_ERROR_* HRESULTs to the corresponding WCF exceptions. - MSMQ-Integration enums (AcknowledgeTypes, Acknowledgment, MessageType, MessagePriority) shipped by this package with values pinned to the native MQMSG_* constants. - Security value types: NetMsmqSecurity, MsmqTransportSecurity, MessageSecurityOverMsmq, MsmqAuthenticationMode, MsmqEncryptionAlgorithm, MsmqSecureHashAlgorithm. Shared-assembly change - Promote AddressAccessDeniedException from System.ServiceModel.NetNamedPipe to System.ServiceModel.Primitives so the MSMQ transport can map MQ_ERROR_ACCESS_DENIED / MQ_ERROR_SHARING_VIOLATION to it without a cross-transport coupling. NetNamedPipe keeps a [TypeForwardedTo] for binary compatibility. Testing - 213 unit tests (binding shape, URI translation, exception mapping, native message layout, enum values, transaction-mode dispatch). - 5 scenario tests against a real localhost MSMQ queue manager (Binding.Msmq.IntegrationTests); 2 are environment-gated for DTC. - Helix CI wired to best-effort enable the Windows MSMQ feature; scenarios skip cleanly via [Condition(MsmqInstalled)] when MSMQ is unavailable. - Localized string resources (13 languages); package validation passes with an empty CompatibilitySuppressions.xml. Scope: client send path only. Service hosting / receive pipeline is out of scope (see CoreWCF). Session-gram framing for IOutputSessionChannel is deferred. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: cffba073-486d-49e6-8683-cf30c1eb5e28
afifi-ins
force-pushed
the
feature/msmq-porting
branch
from
July 24, 2026 04:14
5a373f1 to
64371d9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a new client transport package,
System.ServiceModel.Msmq, thatprovides the WCF client-side surface of .NET Framework's
NetMsmqBindingand
MsmqIntegrationBindingon modern .NET. Sending is wired end-to-endvia the
MSMQ.MessagingNuGet (community port ofSystem.Messaging);listeners and any other server-side concern remain out of scope and
should live in CoreWCF.
Stats
(2 transactional scenarios env-var-gated by design — see below)
-warnaserrorPublic surface (23 types)
System.ServiceModel:NetMsmqBinding,MsmqBindingBase,NetMsmqSecurity,NetMsmqSecurityMode,MsmqTransportSecurity,MessageSecurityOverMsmq,MsmqAuthenticationMode,MsmqEncryptionAlgorithm,MsmqSecureHashAlgorithm,DeadLetterQueue,QueueTransferProtocol,MsmqException,PoisonMessageException,MsmqPoisonMessageExceptionSystem.ServiceModel.Channels:MsmqBindingElementBase,MsmqTransportBindingElementSystem.ServiceModel.MsmqIntegration:MsmqIntegrationBinding,MsmqIntegrationBindingElement,MsmqIntegrationSecurity,MsmqIntegrationSecurityMode,MsmqMessageSerializationFormat,MsmqMessage<T>,MsmqIntegrationMessagePropertyKey architectural decisions (open for review)
MSMQ.Messaging1.0.4 as a hardPackageReferenceinstead ofre-implementing the native MSMQ P/Invoke layer. Saves ~1,300 LOC
from the reference source and matches netfx semantics one-for-one.
net10.0only (notnet462). Full .NET Framework already shipsthe same public types in
System.ServiceModel.dll; co-targetingproduces CS0436 ambiguity for every public type.
ref/project, noSystem.ServiceModel.Shimtype-forwards— matches the modern pattern of
NetNamedPipe,Federation,UnixDomainSocket.AddressAccessDeniedExceptionmappings →CommunicationExceptionbecause the type lives in
System.ServiceModel.NetNamedPipe(notin
Primitives) and shipping our own copy would conflict atconsume time. Could be cleaned up by promoting it to
Primitives.MessageQueueTransactionType.Automaticfor ambient transactions —delegates to mqrt.dll's native DTC, no custom
IEnlistmentNotificationneeded.Bugs caught + fixed during the port
MessageQueueException.ErrorCodeis the generic HRESULT(0x80004005), not the native MQ_ERROR_* code. Had to convert through
MessageQueueErrorCodeforMsmqException.Normalizedto map.Regression:
MsmqMessagingInteropTest.cannot be flipped reliably from inside the xunit-console host. The
two transactional scenarios are env-var-gated
(
WCF_MSMQ_ENABLE_DTC_TESTS=true); product correctness is verifiedout-of-process. Regression:
MsmqConditionsTest.CI
azure-pipelines-arcade-PR.ymlneeds no edits — Helix alreadydiscovers
Scenarios/**/*.IntegrationTests.csproj.eng/SendToHelix.projgets a one-PropertyGroupHelixPreCommandsto best-effort
Enable-WindowsOptionalFeature MSMQ-Server+Start-Service MSMQon Windows workers.[Condition(MsmqInstalled)]skips the scenarios.Follow-ups (intentionally deferred)
IOutputSessionChannelso the channelinter-ops with netfx WCF services hosted with
SessionMode.Required.Today we send one MSMQ message per
Send()with auuid:{Guid}session id.
MsmqUri.ActiveDirectory+DLQtranslators — not on thehappy path; non-breaking add.
— replace the scenario tests' "send + read-back-via-MSMQ.Messaging"
pattern with a real WCF client → CoreWCF host → WCF client
round-trip.
Open questions for reviewers
MSMQ.Messagingas a runtime dependency, or prefer aP/Invoke reimplementation?
AddressAccessDeniedExceptionfromNetNamedPipetoPrimitivesso we can use the right mapping?Enable-WindowsOptionalFeature MSMQ-Servertowindows.11.amd64.client.openHelix image directly, or keep theper-workitem enable in
SendToHelix.proj?