void AddMetadataEndpoint(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher, bool debugMode) { Uri baseAddress = endpoint.Address.Uri; if (baseAddress == null) { return; } ServiceHostBase host = endpointDispatcher.ChannelDispatcher.Host; UriBuilder builder = new UriBuilder(baseAddress); builder.Path += builder.Path.EndsWith("/", StringComparison.OrdinalIgnoreCase) ? (WebScriptClientGenerator.GetMetadataEndpointSuffix(debugMode)) : ("/" + WebScriptClientGenerator.GetMetadataEndpointSuffix(debugMode)); EndpointAddress metadataAddress = new EndpointAddress(builder.Uri); foreach (ServiceEndpoint serviceEndpoint in host.Description.Endpoints) { if (EndpointAddress.UriEquals(serviceEndpoint.Address.Uri, metadataAddress.Uri, true, false))// ignoreCase // includeHostNameInComparison { throw System.ServiceModel.DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException(SR2.GetString(SR2.JsonNoEndpointAtMetadataAddress, this.GetType().ToString(), serviceEndpoint.Address, serviceEndpoint.Name, host.Description.Name))); } } HttpTransportBindingElement transportBindingElement; HttpTransportBindingElement existingTransportBindingElement = endpoint.Binding.CreateBindingElements().Find <HttpTransportBindingElement>(); if (existingTransportBindingElement != null) { transportBindingElement = (HttpTransportBindingElement)existingTransportBindingElement.Clone(); } else { if (baseAddress.Scheme == "https") { transportBindingElement = new HttpsTransportBindingElement(); } else { transportBindingElement = new HttpTransportBindingElement(); } } transportBindingElement.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard; transportBindingElement.TransferMode = TransferMode.Buffered; transportBindingElement.MaxBufferSize = MaxMetadataEndpointBufferSize; transportBindingElement.MaxReceivedMessageSize = MaxMetadataEndpointBufferSize; Binding metadataBinding = new CustomBinding( new WebScriptMetadataMessageEncodingBindingElement(), transportBindingElement); BindingParameterCollection parameters = host.GetBindingParameters(endpoint); // build endpoint dispatcher ContractDescription metadataContract = ContractDescription.GetContract(typeof(ServiceMetadataExtension.IHttpGetMetadata)); OperationDescription metadataOperation = metadataContract.Operations[0]; EndpointDispatcher metadataEndpointDispatcher = new EndpointDispatcher(metadataAddress, metadataContract.Name, metadataContract.Namespace); DispatchOperation dispatchOperation = new DispatchOperation(metadataEndpointDispatcher.DispatchRuntime, metadataOperation.Name, metadataOperation.Messages[0].Action, metadataOperation.Messages[1].Action); dispatchOperation.Formatter = new WebScriptMetadataFormatter(); dispatchOperation.Invoker = new SyncMethodInvoker(metadataOperation.SyncMethod); metadataEndpointDispatcher.DispatchRuntime.Operations.Add(dispatchOperation); metadataEndpointDispatcher.DispatchRuntime.SingletonInstanceContext = new InstanceContext(host, new WebScriptClientGenerator(endpoint, debugMode, !String.IsNullOrEmpty(this.JavascriptCallbackParameterName))); metadataEndpointDispatcher.DispatchRuntime.InstanceContextProvider = new SingletonInstanceContextProvider(metadataEndpointDispatcher.DispatchRuntime); // build channel dispatcher IChannelListener <IReplyChannel> listener = null; if (metadataBinding.CanBuildChannelListener <IReplyChannel>(parameters)) { listener = metadataBinding.BuildChannelListener <IReplyChannel>(metadataAddress.Uri, parameters); } ChannelDispatcher metadataChannelDispatcher = new ChannelDispatcher(listener); metadataChannelDispatcher.MessageVersion = MessageVersion.None; metadataChannelDispatcher.Endpoints.Add(metadataEndpointDispatcher); host.ChannelDispatchers.Add(metadataChannelDispatcher); }
Type BuildChannelListener(StuffPerListenUriInfo stuff, ServiceHostBase serviceHost, Uri listenUri, ListenUriMode listenUriMode, out IChannelListener result) { Binding originalBinding = stuff.Endpoints[0].Binding; CustomBinding binding = new CustomBinding(originalBinding); BindingParameterCollection parameters = stuff.Parameters; Uri listenUriBaseAddress; string listenUriRelativeAddress; GetBaseAndRelativeAddresses(serviceHost, listenUri, binding.Scheme, out listenUriBaseAddress, out listenUriRelativeAddress); // I don't believe InternalDuplexBindingElement is needed, at least not initially. // It looks like it's used when a channel factory is used to supply the outgoing channel // for duplex. I think it binds an incoming listener to an outgoing channel to acheive duplex. //InternalDuplexBindingElement internalDuplex = null; //InternalDuplexBindingElement.AddDuplexListenerSupport(binding, ref internalDuplex); // All types are supported to start bool reply = true; bool replySession = true; bool input = true; bool inputSession = true; bool duplex = true; bool duplexSession = true; string sessionContractName = null; string datagramContractName = null; // each endpoint adds constraints for (int i = 0; i < stuff.Endpoints.Count; ++i) { ContractDescription contract = stuff.Endpoints[i].Contract; if (contract.SessionMode == SessionMode.Required) { sessionContractName = contract.Name; } if (contract.SessionMode == SessionMode.NotAllowed) { datagramContractName = contract.Name; } System.Collections.IList endpointTypes = GetSupportedChannelTypes(contract); if (!endpointTypes.Contains(typeof(IReplyChannel))) { reply = false; } if (!endpointTypes.Contains(typeof(IReplySessionChannel))) { replySession = false; } if (!endpointTypes.Contains(typeof(IInputChannel))) { input = false; } if (!endpointTypes.Contains(typeof(IInputSessionChannel))) { inputSession = false; } if (!endpointTypes.Contains(typeof(IDuplexChannel))) { duplex = false; } if (!endpointTypes.Contains(typeof(IDuplexSessionChannel))) { duplexSession = false; } } if ((sessionContractName != null) && (datagramContractName != null)) { string text = SR.Format(SR.SFxCannotRequireBothSessionAndDatagram3, datagramContractName, sessionContractName, binding.Name); Exception error = new InvalidOperationException(text); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(error); } List <Type> supportedChannelTypes = new List <Type>(); if (input) { supportedChannelTypes.Add(typeof(IInputChannel)); } if (inputSession) { supportedChannelTypes.Add(typeof(IInputSessionChannel)); } if (reply) { supportedChannelTypes.Add(typeof(IReplyChannel)); } if (replySession) { supportedChannelTypes.Add(typeof(IReplySessionChannel)); } if (duplex) { supportedChannelTypes.Add(typeof(IDuplexChannel)); } if (duplexSession) { supportedChannelTypes.Add(typeof(IDuplexSessionChannel)); } // now we know what channel types we can use to support the contracts at this ListenUri Type returnValue = MaybeCreateListener(true, supportedChannelTypes.ToArray(), binding, parameters, listenUriBaseAddress, listenUriRelativeAddress, listenUriMode, out result); if (result == null) { // we put a lot of work into creating a good error message, as this is a common case Dictionary <Type, byte> setOfChannelTypesSupportedByBinding = new Dictionary <Type, byte>(); if (binding.CanBuildChannelListener <IInputChannel>()) { setOfChannelTypesSupportedByBinding.Add(typeof(IInputChannel), 0); } if (binding.CanBuildChannelListener <IReplyChannel>()) { setOfChannelTypesSupportedByBinding.Add(typeof(IReplyChannel), 0); } if (binding.CanBuildChannelListener <IDuplexChannel>()) { setOfChannelTypesSupportedByBinding.Add(typeof(IDuplexChannel), 0); } if (binding.CanBuildChannelListener <IInputSessionChannel>()) { setOfChannelTypesSupportedByBinding.Add(typeof(IInputSessionChannel), 0); } if (binding.CanBuildChannelListener <IReplySessionChannel>()) { setOfChannelTypesSupportedByBinding.Add(typeof(IReplySessionChannel), 0); } if (binding.CanBuildChannelListener <IDuplexSessionChannel>()) { setOfChannelTypesSupportedByBinding.Add(typeof(IDuplexSessionChannel), 0); } throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ChannelRequirements.CantCreateListenerException( setOfChannelTypesSupportedByBinding.Keys, supportedChannelTypes, originalBinding.Name)); } return(returnValue); }