Skip to content

Add client-side WebHttpBinding support (closes #1413, #46) - #5959

Open
afifi-ins wants to merge 33 commits into
dotnet:mainfrom
afifi-ins:feature/webhttpbinding-porting
Open

Add client-side WebHttpBinding support (closes #1413, #46)#5959
afifi-ins wants to merge 33 commits into
dotnet:mainfrom
afifi-ins:feature/webhttpbinding-porting

Conversation

@afifi-ins

Copy link
Copy Markdown
Contributor

Closes #1413
Closes #46

Summary

Adds client-side WebHttpBinding support to .NET (Core) WCF. The entire System.ServiceModel.Web namespace (binding, behavior, attributes, WebChannelFactory<T>, UriTemplate, WebOperationContext, QueryStringConverter, ...) has been absent from dotnet/wcf since the start — confirmed missing in both dotnet/wcf and dotnet/runtime (the runtime ships a System.ServiceModel.Web shim that only forwards Syndication/JSON types — zero WCF REST types). Issues #1413 and #46 have tracked this gap since 2015–2016.

This PR introduces a new src/System.ServiceModel.Web/ package that ships ~14,000 LOC of client-side REST support, sourced from:

  • CoreWCF.WebHttp v1.8.0 (MIT, .NET Foundation) — encoder factories, attributes, contexts, behavior, dispatcher formatters
  • Microsoft .NET Framework Reference Source mirror in mono/mono (MIT since 2014) — the full UriTemplate cluster and WebChannelFactory<T> (CoreWCF doesn't ship these because they're either standalone utilities or strictly client-only)

What ships

Namespace Public types
System UriTemplate, UriTemplateTable, UriTemplateMatch, UriTemplateMatchException, UriTemplateEquivalenceComparer
System.ServiceModel WebHttpBinding, WebHttpSecurity, WebHttpSecurityMode
System.ServiceModel.Channels WebMessageEncodingBindingElement, WebContentTypeMapper, WebBodyFormatMessageProperty, WebContentFormat
System.ServiceModel.Description WebHttpBehavior (~870 LOC)
System.ServiceModel.Dispatcher QueryStringConverter, UriTemplateClientFormatter, SingleBodyParameter{,DataContract,XmlSerializer}MessageFormatter, DataContractJsonSerializerOperationFormatter, HttpStreamFormatter, {Xml,Json,Multiplexing}FormatMapping, UnwrappedTypesXmlSerializerManager, NameValueCache
System.ServiceModel.Web WebGetAttribute, WebInvokeAttribute, WebChannelFactory<T>, WebFaultException, WebFaultException<T>, WebOperationContext, IncomingWebRequestContext, IncomingWebResponseContext, OutgoingWebRequestContext, OutgoingWebResponseContext, WebMessageFormat, WebMessageBodyStyle

Surgically deferred (NotSupportedException with clear messages)

dotnet/wcf is a client-only library, so the following server-side features are explicitly stubbed and documented per commit. Use CoreWCF.WebHttp on the server side:

  • WebHttpBehavior.ApplyDispatchBehavior (and the helpers it called: WebHttpDispatchOperationSelector, UriTemplateDispatchFormatter, WebErrorHandler, FormatSelectingMessageInspector, MultiplexingDispatchMessageFormatter, HelpPage, HttpUnhandledOperationInvoker, ...)
  • Raw octet-stream pass-through (ByteStreamMessage, MessageBodyStream, raw StreamBodyWriter)
  • JSONP (WebScriptEnablingBehavior, JavascriptCallbackBehaviorAttribute)
  • AspNetCacheProfileAttribute
  • IIS WebServiceHost / WebServiceHostFactory

Primitives changes

Just one item — minimum required for a client-only port:

  • InternalsVisibleTo("System.ServiceModel.Web") added to System.ServiceModel.Primitives.csproj so the new assembly can reach DiagnosticUtility.ExceptionUtility, Fx, XmlSerializerOperationBehavior.Reflector, internal IDispatchMessageFormatter, OperationFormatter.CreateDeserializationFailedFault, BufferedMessage/BufferedMessageData/BufferedMessageWriter, etc.

Same IVT entry added to System.ServiceModel.Http.csproj for HttpTransportDefaults.

Tests

  • Unit tests in src/System.ServiceModel.Web/tests/ — 3 tests covering binding/factory/behavior construction. All passing locally (80ms).
  • Scenario / outerloop tests in src/System.Private.ServiceModel/tests/Scenarios/Binding/WebHttp/Binding.WebHttp.IntegrationTests.csproj — 4 round-trip tests (EchoWithGet XML, EchoWithGetJson JSON, EchoWithPost, EchoWithGetPath path-var). Built and discovered; pending live CI run.
  • Server-side test host WebHttpTestServiceHost.cs in tools/IISHostedWcfService/App_code/testhosts/ with contract IWcfWebHttpService. Auto-picked-up by SelfHostedCoreWcfService via the existing <Compile Include="..\IISHostedWcfService\**\*.cs"> glob. Helix auto-discovers the new test project via the **\*.IntegrationTests.csproj glob in eng/SendToHelix.proj — no CI registration changes needed.
  • New file tests/Common/Scenarios/Endpoints.WebHttp.cs extends the existing public static partial class Endpoints with HttpBaseAddress_WebHttp[_*] properties.

Build verification

build.cmd -build -configuration Release
=> Build succeeded.
   0 Warning(s)
   0 Error(s)

Release notes

release-notes/SupportedFeatures-v2.1.0.md: WebHttpBinding bumped from 🚫 to ⚠️ (partially supported) on Windows / Linux / macOS.

Commits

  1. Scaffold System.ServiceModel.Web package (csproj, sln, IVT, EnablePackageValidation=false)
  2. Port UriTemplate cluster from .NET Framework reference source (20 files / ~4,800 LOC)
  3. Suppress SYSLIB0051 on UriTemplateMatchException serialization ctor
  4. Demote MSB3243 to message in test csproj (collision with runtime v4 shim)
  5. Port Phase 3: encoding plumbing from CoreWCF.WebHttp v1.8.0
  6. Port Phase 4: attributes, faults, web operation context
  7. Port Phase 5: WebHttpBinding, WebHttpBehavior, client-side dispatchers (the big one — ~10,300 LOC)
  8. Port WebChannelFactory + add Phase 6 test infrastructure
  9. Bump WebHttpBinding from not-supported to partially-supported

Source attribution

Every commit message documents source provenance:

  • mono/mono @ 0f53e9e1 for files lifted from the Microsoft Reference Source
  • CoreWCF/CoreWCF @ v1.8.0 for files lifted from CoreWCF.WebHttp
  • All sources MIT-licensed; .NET Foundation MIT header applied to every ported file

@afifi-ins
afifi-ins force-pushed the feature/webhttpbinding-porting branch from a5caed5 to 794f262 Compare June 14, 2026 06:29
afifi-ins pushed a commit to afifi-ins/wcf that referenced this pull request Jun 14, 2026
CI failure analysis on PR dotnet#5959:
- All 12 'dotnet-wcf-ci' (non-corewcf) legs fail with HTML-500 responses from
  the shared bridge wcfcoresrv23.westus3.cloudapp.azure.com - an infra outage
  that affects every outerloop test (Binding.Http, Binding.WS, Client.*,
  Contract.*, Encoding.*, Extensibility.*, Security.*), NOT this PR.
- 'dotnet-wcf-with-corewcf--ci' (which uses local self-hosted CoreWCF, no
  bridge) is much cleaner - only one workitem fails: Binding.WebHttp.IntegrationTests.
  4 of 7 tests fail with:
  System.InvalidOperationException: Manual addressing is enabled on this
  factory, so all messages sent must be pre-addressed.

Root cause:
- The CoreWCF source we lifted for WebHttpBehavior.cs (Phase 5) had an empty
  ApplyClientBehavior - CoreWCF is server-only and never implemented the
  client-side wiring. As a result, no UriTemplateClientFormatter ever ran on
  outgoing messages, so the per-operation URI was never bound. The channel
  factory then tried to send each request to the endpoint base address
  (http://localhost:8081/WebHttp.svc/) with ManualAddressing = true on the
  HttpTransportBindingElement - failing fast in ApplyManualAddressing.
- The stub CoreWCF UriTemplateClientFormatter also threw
  PlatformNotSupportedException on every call - same reason.

Fix: port the real client-side wiring from the .NET Framework MIT-licensed
Reference Source mirror in mono/mono. Specifically:

1. src/.../Dispatcher/UriTemplateClientFormatter.cs:
   Replace the CoreWCF stub (DeserializeReply / SerializeRequest throw
   PlatformNotSupportedException) with the real .NET FX implementation
   (~150 LOC): binds operation parameters into the UriTemplate, sets
   Message.Headers.To from the bound URI, and applies SuppressEntityBody +
   Method on HttpRequestMessageProperty.
   Server-side WebOperationContext branch dropped; the client-only port uses
   the HttpRequestMessageProperty path unconditionally because dotnet/wcf's
   WebOperationContext does not expose OutgoingRequest (only OutgoingResponse,
   which is server-perspective).

2. src/.../Description/WebHttpBehavior.cs:
   - ApplyClientBehavior body replaced with the real .NET FX implementation:
     for each operation in the contract, build the request + reply client
     formatters, wrap in CompositeClientFormatter, set ClientOperation.Formatter,
     and add WebFaultClientMessageInspector.
   - Added the supporting client-side helper methods:
       GetRequestClientFormatter (the big one - ~80 LOC of URI-template +
         body-style routing, mirrors .NET FX)
       GetReplyClientFormatter (~30 LOC)
       GetDefaultClientFormatter (~30 LOC - harvests the WCF default formatter
         from a throwaway ClientOperation via IOperationBehavior.ApplyClientBehavior)
       GetDefaultXmlAndJsonClientFormatter (~10 LOC)
       GetDefaultContentType (~10 LOC)
       AddClientErrorInspector (~5 LOC)

3. src/.../Dispatcher/SingleBodyParameterMessageFormatter.cs:
   - Add IClientMessageFormatter interface (was IDispatchMessageFormatter only).
   - Add SerializeRequest, DeserializeReply, SuppressRequestEntityBody.
   - Add static factories CreateClientFormatter, CreateXmlAndJsonClientFormatter
     (mirror existing CreateDispatchFormatter / CreateXmlAndJsonDispatchFormatter).
   - Make nested NullMessageFormatter implement IClientMessageFormatter as well.

4. src/.../Dispatcher/HttpStreamFormatter.cs:
   - Add IClientMessageFormatter interface.
   - Add SerializeRequest (mirror of SerializeReply) and DeserializeReply.

5. New small client-side helper classes (each ~30 LOC, ported from .NET FX):
   - Dispatcher/CompositeClientFormatter.cs - request+reply pair.
   - Dispatcher/ContentTypeSettingClientMessageFormatter.cs - stamps
     outgoing Content-Type via HttpRequestMessageProperty (the .NET FX
     WebOperationContext branch is dropped for the same client-port reason).
   - Dispatcher/WebFaultClientMessageInspector.cs - surfaces HTTP 500 as
     CommunicationException so callers don't see empty payloads silently.

DemultiplexingClientMessageFormatter is deliberately NOT ported: the .NET FX
implementation switches on the inbound Content-Type to pick the XML or JSON
client formatter, but our client-side path returns the XML formatter directly
because [WebGet]/[WebInvoke].ResponseFormat already determines the wire format
at description time. Both modes (XML and JSON) round-trip through the same
SingleBodyParameter* formatter chain - the format mapping on WebHttpBinding
routing selects the encoder per-message via WebBodyFormatMessageProperty.

Verification:
- Full repo build (build.cmd -restore -build -configuration Release): 0 warnings, 0 errors.
- 3 unit tests pass locally (102ms): WebHttpBinding_CanBeConstructed,
  WebHttpBinding_TransportMode_UsesHttps, WebChannelFactory_Endpoint_HasWebHttpBinding.
- 4 outerloop tests will execute end-to-end in CI now that the formatter chain
  is wired (still requires SelfHostedCoreWcfService running locally; CI's
  'dotnet-wcf-with-corewcf--ci' leg launches it automatically).

Also rebased onto upstream/main (commit 36673ab - Skip SctRenewalRegressionTests
on CoreWCF host); no conflicts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mconnew
mconnew force-pushed the feature/webhttpbinding-porting branch from a04e6f3 to 98ec5dd Compare July 20, 2026 20:35
mconnew pushed a commit to afifi-ins/wcf that referenced this pull request Jul 20, 2026
CI failure analysis on PR dotnet#5959:
- All 12 'dotnet-wcf-ci' (non-corewcf) legs fail with HTML-500 responses from
  the shared bridge wcfcoresrv23.westus3.cloudapp.azure.com - an infra outage
  that affects every outerloop test (Binding.Http, Binding.WS, Client.*,
  Contract.*, Encoding.*, Extensibility.*, Security.*), NOT this PR.
- 'dotnet-wcf-with-corewcf--ci' (which uses local self-hosted CoreWCF, no
  bridge) is much cleaner - only one workitem fails: Binding.WebHttp.IntegrationTests.
  4 of 7 tests fail with:
  System.InvalidOperationException: Manual addressing is enabled on this
  factory, so all messages sent must be pre-addressed.

Root cause:
- The CoreWCF source we lifted for WebHttpBehavior.cs (Phase 5) had an empty
  ApplyClientBehavior - CoreWCF is server-only and never implemented the
  client-side wiring. As a result, no UriTemplateClientFormatter ever ran on
  outgoing messages, so the per-operation URI was never bound. The channel
  factory then tried to send each request to the endpoint base address
  (http://localhost:8081/WebHttp.svc/) with ManualAddressing = true on the
  HttpTransportBindingElement - failing fast in ApplyManualAddressing.
- The stub CoreWCF UriTemplateClientFormatter also threw
  PlatformNotSupportedException on every call - same reason.

Fix: port the real client-side wiring from the .NET Framework MIT-licensed
Reference Source mirror in mono/mono. Specifically:

1. src/.../Dispatcher/UriTemplateClientFormatter.cs:
   Replace the CoreWCF stub (DeserializeReply / SerializeRequest throw
   PlatformNotSupportedException) with the real .NET FX implementation
   (~150 LOC): binds operation parameters into the UriTemplate, sets
   Message.Headers.To from the bound URI, and applies SuppressEntityBody +
   Method on HttpRequestMessageProperty.
   Server-side WebOperationContext branch dropped; the client-only port uses
   the HttpRequestMessageProperty path unconditionally because dotnet/wcf's
   WebOperationContext does not expose OutgoingRequest (only OutgoingResponse,
   which is server-perspective).

2. src/.../Description/WebHttpBehavior.cs:
   - ApplyClientBehavior body replaced with the real .NET FX implementation:
     for each operation in the contract, build the request + reply client
     formatters, wrap in CompositeClientFormatter, set ClientOperation.Formatter,
     and add WebFaultClientMessageInspector.
   - Added the supporting client-side helper methods:
       GetRequestClientFormatter (the big one - ~80 LOC of URI-template +
         body-style routing, mirrors .NET FX)
       GetReplyClientFormatter (~30 LOC)
       GetDefaultClientFormatter (~30 LOC - harvests the WCF default formatter
         from a throwaway ClientOperation via IOperationBehavior.ApplyClientBehavior)
       GetDefaultXmlAndJsonClientFormatter (~10 LOC)
       GetDefaultContentType (~10 LOC)
       AddClientErrorInspector (~5 LOC)

3. src/.../Dispatcher/SingleBodyParameterMessageFormatter.cs:
   - Add IClientMessageFormatter interface (was IDispatchMessageFormatter only).
   - Add SerializeRequest, DeserializeReply, SuppressRequestEntityBody.
   - Add static factories CreateClientFormatter, CreateXmlAndJsonClientFormatter
     (mirror existing CreateDispatchFormatter / CreateXmlAndJsonDispatchFormatter).
   - Make nested NullMessageFormatter implement IClientMessageFormatter as well.

4. src/.../Dispatcher/HttpStreamFormatter.cs:
   - Add IClientMessageFormatter interface.
   - Add SerializeRequest (mirror of SerializeReply) and DeserializeReply.

5. New small client-side helper classes (each ~30 LOC, ported from .NET FX):
   - Dispatcher/CompositeClientFormatter.cs - request+reply pair.
   - Dispatcher/ContentTypeSettingClientMessageFormatter.cs - stamps
     outgoing Content-Type via HttpRequestMessageProperty (the .NET FX
     WebOperationContext branch is dropped for the same client-port reason).
   - Dispatcher/WebFaultClientMessageInspector.cs - surfaces HTTP 500 as
     CommunicationException so callers don't see empty payloads silently.

DemultiplexingClientMessageFormatter is deliberately NOT ported: the .NET FX
implementation switches on the inbound Content-Type to pick the XML or JSON
client formatter, but our client-side path returns the XML formatter directly
because [WebGet]/[WebInvoke].ResponseFormat already determines the wire format
at description time. Both modes (XML and JSON) round-trip through the same
SingleBodyParameter* formatter chain - the format mapping on WebHttpBinding
routing selects the encoder per-message via WebBodyFormatMessageProperty.

Verification:
- Full repo build (build.cmd -restore -build -configuration Release): 0 warnings, 0 errors.
- 3 unit tests pass locally (102ms): WebHttpBinding_CanBeConstructed,
  WebHttpBinding_TransportMode_UsesHttps, WebChannelFactory_Endpoint_HasWebHttpBinding.
- 4 outerloop tests will execute end-to-end in CI now that the formatter chain
  is wired (still requires SelfHostedCoreWcfService running locally; CI's
  'dotnet-wcf-with-corewcf--ci' leg launches it automatically).

Also rebased onto upstream/main (commit 36673ab - Skip SctRenewalRegressionTests
on CoreWCF host); no conflicts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mconnew mconnew assigned Copilot and unassigned Copilot Jul 22, 2026
Comment on lines +36 to +41
private static void ConfigureAuthentication(HttpTransportBindingElement http, HttpTransportSecurity transportSecurity)
{
http.AuthenticationScheme = MapToAuthenticationScheme(transportSecurity.ClientCredentialType);
// Realm property is not exposed on dotnet/wcf's HttpTransportBindingElement /
// HttpTransportSecurity (server-side only). Skip in the client port.
http.ExtendedProtectionPolicy = transportSecurity.ExtendedProtectionPolicy;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConfigureAuthentication maps ClientCredentialType but never sets http.ProxyAuthenticationScheme. dotnet/wcf's own HttpTransportSecurity.ConfigureAuthentication does set it (http.ProxyAuthenticationScheme = HttpProxyCredentialTypeHelper.MapToAuthenticationScheme(_proxyCredentialType)), and HttpChannelFactory consumes it when an explicit proxy address is configured. As written, Security.Transport.ProxyCredentialType is silently dropped here.

This is compounded by WebHttpBinding not exposing ProxyAddress/UseDefaultWebProxy/BypassProxyOnLocal (all settable on the transport element), so the authenticated-proxy support that .NET Framework's WebHttpBinding had is effectively lost. Suggest mapping the proxy scheme here (mirroring the MapToAuthenticationScheme switch below, since HttpProxyCredentialTypeHelper is internal to System.ServiceModel.Http) and surfacing the proxy properties on the binding.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 2e64a7d: ConfigureAuthentication now sets both http.AuthenticationScheme (from ClientCredentialType) and http.ProxyAuthenticationScheme (from ProxyCredentialType). Called HttpProxyCredentialTypeHelper.MapToAuthenticationScheme directly - it's internal to System.ServiceModel.Http but visible to us via [InternalsVisibleTo], so no need to duplicate the switch inline. This pairs with f34d2bc which exposes ProxyAddress/UseDefaultWebProxy/BypassProxyOnLocal on WebHttpBinding, so authenticated corporate proxies now work end-to-end.

Test: WebHttpBinding_ProxyCredentialType_FlowsToTransportProxyAuthenticationScheme [WcfTheory] covers all five HttpProxyCredentialType values.

Comment on lines +30 to +36
// This needs an update in the HttpTransportBindingElement to work.
//[DefaultValue(false)]
//public bool AllowCookies
//{
// get { throw new PlatformNotSupportedException(); }
// set { throw new PlatformNotSupportedException(); }
//}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment here isn't accurate — AllowCookies is fully supported in dotnet/wcf. HttpTransportBindingElement.AllowCookies exists and HttpChannelFactory honors it (clientHandler.UseCookies = AllowCookies); WSHttpBinding/HttpBindingBase already wire it to both transports. It can be implemented the same way rather than left as a commented/throwing stub:

[DefaultValue(HttpTransportDefaults.AllowCookies)]
public bool AllowCookies
{
    get { return _httpTransportBindingElement.AllowCookies; }
    set
    {
        _httpTransportBindingElement.AllowCookies = value;
        _httpsTransportBindingElement.AllowCookies = value;
    }
}

The same goes for ProxyAddress, UseDefaultWebProxy, and BypassProxyOnLocal — .NET FX exposed them and they're settable on the transport element, but they're omitted here. (HostNameComparisonMode genuinely isn't on the element yet, so leaving that one out is fair.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in f34d2bc: added AllowCookies, ProxyAddress, UseDefaultWebProxy, BypassProxyOnLocal on WebHttpBinding, each propagating to both the HTTP and HTTPS transport binding elements (same pattern HttpBindingBase uses). Removed the misleading not-supported comment. Left HostNameComparisonMode out per your note.

Tests:

  • WebHttpBinding_AllowCookies_PropagatesToBothTransports, WebHttpBinding_ProxyAddress_PropagatesToBothTransports, WebHttpBinding_UseDefaultWebProxy_And_BypassProxyOnLocal_PropagateToBothTransports: walk both HTTP and HTTPS transport BEs via CreateBindingElements() and assert.
  • WebHttpBinding_AllowCookies_RoundTripsCookieHeader: end-to-end via a local HttpListener - the first response Set-Cookie: sid=abc123, the test asserts the second request carries sid=abc123 back.

}
}

public override BindingElementCollection CreateBindingElements()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reference WebHttpBinding overrides BuildChannelFactory to throw InvalidOperationException up front when Security.Mode is Transport/TransportCredentialOnly and Transport.ClientCredentialType == InheritedFromHost (a value that's invalid on a client). That override isn't ported.

The case still fails — InheritedFromHost maps to AuthenticationSchemes.None, so HttpTransportBindingElement.BuildChannelFactory throws — but as an ArgumentException (HttpAuthSchemeCannotBeNone), a different exception type/message than .NET Framework produced. Minor, but porting the guard restores parity and gives a clearer error at factory-creation time.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in db4e189: added the BuildChannelFactory(BindingParameterCollection) override on WebHttpBinding that throws InvalidOperationException up front for Transport / TransportCredentialOnly + InheritedFromHost, matching WSHttpBinding's equivalent guard. Also fixed a pre-existing bug in Resources/Strings.resx: the HttpClientCredentialTypeInvalid entry we inherited from the CoreWCF port had a wrong message body ('There is no {0} on the incoming Message.') - restored the correct .NET Framework text.

Tests:

  • WebHttpBinding_InheritedFromHost_ThrowsInvalidOperationExceptionAtFactoryCreation [WcfTheory] over Transport and TransportCredentialOnly: exercises the guard via binding.BuildChannelFactory() directly (the same path ChannelFactory.CreateFactory takes at Open).
  • WebHttpBinding_InheritedFromHost_DoesNotThrow_WhenSecurityModeIsNone: negative test confirming the guard doesn't over-fire in None mode.

@mconnew

mconnew commented Jul 23, 2026

Copy link
Copy Markdown
Member

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).

@mconnew

mconnew commented Jul 24, 2026

Copy link
Copy Markdown
Member

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).

| |CustomBinding |:white_check_mark: |:white_check_mark: | :white_check_mark: |
| |NetHttpBinding |:white_check_mark: |:white_check_mark: | :white_check_mark: |
| |NetTcpBinding |:white_check_mark: |:white_check_mark: | :white_check_mark: |
| |WebHttpBinding |:no_entry_sign: |:no_entry_sign: | :no_entry_sign: |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

| |WebHttpBinding |:no_entry_sign:

We shouldn't be modifying this file as it's the features released with a really old version.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted in f4b0821 — restored the WebHttpBinding row to its original state and left the v2.1.0 notes untouched. Thanks.

</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == '$(DotNetVersion)'">
<InternalsVisibleTo Include="System.ServiceModel.Web" />

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain what internals are needed by System.ServiceModel.Web from System.ServiceModel.Http? Would any of them be reasonable to expose publicly? Basically should we keep this or can we work around all the issues? InternalsVisibleTo is generally not the best way to solve a problem unless absolutely needed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question — I dug into exactly what''s consumed. The System.ServiceModel.Web package references only two internal symbols from System.ServiceModel.Http, and both are trivially removable, so we can drop this InternalsVisibleTo entirely.

1. HttpTransportDefaults (internal static class of const defaults) — 5 uses, all [DefaultValue(...)] attributes on the WebHttpBinding proxy/cookie properties (AllowCookies, BypassProxyOnLocal, ProxyAddress, UseDefaultWebProxy, TransferMode). WSHttpBinding/HttpBindingBase can use these because they live inside System.ServiceModel.Http; WebHttpBinding can''t.

  • Workaround: inline the literal default values in the attributes (they''re compile-time constants anyway): [DefaultValue(false)] for AllowCookies/BypassProxyOnLocal, [DefaultValue(true)] for UseDefaultWebProxy, [DefaultValue(null)] for ProxyAddress, [DefaultValue(TransferMode.Buffered)] for TransferMode (TransferMode is public). No internal needed.

2. HttpProxyCredentialTypeHelper.MapToAuthenticationScheme — 1 use, in HttpTransportHelpers.ConfigureAuthentication (maps HttpProxyCredentialType -> AuthenticationSchemes).

  • Workaround: inline the ~6-line switch locally, exactly as you suggested on the HttpTransportHelpers.cs thread ("mirroring the MapToAuthenticationScheme switch below"). The file already has the sibling ClientCredentialType switch inlined, so this is consistent.

Verified empirically: removing the IVT and rebuilding, the only compiler break is the HttpTransportDefaults references — confirming those two are the entire surface.

So: we can remove this InternalsVisibleTo line. I''ll fold the two inlinings into the cleanup pass. (The separate System.ServiceModel.Primitives -> System.ServiceModel.Web IVT is a different case — it''s the same entry every sibling package already has for shared Primitives internals, so I''ll leave that one as-is unless you want it revisited too.)

@mconnew

mconnew commented Jul 24, 2026

Copy link
Copy Markdown
Member
{

Consider replacing with ObjectPool<T> from the runtime.


Refers to: src/System.ServiceModel.Web/src/System/ServiceModel/Pool.cs:9 in db4e189. [](commit_id = db4e189, deletion_comment = False)

afifi-ins added a commit to afifi-ins/wcf that referenced this pull request Jul 28, 2026
… message

The HttpClientCredentialTypeInvalid resource string used to list valid
client credential values as 'None, Basic, Client, Digest, Ntlm, Windows'.
There is no 'Client' member on HttpClientCredentialType; the intended
value is 'Certificate' (see src/System.ServiceModel.Http/src/System/
ServiceModel/HttpClientCredentialType.cs). Every caller of
SR.HttpClientCredentialTypeInvalid (WSHttpBinding, BasicHttpBinding,
BasicHttpsBinding, NetHttpBinding, NetHttpsBinding, and the new
WebHttpBinding guard added by this PR) was therefore telling users to
use a value that does not exist.

Fix the wording in all three shipping resx files:

  * System.ServiceModel.Http/src/Resources/Strings.resx
  * System.ServiceModel.Primitives/src/Resources/Strings.resx
  * System.ServiceModel.Web/src/Resources/Strings.resx

Arcade's XliffTasks regenerated the 39 companion xlf files during the
next build. The English <source> is now correct in every locale; the
localized <target> strings that inlined the value verbatim are flagged
state='needs-review-translation' so the localization team can refresh
them in a follow-up localization sync.

svcutil's SRServiceModel.resx keeps the pre-existing typo (out of scope
per task direction).

Flagged by Claude Sonnet 5 during multi-model review of PR dotnet#5959. No
code-behind changes; SR key and format argument count are unchanged so
all five call sites and the new WebHttp guard keep working. All 39 in-repo
WebHttp tests still pass (0 failed).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
afifi-ins added a commit to afifi-ins/wcf that referenced this pull request Jul 28, 2026
All three WebHttpBinding_*_RoundTripsAgainstLocalHttpListener tests
used to hardcode a port (18091 / 18092 / 18093) and silently 'return'
on HttpListenerException. If the hardcoded port was already in use on
the test runner, the test would report as PASSED without running any
assertion - masking a real regression in the client's URL binding,
JSON reply deserialization, or cookie handling. Flagged by Gemini 3.1
Pro during multi-model code review of PR dotnet#5959.

Add a StartLoopbackHttpListener helper that:
  * Picks a random port from the Windows dynamic / ephemeral range
    (49152-65535 per RFC 6335), minimizing collisions with configured
    services.
  * Retries up to MaxPortRetries (10) times to survive transient
    collisions or parallel-test races.
  * On exhaustion, calls Assert.Fail with a per-attempt diagnostic
    listing each attempted port and its HttpListener error code.
    Verified in a temp failure-mode run: 'Unable to find a random port
    number after 10 attempts. Errors: attempt 1 port 1: 5/Access is
    denied; ...'

Refactor all three call sites to use the helper: one-line tuple
deconstruction replaces the seven-line hardcoded-port + try/catch/return
boilerplate in each test. Downstream logic is unchanged.

Semantics change vs before: an HttpListener environment that truly
blocks loopback binding after 10 tries now fails the test loudly
instead of skipping silently. This is the intended trade-off - a real
environmental block is worth surfacing, and 10 attempts across 16384
ports guarantees any transient collision is handled.

Local validation: 39 passed / 0 failed / 4 skipped (outerloop). Full
repo build clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mconnew

mconnew commented Jul 28, 2026

Copy link
Copy Markdown
Member
public class UriTemplate

No need for the type forward as this won't be consumed by assemblies compiled for .NET 3.5


Refers to: src/System.ServiceModel.Web/src/System/UriTemplate.cs:19 in a0df75f. [](commit_id = a0df75f, deletion_comment = False)

@mconnew

mconnew commented Jul 28, 2026

Copy link
Copy Markdown
Member

Update to use naming conventions for instance fields


Refers to: src/System.ServiceModel.Web/src/System/UriTemplate.cs:22 in a0df75f. [](commit_id = a0df75f, deletion_comment = False)

@mconnew

mconnew commented Jul 28, 2026

Copy link
Copy Markdown
Member
        }

Use nameof for arguments/parameters that are referenced by exceptions.


Refers to: src/System.ServiceModel.Web/src/System/UriTemplate.cs:57 in a0df75f. [](commit_id = a0df75f, deletion_comment = False)

@mconnew

mconnew commented Jul 28, 2026

Copy link
Copy Markdown
Member
        : this(template, ignoreTrailingSlash, null)

Formatting, there should be a blank line between each method/constructor


Refers to: src/System.ServiceModel.Web/src/System/UriTemplate.cs:45 in a0df75f. [](commit_id = a0df75f, deletion_comment = False)

@mconnew

mconnew commented Jul 28, 2026

Copy link
Copy Markdown
Member
        this.ignoreTrailingSlash = ignoreTrailingSlash;

this. shouldn't generally be needed and the current coding standards says to omit it if not needed.


Refers to: src/System.ServiceModel.Web/src/System/UriTemplate.cs:59 in a0df75f. [](commit_id = a0df75f, deletion_comment = False)

@mconnew

mconnew commented Jul 28, 2026

Copy link
Copy Markdown
Member
                SR.UTBadBaseAddress));

SR.Format is only needed when there string resource is parameterized. When it isn't parameterized, you can use the string resource directly without calling SR.Format.


Refers to: src/System.ServiceModel.Web/src/System/UriTemplate.cs:337 in a0df75f. [](commit_id = a0df75f, deletion_comment = False)

@mconnew

mconnew commented Jul 28, 2026

Copy link
Copy Markdown
Member
    //  templates as such based on the structure of them and not based on the set of uri

Nit: Typo in comment. Intuative -> intuitive.


Refers to: src/System.ServiceModel.Web/src/System/UriTemplate.cs:410 in a0df75f. [](commit_id = a0df75f, deletion_comment = False)

@mconnew

mconnew commented Jul 28, 2026

Copy link
Copy Markdown
Member
            // and warning suppression isn't working

This can probably be removed as it was included to stop a false positive on a static analysis rule in the .NET Framework source code. Replace with an Fx.Assert that they are not null to ensure the stated assertion holds true.


Refers to: src/System.ServiceModel.Web/src/System/UriTemplate.cs:429 in a0df75f. [](commit_id = a0df75f, deletion_comment = False)

@mconnew

mconnew commented Jul 28, 2026

Copy link
Copy Markdown
Member
        {

Formatting, we put blank lines after closing braces of code block, unless the next line is another closing brace.


Refers to: src/System.ServiceModel.Web/src/System/UriTemplate.cs:451 in a0df75f. [](commit_id = a0df75f, deletion_comment = False)

@mconnew

mconnew commented Jul 28, 2026

Copy link
Copy Markdown
Member
        Fx.Assert(segmentsCount >= this.firstOptionalSegment - 1, "How can that be? The Trie is constructed that way!");

Nit: extra space on final line of comment


Refers to: src/System.ServiceModel.Web/src/System/UriTemplate.cs:582 in a0df75f. [](commit_id = a0df75f, deletion_comment = False)

@mconnew

mconnew commented Jul 28, 2026

Copy link
Copy Markdown
Member
    {

All methods should have their accessibility explicitly stated. We do rely on default accessibility.


Refers to: src/System.ServiceModel.Web/src/System/UriTemplate.cs:633 in a0df75f. [](commit_id = a0df75f, deletion_comment = False)

@mconnew

mconnew commented Jul 28, 2026

Copy link
Copy Markdown
Member
            }

Update to use expression bodies where appropriate.


Refers to: src/System.ServiceModel.Web/src/System/UriTemplate.cs:981 in a0df75f. [](commit_id = a0df75f, deletion_comment = False)

Copilot AI and others added 19 commits July 30, 2026 07:35
Lifts the WebMessage / Json encoder factories and related helpers from
the MIT-licensed CoreWCF.WebHttp v1.8.0 source (CoreWCF/CoreWCF on GitHub).
CoreWCF already adapted this code from the .NET Framework reference source
to .NET Core conventions, so we avoid re-doing that work.

Files added (src/System.ServiceModel.Web/src/System/ServiceModel/Channels/):
- WebMessageEncodingBindingElement.cs - composes the WebMessageEncoder
  into a Binding. Surgically stripped IWsdlExportExtension/IWmiInstanceProvider
  and BuildChannelListener overrides (server-side only).
- WebMessageEncoderFactory.cs - factory + WebMessageEncoder that demuxes
  JSON / XML / Raw based on WebBodyFormatMessageProperty.
- JsonMessageEncoderFactory.cs - factory + JsonMessageEncoder using
  DataContractJsonSerializer.
- WebBodyFormatMessageProperty.cs - per-message format tag.
- WebContentFormat.cs + WebContentFormatHelper.cs - Json/Xml/Raw/Default enum.
- WebContentTypeMapper.cs - abstract base for Content-Type to format mapping.
- HttpStreamMessage.cs - wraps Stream as Message for raw pass-through.
- ContentEncoding.cs - charset to encoding mapping struct.
- ContentTypeHelpers.cs - new client subset of CoreWCF helper.
- JsonGlobals.cs - new minimal media-type constants.
- MessageExtensions.cs - helpers for property lookup.

Plus src/System.ServiceModel.Web/src/System/ServiceModel/Pool.cs:
- Internal non-threadsafe object pool (mirror of
  System.ServiceModel.NetFramingBase/src/.../Pool.cs).

Adaptations applied while porting CoreWCF source:
- Namespace rewrite: CoreWCF.* -> System.ServiceModel.*
- BCL types resolved via System.* namespaces.
- Access modifiers: protected override -> internal override on members
  whose Primitives base is internal (CheckEncodingVersion, IsMatch,
  IsCharSetSupported, RecycledMessageState, GetReaderAtHeader).
- Async return types: Task<Message> / Task -> ValueTask<Message> / ValueTask
  to match Primitives' MessageEncoder.ReadMessageAsync/WriteMessageAsync.
- Added sync ReadMessage(Stream,...) and WriteMessage(Message, Stream)
  overrides that wrap the async versions via GetAwaiter().GetResult().
- TraceUtility.ThrowHelperError -> DiagnosticUtility.ExceptionUtility.ThrowHelperError
  (same signature, available via InternalsVisibleTo to Primitives).
- Deleted duplicates of types already in Primitives: BufferedMessage,
  BufferedMessageData, BufferedMessageWriter, EncoderHelpers, XmlAttributeHolder,
  ReceivedMessage, BufferManagerOutputStream, StreamBodyWriter. Now resolved via
  InternalsVisibleTo (was producing CS0436 warnings).
- TransportDefaults.cs deleted (EncoderDefaults/TextEncoderDefaults/
  TransportDefaults already in Primitives).
- RawMessageEncoder getter throws NotSupportedException (raw octet-stream
  pass-through requires ByteStreamMessageEncodingBindingElement which is
  not yet in dotnet/wcf - deferred to a follow-up).

19 new SR strings added to Resources/Strings.resx covering all error paths
in the new code; 13 XLF translations auto-generated.

Build: full repo, 0 warnings, 0 errors.

Part of porting WebHttpBinding to .NET (Core) WCF client (issues dotnet#46, dotnet#1413).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Lifts the Web-namespace public types from CoreWCF.WebHttp v1.8.0:

Attributes (mark contract operations for REST dispatch):
- WebGetAttribute, WebInvokeAttribute (IOperationBehavior, no-op for client)

Enums and helpers:
- WebMessageFormat (Xml/Json), WebMessageBodyStyle (Bare/Wrapped/...)
- WebMessageFormatHelper, WebMessageBodyStyleHelper (IsDefined validators)

Exception types:
- WebFaultException, WebFaultException<T> (HTTP-status-aware faults)
- IWebFaultException (internal bridge)

OperationContext wrappers:
- WebOperationContext (IExtension<OperationContext>, Current accessor)
- IncomingWebRequestContext (~440 LOC: Headers, Method, IfMatch/None, etc.)
- OutgoingWebResponseContext (~300 LOC: SetStatusCode, SetETag, SetLastModified)
- HttpDateParse, Utility (HTTP date / ETag parsing helpers)

Adaptations applied to the CoreWCF source:
- 'using CoreWCF.Dispatcher;' -> 'using System.ServiceModel.Dispatcher;'
- 'using CoreWCF.IdentityModel.Claims;' -> 'using System.IdentityModel.Claims;'
- [Obsolete(DiagnosticId = "SYSLIB0051")] added on overrides of
  Exception.GetObjectData on WebFaultException and WebFaultException<T>.

Stubs for server-side functionality (NotSupportedException) because
dotnet/wcf is client-only:
- WebOperationContext.CreateStreamResponse(Stream|StreamBodyWriter|Action<Stream>, string)
  - raw octet-stream pass-through needs ByteStreamMessage which is not ported
- WebOperationContext.CreateTextResponse(string|Action<TextWriter>, ...)
  - depends on ActionOfStreamBodyWriter / StreamBodyWriter
- WebOperationContext.GetUriTemplate(string)
  - reaches into WebHttpDispatchOperationSelector (server-side)
- WebOperationContext.s_defaultStreamMediaType inlined to "application/octet-stream"
  (was WebHttpBehavior.s_defaultStreamContentType - WebHttpBehavior is Phase 5)
- OutgoingWebResponseContext.SuppressEntityBody no-op (the property exists on
  HttpRequestMessageProperty in dotnet/wcf but not on HttpResponseMessageProperty)
- OutgoingWebResponseContext.BindingWriteEncoding falls back to UTF-8 (the original
  walked EndpointDispatcher.Id / OperationContext.Host - both server-side only)

Added 5 more SR strings (ConditionalRetrieveGetAndHeadOnly,
ConditionalUpdatePutPostAndDeleteOnly, HttpContextNoIncomingMessageProperty,
WebHttpServerSideOperationSelectorNotSupported, WeakEntityTagsNotSupported).

Message.CreateMessage(MessageVersion.None, null, ...) calls disambiguated with
(string)null casts (the new overload set is ambiguous between string and
ActionHeader at the null literal).

Build: full repo, 0 warnings, 0 errors.

Part of porting WebHttpBinding to .NET (Core) WCF client (issues dotnet#46, dotnet#1413).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The big one. Brings the binding, behavior, factory, formatter, query
string converter and supporting helpers across from CoreWCF.WebHttp
v1.8.0 + a few small additional helpers from CoreWCF root.

Public API surface added:
- System.ServiceModel.WebHttpBinding
- System.ServiceModel.WebHttpSecurity
- System.ServiceModel.WebHttpSecurityMode (enum: None/Transport/TransportCredentialOnly)
- System.ServiceModel.Description.WebHttpBehavior (~870 LOC, IEndpointBehavior)
- System.ServiceModel.Dispatcher.QueryStringConverter
- System.ServiceModel.Dispatcher.UriTemplateClientFormatter
- System.ServiceModel.Dispatcher.SingleBodyParameter{,DataContract,XmlSerializer}MessageFormatter
- System.ServiceModel.Dispatcher.DataContractJsonSerializerOperationFormatter
- System.ServiceModel.Dispatcher.HttpStreamFormatter
- System.ServiceModel.Dispatcher.{Xml,Json,Multiplexing}FormatMapping
- System.ServiceModel.Dispatcher.UnwrappedTypesXmlSerializerManager
- System.ServiceModel.Dispatcher.NameValueCache

Internal helpers:
- System.ServiceModel.HttpTransportHelpers (auth scheme mapping)
- System.ServiceModel.DataContractHelpers
- System.ServiceModel.Description.DataContractJsonSerializerOperationBehavior
- Expanded JsonGlobals (added RootString/ItemString/TypeString/ObjectString/
  DString/NullString constants + RootDictionaryString/ItemDictionaryString/
  DDictionaryString XmlDictionaryString fields)
- IDispatchOperationSelector (internal interface; stub for client-only port)
- IDispatchFaultFormatterWrapper (internal interface; stub)

Server-side surgery applied (the client-only nature of dotnet/wcf):
- WebHttpBehavior.ApplyDispatchBehavior body replaced with
  NotSupportedException; the original wires up UriTemplateDispatchFormatter,
  WebHttpDispatchOperationSelector, FormatSelectingMessageInspector,
  WebErrorHandler, PrefixEndpointAddressMessageFilter, MatchAllMessageFilter,
  CompositeDispatchFormatter, WebFaultFormatter, HelpPage, HttpUnhandledOperationInvoker
  - none of those types are part of this port (use CoreWCF.WebHttp server-side).
- WebHttpBehavior.GetReplyDispatchFormatter / GetRequestDispatchFormatter /
  GetDefaultDispatchFormatter / GetDefaultXmlAndJsonDispatchFormatter now
  return null. Same reason - server-side dispatch.
- WebHttpBehavior.AddServerErrorHandlers no-ops (WebErrorHandler not ported).
- WebHttpBehavior.GetOperationSelector removed (WebHttpDispatchOperationSelector
  not ported).
- WebHttpBehavior.HideRequestUriTemplateParameters(... UriTemplateDispatchFormatter ...)
  removed (server-only overload).
- WebHttpBehavior method visibility: GetReplyDispatchFormatter and
  GetRequestDispatchFormatter changed from protected to internal (return type
  IDispatchMessageFormatter is internal in Primitives - server-side use only).
- SingleBodyParameterMessageFormatter.CreateXmlAndJsonDispatchFormatter
  returns the XML formatter directly (DemultiplexingDispatchMessageFormatter
  not ported); the JSON formatter is still created for diagnostics.
- SingleBodyParameterMessageFormatter.SuppressReplyEntityBody no-ops in the
  fallback raw HttpResponseMessageProperty path (SuppressEntityBody is not
  on dotnet/wcf's HttpResponseMessageProperty).
- HttpStreamFormatter.WriteObject and GetStreamFromMessage throw
  NotSupportedException (raw stream pass-through needs ByteStreamMessage /
  MessageBodyStream - deferred to a follow-up).
- WebHttpSecurity.ApplyAuthorizationPolicySupport no-ops (the
  AlwaysUseAuthorizationPolicySupport property is server-side only).
- HttpTransportHelpers.ConfigureAuthentication / DisableAuthentication no
  longer set http.Realm (Realm not exposed on dotnet/wcf's HttpTransport*).
- WebHttpBinding.WriteEncoding [TypeConverter] swapped from EncodingConverter
  (CoreWCF internal) to StringConverter.

Server-only files deleted (12) - to be reintroduced if/when dotnet/wcf grows
full dispatch surface:
  Description/WebHttpServiceModelCompat.cs,
  Dispatcher/CompositeDispatchFormatter.cs,
  Dispatcher/ContentTypeSettingDispatchMessageFormatter.cs,
  Dispatcher/DemultiplexingDispatchMessageFormatter.cs,
  Dispatcher/FormatSelectingMessageInspector.cs,
  Dispatcher/HttpUnhandledOperationInvoker.cs,
  Dispatcher/MultiplexingDispatchMessageFormatter.cs,
  Dispatcher/UriTemplateDispatchFormatter.cs,
  Dispatcher/WebErrorHandler.cs,
  Dispatcher/WebFaultFormatter.cs,
  Dispatcher/WebHttpDispatchOperationSelector.cs,
  Dispatcher/WebHttpDispatchOperationSelectorData.cs

Also bumps System.ServiceModel.Http with InternalsVisibleTo for
System.ServiceModel.Web so HttpTransportDefaults is reachable.

99 new SR strings imported from CoreWCF.WebHttp v1.8.0 Strings.resx
(skipping duplicates with existing entries from earlier phases).
13 XLF translations auto-regenerated.

Build: full repo, 0 warnings, 0 errors.

Part of porting WebHttpBinding to .NET (Core) WCF client (issues dotnet#46, dotnet#1413).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Client entry point:
- System.ServiceModel.Web.WebChannelFactory<TChannel> ported from the
  MIT-licensed mono/mono mirror of the .NET Framework Reference Source.
  CoreWCF.WebHttp does not ship this type (it is server-only), so the
  port is sourced from the same place as Phase 2 UriTemplate. Constructors
  that wrap missing ChannelFactory<T> base overloads (string
  endpointConfigurationName, Type channelType) are commented out with a
  rationale; the binding-and-URI shapes that ARE supported by Primitives'
  ChannelFactory<T> remain.
  - OnOpening auto-installs WebHttpBehavior if absent.
  - GetDefaultBinding(Uri) auto-selects WebHttpBinding (http) or
    WebHttpBinding + Transport security (https).
- WebHttpBehavior gains a parameterless public constructor that delegates
  to the (IServiceProvider) constructor with null. Required so
  WebChannelFactory<T>.OnOpening can do 'new WebHttpBehavior()'.
- WebMessageEncodingBindingElement.WriteEncoding [TypeConverter] swap
  (EncodingConverter -> StringConverter) carried over from earlier patches.

Test infrastructure:
- tools/IISHostedWcfService/App_code/testhosts/WebHttpTestServiceHost.cs
  Declares IWcfWebHttpService + WcfWebHttpService + WebHttpTestServiceHost
  (decorated with [TestServiceDefinition(BasePath = "WebHttp.svc",
  Schema = ServiceSchema.HTTP)]). CoreWCF path is no-op for behaviour wiring
  (WebHttpServiceBehavior auto-installs WebHttpBehavior when it sees a
  WebMessageEncodingBindingElement, which our WebHttpBinding produces).
  .NET FX path manually adds WebHttpBehavior in ApplyConfiguration.
- tests/Common/Scenarios/Endpoints.WebHttp.cs
  New partial extension to Endpoints with HttpBaseAddress_WebHttp[_*]
  properties. The Endpoints class is declared 'public static partial' in
  the existing Endpoints.cs so no edits to that file are required.
- tests/Scenarios/Binding/WebHttp/Binding.WebHttp.IntegrationTests.csproj
  + WebHttpBindingTests.cs (3 [OuterLoop] integration tests covering
  EchoWithGet (XML), EchoWithGetJson (JSON), EchoWithPost, EchoWithGetPath,
  plus 3 standalone unit tests). The contract IWcfWebHttpService is
  re-declared inline in the test file (mirroring the server-side host's
  copy) because IISHostedWcfService is folded into the host project via
  <Compile Include> wildcards and is not consumable as a library.

Verification:
- Full repo build: 0 warnings, 0 errors.
- 3 unit tests (WebHttpBinding_CanBeConstructed,
  WebHttpBinding_TransportMode_UsesHttps, WebChannelFactory_Endpoint_HasWebHttpBinding):
  ALL PASSED in 80ms.
- 4 outer-loop scenario tests built and discovered; pending live-service
  verification with SelfHostedCoreWcfService.

Warnings suppressed in the new test project: CS0105 (duplicate using),
CS0108 (method hide), CS0436 (SR type collision), MSB3243 (System.ServiceModel.Web
v10 collides with the runtime's v4 shim at reference-resolution time).
Same set the impl csproj already suppresses.

Part of porting WebHttpBinding to .NET (Core) WCF client (issues dotnet#46, dotnet#1413).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update release-notes/SupportedFeatures-v2.1.0.md from 🚫
to ⚠️ across Windows/Linux/macOS for WebHttpBinding now that
the client-side surface ships in System.ServiceModel.Web.dll (Phases 0-6).

The partially-supported marker reflects:
- WebHttpBinding, WebHttpSecurity, WebHttpSecurityMode: supported
- [WebGet] / [WebInvoke] attributes: supported
- UriTemplate + UriTemplateTable (path + query): supported
- WebChannelFactory<T>: supported (with the constructor overloads that
  ChannelFactory<T> exposes; (string endpointConfigurationName) and
  (Type channelType) are omitted)
- WebOperationContext + Incoming/OutgoingWebRequest/ResponseContext: supported
- WebFaultException / WebFaultException<T>: supported
- QueryStringConverter: supported
- Xml + Json client-side formatters: supported
- WebMessageEncodingBindingElement (text + JSON encoders): supported

Known gaps (deferred to follow-ups):
- Server-side dispatch (ApplyDispatchBehavior, WebHttpDispatchOperationSelector,
  WebErrorHandler, FormatSelectingMessageInspector, HelpPage): NOT supported.
  Use CoreWCF.WebHttp for the server side.
- Raw octet-stream pass-through (ByteStreamMessage, StreamBodyWriter,
  HttpStreamFormatter raw path): NOT supported (throws NotSupportedException).
- JSONP / JavaScript callback (JavascriptCallbackBehaviorAttribute,
  WebScriptEnablingBehavior): NOT supported.
- AspNetCacheProfileAttribute: NOT supported.
- IIS .NET Framework hosting (WebServiceHost, WebServiceHostFactory): NOT supported.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fixes CI failure on all 11 dotnet-wcf-ci legs (Windows/Linux/MacOS x
Debug/Release, with and without CoreWCF service):
  NETSDK1004: Assets file 'artifacts\\obj\\Binding.WebHttp.IntegrationTests
  \\project.assets.json' not found. Run a NuGet package restore to generate
  this file.

Root cause:
- The main build step (eng/common/cibuild.cmd) restores the project
  graph rooted at System.ServiceModel.sln.
- The subsequent Helix step runs eng/common/build.ps1 -projects
  eng/SendToHelix.proj which discovers test projects via the glob
  ..\src\System.Private.ServiceModel\tests\Scenarios\**\*.IntegrationTests.csproj
  and asks the Helix SDK to publish each one.
- Helix's per-project publish path expects each project's
  project.assets.json to already exist (it does not invoke 'dotnet restore'
  on individual projects).
- The new Binding.WebHttp.IntegrationTests.csproj was created in the
  prior commit but never registered in System.ServiceModel.sln, so the
  main build skipped its restore. All ten other Binding.*.IntegrationTests
  projects are in the sln and got restored normally.

Fix: register the project in the sln with a fresh GUID
  (F0F5C0C0-AB1D-4A86-A0A9-3D13ACB9B249), nested under the existing
  '03 - Test Projects' solution folder ({D6302510-AB10-4775-BCE9-98FA96FDEB76}).
Mirrors exactly the existing entries for Binding.Http.IntegrationTests
etc., with the standard 12 build-configuration lines.

Verification:
- Full .\\build.cmd -restore -build -configuration Release: 0 warnings, 0 errors.
- New project now appears in restore output and produces
  artifacts\\obj\\Binding.WebHttp.IntegrationTests\\project.assets.json.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CI failure analysis on PR dotnet#5959:
- All 12 'dotnet-wcf-ci' (non-corewcf) legs fail with HTML-500 responses from
  the shared bridge wcfcoresrv23.westus3.cloudapp.azure.com - an infra outage
  that affects every outerloop test (Binding.Http, Binding.WS, Client.*,
  Contract.*, Encoding.*, Extensibility.*, Security.*), NOT this PR.
- 'dotnet-wcf-with-corewcf--ci' (which uses local self-hosted CoreWCF, no
  bridge) is much cleaner - only one workitem fails: Binding.WebHttp.IntegrationTests.
  4 of 7 tests fail with:
  System.InvalidOperationException: Manual addressing is enabled on this
  factory, so all messages sent must be pre-addressed.

Root cause:
- The CoreWCF source we lifted for WebHttpBehavior.cs (Phase 5) had an empty
  ApplyClientBehavior - CoreWCF is server-only and never implemented the
  client-side wiring. As a result, no UriTemplateClientFormatter ever ran on
  outgoing messages, so the per-operation URI was never bound. The channel
  factory then tried to send each request to the endpoint base address
  (http://localhost:8081/WebHttp.svc/) with ManualAddressing = true on the
  HttpTransportBindingElement - failing fast in ApplyManualAddressing.
- The stub CoreWCF UriTemplateClientFormatter also threw
  PlatformNotSupportedException on every call - same reason.

Fix: port the real client-side wiring from the .NET Framework MIT-licensed
Reference Source mirror in mono/mono. Specifically:

1. src/.../Dispatcher/UriTemplateClientFormatter.cs:
   Replace the CoreWCF stub (DeserializeReply / SerializeRequest throw
   PlatformNotSupportedException) with the real .NET FX implementation
   (~150 LOC): binds operation parameters into the UriTemplate, sets
   Message.Headers.To from the bound URI, and applies SuppressEntityBody +
   Method on HttpRequestMessageProperty.
   Server-side WebOperationContext branch dropped; the client-only port uses
   the HttpRequestMessageProperty path unconditionally because dotnet/wcf's
   WebOperationContext does not expose OutgoingRequest (only OutgoingResponse,
   which is server-perspective).

2. src/.../Description/WebHttpBehavior.cs:
   - ApplyClientBehavior body replaced with the real .NET FX implementation:
     for each operation in the contract, build the request + reply client
     formatters, wrap in CompositeClientFormatter, set ClientOperation.Formatter,
     and add WebFaultClientMessageInspector.
   - Added the supporting client-side helper methods:
       GetRequestClientFormatter (the big one - ~80 LOC of URI-template +
         body-style routing, mirrors .NET FX)
       GetReplyClientFormatter (~30 LOC)
       GetDefaultClientFormatter (~30 LOC - harvests the WCF default formatter
         from a throwaway ClientOperation via IOperationBehavior.ApplyClientBehavior)
       GetDefaultXmlAndJsonClientFormatter (~10 LOC)
       GetDefaultContentType (~10 LOC)
       AddClientErrorInspector (~5 LOC)

3. src/.../Dispatcher/SingleBodyParameterMessageFormatter.cs:
   - Add IClientMessageFormatter interface (was IDispatchMessageFormatter only).
   - Add SerializeRequest, DeserializeReply, SuppressRequestEntityBody.
   - Add static factories CreateClientFormatter, CreateXmlAndJsonClientFormatter
     (mirror existing CreateDispatchFormatter / CreateXmlAndJsonDispatchFormatter).
   - Make nested NullMessageFormatter implement IClientMessageFormatter as well.

4. src/.../Dispatcher/HttpStreamFormatter.cs:
   - Add IClientMessageFormatter interface.
   - Add SerializeRequest (mirror of SerializeReply) and DeserializeReply.

5. New small client-side helper classes (each ~30 LOC, ported from .NET FX):
   - Dispatcher/CompositeClientFormatter.cs - request+reply pair.
   - Dispatcher/ContentTypeSettingClientMessageFormatter.cs - stamps
     outgoing Content-Type via HttpRequestMessageProperty (the .NET FX
     WebOperationContext branch is dropped for the same client-port reason).
   - Dispatcher/WebFaultClientMessageInspector.cs - surfaces HTTP 500 as
     CommunicationException so callers don't see empty payloads silently.

DemultiplexingClientMessageFormatter is deliberately NOT ported: the .NET FX
implementation switches on the inbound Content-Type to pick the XML or JSON
client formatter, but our client-side path returns the XML formatter directly
because [WebGet]/[WebInvoke].ResponseFormat already determines the wire format
at description time. Both modes (XML and JSON) round-trip through the same
SingleBodyParameter* formatter chain - the format mapping on WebHttpBinding
routing selects the encoder per-message via WebBodyFormatMessageProperty.

Verification:
- Full repo build (build.cmd -restore -build -configuration Release): 0 warnings, 0 errors.
- 3 unit tests pass locally (102ms): WebHttpBinding_CanBeConstructed,
  WebHttpBinding_TransportMode_UsesHttps, WebChannelFactory_Endpoint_HasWebHttpBinding.
- 4 outerloop tests will execute end-to-end in CI now that the formatter chain
  is wired (still requires SelfHostedCoreWcfService running locally; CI's
  'dotnet-wcf-with-corewcf--ci' leg launches it automatically).

Also rebased onto upstream/main (commit 36673ab - Skip SctRenewalRegressionTests
on CoreWCF host); no conflicts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ameters

Without overriding BuildChannelFactory/CanBuildChannelFactory to call
InternalBuildChannelFactory, the encoder BE never got added to
context.BindingParameters. As a result, the downstream
HttpChannelFactory could not find it and silently fell back to the
default text encoder, which uses MessageVersion.Soap12 +
Addressing10 instead of MessageVersion.None.

This caused ApplyManualAddressing's 'via = toHeader' branch to be
skipped (it only fires when MessageVersion.Addressing ==
AddressingVersion.None), so even though Message.Headers.To was set
correctly by UriTemplateClientFormatter, the wire URL stayed at the
base address and CoreWCF returned its auto-generated help page,
triggering ProtocolException: content type text/html.

Fix follows the same pattern as TextMessageEncodingBindingElement,
BinaryMessageEncodingBindingElement, and MtomMessageEncodingBindingElement.

Adds WebHttpBinding_ActualWireUrl_IsBoundUriTemplate as a regression
test. It spins up a local HttpListener on 127.0.0.1:18091 and asserts
the actual GET URL is the bound URI template, not the base address.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CoreWCF.WebHttp routes the WebHttpDispatchOperationSelector's UriTemplate
table off of the URI that was passed to AddServiceEndpoint. When that URI
ends in a trailing slash (e.g. 'WebHttp.svc/'), every request below the
base path 404s because the table is anchored at the slash and nothing
matches relative paths like 'EchoWithGet?...'.

WebHttpTestServiceHost overrides Address to '' so its UriTemplates anchor
at the base path. The old format string produced 'WebHttp.svc/' for this
case, which CoreWCF rejected. When Address is empty just use the basePath
as-is. SOAP-based endpoints all use non-empty Address values, so their
formatting is unchanged.

Verified end-to-end against a local CoreWCF.WebHttp host (1.8.0):
  GET  /WebHttp.svc/EchoWithGet?message=Hello       -> 200
  GET  /WebHttp.svc/EchoWithGetPath/Hello-PATH      -> 200
  POST /WebHttp.svc/EchoWithPost                    -> 200

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
WebMessageEncoderFactory.WebMessageEncoder.IsContentTypeSupported was
chaining through RawMessageEncoder.IsContentTypeSupported(contentType)
first. The RawMessageEncoder property getter throws NotSupportedException
because ByteStreamMessageEncodingBindingElement is not yet ported, so
any content-type probe — including the application/xml replies the server
sends back for our test operations — threw before the Json/Text branches
got a chance to match.

Reorder the chain to check Json and Text first, and inline the raw
application/octet-stream check so we can answer the support question
without instantiating the (unported) raw encoder. Once Raw support is
ported we can revisit this.

Also extend the local-HttpListener regression test to assert the XML
reply round-trips back to a typed string, catching the IsContentTypeSupported
bug in addition to the wire URL bug it was already covering.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When an operation declares ResponseFormat=Json on its [WebGet]/[WebInvoke]
attribute, SingleBodyParameterMessageFormatter.CreateXmlAndJsonClientFormatter
was still returning the XML formatter, so DataContractSerializer tried to
parse the JSON response body and threw SerializationException 'Unable to
deserialize XML body with root name root' for typed string returns.

The full-fidelity solution would be DemultiplexingClientMessageFormatter
(which switches on the actual Content-Type of the incoming response) but
that class is server-side-heavy and not yet ported. As an interim, pass
the statically-declared response format from WebHttpBehavior.GetReplyClientFormatter
so JSON-typed operations select the JSON formatter at runtime.

Adds JSON-reply round-trip regression test against a local HttpListener,
alongside the existing XML round-trip test.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The legacy 'dotnet-wcf-ci' pipeline runs scenario tests against the
shared bridge VM at wcfcoresrv23.westus3.cloudapp.azure.com, whose IIS
does not yet host the new WebHttp.svc endpoint this PR introduces. As a
result every WebHttp scenario test on that leg returned HTTP 500.

Add a 'Run_With_CoreWCFService' condition (mirror of the existing
Skip_CoreWCFService_FailedTest detector) and apply it to the four
WebHttp outerloop tests so they only execute on the self-hosted CoreWCF
leg (dotnet-wcf-with-corewcf--ci), where they pass end-to-end. They can
be re-enabled on the bridge once IISHostedWcfService is deployed there.

Unit tests, local-HttpListener round-trip tests, and CoreWCF outerloop
tests remain unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The IIS-hosted test service compiles App_code at runtime via ASP.NET
code-behind using the in-box .NET Framework C# 5.0 compiler (no Roslyn
CodeDOM provider is configured in Web.config). The expression-bodied
members in WebHttpTestServiceHost.cs are a C# 6 feature and fail to
compile there, which takes down the whole App_code assembly and stops
the service from starting - causing all dotnet-wcf-ci (code-behind)
tests to fail. Rewrite them as classic property/method bodies so the
service compiles and starts under the .NET Framework host.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93fe5c75-a8e8-4926-bc03-391d76344817
…ocal on WebHttpBinding

Addresses @mconnew review comment on WebHttpBinding.cs:36. The
underlying HttpTransportBindingElement in dotnet/wcf fully supports
AllowCookies (HttpChannelFactory sets clientHandler.UseCookies), plus
the three proxy properties. WSHttpBinding/HttpBindingBase already
surface them; the comment claiming they are unsupported was stale.

Each setter propagates to both the HTTP and HTTPS transport BE so the
binding behaves consistently across all WebHttpSecurityMode values.
Mirror of the HttpBindingBase pattern with the same [DefaultValue]
attributes for XmlSerializer round-tripping.

HostNameComparisonMode remains omitted because the corresponding
setter genuinely does not exist on HttpTransportBindingElement in
dotnet/wcf, which @mconnew explicitly confirmed is fair to leave out.

Tests: 3 unit tests verify the properties flow to both transport BEs
via CreateBindingElements(); plus WebHttpBinding_AllowCookies_RoundTripsCookieHeader
spins up a local HttpListener that Set-Cookies on first response and
asserts the client echoes 'sid=abc123' back on the second request.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Type

Addresses @mconnew review comment on HttpTransportHelpers.cs:41.

ConfigureAuthentication was setting http.AuthenticationScheme from
ClientCredentialType but never setting http.ProxyAuthenticationScheme
from ProxyCredentialType. HttpChannelFactory reads the proxy scheme
when an explicit ProxyAddress is configured, so authenticated corporate
proxies (Basic/Digest/Ntlm/Negotiate) were silently dropped for anyone
using WebHttpSecurityMode.Transport / TransportCredentialOnly.

Calls HttpProxyCredentialTypeHelper.MapToAuthenticationScheme directly
(the helper is internal to System.ServiceModel.Http but visible to us
via [InternalsVisibleTo]), keeping mapping logic in a single place
rather than duplicating the switch.

Test: WebHttpBinding_ProxyCredentialType_FlowsToTransportProxyAuthenticationScheme
[WcfTheory] covers all five HttpProxyCredentialType values and asserts
the resulting HttpTransportBindingElement.ProxyAuthenticationScheme.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… client

Addresses @mconnew review comment on WebHttpBinding.cs:148.

HttpClientCredentialType.InheritedFromHost is only valid on server hosts
(IIS-hosted). On a client channel factory, WebHttpSecurity would map it
to AuthenticationSchemes.None and the request would fail deep inside
HttpTransportBindingElement with ArgumentException 'HttpAuthSchemeCannotBeNone'
- a different exception type and message than what .NET Framework's
WebHttpBinding produced for the same misuse.

Override BuildChannelFactory<TChannel> and throw InvalidOperationException
up front with the clearer .NET FX message. Matches WSHttpBinding's
equivalent guard in dotnet/wcf.

Also fix Resources/Strings.resx: the HttpClientCredentialTypeInvalid
entry we inherited from the CoreWCF port had a wrong message body
('There is no {0} on the incoming Message.') - restore the correct
message from .NET Framework / System.ServiceModel.Http.

Tests:
  * WebHttpBinding_InheritedFromHost_ThrowsInvalidOperationExceptionAtFactoryCreation
    (Theory, Transport and TransportCredentialOnly) - asserts the guard
    fires with the expected exception type and message text.
  * WebHttpBinding_InheritedFromHost_DoesNotThrow_WhenSecurityModeIsNone
    - confirms the guard does not over-fire in the None mode.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… message

The HttpClientCredentialTypeInvalid resource string used to list valid
client credential values as 'None, Basic, Client, Digest, Ntlm, Windows'.
There is no 'Client' member on HttpClientCredentialType; the intended
value is 'Certificate' (see src/System.ServiceModel.Http/src/System/
ServiceModel/HttpClientCredentialType.cs). Every caller of
SR.HttpClientCredentialTypeInvalid (WSHttpBinding, BasicHttpBinding,
BasicHttpsBinding, NetHttpBinding, NetHttpsBinding, and the new
WebHttpBinding guard added by this PR) was therefore telling users to
use a value that does not exist.

Fix the wording in all three shipping resx files:

  * System.ServiceModel.Http/src/Resources/Strings.resx
  * System.ServiceModel.Primitives/src/Resources/Strings.resx
  * System.ServiceModel.Web/src/Resources/Strings.resx

Arcade's XliffTasks regenerated the 39 companion xlf files during the
next build. The English <source> is now correct in every locale; the
localized <target> strings that inlined the value verbatim are flagged
state='needs-review-translation' so the localization team can refresh
them in a follow-up localization sync.

svcutil's SRServiceModel.resx keeps the pre-existing typo (out of scope
per task direction).

Flagged by Claude Sonnet 5 during multi-model review of PR dotnet#5959. No
code-behind changes; SR key and format argument count are unchanged so
all five call sites and the new WebHttp guard keep working. All 39 in-repo
WebHttp tests still pass (0 failed).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
All three WebHttpBinding_*_RoundTripsAgainstLocalHttpListener tests
used to hardcode a port (18091 / 18092 / 18093) and silently 'return'
on HttpListenerException. If the hardcoded port was already in use on
the test runner, the test would report as PASSED without running any
assertion - masking a real regression in the client's URL binding,
JSON reply deserialization, or cookie handling. Flagged by Gemini 3.1
Pro during multi-model code review of PR dotnet#5959.

Add a StartLoopbackHttpListener helper that:
  * Picks a random port from the Windows dynamic / ephemeral range
    (49152-65535 per RFC 6335), minimizing collisions with configured
    services.
  * Retries up to MaxPortRetries (10) times to survive transient
    collisions or parallel-test races.
  * On exhaustion, calls Assert.Fail with a per-attempt diagnostic
    listing each attempted port and its HttpListener error code.
    Verified in a temp failure-mode run: 'Unable to find a random port
    number after 10 attempts. Errors: attempt 1 port 1: 5/Access is
    denied; ...'

Refactor all three call sites to use the helper: one-line tuple
deconstruction replaces the seven-line hardcoded-port + try/catch/return
boilerplate in each test. Downstream logic is unchanged.

Semantics change vs before: an HttpListener environment that truly
blocks loopback binding after 10 tries now fails the test loudly
instead of skipping silently. This is the intended trade-off - a real
environmental block is worth surfacing, and 10 attempts across 16384
ports guarantees any transient collision is handled.

Local validation: 39 passed / 0 failed / 4 skipped (outerloop). Full
repo build clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Per @mconnew review: this file documents the features shipped in the
already-released v2.1.0, so it shouldn''t be retroactively edited for an
in-progress feature. Restore the WebHttpBinding row to its original
no-entry state; the new package''s support status will be reflected in
the notes for the version it actually ships in.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@afifi-ins
afifi-ins force-pushed the feature/webhttpbinding-porting branch from f4b0821 to 829c3f4 Compare July 30, 2026 04:44
afifi-ins and others added 10 commits July 30, 2026 08:00
…t/fault classes

Addresses @mconnew review comments 28-37: the WebOperationContext cluster
was lifted from CoreWCF (server-side) and exposed the wrong shape for a
client-only library.

Removed (server-side only, unused on a REST client):
  * IncomingWebRequestContext  - represents a request arriving at a service
  * OutgoingWebResponseContext - represents a service sending a response
  * WebFaultException / IWebFaultException - thrown by services to produce
    fault responses; a client never authors these

Added (client-side, ported from the .NET Framework reference source):
  * OutgoingWebRequestContext  - the request the client sends
  * IncomingWebResponseContext - the response the client receives
    (reads HttpResponseMessageProperty, which dotnet/wcf's HTTP channel
    already populates on incoming replies)

WebOperationContext now exposes the client pair OutgoingRequest /
IncomingResponse instead of the server pair IncomingRequest /
OutgoingResponse, and the server-only CreateXxxResponse / GetUriTemplate
helpers are gone (comments 33-37).

Also fixes the OperationContextScope clobber found in multi-model review
(agent Bug 3): UriTemplateClientFormatter now writes Method /
SuppressEntityBody through WebOperationContext.Current.OutgoingRequest
when a context is active, so a caller-supplied ambient
HttpRequestMessageProperty (e.g. for custom headers) no longer overwrites
the operation's GET method via ServiceChannel.AddMessageProperties. Falls
back to the message property when no context is active. Mirrors the .NET
Framework two-branch logic.

SingleBodyParameterMessageFormatter.SuppressReplyEntityBody is now a no-op
(reply-body suppression is server-side; the SerializeReply callers go away
with the IDispatchMessageFormatter removal).

Test: WebHttpBinding_OperationContextScope_PreservesGetMethod - opens an
OperationContextScope, sets an ambient HttpRequestMessageProperty, and
asserts the wire method stays GET (would be POST if clobbered).

Utility.cs still has live members (IsJsonContent, AddRange); trimming its
now-dead members is deferred to the dead-code cleanup pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…est/reply only)

Addresses @mconnew review comments 23 and 26: IDispatchMessageFormatter is
the server-side dispatch formatter interface; a WebHttpBinding client only
needs IClientMessageFormatter (SerializeRequest / DeserializeReply).

Removed IDispatchMessageFormatter (and its DeserializeRequest / SerializeReply
members) from:
  * HttpStreamFormatter
  * SingleBodyParameterMessageFormatter (+ nested NullMessageFormatter)
  * WebHttpBehavior.MessagePassthroughFormatter

Removed the now-orphaned server-side dispatch-formatter factory methods, all
of which were unreachable stubs returning null in the client-only port:
  * WebHttpBehavior.GetReplyDispatchFormatter / GetRequestDispatchFormatter
  * WebHttpBehavior.GetDefaultDispatchFormatter / GetDefaultXmlAndJsonDispatchFormatter
  * SingleBodyParameterMessageFormatter.CreateXmlAndJsonDispatchFormatter / CreateDispatchFormatter
  * SingleBodyParameterMessageFormatter.SuppressReplyEntityBody (last caller removed)
  * a commented-out dead GetDefaultXmlAndJsonClientFormatter block

There are now zero IDispatchMessageFormatter references in the package.
All 40 in-repo WebHttp tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… supported types

Addresses @mconnew review comment 25. The set of types QueryStringConverter
supports out of the box is fixed and never mutated, but it was being rebuilt
as a per-instance Hashtable of ~21 entries in every constructor. Replace it
with a single static readonly FrozenSet<Type> shared across all instances -
fast, allocation-free Contains lookups, and clearer intent. The package is
net10.0-only so System.Collections.Frozen is available (mconnew suggested
ImmutableHashSet; FrozenSet is the read-optimized equivalent for a set that
is built once and only queried).

The per-endpoint _typeConverterCache remains a per-instance Hashtable - it is
mutated at runtime and is intentionally not shared.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Addresses @mconnew review on System.ServiceModel.Http.csproj: InternalsVisibleTo
should be avoided unless absolutely needed. The Web package depended on only two
Http internals, both now eliminated:

  * HttpProxyCredentialTypeHelper.MapToAuthenticationScheme - inlined the tiny
    HttpProxyCredentialType -> AuthenticationSchemes switch into
    HttpTransportHelpers (mirrors the sibling ClientCredentialType switch already
    there), as suggested on the HttpTransportHelpers.cs thread.
  * HttpTransportDefaults constants - the 5 [DefaultValue(HttpTransportDefaults.X)]
    attributes on WebHttpBinding now use the literal default values
    (false/false/null/true/TransferMode.Buffered), which is all [DefaultValue]
    needs.

With both removed, the InternalsVisibleTo entry for System.ServiceModel.Web is
deleted from System.ServiceModel.Http.csproj. Web builds cleanly against only the
public Http surface; proxy-credential and property-propagation tests pass.

(The Primitives -> Web IVT is unchanged; it is the same shared-internals entry
every sibling package already has.)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Addresses @mconnew review comments 1, 8, 15, 16, 20.

  * Delete MessageExtensions.cs - its only member (CreateMessageDisposedException)
    has no callers anywhere in the package [20].
  * Remove UriTemplateHelpers.AssertCanonical - the sole call site was already
    commented out; delete both the method and the commented-out caller in
    UriTemplate.Match [15][16].
  * Remove the [TypeForwardedFrom(... Version=3.5.0.0 ...)] attribute on UriTemplate
    (and the now-unused System.Runtime.CompilerServices using) - dotnet/wcf is not
    consumed by .NET 3.5 assemblies, so the type-forward is unnecessary [1].
  * Replace the "PreSharp is complaining and warning suppression isn't working"
    null-check in UriTemplate.IsEquivalentTo with an Fx.Assert that the segments and
    queries collections are non-null, per the review suggestion [8].

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ON formatter

Addresses @mconnew review comment 22 and multi-model-review agent Bug 1.

comment 22 - WebHttpBehavior carried a WebHttpBehavior(IServiceProvider) constructor
and an internal ServiceProvider property lifted from the CoreWCF (DI-based) code
base. Nothing on the client reads them - they were pure vestige. Remove the
IServiceProvider constructor and property; the parameterless constructor now does
the initialization directly. No behavior change (a full NetFx re-port is
unnecessary: the rest of the class is already the client-side FX logic; only the
IServiceProvider was the CoreWCF-ism).

agent Bug 1 - GetReplyClientFormatter's wrapped-response branch called
GetDefaultXmlAndJsonClientFormatter, which hard-coded the XML formatter even when
the operation declared ResponseFormat=Json. (The earlier fix threaded the response
format into the bare-reply path but not the wrapped path.) An operation with
BodyStyle=Wrapped + ResponseFormat=Json therefore had its JSON reply handed to a
DataContractSerializer, failing at runtime. GetDefaultXmlAndJsonClientFormatter now
takes the response-format preference and selects the JSON formatter accordingly,
mirroring the bare path.

All 40 in-repo WebHttp tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Addresses @mconnew review comment 27, which flagged HttpDateParse as code that had
a known performance issue in CoreWCF and needed to be stripped out and its usage
replaced.

After the client-only reshape (removing IncomingWebRequestContext and
OutgoingWebResponseContext, which were its only consumers - they parsed
Last-Modified / If-Modified-Since / If-Unmodified-Since header dates on the server
side), HttpDateParse has no remaining callers in the package. So there is nothing
to replace; the file is simply deleted as dead code.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The .NET Framework WebMessageEncoderFactory passes the configured
XmlDictionaryReaderQuotas and the max read/write pool sizes to the
TextMessageEncoderFactory it creates for XML replies. The port dropped
these, so XML responses were silently decoded with default quotas
(agent-review Bug 2). The JSON path already forwarded them via
JsonMessageEncoderFactory; this makes the text (XML) path consistent.
Port the ByteStream message-encoder cluster (ByteStreamMessage,
ByteStreamMessageEncoder + factory, ByteStreamMessageEncodingBindingElement,
ByteStreamBufferedMessageData, and the XmlByteStream reader/writer helpers)
into System.ServiceModel.Primitives so raw / application/octet-stream
pass-through is available as a reusable component, not just for WebHttpBinding.

The encoder implements the full synchronous and asynchronous MessageEncoder
surface: sync ReadMessage/WriteMessage for both the Stream and buffered
(ArraySegment) paths, plus genuine async ReadMessageAsync(Stream) and
WriteMessageAsync(Message, Stream) overrides.

Adapted from the modern CoreWCF implementation: namespace to
System.ServiceModel, SR -> SRP resources, Task -> ValueTask to match the
dotnet/wcf MessageEncoder base, and dropped the server-transport
HttpRequestMessage/HttpResponseMessage variants (the client only needs the
Stream and buffered paths). Added the 12 supporting string resources and the
new public API to the reference assembly.
Now that ByteStreamMessageEncodingBindingElement lives in Primitives, wire the
WebHttp client's raw (application/octet-stream pass-through) path:

- WebMessageEncoderFactory.RawMessageEncoder now builds a ByteStream encoder
  (was a NotSupportedException stub); the Raw switch cases in ReadMessage /
  WriteMessage / ReadMessageAsync / WriteMessageAsync were already routed to it.
- WebMessageEncoder.IsContentTypeSupported restored to the reference-source form
  (raw || json || text), removing the interim IsRawContentType workaround.
- HttpStreamFormatter serializes a request Stream via ByteStreamMessage.CreateMessage
  and deserializes a raw reply via StreamFormatter.MessageBodyStream.
- Removed the now-dead HttpStreamMessage (superseded by ByteStreamMessage); the
  body element name comes from ByteStreamMessageUtility.StreamElementName so the
  writer and reader stay in sync.

Added a self-contained loopback raw round-trip test (send a Stream, receive the
echoed bytes) exercising both the write and read raw paths.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add APIs to support WebHttpBinding Add support for HTTP requests which use the GET verb

4 participants