Add client-side WebHttpBinding support (closes #1413, #46)#5959
Open
afifi-ins wants to merge 16 commits into
Open
Add client-side WebHttpBinding support (closes #1413, #46)#5959afifi-ins wants to merge 16 commits into
afifi-ins wants to merge 16 commits into
Conversation
Add empty System.ServiceModel.Web package targeting $(DotNetVersion).
Mirrors the System.ServiceModel.NetNamedPipe template:
- Single TFM, no ref/ folder, two-entry solution wiring.
- System.SR resource class via Resources/Strings.resx auto-generation.
- ProjectReference to System.ServiceModel.Primitives and System.ServiceModel.Http.
Add InternalsVisibleTo("System.ServiceModel.Web") to
System.ServiceModel.Primitives so the upcoming WebHttp port can reach
internal helpers (Fx, DiagnosticUtility, XmlSerializerOperationBehavior.Reflector).
Disable PackageValidation for this new package (no baseline on NuGet yet).
Part of porting WebHttpBinding to .NET (Core) WCF client (issues dotnet#46, dotnet#1413).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Port 19 UriTemplate* source files (~4,800 LOC) from the MIT-licensed
Microsoft Reference Source mirror in mono/mono (commit 0f53e9e1) into
the new System.ServiceModel.Web package.
Files ported under src/System.ServiceModel.Web/src/System/:
- UriTemplate.cs (top-level public class, template parsing + binding)
- UriTemplateTable.cs (thread-safe template table, Match/MatchSingle)
- UriTemplateMatch.cs (match result with BoundVariables, QueryParameters)
- UriTemplateMatchException.cs
- UriTemplateEquivalenceComparer.cs
- UriTemplateHelpers.cs (internal escape/comparer helpers)
- UriTemplatePartType.cs (enum)
- UriTemplate{Path,Variable,Compound,Literal}*PathSegment.cs (segment AST)
- UriTemplate{Literal,Variable}QueryValue.cs (query AST)
- UriTemplatePathPartiallyEquivalentSet.cs (internal trie helper)
- UriTemplateTableMatchCandidate.cs (internal struct)
- UriTemplateTrieNode.cs (trie-based matching engine, ~960 LOC)
- UriTemplate{Trie,Path}*.cs (internal trie cursors / enums)
Plus a small companion type:
- System/Collections/ObjectModel/FreezableCollection.cs (internal, ported from
System.ServiceModel/System/Collections/ObjectModel; used by UriTemplateTable)
Transformations applied to every file:
1. MS copyright header swapped for .NET Foundation MIT header.
2. SR.GetString(...) calls rewritten to SR.Format(...) (the modern convention
in dotnet/wcf; string.Format with a single-arg pattern is a no-op).
3. No changes to logic, type signatures, or internal layout - byte-for-byte
equivalent to the reference source after these mechanical edits.
42 new SR strings added to Resources/Strings.resx (ObjectIsReadOnly +
41 UT* error messages); XLF localization files auto-generated by
Microsoft.DotNet.XliffTasks for all 13 target locales.
Build: 0 warnings, 0 errors.
Deps satisfied via InternalsVisibleTo from previous commit:
- DiagnosticUtility.ExceptionUtility.ThrowHelperError/Argument/ArgumentNull
- Fx.Assert
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 .NET FX reference source provides the protected SerializationInfo constructor for binary-formatter compat. On .NET 8+ this constructor is obsolete (SYSLIB0051). Mark with [Obsolete(DiagnosticId = "SYSLIB0051")] to pin the obsolescence inline and let it pass under -warnaserror. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Our new System.ServiceModel.Web v10 collides at reference resolution
time with the BCL shim System.ServiceModel.Web v4.0.0.0 (the one that
type-forwards only Syndication and JSON types). MSBuild emits MSB3243
("No way to resolve conflict"), arbitrarily picking our v10 - which is
the correct outcome - but the warning is escalated to an error under
-warnaserror.
Suppress the noise by adding MSB3243 to MSBuildWarningsAsMessages on
the test project only. The conflict only exists in test reference
closure (Infrastructure.Common pulls in shim transitively); the impl
project does not see it.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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>
a5caed5 to
794f262
Compare
…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>
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.
Closes #1413
Closes #46
Summary
Adds client-side
WebHttpBindingsupport to .NET (Core) WCF. The entireSystem.ServiceModel.Webnamespace (binding, behavior, attributes,WebChannelFactory<T>,UriTemplate,WebOperationContext,QueryStringConverter, ...) has been absent fromdotnet/wcfsince the start — confirmed missing in bothdotnet/wcfanddotnet/runtime(the runtime ships aSystem.ServiceModel.Webshim 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:mono/mono(MIT since 2014) — the fullUriTemplatecluster andWebChannelFactory<T>(CoreWCF doesn't ship these because they're either standalone utilities or strictly client-only)What ships
SystemUriTemplate,UriTemplateTable,UriTemplateMatch,UriTemplateMatchException,UriTemplateEquivalenceComparerSystem.ServiceModelWebHttpBinding,WebHttpSecurity,WebHttpSecurityModeSystem.ServiceModel.ChannelsWebMessageEncodingBindingElement,WebContentTypeMapper,WebBodyFormatMessageProperty,WebContentFormatSystem.ServiceModel.DescriptionWebHttpBehavior(~870 LOC)System.ServiceModel.DispatcherQueryStringConverter,UriTemplateClientFormatter,SingleBodyParameter{,DataContract,XmlSerializer}MessageFormatter,DataContractJsonSerializerOperationFormatter,HttpStreamFormatter,{Xml,Json,Multiplexing}FormatMapping,UnwrappedTypesXmlSerializerManager,NameValueCacheSystem.ServiceModel.WebWebGetAttribute,WebInvokeAttribute,WebChannelFactory<T>,WebFaultException,WebFaultException<T>,WebOperationContext,IncomingWebRequestContext,IncomingWebResponseContext,OutgoingWebRequestContext,OutgoingWebResponseContext,WebMessageFormat,WebMessageBodyStyleSurgically deferred (NotSupportedException with clear messages)
dotnet/wcfis 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, ...)ByteStreamMessage,MessageBodyStream, rawStreamBodyWriter)WebScriptEnablingBehavior,JavascriptCallbackBehaviorAttribute)AspNetCacheProfileAttributeWebServiceHost/WebServiceHostFactoryPrimitives changes
Just one item — minimum required for a client-only port:
InternalsVisibleTo("System.ServiceModel.Web")added toSystem.ServiceModel.Primitives.csprojso the new assembly can reachDiagnosticUtility.ExceptionUtility,Fx,XmlSerializerOperationBehavior.Reflector, internalIDispatchMessageFormatter,OperationFormatter.CreateDeserializationFailedFault,BufferedMessage/BufferedMessageData/BufferedMessageWriter, etc.Same IVT entry added to
System.ServiceModel.Http.csprojforHttpTransportDefaults.Tests
src/System.ServiceModel.Web/tests/— 3 tests covering binding/factory/behavior construction. All passing locally (80ms).src/System.Private.ServiceModel/tests/Scenarios/Binding/WebHttp/Binding.WebHttp.IntegrationTests.csproj— 4 round-trip tests (EchoWithGetXML,EchoWithGetJsonJSON,EchoWithPost,EchoWithGetPathpath-var). Built and discovered; pending live CI run.WebHttpTestServiceHost.csintools/IISHostedWcfService/App_code/testhosts/with contractIWcfWebHttpService. Auto-picked-up bySelfHostedCoreWcfServicevia the existing<Compile Include="..\IISHostedWcfService\**\*.cs">glob. Helix auto-discovers the new test project via the**\*.IntegrationTests.csprojglob ineng/SendToHelix.proj— no CI registration changes needed.tests/Common/Scenarios/Endpoints.WebHttp.csextends the existingpublic static partial class EndpointswithHttpBaseAddress_WebHttp[_*]properties.Build verification
Release notes
release-notes/SupportedFeatures-v2.1.0.md: WebHttpBinding bumped from 🚫 toCommits
System.ServiceModel.Webpackage (csproj, sln, IVT,EnablePackageValidation=false)UriTemplateMatchExceptionserialization ctorSource attribution
Every commit message documents source provenance:
mono/mono@0f53e9e1for files lifted from the Microsoft Reference SourceCoreWCF/CoreWCF@v1.8.0for files lifted from CoreWCF.WebHttp