< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Description.ServiceMetadataExtension
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Description/ServiceMetadataExtension.cs
Line coverage
64%
Covered lines: 524
Uncovered lines: 291
Coverable lines: 815
Total lines: 1797
Line coverage: 64.2%
Branch coverage
55%
Covered branches: 194
Total branches: 352
Branch coverage: 55.1%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.cctor()100%110%
.ctor(...)100%11100%
.ctor()100%11100%
TryGetHttpHostAndPort(...)66.66%6691.66%
CreateMiddleware(...)100%11100%
EnsureInitialized()87.5%8891.66%
EnsureSingleWsdlInitialized()100%44100%
CoreWCF.IExtension<CoreWCF.ServiceHostBase>.Attach(...)50%8862.5%
CoreWCF.IExtension<CoreWCF.ServiceHostBase>.Detach(...)0%10100%
EnsureServiceMetadataExtension(...)100%22100%
GetWriteFilter(...)83.33%6687.5%
GetWriteFilter(...)0%660%
GetDynamicAddressWriter(...)92.85%141490%
GetDynamicAddressWriter(...)0%20200%
.ctor(...)0%440%
GetLocationToReturn()0%880%
GatherMetadata(...)0%12120%
Get(...)0%220%
GetAsync(...)100%110%
.ctor(...)100%22100%
GetInitData()100%44100%
FindWsdlReference(...)33.33%6628.57%
TryHandleDocumentationRequestAsync()71.42%141480%
GetHttpGetUrl(...)57.14%141460%
GetMexUrl(...)0%440%
TryHandleMetadataRequestAsync()53.57%282855.31%
CreateDiscoMessage(...)57.14%141464.7%
CombineKeyAndValues(System.String,System.String)0%220%
FindQuery(...)80%101077.77%
ProcessHttpRequest()62.5%8869.23%
.ctor(...)100%11100%
TryQueryLookup(...)100%11100%
InitializeFrom(...)83.33%121296.77%
CollectWsdls(...)100%44100%
CollectXsds(...)100%44100%
FixImportAddresses()100%44100%
FixImportAddresses(...)58.33%121250%
FixImportAddresses(...)78.57%1414100%
GetAnyContractName(...)70%101088.88%
GetAnyService(...)75%4480%
GetAnyWsdlName(...)75%4480%
MetadataMiddleware(...)100%11100%
HandleRequest()50%2237.5%
SetResponseStatusAndContentType(...)100%11100%
RespondWithRedirect(...)100%110%
SetHttpResponseStatus(...)100%110%
GetUri(...)100%110%
GetUri(...)0%14140%
.ctor(...)100%11100%
Write(...)100%11100%
.ctor(...)100%11100%
.ctor(...)100%110%
Write(...)62.5%8882.35%
.ctor(...)100%11100%
WriteClass(...)100%11100%
WriteComment(...)100%11100%
WriteDiscoLink(...)100%11100%
WriteError(...)100%110%
WriteKeyword(...)100%11100%
WriteSampleCode(...)100%11100%
WriteExceptionDetail(...)100%110%
WriteStyleSheet()100%11100%
WriteTitle(...)100%11100%
WriteToolUsage(...)75%4490.9%
WriteMetadataAddress(...)100%66100%
Write(...)100%110%
WriteResponseAsync()100%11100%
.ctor(...)100%11100%
Write(...)100%11100%
.ctor(...)100%11100%
WriteCore(...)100%11100%
.ctor(...)100%110%
WriteCore(...)100%110%
Close()100%110%
Flush()100%11100%
LookupPrefix(...)100%11100%
WriteBase64(...)100%110%
WriteCData(...)100%110%
WriteCharEntity(...)100%110%
WriteChars(...)100%110%
WriteComment(...)100%110%
WriteDocType(...)100%110%
WriteEndAttribute()100%11100%
WriteEndDocument()100%110%
WriteEndElement()100%11100%
WriteEntityRef(...)100%110%
WriteFullEndElement()100%11100%
WriteProcessingInstruction(...)100%110%
WriteRaw(...)100%110%
WriteRaw(...)100%110%
WriteStartAttribute(...)100%11100%
WriteStartDocument(...)100%110%
WriteStartDocument()100%11100%
WriteStartElement(...)100%11100%
WriteString(...)100%11100%
WriteSurrogateCharEntity(...)100%110%
WriteWhitespace(...)100%110%
.ctor(...)100%11100%
CloneWriteFilter()100%110%
WriteString(...)50%4466.66%
.ctor(...)100%11100%
CloneWriteFilter()100%110%
UpdateUri(...)100%22100%
UpdateUri(...)0%220%
WriteString(...)83.33%121283.33%
.ctor(...)100%11100%
.ctor(...)100%110%
.ctor(...)100%11100%
CloneWriteFilter()100%110%
UpdateUri(...)75%8884.61%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Description/ServiceMetadataExtension.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.Collections.Generic;
 6using System.Globalization;
 7using System.IO;
 8using System.Net;
 9using System.Text;
 10using System.Threading;
 11using System.Threading.Tasks;
 12using System.Xml;
 13using System.Xml.Schema;
 14using CoreWCF.Channels;
 15using CoreWCF.Configuration;
 16using CoreWCF.Runtime;
 17using Microsoft.AspNetCore.Http;
 18using WsdlNS = System.Web.Services.Description;
 19
 20namespace CoreWCF.Description
 21{
 22    // the description/metadata "mix-in"
 23    public class ServiceMetadataExtension : IExtension<ServiceHostBase>
 24    {
 25        private const string BaseAddressPattern = "{%BaseAddress%}";
 026        private static readonly Uri s_emptyUri = new Uri(string.Empty, UriKind.Relative);
 27        private MetadataSet _metadata;
 28        private WsdlNS.ServiceDescription _singleWsdl;
 29        private bool _isInitialized = false;
 30        private bool _isSingleWsdlInitialized = false;
 31        private ServiceHostBase _owner;
 57632        private readonly object _syncRoot = new object();
 57633        private readonly object _singleWsdlSyncRoot = new object();
 34
 115235        public ServiceMetadataExtension() : this(null) { }
 36
 57637        internal ServiceMetadataExtension(ServiceMetadataBehavior.MetadataExtensionInitializer initializer)
 38        {
 57639            Initializer = initializer;
 57640        }
 41
 67342        internal ServiceMetadataBehavior.MetadataExtensionInitializer Initializer { get; set; }
 43
 44        public MetadataSet Metadata
 45        {
 46            get
 47            {
 6948                EnsureInitialized();
 6949                return _metadata;
 50            }
 51        }
 52
 53        public WsdlNS.ServiceDescription SingleWsdl
 54        {
 55            get
 56            {
 1957                EnsureSingleWsdlInitialized();
 1958                return _singleWsdl;
 59            }
 60        }
 61
 2962        internal Uri ExternalMetadataLocation { get; set; }
 63
 464        internal bool MexEnabled { get; set; } = false;
 65
 7766        internal bool HttpGetEnabled { get; set; } = false;
 67
 8768        internal bool HttpsGetEnabled { get; set; } = false;
 69
 6570        internal bool HelpPageEnabled => HttpHelpPageEnabled || HttpsHelpPageEnabled;
 71
 472        internal bool MetadataEnabled => MexEnabled || HttpGetEnabled || HttpsGetEnabled;
 73
 66774        internal bool HttpHelpPageEnabled { get; set; } = false;
 75
 60276        internal bool HttpsHelpPageEnabled { get; set; } = false;
 77
 078        internal Uri MexUrl { get; set; }
 79
 9080        internal Uri HttpGetUrl { get; set; }
 81
 4582        internal Uri HttpsGetUrl { get; set; }
 83
 65284        internal Uri HttpHelpPageUrl { get; set; }
 85
 63386        internal Uri HttpsHelpPageUrl { get; set; }
 87
 2988        internal bool UpdateAddressDynamically => DynamicMetadataEndpointAddressProvider != null;
 89
 90        // This dictionary should not be mutated after open
 791        internal IDictionary<string, int> UpdatePortsByScheme { get; set; }
 92
 4493        public IMetadataEndpointAddressProvider DynamicMetadataEndpointAddressProvider { get; internal set; }
 94
 95        internal bool TryGetHttpHostAndPort(Uri listenUri, HttpRequest httpRequest, out string host, out int port, out s
 96        {
 497            host = null;
 498            port = 0;
 499            scheme = null;
 100
 4101            Uri customUri = DynamicMetadataEndpointAddressProvider?.GetEndpointAddress(httpRequest);
 4102            if (customUri != null)
 103            {
 4104                host = customUri.Host;
 4105                port = customUri.Port;
 4106                scheme = DynamicMetadataEndpointAddressProvider is UseRequestHeadersForMetadataAddressBehavior.UseHostHe
 4107                    ? listenUri.Scheme
 4108                    : customUri.Scheme;
 4109                return true;
 110            }
 111
 0112            return false;
 113        }
 114
 115        internal Func<RequestDelegate, RequestDelegate> CreateMiddleware(Uri baseAddress, bool isHttps)
 116        {
 34117            HttpGetImpl impl = new HttpGetImpl(this, baseAddress, isHttps);
 34118            return impl.MetadataMiddleware;
 119        }
 120
 121        private void EnsureInitialized()
 122        {
 69123            if (!_isInitialized)
 124            {
 24125                lock (_syncRoot)
 126                {
 24127                    if (!_isInitialized)
 128                    {
 24129                        if (Initializer != null)
 130                        {
 131                            // the following call will initialize this
 132                            // it will use the Metadata property to do the initialization
 133                            // this will call back into this method, but exit because isInitialized is set.
 134                            // if other threads try to call these methods, they will block on the lock
 24135                            _metadata = Initializer.GenerateMetadata();
 136                        }
 137
 24138                        if (_metadata == null)
 139                        {
 0140                            _metadata = new MetadataSet();
 141                        }
 142
 24143                        Thread.MemoryBarrier();
 144
 24145                        _isInitialized = true;
 24146                        Initializer = null;
 147                    }
 24148                }
 149            }
 69150        }
 151
 152        private void EnsureSingleWsdlInitialized()
 153        {
 19154            if (!_isSingleWsdlInitialized)
 155            {
 19156                lock (_singleWsdlSyncRoot)
 157                {
 19158                    if (!_isSingleWsdlInitialized)
 159                    {
 160                        // Could throw NotSupportedException if multiple contract namespaces. Let the exception propagat
 19161                        _singleWsdl = WsdlHelper.GetSingleWsdl(Metadata);
 19162                        _isSingleWsdlInitialized = true;
 163                    }
 19164                }
 165            }
 19166        }
 167
 168        void IExtension<ServiceHostBase>.Attach(ServiceHostBase owner)
 169        {
 576170            if (owner == null)
 171            {
 0172                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(owner)));
 173            }
 174
 576175            if (_owner != null)
 176            {
 0177                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.TheServiceMet
 178            }
 179
 576180            if (owner.State != CommunicationState.Created && owner.State != CommunicationState.Opening)
 181            {
 0182                throw new InvalidOperationException(owner.State.ToString());
 183            }
 184
 576185            _owner = owner;
 576186        }
 187
 188        void IExtension<ServiceHostBase>.Detach(ServiceHostBase owner)
 189        {
 0190            if (owner == null)
 191            {
 0192                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(owner));
 193            }
 194
 0195            if (_owner == null)
 196            {
 0197                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.TheServiceMet
 198            }
 199
 0200            if (_owner != owner)
 201            {
 0202                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(nameof(owner), SR.TheServiceMetadataExtensi
 203            }
 204
 0205            if (owner.State != CommunicationState.Created && owner.State != CommunicationState.Opening)
 206            {
 0207                throw new InvalidOperationException(owner.State.ToString());
 208            }
 209
 0210            _owner = null;
 0211        }
 212
 213        internal static ServiceMetadataExtension EnsureServiceMetadataExtension(ServiceHostBase host)
 214        {
 605215            ServiceMetadataExtension mex = host.Extensions.Find<ServiceMetadataExtension>();
 605216            if (mex == null)
 217            {
 576218                mex = new ServiceMetadataExtension();
 576219                host.Extensions.Add(mex);
 220            }
 221
 605222            return mex;
 223        }
 224
 225        private WriteFilter GetWriteFilter(HttpRequest httpRequest, Uri listenUri, bool removeBaseAddress)
 226        {
 25227            WriteFilter result = null;
 25228            if (UpdateAddressDynamically)
 229            {
 230                // Update address dynamically based on the request URI
 4231                result = GetDynamicAddressWriter(httpRequest, listenUri, removeBaseAddress);
 232            }
 233
 25234            if (result == null)
 235            {
 236                // Just use the statically known listen URI
 22237                if (removeBaseAddress)
 238                {
 0239                    result = new LocationUpdatingWriter(BaseAddressPattern, null);
 240                }
 241                else
 242                {
 22243                    result = new LocationUpdatingWriter(BaseAddressPattern, listenUri.ToString());
 244                }
 245            }
 246
 25247            return result;
 248        }
 249
 250        private WriteFilter GetWriteFilter(Message request, Uri listenUri, bool removeBaseAddress)
 251        {
 0252            WriteFilter result = null;
 0253            if (UpdateAddressDynamically)
 254            {
 255                // Update address dynamically based on the request URI
 0256                result = GetDynamicAddressWriter(request, listenUri, removeBaseAddress);
 257            }
 0258            if (result == null)
 259            {
 260                // Just use the statically known listen URI
 0261                if (removeBaseAddress)
 262                {
 0263                    result = new LocationUpdatingWriter(BaseAddressPattern, null);
 264                }
 265                else
 266                {
 0267                    result = new LocationUpdatingWriter(BaseAddressPattern, listenUri.ToString());
 268                }
 269            }
 270
 0271            return result;
 272        }
 273
 274        private DynamicAddressUpdateWriter GetDynamicAddressWriter(HttpRequest httpRequest, Uri listenUri, bool removeBa
 275        {
 4276            if (!TryGetHttpHostAndPort(listenUri, httpRequest, out string requestHost, out int requestPort, out string r
 277            {
 0278                return null;
 279            }
 280
 281            // Perf optimization: don't do dynamic update if it would be a no-op.
 282            // Ordinal string comparison is okay; it just means we don't get the perf optimization
 283            // if the listen host and request host are case-insensitively equal.
 4284            if (requestHost == listenUri.Host &&
 4285                requestPort == listenUri.Port &&
 4286                requestScheme == listenUri.Scheme &&
 4287                (UpdatePortsByScheme == null || UpdatePortsByScheme.Count == 0))
 288            {
 1289                return null;
 290            }
 291
 3292            if (DynamicMetadataEndpointAddressProvider is UseRequestHeadersForMetadataAddressBehavior.UseHostHeaderMetad
 293            {
 2294                return new RequestHeadersDynamicAddressUpdateWriter(listenUri, requestHost, requestPort, UpdatePortsBySc
 295            }
 296
 1297            return new CustomDynamicAddressUpdateWriter(listenUri, requestScheme, requestHost, requestPort);
 298        }
 299
 300        private DynamicAddressUpdateWriter GetDynamicAddressWriter(Message request, Uri listenUri, bool removeBaseAddres
 301        {
 0302            HttpContext context = null;
 0303            if (request.Properties.TryGetValue("Microsoft.AspNetCore.Http.HttpContext", out object contextObj))
 304            {
 0305                context = contextObj as HttpContext;
 306            }
 307
 0308            if (context==null || !TryGetHttpHostAndPort(listenUri, context.Request, out string requestHost, out int requ
 309            {
 0310                if (request.Headers.To == null)
 311                {
 0312                    return null;
 313                }
 0314                requestHost = request.Headers.To.Host;
 0315                requestPort = request.Headers.To.Port;
 0316                requestScheme = request.Headers.To.Scheme;
 317            }
 318
 319            // Perf optimization: don't do dynamic update if it would be a no-op.
 320            // Ordinal string comparison is okay; it just means we don't get the perf optimization
 321            // if the listen host and request host are case-insensitively equal.
 0322            if (requestHost == listenUri.Host &&
 0323                requestPort == listenUri.Port &&
 0324                requestScheme == listenUri.Scheme &&
 0325                (UpdatePortsByScheme == null || UpdatePortsByScheme.Count == 0))
 326            {
 0327                return null;
 328            }
 329
 0330            if (DynamicMetadataEndpointAddressProvider is UseRequestHeadersForMetadataAddressBehavior.UseHostHeaderMetad
 331            {
 0332                return new RequestHeadersDynamicAddressUpdateWriter(listenUri, requestHost, requestPort, UpdatePortsBySc
 333            }
 334
 0335            return new CustomDynamicAddressUpdateWriter(listenUri, requestScheme, requestHost, requestPort);
 336        }
 337
 338        internal class WSMexImpl : IMetadataExchange
 339        {
 340            internal const string MetadataMexBinding = "ServiceMetadataBehaviorMexBinding";
 341            internal const string ContractName = MetadataStrings.WSTransfer.Name;
 342            internal const string ContractNamespace = MetadataStrings.WSTransfer.Namespace;
 343            internal const string GetMethodName = "Get";
 344            internal const string RequestAction = MetadataStrings.WSTransfer.GetAction;
 345            internal const string ReplyAction = MetadataStrings.WSTransfer.GetResponseAction;
 346            private readonly ServiceMetadataExtension _parent;
 347            private readonly MetadataSet _metadataLocationSet;
 348            private TypedMessageConverter _converter;
 349            private readonly Uri _listenUri;
 350
 0351            internal WSMexImpl(ServiceMetadataExtension parent, bool isListeningOnHttps, Uri listenUri)
 352            {
 0353                _parent = parent;
 0354                IsListeningOnHttps = isListeningOnHttps;
 0355                _listenUri = listenUri;
 356
 0357                if (_parent.ExternalMetadataLocation != null && _parent.ExternalMetadataLocation != s_emptyUri)
 358                {
 0359                    _metadataLocationSet = new MetadataSet();
 0360                    string location = GetLocationToReturn();
 0361                    MetadataSection metadataLocationSection = new MetadataSection(MetadataSection.ServiceDescriptionDial
 0362                    _metadataLocationSet.MetadataSections.Add(metadataLocationSection);
 363                }
 0364            }
 365
 0366            internal bool IsListeningOnHttps { get; set; }
 367
 368            private string GetLocationToReturn()
 369            {
 370                Fx.Assert(_parent.ExternalMetadataLocation != null, "");
 0371                Uri location = _parent.ExternalMetadataLocation;
 372
 0373                if (!location.IsAbsoluteUri)
 374                {
 0375                    Uri httpAddr = _parent._owner.GetVia(Uri.UriSchemeHttp, location);
 0376                    Uri httpsAddr = _parent._owner.GetVia(Uri.UriSchemeHttps, location);
 377
 0378                    if (IsListeningOnHttps && httpsAddr != null)
 379                    {
 0380                        location = httpsAddr;
 381                    }
 0382                    else if (httpAddr != null)
 383                    {
 0384                        location = httpAddr;
 385                    }
 386                    else
 387                    {
 0388                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(nameof(_parent.ExternalMetadataLoca
 389                    }
 390                }
 391
 0392                return location.ToString();
 393            }
 394
 395            private MetadataSet GatherMetadata(string dialect, string identifier)
 396            {
 0397                if (_metadataLocationSet != null)
 398                {
 0399                    return _metadataLocationSet;
 400                }
 401                else
 402                {
 0403                    MetadataSet metadataSet = new MetadataSet();
 0404                    foreach (MetadataSection document in _parent.Metadata.MetadataSections)
 405                    {
 0406                        if ((dialect == null || dialect == document.Dialect) &&
 0407                            (identifier == null || identifier == document.Identifier))
 408                        {
 0409                            metadataSet.MetadataSections.Add(document);
 410                        }
 411                    }
 412
 0413                    return metadataSet;
 414                }
 415            }
 416
 417            public Message Get(Message request)
 418            {
 0419                GetResponse response = new GetResponse
 0420                {
 0421                    Metadata = GatherMetadata(null, null)
 0422                };
 423
 0424                response.Metadata.WriteFilter = _parent.GetWriteFilter(request, _listenUri, true);
 425
 0426                if (_converter == null)
 427                {
 0428                    _converter = TypedMessageConverter.Create(typeof(GetResponse), ReplyAction);
 429                }
 430
 0431                return _converter.ToMessage(response, request.Version);
 432            }
 433
 434            public Task<Message> GetAsync(Message request)
 435            {
 0436                return Task.FromException<Message>(DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplemente
 437            }
 438        }
 439
 440        internal class HttpGetImpl
 441        {
 442            private const string DiscoToken = "disco token";
 443            private const string DiscoQueryString = "disco";
 444            private const string WsdlQueryString = "wsdl";
 445            private const string XsdQueryString = "xsd";
 446            private const string SingleWsdlQueryString = "singleWsdl";
 447            private const string HtmlContentType = "text/html; charset=UTF-8";
 448            private const string XmlContentType = "text/xml; charset=UTF-8";
 449            private const int MaxQueryStringChars = 2048;
 450
 451            internal const string MetadataHttpGetBinding = "ServiceMetadataBehaviorHttpGetBinding";
 452            internal const string ContractName = "IHttpGetHelpPageAndMetadataContract";
 453            internal const string ContractNamespace = "http://schemas.microsoft.com/2006/04/http/metadata";
 454            internal const string GetMethodName = "Get";
 455            internal const string RequestAction = "*"; // MessageHeaders.WildcardAction;
 456            internal const string ReplyAction = "*"; // MessageHeaders.WildcardAction;
 457            internal const string HtmlBreak = "<BR/>";
 458
 459            private readonly ServiceMetadataExtension _parent;
 34460            private readonly object _sync = new object();
 461            private InitializationData _initData;
 462            private readonly Uri _listenUri;
 463            private readonly bool _isHttps;
 464
 34465            internal HttpGetImpl(ServiceMetadataExtension parent, Uri listenUri, bool isHttps)
 466            {
 34467                _parent = parent;
 34468                _listenUri = listenUri;
 34469                GetWsdlEnabled = parent.HttpsGetEnabled || parent.HttpGetEnabled;
 34470                HelpPageEnabled = parent.HelpPageEnabled;
 34471                _isHttps = isHttps;
 34472            }
 473
 42474            public bool HelpPageEnabled { get; set; } = false;
 475
 59476            public bool GetWsdlEnabled { get; set; }
 477
 478            private InitializationData GetInitData()
 479            {
 31480                if (_initData == null)
 481                {
 25482                    lock (_sync)
 483                    {
 25484                        if (_initData == null)
 485                        {
 25486                            _initData = InitializationData.InitializeFrom(_parent);
 487                        }
 25488                    }
 489                }
 490
 31491                return _initData;
 492            }
 493
 494            private string FindWsdlReference(DynamicAddressUpdateWriter addressUpdater)
 495            {
 4496                if (_parent.ExternalMetadataLocation == null || _parent.ExternalMetadataLocation == s_emptyUri)
 497                {
 4498                    return null;
 499                }
 500                else
 501                {
 0502                    Uri location = _parent.ExternalMetadataLocation;
 503
 0504                    Uri result = GetUri(_listenUri, location);
 0505                    if (addressUpdater != null)
 506                    {
 0507                        addressUpdater.UpdateUri(ref result);
 508                    }
 509
 0510                    return result.ToString();
 511                }
 512            }
 513
 514            private async Task<bool> TryHandleDocumentationRequestAsync(HttpContext requestContext)
 515            {
 4516                if (!HelpPageEnabled)
 517                {
 0518                    return false;
 519                }
 520
 521                MetadataResult result;
 4522                if (_parent.MetadataEnabled)
 523                {
 4524                    string discoUrl = null;
 4525                    string singleWsdlUrl = null;
 4526                    bool linkMetadata = true;
 527
 4528                    DynamicAddressUpdateWriter addressUpdater = null;
 4529                    if (_parent.UpdateAddressDynamically)
 530                    {
 0531                        addressUpdater = _parent.GetDynamicAddressWriter(requestContext.Request, _listenUri, false);
 532                    }
 533
 4534                    string wsdlUrl = FindWsdlReference(addressUpdater);
 535
 4536                    string httpGetUrl = GetHttpGetUrl(addressUpdater);
 537
 4538                    if (wsdlUrl == null && httpGetUrl != null)
 539                    {
 4540                        wsdlUrl = httpGetUrl + "?" + WsdlQueryString;
 4541                        singleWsdlUrl = httpGetUrl + "?" + SingleWsdlQueryString;
 542                    }
 543
 4544                    if (httpGetUrl != null)
 545                    {
 4546                        discoUrl = httpGetUrl + "?" + DiscoQueryString;
 547                    }
 548
 4549                    if (wsdlUrl == null)
 550                    {
 0551                        wsdlUrl = GetMexUrl(addressUpdater);
 0552                        linkMetadata = false;
 553                    }
 554
 4555                    result = new MetadataOnHelpPageResult(discoUrl, wsdlUrl, singleWsdlUrl, GetInitData().ServiceName, G
 556                }
 557                else
 558                {
 0559                    result = new MetadataOffHelpPageMessage();
 560                }
 561
 4562                SetResponseStatusAndContentType(requestContext.Response, HttpStatusCode.OK, HtmlContentType);
 4563                await result.WriteResponseAsync(requestContext.Response);
 4564                return true;
 4565            }
 566
 567            private string GetHttpGetUrl(DynamicAddressUpdateWriter addressUpdater)
 568            {
 4569                Uri result = null;
 4570                if (_listenUri.Scheme == Uri.UriSchemeHttp)
 571                {
 2572                    if (_parent.HttpGetEnabled)
 573                    {
 2574                        result = _parent.HttpGetUrl;
 575                    }
 0576                    else if (_parent.HttpsGetEnabled)
 577                    {
 0578                        result = _parent.HttpsGetUrl;
 579                    }
 580                }
 581                else
 582                {
 2583                    if (_parent.HttpsGetEnabled)
 584                    {
 2585                        result = _parent.HttpsGetUrl;
 586                    }
 0587                    else if (_parent.HttpGetEnabled)
 588                    {
 0589                        result = _parent.HttpGetUrl;
 590                    }
 591                }
 592
 4593                if (result != null)
 594                {
 4595                    if (addressUpdater != null)
 596                    {
 0597                        addressUpdater.UpdateUri(ref result, _listenUri.Scheme != result.Scheme /*updateBaseAddressOnly*
 598                    }
 599
 4600                    return result.ToString();
 601                }
 602
 0603                return null;
 604            }
 605
 606            private string GetMexUrl(DynamicAddressUpdateWriter addressUpdater)
 607            {
 0608                if (_parent.MexEnabled)
 609                {
 0610                    Uri result = _parent.MexUrl;
 0611                    if (addressUpdater != null)
 612                    {
 0613                        addressUpdater.UpdateUri(ref result);
 614                    }
 615
 0616                    return result.ToString();
 617                }
 618
 0619                return null;
 620            }
 621
 622            private async Task<bool> TryHandleMetadataRequestAsync(HttpContext requestContext, IQueryCollection queries)
 623            {
 25624                if (!GetWsdlEnabled)
 625                {
 0626                    return false;
 627                }
 628
 25629                requestContext.Items["CoreWCF.Description.ServiceMetadataExtension.HttpGetImpl._listenUri"] = _listenUri
 630
 25631                WriteFilter writeFilter = _parent.GetWriteFilter(requestContext.Request, _listenUri, false);
 632
 25633                string query = FindQuery(queries);
 634
 635                MetadataResult result;
 25636                if (string.IsNullOrEmpty(query))
 637                {
 638                    //if the documentation page is not available return the default wsdl if it exists
 4639                    if (!HelpPageEnabled && GetInitData().DefaultWsdl != null)
 640                    {
 641                        // use the default WSDL
 0642                        result = new ServiceDescriptionResult(GetInitData().DefaultWsdl, writeFilter);
 0643                        SetResponseStatusAndContentType(requestContext.Response, HttpStatusCode.OK, XmlContentType);
 0644                        GetInitData().FixImportAddresses();
 0645                        await result.WriteResponseAsync(requestContext.Response);
 0646                        return true;
 647                    }
 648
 4649                    return false;
 650                }
 651
 652                // try to look the document up in the query table
 21653                if (GetInitData().TryQueryLookup(query, out object doc))
 654                {
 2655                    if (doc is WsdlNS.ServiceDescription description)
 656                    {
 0657                        result = new ServiceDescriptionResult(description, writeFilter);
 658                    }
 2659                    else if (doc is XmlSchema schema)
 660                    {
 0661                        result = new XmlSchemaResult(schema, writeFilter);
 662                    }
 2663                    else if (doc is string @string)
 664                    {
 2665                        if (@string == DiscoToken)
 666                        {
 2667                            result = CreateDiscoMessage(writeFilter as DynamicAddressUpdateWriter);
 668                        }
 669                        else
 670                        {
 671                            Fx.Assert("Bad object in HttpGetImpl docFromQuery table");
 0672                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(stri
 673                        }
 674                    }
 675                    else
 676                    {
 677                        Fx.Assert("Bad object in HttpGetImpl docFromQuery table");
 0678                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.F
 679                    }
 680
 2681                    SetResponseStatusAndContentType(requestContext.Response, HttpStatusCode.OK, XmlContentType);
 2682                    GetInitData().FixImportAddresses();
 2683                    await result.WriteResponseAsync(requestContext.Response);
 2684                    return true;
 685                }
 686
 687                // otherwise see if they just wanted ?WSDL
 19688                if (string.Compare(query, WsdlQueryString, StringComparison.OrdinalIgnoreCase) == 0)
 689                {
 0690                    if (GetInitData().DefaultWsdl != null)
 691                    {
 692                        // use the default WSDL
 0693                        result = new ServiceDescriptionResult(GetInitData().DefaultWsdl, writeFilter);
 0694                        SetResponseStatusAndContentType(requestContext.Response, HttpStatusCode.OK, XmlContentType);
 0695                        GetInitData().FixImportAddresses();
 0696                        await result.WriteResponseAsync(requestContext.Response);
 0697                        return true;
 698                    }
 699
 700                    // or redirect to an external WSDL
 0701                    string wsdlReference = FindWsdlReference(writeFilter as DynamicAddressUpdateWriter);
 0702                    if (wsdlReference != null)
 703                    {
 0704                        RespondWithRedirect(requestContext.Response, wsdlReference);
 0705                        return true;
 706                    }
 707                }
 708
 709                // ?singleWSDL
 19710                if (string.Compare(query, SingleWsdlQueryString, StringComparison.OrdinalIgnoreCase) == 0)
 711                {
 19712                    WsdlNS.ServiceDescription singleWSDL = _parent.SingleWsdl;
 19713                    if (singleWSDL != null)
 714                    {
 19715                        result = new ServiceDescriptionResult(singleWSDL, writeFilter);
 19716                        SetResponseStatusAndContentType(requestContext.Response, HttpStatusCode.OK, XmlContentType);
 19717                        await result.WriteResponseAsync(requestContext.Response);
 19718                        return true;
 719                    }
 720                }
 721
 722                // we weren't able to handle the request -- return the documentation page if available
 0723                return false;
 25724            }
 725
 726            private MetadataResult CreateDiscoMessage(DynamicAddressUpdateWriter addressUpdater)
 727            {
 2728                Uri wsdlUrlBase = _listenUri;
 2729                if (addressUpdater != null)
 730                {
 0731                    addressUpdater.UpdateUri(ref wsdlUrlBase);
 732                }
 733
 2734                string wsdlUrl = wsdlUrlBase.ToString() + "?" + WsdlQueryString;
 735
 2736                Uri docUrl = null;
 2737                if (_listenUri.Scheme == Uri.UriSchemeHttp)
 738                {
 1739                    if (_parent.HttpHelpPageEnabled)
 740                    {
 1741                        docUrl = _parent.HttpHelpPageUrl;
 742                    }
 0743                    else if (_parent.HttpsHelpPageEnabled)
 744                    {
 0745                        docUrl = _parent.HttpsGetUrl;
 746                    }
 747                }
 748                else
 749                {
 1750                    if (_parent.HttpsHelpPageEnabled)
 751                    {
 1752                        docUrl = _parent.HttpsHelpPageUrl;
 753                    }
 0754                    else if (_parent.HttpHelpPageEnabled)
 755                    {
 0756                        docUrl = _parent.HttpGetUrl;
 757                    }
 758                }
 2759                if (addressUpdater != null)
 760                {
 0761                    addressUpdater.UpdateUri(ref docUrl);
 762                }
 763
 2764                return new DiscoResult(wsdlUrl, docUrl.ToString());
 765            }
 766
 767            private string FindQuery(IQueryCollection queries)
 768            {
 769                string CombineKeyAndValues(string key, string values)
 770                {
 0771                    return string.IsNullOrWhiteSpace(values)
 0772                        ? key
 0773                        : $"{key}={values}";
 774                }
 775
 25776                if (queries.TryGetValue(WsdlQueryString, out var values))
 777                {
 0778                    return CombineKeyAndValues(WsdlQueryString, values);
 779                }
 780
 25781                if (queries.TryGetValue(XsdQueryString, out values))
 782                {
 0783                    return CombineKeyAndValues(XsdQueryString, values);
 784                }
 785
 25786                if (queries.TryGetValue(SingleWsdlQueryString, out _))
 787                {
 19788                    return SingleWsdlQueryString;
 789                }
 790
 6791                if (_parent.HelpPageEnabled && queries.ContainsKey(DiscoQueryString))
 792                {
 2793                    return DiscoQueryString;
 794                }
 795
 4796                return null;
 797            }
 798
 799            private async Task<bool> ProcessHttpRequest(HttpContext requestContext)
 800            {
 25801                if (!"GET".Equals(requestContext.Request.Method, StringComparison.OrdinalIgnoreCase))
 802                {
 0803                    return false;
 804                }
 805
 25806                string queryString = requestContext.Request.QueryString.Value;
 807
 25808                if (queryString.Length > MaxQueryStringChars)
 809                {
 0810                    SetHttpResponseStatus(requestContext.Response, HttpStatusCode.RequestUriTooLong);
 0811                    return true;
 812                }
 813
 25814                var queries = requestContext.Request.Query;
 25815                if (await TryHandleMetadataRequestAsync(requestContext, queries))
 816                {
 21817                    return true;
 818                }
 819
 4820                if (await TryHandleDocumentationRequestAsync(requestContext))
 821                {
 4822                    return true;
 823                }
 824
 0825                return false;
 25826            }
 827
 828            private class InitializationData
 829            {
 830                private readonly Dictionary<string, object> _docFromQuery;
 831                private readonly Dictionary<object, string> _queryFromDoc;
 832                private readonly WsdlNS.ServiceDescriptionCollection _wsdls;
 833                private readonly XmlSchemaSet _xsds;
 834
 835                public string ServiceName;
 836                public string ClientName;
 837                public WsdlNS.ServiceDescription DefaultWsdl;
 838
 25839                private InitializationData(
 25840                    Dictionary<string, object> docFromQuery,
 25841                    Dictionary<object, string> queryFromDoc,
 25842                    WsdlNS.ServiceDescriptionCollection wsdls,
 25843                    XmlSchemaSet xsds)
 844                {
 25845                    _docFromQuery = docFromQuery;
 25846                    _queryFromDoc = queryFromDoc;
 25847                    _wsdls = wsdls;
 25848                    _xsds = xsds;
 25849                }
 850
 851                public bool TryQueryLookup(string query, out object doc)
 852                {
 21853                    return _docFromQuery.TryGetValue(query, out doc);
 854                }
 855
 856                public static InitializationData InitializeFrom(ServiceMetadataExtension extension)
 857                {
 25858                    Dictionary<string, object> docFromQueryInit = new Dictionary<string, object>(StringComparer.OrdinalI
 25859                    Dictionary<object, string> queryFromDocInit = new Dictionary<object, string>();
 860
 861                    // this collection type provides useful lookup features
 25862                    WsdlNS.ServiceDescriptionCollection wsdls = CollectWsdls(extension.Metadata);
 25863                    XmlSchemaSet xsds = CollectXsds(extension.Metadata);
 864
 25865                    WsdlNS.ServiceDescription defaultWsdl = null;
 25866                    WsdlNS.Service someService = GetAnyService(wsdls);
 25867                    if (someService != null)
 868                    {
 25869                        defaultWsdl = someService.ServiceDescription;
 870                    }
 871
 872                    // WSDLs
 873                    {
 25874                        int i = 0;
 100875                        foreach (WsdlNS.ServiceDescription wsdlDoc in wsdls)
 876                        {
 25877                            string query = WsdlQueryString;
 25878                            if (wsdlDoc != defaultWsdl) // don't count the WSDL at ?WSDL
 879                            {
 0880                                query += "=wsdl" + (i++).ToString(CultureInfo.InvariantCulture);
 881                            }
 882
 25883                            docFromQueryInit.Add(query, wsdlDoc);
 25884                            queryFromDocInit.Add(wsdlDoc, query);
 885                        }
 886                    }
 887
 888                    // XSDs
 889                    {
 25890                        int i = 0;
 198891                        foreach (XmlSchema xsdDoc in xsds.Schemas())
 892                        {
 74893                            string query = XsdQueryString + "=xsd" + (i++).ToString(CultureInfo.InvariantCulture);
 74894                            docFromQueryInit.Add(query, xsdDoc);
 74895                            queryFromDocInit.Add(xsdDoc, query);
 896                        }
 897                    }
 898
 899                    // Disco
 25900                    if (extension.HelpPageEnabled)
 901                    {
 25902                        string query = DiscoQueryString;
 25903                        docFromQueryInit.Add(query, DiscoToken);
 25904                        queryFromDocInit.Add(DiscoToken, query);
 905                    }
 906
 25907                    InitializationData data = new InitializationData(docFromQueryInit, queryFromDocInit, wsdls, xsds)
 25908                    {
 25909                        DefaultWsdl = defaultWsdl,
 25910                        ServiceName = GetAnyWsdlName(wsdls),
 25911                        ClientName = ClientClassGenerator.GetClientClassName(GetAnyContractName(wsdls) ?? "IHello")
 25912                    };
 913
 25914                    return data;
 915                }
 916
 917                private static WsdlNS.ServiceDescriptionCollection CollectWsdls(MetadataSet metadata)
 918                {
 25919                    WsdlNS.ServiceDescriptionCollection wsdls = new WsdlNS.ServiceDescriptionCollection();
 248920                    foreach (MetadataSection section in metadata.MetadataSections)
 921                    {
 99922                        if (section.Metadata is WsdlNS.ServiceDescription description)
 923                        {
 25924                            wsdls.Add(description);
 925                        }
 926                    }
 927
 25928                    return wsdls;
 929                }
 930
 931                private static XmlSchemaSet CollectXsds(MetadataSet metadata)
 932                {
 25933                    XmlSchemaSet xsds = new XmlSchemaSet
 25934                    {
 25935                        XmlResolver = null
 25936                    };
 248937                    foreach (MetadataSection section in metadata.MetadataSections)
 938                    {
 99939                        if (section.Metadata is XmlSchema schema)
 940                        {
 74941                            xsds.Add(schema);
 942                        }
 943                    }
 944
 25945                    return xsds;
 946                }
 947
 948                internal void FixImportAddresses()
 949                {
 950                    // fixup imports and includes with addresses
 951                    // WSDLs
 8952                    foreach (WsdlNS.ServiceDescription wsdlDoc in _wsdls)
 953                    {
 2954                        FixImportAddresses(wsdlDoc);
 955                    }
 956                    // XSDs
 16957                    foreach (XmlSchema xsdDoc in _xsds.Schemas())
 958                    {
 6959                        FixImportAddresses(xsdDoc);
 960                    }
 2961                }
 962
 963                private void FixImportAddresses(WsdlNS.ServiceDescription wsdlDoc)
 964                {
 4965                    foreach (WsdlNS.Import import in wsdlDoc.Imports)
 966                    {
 0967                        if (!string.IsNullOrEmpty(import.Location))
 968                        {
 969                            continue;
 970                        }
 971
 0972                        WsdlNS.ServiceDescription targetDoc = _wsdls[import.Namespace ?? string.Empty];
 0973                        if (targetDoc != null)
 974                        {
 0975                            string query = _queryFromDoc[targetDoc];
 0976                            import.Location = BaseAddressPattern + "?" + query;
 977                        }
 978                    }
 979
 2980                    if (wsdlDoc.Types != null)
 981                    {
 8982                        foreach (XmlSchema xsdDoc in wsdlDoc.Types.Schemas)
 983                        {
 2984                            FixImportAddresses(xsdDoc);
 985                        }
 986                    }
 2987                }
 988
 989                private void FixImportAddresses(XmlSchema xsdDoc)
 990                {
 32991                    foreach (XmlSchemaObject o in xsdDoc.Includes)
 992                    {
 8993                        if (!(o is XmlSchemaExternal external) || !string.IsNullOrEmpty(external.SchemaLocation))
 994                        {
 995                            continue;
 996                        }
 997
 8998                        string targetNs = external is XmlSchemaImport import ? import.Namespace : xsdDoc.TargetNamespace
 999
 241000                        foreach (XmlSchema targetXsd in _xsds.Schemas(targetNs ?? string.Empty))
 1001                        {
 81002                            if (targetXsd != xsdDoc)
 1003                            {
 81004                                string query = _queryFromDoc[targetXsd];
 81005                                external.SchemaLocation = BaseAddressPattern + "?" + query;
 81006                                break;
 1007                            }
 1008                        }
 1009                    }
 81010                }
 1011
 1012                private static string GetAnyContractName(WsdlNS.ServiceDescriptionCollection wsdls)
 1013                {
 1014                    // try to track down a WSDL portType name using a wsdl:service as a starting point
 751015                    foreach (WsdlNS.ServiceDescription wsdl in wsdls)
 1016                    {
 751017                        foreach (WsdlNS.Service service in wsdl.Services)
 1018                        {
 751019                            foreach (WsdlNS.Port port in service.Ports)
 1020                            {
 251021                                if (!port.Binding.IsEmpty)
 1022                                {
 251023                                    WsdlNS.Binding binding = wsdls.GetBinding(port.Binding);
 251024                                    if (!binding.Type.IsEmpty)
 1025                                    {
 251026                                        return binding.Type.Name;
 1027                                    }
 1028                                }
 1029                            }
 1030                        }
 1031                    }
 1032
 01033                    return null;
 251034                }
 1035
 1036                private static WsdlNS.Service GetAnyService(WsdlNS.ServiceDescriptionCollection wsdls)
 1037                {
 1038                    // try to track down a WSDL service
 751039                    foreach (WsdlNS.ServiceDescription wsdl in wsdls)
 1040                    {
 251041                        if (wsdl.Services.Count > 0)
 1042                        {
 251043                            return wsdl.Services[0];
 1044                        }
 1045                    }
 1046
 01047                    return null;
 251048                }
 1049
 1050                private static string GetAnyWsdlName(WsdlNS.ServiceDescriptionCollection wsdls)
 1051                {
 1052                    // try to track down a WSDL name
 751053                    foreach (WsdlNS.ServiceDescription wsdl in wsdls)
 1054                    {
 251055                        if (!string.IsNullOrEmpty(wsdl.Name))
 1056                        {
 251057                            return wsdl.Name;
 1058                        }
 1059                    }
 1060
 01061                    return null;
 251062                }
 1063            }
 1064
 1065            internal RequestDelegate MetadataMiddleware(RequestDelegate _next)
 1066            {
 341067                string path = _listenUri.AbsolutePath;
 341068                return async context =>
 341069                {
 311070                    if (context.Request.Path != path ||
 311071                        !await HandleRequest(context))
 341072                    {
 61073                        await _next(context);
 341074                    }
 651075                };
 1076            }
 1077
 1078            internal async Task<bool> HandleRequest(HttpContext httpContext)
 1079            {
 1080                try
 1081                {
 251082                    if (httpContext.Request.IsHttps != _isHttps) // Prevent handling requests on HTTP url's for HTTPS re
 1083                    {
 01084                        return false;
 1085                    }
 1086
 251087                    return await ProcessHttpRequest(httpContext);
 1088                }
 1089                catch (Exception exception)
 1090                {
 01091                    var result = new MetadataOnHelpPageResult(SR.SFxDocExt_Error, new ExceptionDetail(exception));
 01092                    SetResponseStatusAndContentType(httpContext.Response, HttpStatusCode.InternalServerError, HtmlConten
 01093                    await result.WriteResponseAsync(httpContext.Response);
 01094                    return true;
 1095                }
 251096            }
 1097
 1098            #region static helpers
 1099            private static void SetResponseStatusAndContentType(HttpResponse httpResponse, HttpStatusCode status, string
 1100            {
 251101                httpResponse.StatusCode = (int)status;
 251102                httpResponse.ContentType = contentType;
 251103            }
 1104
 1105            private static void RespondWithRedirect(HttpResponse httpResponse, string redirectedDestination)
 1106            {
 01107                httpResponse.StatusCode = (int)HttpStatusCode.RedirectKeepVerb;
 01108                httpResponse.Headers["Location"] = redirectedDestination;
 01109            }
 1110
 1111            private static void SetHttpResponseStatus(HttpResponse response, HttpStatusCode code)
 1112            {
 01113                response.StatusCode = (int)code;
 01114            }
 1115
 1116            internal static Uri GetUri(Uri baseUri, Uri relativeUri)
 1117            {
 01118                return GetUri(baseUri, relativeUri.OriginalString);
 1119            }
 1120
 1121            internal static Uri GetUri(Uri baseUri, string path)
 1122            {
 01123                if (path.StartsWith("/", StringComparison.Ordinal) || path.StartsWith("\\", StringComparison.Ordinal))
 1124                {
 01125                    int i = 1;
 01126                    for (; i < path.Length; ++i)
 1127                    {
 01128                        if (path[i] != '/' && path[i] != '\\')
 1129                        {
 1130                            break;
 1131                        }
 1132                    }
 1133
 01134                    path = path.Substring(i);
 1135                }
 1136
 01137                if (path.Length == 0)
 1138                {
 01139                    return baseUri;
 1140                }
 1141
 01142                if (!baseUri.AbsoluteUri.EndsWith("/", StringComparison.Ordinal))
 1143                {
 01144                    baseUri = new Uri(baseUri.AbsoluteUri + "/");
 1145                }
 1146
 01147                return new Uri(baseUri, path);
 1148            }
 1149
 1150            #endregion static helpers
 1151
 1152            #region Helper Message implementations
 1153            private class DiscoResult : MetadataResult
 1154            {
 1155                private readonly string _wsdlAddress;
 1156                private readonly string _docAddress;
 1157
 21158                public DiscoResult(string wsdlAddress, string docAddress)
 1159                {
 21160                    _wsdlAddress = wsdlAddress;
 21161                    _docAddress = docAddress;
 21162                }
 1163
 1164                protected override void Write(XmlWriter writer)
 1165                {
 21166                    writer.WriteStartDocument();
 21167                    writer.WriteStartElement("discovery", "http://schemas.xmlsoap.org/disco/");
 21168                    writer.WriteStartElement("contractRef", "http://schemas.xmlsoap.org/disco/scl/");
 21169                    writer.WriteAttributeString("ref", _wsdlAddress);
 21170                    writer.WriteAttributeString("docRef", _docAddress);
 21171                    writer.WriteEndElement(); // </contractRef>
 21172                    writer.WriteEndElement(); // </discovery>
 21173                    writer.WriteEndDocument();
 21174                }
 1175            }
 1176
 1177            private class MetadataOnHelpPageResult : MetadataResult
 1178            {
 1179                private readonly string _discoUrl;
 1180                private readonly string _metadataUrl;
 1181                private readonly string _singleWsdlUrl;
 1182                private readonly string _serviceName;
 1183                private readonly string _clientName;
 1184                private readonly bool _linkMetadata;
 1185                private readonly string _errorMessage;
 1186                private readonly ExceptionDetail _exceptionDetail;
 1187
 1188                public MetadataOnHelpPageResult(string discoUrl, string metadataUrl, string singleWsdlUrl, string servic
 41189                    : base()
 1190                {
 41191                    _discoUrl = discoUrl;
 41192                    _metadataUrl = metadataUrl;
 41193                    _singleWsdlUrl = singleWsdlUrl;
 41194                    _serviceName = serviceName;
 41195                    _clientName = clientName;
 41196                    _linkMetadata = linkMetadata;
 41197                }
 1198
 1199                public MetadataOnHelpPageResult(string errorMessage, ExceptionDetail exceptionDetail)
 01200                    : base()
 1201                {
 01202                    _errorMessage = errorMessage;
 01203                    _exceptionDetail = exceptionDetail;
 01204                }
 1205
 1206                protected override void Write(XmlWriter writer)
 1207                {
 41208                    HelpPageWriter page = new HelpPageWriter(writer);
 1209
 41210                    writer.WriteStartElement("HTML");
 41211                    writer.WriteAttributeString("lang", "en"); // We don't have localized strings so no need to look up 
 41212                    writer.WriteStartElement("HEAD");
 1213
 41214                    if (!string.IsNullOrEmpty(_discoUrl))
 1215                    {
 41216                        page.WriteDiscoLink(_discoUrl);
 1217                    }
 1218
 41219                    page.WriteStyleSheet();
 1220
 41221                    page.WriteTitle(!string.IsNullOrEmpty(_serviceName) ? SR.Format(SR.SFxDocExt_MainPageTitle, _service
 1222
 41223                    if (!string.IsNullOrEmpty(_errorMessage))
 1224                    {
 01225                        page.WriteError(_errorMessage);
 1226
 01227                        if (_exceptionDetail != null)
 1228                        {
 01229                            page.WriteExceptionDetail(_exceptionDetail);
 1230                        }
 1231                    }
 1232                    else
 1233                    {
 41234                        page.WriteToolUsage(_metadataUrl, _singleWsdlUrl, _linkMetadata);
 41235                        page.WriteSampleCode(_clientName);
 1236                    }
 1237
 41238                    writer.WriteEndElement(); // BODY
 41239                    writer.WriteEndElement(); // HTML
 41240                }
 1241
 1242                private struct HelpPageWriter
 1243                {
 1244                    private readonly XmlWriter _writer;
 1245                    public HelpPageWriter(XmlWriter writer)
 1246                    {
 41247                        _writer = writer;
 41248                    }
 1249
 1250                    internal void WriteClass(string className)
 1251                    {
 241252                        _writer.WriteStartElement("font");
 241253                        _writer.WriteAttributeString("color", "black");
 241254                        _writer.WriteString(className);
 241255                        _writer.WriteEndElement(); // font
 241256                    }
 1257
 1258                    internal void WriteComment(string comment)
 1259                    {
 161260                        _writer.WriteStartElement("font");
 161261                        _writer.WriteAttributeString("color", "darkgreen");
 161262                        _writer.WriteString(comment);
 161263                        _writer.WriteEndElement(); // font
 161264                    }
 1265
 1266                    internal void WriteDiscoLink(string discoUrl)
 1267                    {
 41268                        _writer.WriteStartElement("link");
 41269                        _writer.WriteAttributeString("rel", "alternate");
 41270                        _writer.WriteAttributeString("type", "text/xml");
 41271                        _writer.WriteAttributeString("href", discoUrl);
 41272                        _writer.WriteEndElement(); // link
 41273                    }
 1274
 1275                    internal void WriteError(string message)
 1276                    {
 01277                        _writer.WriteStartElement("P");
 01278                        _writer.WriteAttributeString("class", "intro");
 01279                        _writer.WriteString(message);
 01280                        _writer.WriteEndElement(); // P
 1281
 01282                    }
 1283
 1284                    internal void WriteKeyword(string keyword)
 1285                    {
 361286                        _writer.WriteStartElement("font");
 361287                        _writer.WriteAttributeString("color", "blue");
 361288                        _writer.WriteString(keyword);
 361289                        _writer.WriteEndElement(); // font
 361290                    }
 1291
 1292                    internal void WriteSampleCode(string clientName)
 1293                    {
 41294                        _writer.WriteStartElement("P");
 41295                        _writer.WriteAttributeString("class", "intro");
 41296                        _writer.WriteRaw(SR.SFxDocExt_MainPageIntro2);
 41297                        _writer.WriteEndElement(); // P
 1298
 1299                        // C#
 41300                        _writer.WriteRaw("<h2 class='intro'>C#</h2><br />");
 41301                        _writer.WriteStartElement("PRE");
 41302                        WriteKeyword("class ");
 41303                        WriteClass("Test\n");
 41304                        _writer.WriteString("{\n");
 41305                        WriteKeyword("    static void ");
 41306                        _writer.WriteString("Main()\n");
 41307                        _writer.WriteString("    {\n");
 41308                        _writer.WriteString("        ");
 41309                        WriteClass(clientName);
 41310                        _writer.WriteString(" client = ");
 41311                        WriteKeyword("new ");
 41312                        WriteClass(clientName);
 41313                        _writer.WriteString("();\n\n");
 41314                        WriteComment("        // " + SR.SFxDocExt_MainPageComment+ "\n\n");
 41315                        WriteComment("        // " + SR.SFxDocExt_MainPageComment2+ "\n");
 41316                        _writer.WriteString("        client.Close();\n");
 41317                        _writer.WriteString("    }\n");
 41318                        _writer.WriteString("}\n");
 41319                        _writer.WriteEndElement(); // PRE
 41320                        _writer.WriteRaw(HtmlBreak);
 1321
 1322
 1323                        // VB
 41324                        _writer.WriteRaw("<h2 class='intro'>Visual Basic</h2><br />");
 41325                        _writer.WriteStartElement("PRE");
 41326                        WriteKeyword("Class ");
 41327                        WriteClass("Test\n");
 41328                        WriteKeyword("    Shared Sub ");
 41329                        _writer.WriteString("Main()\n");
 41330                        WriteKeyword("        Dim ");
 41331                        _writer.WriteString("client As ");
 41332                        WriteClass(clientName);
 41333                        _writer.WriteString(" = ");
 41334                        WriteKeyword("New ");
 41335                        WriteClass(clientName);
 41336                        _writer.WriteString("()\n");
 41337                        WriteComment("        ' " + SR.SFxDocExt_MainPageComment+ "\n\n");
 41338                        WriteComment("        ' " + SR.SFxDocExt_MainPageComment2+ "\n");
 41339                        _writer.WriteString("        client.Close()\n");
 41340                        WriteKeyword("    End Sub\n");
 41341                        WriteKeyword("End Class");
 41342                        _writer.WriteEndElement(); // PRE
 41343                    }
 1344
 1345                    internal void WriteExceptionDetail(ExceptionDetail exceptionDetail)
 1346                    {
 01347                        _writer.WriteStartElement("PRE");
 01348                        _writer.WriteString(exceptionDetail.ToString().Replace("\r", ""));
 01349                        _writer.WriteEndElement(); // PRE
 01350                    }
 1351
 1352                    internal void WriteStyleSheet()
 1353                    {
 41354                        _writer.WriteStartElement("STYLE");
 41355                        _writer.WriteAttributeString("type", "text/css");
 41356                        _writer.WriteString("#content{ FONT-SIZE: 0.7em; PADDING-BOTTOM: 2em; MARGIN-LEFT: 30px}");
 41357                        _writer.WriteString("BODY{MARGIN-TOP: 0px; MARGIN-LEFT: 0px; COLOR: #000000; FONT-FAMILY: Verdan
 41358                        _writer.WriteString("P{MARGIN-TOP: 0px; MARGIN-BOTTOM: 12px; COLOR: #000000; FONT-FAMILY: Verdan
 41359                        _writer.WriteString("PRE{BORDER-RIGHT: #f0f0e0 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #f0f0e
 41360                        _writer.WriteString(".heading1{MARGIN-TOP: 0px; PADDING-LEFT: 15px; FONT-WEIGHT: normal; FONT-SI
 41361                        _writer.WriteString(".intro{display: block; font-size: 1em;}");
 41362                        _writer.WriteEndElement();
 41363                    }
 1364
 1365                    internal void WriteTitle(string title)
 1366                    {
 41367                        _writer.WriteElementString("TITLE", title);
 41368                        _writer.WriteEndElement();
 41369                        _writer.WriteStartElement("BODY");
 41370                        _writer.WriteStartElement("DIV");
 41371                        _writer.WriteAttributeString("id", "content");
 41372                        _writer.WriteAttributeString("role", "main");
 41373                        _writer.WriteStartElement("h1");
 41374                        _writer.WriteAttributeString("class", "heading1");
 41375                        _writer.WriteString(title);
 41376                        _writer.WriteEndElement();
 41377                        _writer.WriteRaw(HtmlBreak);
 1378
 41379                    }
 1380
 1381                    internal void WriteToolUsage(string wsdlUrl, string singleWsdlUrl, bool linkMetadata)
 1382                    {
 41383                        _writer.WriteStartElement("P");
 41384                        _writer.WriteAttributeString("class", "intro");
 1385
 41386                        if (wsdlUrl != null)
 1387                        {
 41388                            WriteMetadataAddress(SR.SFxDocExt_MainPageIntro1a, "svcutil.exe ", wsdlUrl, linkMetadata);
 41389                            if (singleWsdlUrl != null)
 1390                            {
 1391                                // ?singleWsdl message
 41392                                _writer.WriteStartElement("P");
 41393                                WriteMetadataAddress(SR.SFxDocExt_MainPageIntroSingleWsdl, null, singleWsdlUrl, linkMeta
 41394                                _writer.WriteEndElement();
 1395                            }
 1396                        }
 1397                        else
 1398                        {
 1399                            // no metadata message
 01400                            _writer.WriteRaw(SR.SFxDocExt_MainPageIntro1b);
 1401                        }
 41402                        _writer.WriteEndElement(); // P
 41403                    }
 1404
 1405                    private void WriteMetadataAddress(string introductionText, string clientToolName, string wsdlUrl, bo
 1406                    {
 81407                        _writer.WriteRaw(introductionText);
 81408                        _writer.WriteRaw(HtmlBreak);
 81409                        _writer.WriteStartElement("PRE");
 81410                        if (!string.IsNullOrEmpty(clientToolName))
 1411                        {
 41412                            _writer.WriteString(clientToolName);
 1413                        }
 1414
 81415                        if (linkMetadata)
 1416                        {
 81417                            _writer.WriteStartElement("A");
 81418                            _writer.WriteAttributeString("HREF", wsdlUrl);
 1419                        }
 1420
 81421                        _writer.WriteString(wsdlUrl);
 1422
 81423                        if (linkMetadata)
 1424                        {
 81425                            _writer.WriteEndElement(); // A
 1426                        }
 1427
 81428                        _writer.WriteEndElement(); // PRE
 81429                    }
 1430                }
 1431            }
 1432
 1433            private class MetadataOffHelpPageMessage : MetadataResult
 1434            {
 1435                protected override void Write(XmlWriter writer)
 1436                {
 01437                    writer.WriteStartElement("HTML");
 01438                    writer.WriteStartElement("HEAD");
 01439                    writer.WriteRaw(string.Format(CultureInfo.InvariantCulture,
 01440                        @"<STYLE type=""text/css"">#content{{ FONT-SIZE: 0.7em; PADDING-BOTTOM: 2em; MARGIN-LEFT: 30px}}
 01441<TITLE>Service</TITLE>"));
 01442                    writer.WriteEndElement(); //HEAD
 1443
 01444                    writer.WriteRaw(string.Format(CultureInfo.InvariantCulture,
 01445                                            @"<BODY>
 01446<DIV id=""content"">
 01447<P class=""heading1"">Service</P>
 01448<BR/>
 01449<P class=""intro"">{0}</P>
 01450<PRE>
 01451<font color=""blue"">&lt;<font color=""darkred"">" + ConfigurationStrings.BehaviorsSectionName + @"</font>&gt;</font>
 01452<font color=""blue"">    &lt;<font color=""darkred"">" + ConfigurationStrings.ServiceBehaviors + @"</font>&gt;</font>
 01453<font color=""blue"">        &lt;<font color=""darkred"">" + ConfigurationStrings.Behavior + @" </font><font color=""red
 01454<font color=""blue"">            &lt;<font color=""darkred"">" + ConfigurationStrings.ServiceMetadataPublishingSectionNa
 01455<font color=""blue"">        &lt;<font color=""darkred"">/" + ConfigurationStrings.Behavior + @"</font>&gt;</font>
 01456<font color=""blue"">    &lt;<font color=""darkred"">/" + ConfigurationStrings.ServiceBehaviors + @"</font>&gt;</font>
 01457<font color=""blue"">&lt;<font color=""darkred"">/" + ConfigurationStrings.BehaviorsSectionName + @"</font>&gt;</font>
 01458</PRE>
 01459<P class=""intro"">{1}</P>
 01460<PRE>
 01461<font color=""blue"">&lt;<font color=""darkred"">" + ConfigurationStrings.Service + @" </font><font color=""red"">" + Co
 01462</PRE>
 01463<P class=""intro"">{2}</P>
 01464<PRE>
 01465<font color=""blue"">&lt;<font color=""darkred"">" + ConfigurationStrings.Endpoint + @" </font><font color=""red"">" + C
 01466</PRE>
 01467
 01468<P class=""intro"">{3}</P>
 01469<PRE>
 01470<font color=""blue"">&lt;<font color=""darkred"">configuration</font>&gt;</font>
 01471<font color=""blue"">    &lt;<font color=""darkred"">" + ConfigurationStrings.SectionGroupName + @"</font>&gt;</font>
 01472
 01473<font color=""blue"">        &lt;<font color=""darkred"">" + ConfigurationStrings.ServicesSectionName + @"</font>&gt;</f
 01474<font color=""blue"">            &lt;!-- <font color=""green"">{4}</font> --&gt;</font>
 01475<font color=""blue"">            &lt;<font color=""darkred"">" + ConfigurationStrings.Service + @" </font><font color=""
 01476<font color=""blue"">                &lt;!-- <font color=""green"">{5}</font> --&gt;</font>
 01477<font color=""blue"">                &lt;!-- <font color=""green"">{6}</font> --&gt;</font>
 01478<font color=""blue"">                &lt;<font color=""darkred"">" + ConfigurationStrings.Endpoint + @" </font><font col
 01479<font color=""blue"">            &lt;<font color=""darkred"">/" + ConfigurationStrings.Service + @"</font>&gt;</font>
 01480<font color=""blue"">        &lt;<font color=""darkred"">/" + ConfigurationStrings.ServicesSectionName + @"</font>&gt;</
 01481
 01482<font color=""blue"">        &lt;<font color=""darkred"">" + ConfigurationStrings.BehaviorsSectionName + @"</font>&gt;</
 01483<font color=""blue"">            &lt;<font color=""darkred"">" + ConfigurationStrings.ServiceBehaviors + @"</font>&gt;</
 01484<font color=""blue"">                &lt;<font color=""darkred"">" + ConfigurationStrings.Behavior + @" </font><font col
 01485<font color=""blue"">                    &lt;!-- <font color=""green"">{7}</font> --&gt;</font>
 01486<font color=""blue"">                    &lt;<font color=""darkred"">" + ConfigurationStrings.ServiceMetadataPublishingS
 01487<font color=""blue"">                &lt;<font color=""darkred"">/" + ConfigurationStrings.Behavior + @"</font>&gt;</fon
 01488<font color=""blue"">            &lt;<font color=""darkred"">/" + ConfigurationStrings.ServiceBehaviors + @"</font>&gt;<
 01489<font color=""blue"">        &lt;<font color=""darkred"">/" + ConfigurationStrings.BehaviorsSectionName + @"</font>&gt;<
 01490
 01491<font color=""blue"">    &lt;<font color=""darkred"">/" + ConfigurationStrings.SectionGroupName + @"</font>&gt;</font>
 01492<font color=""blue"">&lt;<font color=""darkred"">/configuration</font>&gt;</font>
 01493</PRE>
 01494<P class=""intro"">{8}</P>
 01495</DIV>
 01496</BODY>",
 01497SR.SFxDocExt_NoMetadataSection1, SR.SFxDocExt_NoMetadataSection2,
 01498SR.SFxDocExt_NoMetadataSection3, SR.SFxDocExt_NoMetadataSection4,
 01499SR.SFxDocExt_NoMetadataConfigComment1, SR.SFxDocExt_NoMetadataConfigComment2,
 01500SR.SFxDocExt_NoMetadataConfigComment3, SR.SFxDocExt_NoMetadataConfigComment4,
 01501SR.SFxDocExt_NoMetadataSection5        ));
 1502
 01503                    writer.WriteEndElement(); //HTML
 01504                }
 1505            }
 1506
 1507            internal abstract class MetadataResult
 1508            {
 1509                public async Task WriteResponseAsync(HttpResponse response)
 1510                {
 1511                    // TODO : Remove use of MemoryStream and write more directly asynchronously
 251512                    using (var memoryStream = new MemoryStream())
 1513                    {
 251514                        var utf8NoBomEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidB
 251515                        using (var xmlTextWriter = XmlDictionaryWriter.CreateTextWriter(memoryStream, utf8NoBomEncoding,
 1516                        {
 251517                            Write(xmlTextWriter);
 251518                        }
 251519                        memoryStream.Position = 0;
 251520                        await memoryStream.CopyToAsync(response.Body);
 251521                    }
 251522                }
 1523
 1524                protected abstract void Write(XmlWriter writer);
 1525            }
 1526
 1527            // TODO: Cache the written response in memory and write async
 1528            // Need to accomodate different WriteFilter possibilities. If the first client sends request to http://inter
 1529            // and second client sends request to hhtp://public-hostname/service.svc?wsdl, we need to make sure the inte
 1530            // to an external client.
 1531            private abstract class MetadataFilteredResult : MetadataResult
 1532            {
 1533                private readonly WriteFilter _responseWriter;
 1534
 191535                protected MetadataFilteredResult(WriteFilter responseWriter)
 1536                {
 191537                    _responseWriter = responseWriter;
 191538                }
 1539
 1540                protected override void Write(XmlWriter xmlWriter)
 1541                {
 191542                    _responseWriter.Writer = xmlWriter;
 191543                    WriteCore(_responseWriter);
 191544                }
 1545
 1546                protected abstract void WriteCore(XmlWriter xmlWriter);
 1547            }
 1548
 1549            private class ServiceDescriptionResult : MetadataFilteredResult
 1550            {
 1551                private readonly WsdlNS.ServiceDescription _description;
 1552
 191553                public ServiceDescriptionResult(WsdlNS.ServiceDescription description, WriteFilter responseWriter) : bas
 1554                {
 191555                    _description = description;
 191556                }
 1557
 191558                protected override void WriteCore(XmlWriter writer) => _description.Write(writer);
 1559            }
 1560
 1561            private class XmlSchemaResult : MetadataFilteredResult
 1562            {
 1563                private readonly XmlSchema _schema;
 1564
 01565                public XmlSchemaResult(XmlSchema schema, WriteFilter responseWriter) : base(responseWriter)
 1566                {
 01567                    _schema = schema;
 01568                }
 1569
 01570                protected override void WriteCore(XmlWriter writer) => _schema.Write(writer);
 1571            }
 1572            #endregion //Helper Message implementations
 1573        }
 1574
 1575        internal abstract class WriteFilter : XmlDictionaryWriter
 1576        {
 253051577            internal XmlWriter Writer { get; set; }
 1578            public abstract WriteFilter CloneWriteFilter();
 01579            public override void Close() => Writer.Close();
 191580            public override void Flush() => Writer.Flush();
 19131581            public override string LookupPrefix(string ns) => Writer.LookupPrefix(ns);
 01582            public override void WriteBase64(byte[] buffer, int index, int count) => Writer.WriteBase64(buffer, index, c
 01583            public override void WriteCData(string text) => Writer.WriteCData(text);
 01584            public override void WriteCharEntity(char ch) => Writer.WriteCharEntity(ch);
 01585            public override void WriteChars(char[] buffer, int index, int count) => Writer.WriteChars(buffer, index, cou
 01586            public override void WriteComment(string text) => Writer.WriteComment(text);
 01587            public override void WriteDocType(string name, string pubid, string sysid, string subset) => Writer.WriteDoc
 51661588            public override void WriteEndAttribute() => Writer.WriteEndAttribute();
 01589            public override void WriteEndDocument() => Writer.WriteEndDocument();
 35011590            public override void WriteEndElement() => Writer.WriteEndElement();
 01591            public override void WriteEntityRef(string name) => Writer.WriteEntityRef(name);
 3991592            public override void WriteFullEndElement() => Writer.WriteFullEndElement();
 01593            public override void WriteProcessingInstruction(string name, string text) => Writer.WriteProcessingInstructi
 01594            public override void WriteRaw(string data) => Writer.WriteRaw(data);
 01595            public override void WriteRaw(char[] buffer, int index, int count) => Writer.WriteRaw(buffer, index, count);
 51661596            public override void WriteStartAttribute(string prefix, string localName, string ns) => Writer.WriteStartAtt
 01597            public override void WriteStartDocument(bool standalone) => Writer.WriteStartDocument(standalone);
 191598            public override void WriteStartDocument() => Writer.WriteStartDocument();
 39001599            public override void WriteStartElement(string prefix, string localName, string ns) => Writer.WriteStartEleme
 191600            public override WriteState WriteState => Writer.WriteState;
 51841601            public override void WriteString(string text) => Writer.WriteString(text);
 01602            public override void WriteSurrogateCharEntity(char lowChar, char highChar) => Writer.WriteSurrogateCharEntit
 01603            public override void WriteWhitespace(string ws) => Writer.WriteWhitespace(ws);
 1604        }
 1605
 1606        private class LocationUpdatingWriter : WriteFilter
 1607        {
 1608            private readonly string _oldValue;
 1609            private readonly string _newValue;
 1610
 1611            // passing null for newValue filters any string with oldValue as a prefix rather than replacing
 221612            internal LocationUpdatingWriter(string oldValue, string newValue)
 1613            {
 221614                _oldValue = oldValue;
 221615                _newValue = newValue;
 221616            }
 1617
 1618            public override WriteFilter CloneWriteFilter()
 1619            {
 01620                return new LocationUpdatingWriter(_oldValue, _newValue);
 1621            }
 1622
 1623            public override void WriteString(string text)
 1624            {
 44431625                if (_newValue != null)
 1626                {
 44431627                    text = text.Replace(_oldValue, _newValue);
 1628                }
 01629                else if (text.StartsWith(_oldValue, StringComparison.Ordinal))
 1630                {
 01631                    text = string.Empty;
 1632                }
 1633
 44431634                base.WriteString(text);
 44431635            }
 1636        }
 1637
 1638        private class CustomDynamicAddressUpdateWriter : DynamicAddressUpdateWriter
 1639        {
 1640            private readonly Uri _listenUri;
 1641            private readonly string _scheme;
 1642            private readonly string _host;
 1643            private readonly int _port;
 1644            private readonly string _newBaseAddress;
 1645
 11646            internal CustomDynamicAddressUpdateWriter(Uri listenUri, string scheme, string host, int port)
 1647            {
 11648                _listenUri = listenUri;
 11649                _scheme = scheme;
 11650                _host = host;
 11651                _port = port;
 11652                _newBaseAddress = UpdateUri(listenUri).ToString();
 11653            }
 1654
 01655            protected override string NewBaseAddress => _newBaseAddress;
 1656
 4941657            protected override bool RemoveBaseAddress => true;
 1658
 1659            public override WriteFilter CloneWriteFilter()
 1660            {
 01661                return new CustomDynamicAddressUpdateWriter(_listenUri, _scheme, _host, _port);
 1662            }
 1663
 1664            protected override Uri UpdateUri(Uri uri, bool updateBaseAddressOnly = false)
 1665            {
 1051666                if (uri.Host != _listenUri.Host)
 1667                {
 1031668                    return null;
 1669                }
 1670
 21671                UriBuilder result = new UriBuilder(uri)
 21672                {
 21673                    Host = _host,
 21674                    Port = _port,
 21675                    Scheme = _scheme
 21676                };
 21677                return result.Uri;
 1678            }
 1679        }
 1680
 1681        private abstract class DynamicAddressUpdateWriter : WriteFilter
 1682        {
 1683            protected abstract string NewBaseAddress { get; }
 1684            protected abstract bool RemoveBaseAddress { get; }
 1685
 1686            public void UpdateUri(ref Uri uri, bool updateBaseAddressOnly = false)
 1687            {
 01688                Uri newUri = UpdateUri(uri, updateBaseAddressOnly);
 01689                if (newUri != null)
 1690                {
 01691                    uri = newUri;
 1692                }
 01693            }
 1694
 1695            protected abstract Uri UpdateUri(Uri uri, bool updateBaseAddressOnly = false);
 1696
 1697            public override void WriteString(string text)
 1698            {
 7411699                if (RemoveBaseAddress &&
 7411700                    text.StartsWith(BaseAddressPattern, StringComparison.Ordinal))
 1701                {
 01702                    text = string.Empty;
 1703                }
 7411704                else if (!RemoveBaseAddress &&
 7411705                    text.Contains(BaseAddressPattern))
 1706                {
 01707                    text = text.Replace(BaseAddressPattern, NewBaseAddress);
 1708                }
 7411709                else if (Uri.TryCreate(text, UriKind.Absolute, out Uri uri))
 1710                {
 3121711                    Uri newUri = UpdateUri(uri);
 3121712                    if (newUri != null)
 1713                    {
 31714                        text = newUri.ToString();
 1715                    }
 1716                }
 7411717                base.WriteString(text);
 7411718            }
 1719        }
 1720
 1721        private class RequestHeadersDynamicAddressUpdateWriter : DynamicAddressUpdateWriter
 1722        {
 1723            private readonly string _oldHostName;
 1724            private readonly string _newHostName;
 1725            private readonly string _newBaseAddress;
 1726            private readonly bool _removeBaseAddress;
 1727            private readonly string _requestScheme;
 1728            private readonly int _requestPort;
 1729            private readonly IDictionary<string, int> _updatePortsByScheme;
 1730
 01731            protected override string NewBaseAddress => _newBaseAddress;
 9881732            protected override bool RemoveBaseAddress => _removeBaseAddress;
 1733
 1734            internal RequestHeadersDynamicAddressUpdateWriter(Uri listenUri, string requestHost, int requestPort,
 1735                IDictionary<string, int> updatePortsByScheme, bool removeBaseAddress)
 21736                : this(listenUri.Host, requestHost, removeBaseAddress, listenUri.Scheme, requestPort, updatePortsBySchem
 1737            {
 21738                _newBaseAddress = UpdateUri(listenUri).ToString();
 21739            }
 1740
 1741            private RequestHeadersDynamicAddressUpdateWriter(string oldHostName, string newHostName, string newBaseAddre
 1742                int requestPort, IDictionary<string, int> updatePortsByScheme)
 01743                : this(oldHostName, newHostName, removeBaseAddress, requestScheme, requestPort, updatePortsByScheme)
 1744            {
 01745                _newBaseAddress = newBaseAddress;
 01746            }
 1747
 21748            private RequestHeadersDynamicAddressUpdateWriter(string oldHostName, string newHostName, bool removeBaseAddr
 21749                int requestPort, IDictionary<string, int> updatePortsByScheme)
 1750            {
 21751                _oldHostName = oldHostName;
 21752                _newHostName = newHostName;
 21753                _removeBaseAddress = removeBaseAddress;
 21754                _requestScheme = requestScheme;
 21755                _requestPort = requestPort;
 21756                _updatePortsByScheme = updatePortsByScheme;
 21757            }
 1758
 1759            public override WriteFilter CloneWriteFilter()
 1760            {
 01761                return new RequestHeadersDynamicAddressUpdateWriter(_oldHostName, _newHostName, _newBaseAddress, _remove
 01762                    _requestScheme, _requestPort, _updatePortsByScheme);
 1763            }
 1764
 1765            protected override Uri UpdateUri(Uri uri, bool updateBaseAddressOnly = false)
 1766            {
 1767                // Ordinal comparison okay: we're filtering for auto-generated URIs which will
 1768                // always be based off the listenURI, so always match in case
 2101769                if (uri.Host != _oldHostName)
 1770                {
 2061771                    return null;
 1772                }
 1773
 41774                UriBuilder result = new UriBuilder(uri)
 41775                {
 41776                    Host = _newHostName
 41777                };
 1778
 41779                if (!updateBaseAddressOnly)
 1780                {
 1781                    int port;
 41782                    if (uri.Scheme == _requestScheme)
 1783                    {
 41784                        port = _requestPort;
 1785                    }
 01786                    else if (!_updatePortsByScheme.TryGetValue(uri.Scheme, out port))
 1787                    {
 01788                        return null;
 1789                    }
 41790                    result.Port = port;
 1791                }
 1792
 41793                return result.Uri;
 1794            }
 1795        }
 1796    }
 1797}

Methods/Properties

.cctor()
.ctor(CoreWCF.Description.ServiceMetadataBehavior/MetadataExtensionInitializer)
.ctor()
Initializer()
Metadata()
SingleWsdl()
ExternalMetadataLocation()
MexEnabled()
HttpGetEnabled()
HttpsGetEnabled()
HelpPageEnabled()
MetadataEnabled()
HttpHelpPageEnabled()
HttpsHelpPageEnabled()
MexUrl()
HttpGetUrl()
HttpsGetUrl()
HttpHelpPageUrl()
HttpsHelpPageUrl()
UpdateAddressDynamically()
UpdatePortsByScheme()
DynamicMetadataEndpointAddressProvider()
TryGetHttpHostAndPort(System.Uri,Microsoft.AspNetCore.Http.HttpRequest,System.String&,System.Int32&,System.String&)
CreateMiddleware(System.Uri,System.Boolean)
EnsureInitialized()
EnsureSingleWsdlInitialized()
CoreWCF.IExtension<CoreWCF.ServiceHostBase>.Attach(CoreWCF.ServiceHostBase)
CoreWCF.IExtension<CoreWCF.ServiceHostBase>.Detach(CoreWCF.ServiceHostBase)
EnsureServiceMetadataExtension(CoreWCF.ServiceHostBase)
GetWriteFilter(Microsoft.AspNetCore.Http.HttpRequest,System.Uri,System.Boolean)
GetWriteFilter(CoreWCF.Channels.Message,System.Uri,System.Boolean)
GetDynamicAddressWriter(Microsoft.AspNetCore.Http.HttpRequest,System.Uri,System.Boolean)
GetDynamicAddressWriter(CoreWCF.Channels.Message,System.Uri,System.Boolean)
.ctor(CoreWCF.Description.ServiceMetadataExtension,System.Boolean,System.Uri)
IsListeningOnHttps()
GetLocationToReturn()
GatherMetadata(System.String,System.String)
Get(CoreWCF.Channels.Message)
GetAsync(CoreWCF.Channels.Message)
.ctor(CoreWCF.Description.ServiceMetadataExtension,System.Uri,System.Boolean)
HelpPageEnabled()
GetWsdlEnabled()
GetInitData()
FindWsdlReference(CoreWCF.Description.ServiceMetadataExtension/DynamicAddressUpdateWriter)
TryHandleDocumentationRequestAsync()
GetHttpGetUrl(CoreWCF.Description.ServiceMetadataExtension/DynamicAddressUpdateWriter)
GetMexUrl(CoreWCF.Description.ServiceMetadataExtension/DynamicAddressUpdateWriter)
TryHandleMetadataRequestAsync()
CreateDiscoMessage(CoreWCF.Description.ServiceMetadataExtension/DynamicAddressUpdateWriter)
CombineKeyAndValues(System.String,System.String)
FindQuery(Microsoft.AspNetCore.Http.IQueryCollection)
ProcessHttpRequest()
.ctor(System.Collections.Generic.Dictionary`2<System.String,System.Object>,System.Collections.Generic.Dictionary`2<System.Object,System.String>,System.Web.Services.Description.ServiceDescriptionCollection,System.Xml.Schema.XmlSchemaSet)
TryQueryLookup(System.String,System.Object&)
InitializeFrom(CoreWCF.Description.ServiceMetadataExtension)
CollectWsdls(CoreWCF.Description.MetadataSet)
CollectXsds(CoreWCF.Description.MetadataSet)
FixImportAddresses()
FixImportAddresses(System.Web.Services.Description.ServiceDescription)
FixImportAddresses(System.Xml.Schema.XmlSchema)
GetAnyContractName(System.Web.Services.Description.ServiceDescriptionCollection)
GetAnyService(System.Web.Services.Description.ServiceDescriptionCollection)
GetAnyWsdlName(System.Web.Services.Description.ServiceDescriptionCollection)
MetadataMiddleware(Microsoft.AspNetCore.Http.RequestDelegate)
HandleRequest()
SetResponseStatusAndContentType(Microsoft.AspNetCore.Http.HttpResponse,System.Net.HttpStatusCode,System.String)
RespondWithRedirect(Microsoft.AspNetCore.Http.HttpResponse,System.String)
SetHttpResponseStatus(Microsoft.AspNetCore.Http.HttpResponse,System.Net.HttpStatusCode)
GetUri(System.Uri,System.Uri)
GetUri(System.Uri,System.String)
.ctor(System.String,System.String)
Write(System.Xml.XmlWriter)
.ctor(System.String,System.String,System.String,System.String,System.String,System.Boolean)
.ctor(System.String,CoreWCF.ExceptionDetail)
Write(System.Xml.XmlWriter)
.ctor(System.Xml.XmlWriter)
WriteClass(System.String)
WriteComment(System.String)
WriteDiscoLink(System.String)
WriteError(System.String)
WriteKeyword(System.String)
WriteSampleCode(System.String)
WriteExceptionDetail(CoreWCF.ExceptionDetail)
WriteStyleSheet()
WriteTitle(System.String)
WriteToolUsage(System.String,System.String,System.Boolean)
WriteMetadataAddress(System.String,System.String,System.String,System.Boolean)
Write(System.Xml.XmlWriter)
WriteResponseAsync()
.ctor(CoreWCF.Description.ServiceMetadataExtension/WriteFilter)
Write(System.Xml.XmlWriter)
.ctor(System.Web.Services.Description.ServiceDescription,CoreWCF.Description.ServiceMetadataExtension/WriteFilter)
WriteCore(System.Xml.XmlWriter)
.ctor(System.Xml.Schema.XmlSchema,CoreWCF.Description.ServiceMetadataExtension/WriteFilter)
WriteCore(System.Xml.XmlWriter)
Writer()
Close()
Flush()
LookupPrefix(System.String)
WriteBase64(System.Byte[],System.Int32,System.Int32)
WriteCData(System.String)
WriteCharEntity(System.Char)
WriteChars(System.Char[],System.Int32,System.Int32)
WriteComment(System.String)
WriteDocType(System.String,System.String,System.String,System.String)
WriteEndAttribute()
WriteEndDocument()
WriteEndElement()
WriteEntityRef(System.String)
WriteFullEndElement()
WriteProcessingInstruction(System.String,System.String)
WriteRaw(System.String)
WriteRaw(System.Char[],System.Int32,System.Int32)
WriteStartAttribute(System.String,System.String,System.String)
WriteStartDocument(System.Boolean)
WriteStartDocument()
WriteStartElement(System.String,System.String,System.String)
WriteState()
WriteString(System.String)
WriteSurrogateCharEntity(System.Char,System.Char)
WriteWhitespace(System.String)
.ctor(System.String,System.String)
CloneWriteFilter()
WriteString(System.String)
.ctor(System.Uri,System.String,System.String,System.Int32)
NewBaseAddress()
RemoveBaseAddress()
CloneWriteFilter()
UpdateUri(System.Uri,System.Boolean)
UpdateUri(System.Uri&,System.Boolean)
WriteString(System.String)
NewBaseAddress()
RemoveBaseAddress()
.ctor(System.Uri,System.String,System.Int32,System.Collections.Generic.IDictionary`2<System.String,System.Int32>,System.Boolean)
.ctor(System.String,System.String,System.String,System.Boolean,System.String,System.Int32,System.Collections.Generic.IDictionary`2<System.String,System.Int32>)
.ctor(System.String,System.String,System.Boolean,System.String,System.Int32,System.Collections.Generic.IDictionary`2<System.String,System.Int32>)
CloneWriteFilter()
UpdateUri(System.Uri,System.Boolean)