在 WCF 端点的相同 windows 服务器服务总线命名空间中有两个不同的主题

Having two different topics within same windows server service bus namespace in WCF endpoint

我定义了两个端点,指向两个不同的服务总线主题。使用相同的 transportClientEndpointBehavior 和相同的服务。

<endpointBehaviors>
            <behavior name="securityBehavior">

          <transportClientEndpointBehavior>
            <tokenProvider>
              <windowsAuthentication>
                <stsUris>
                  <stsUri value="https://on-permises:9355/Namespace" />
                </stsUris>
              </windowsAuthentication>
            </tokenProvider>
          </transportClientEndpointBehavior>
</endpointBehaviors>

<customBinding>
        <binding name="messagingBinding" >
          <textMessageEncoding messageVersion="None" writeEncoding="utf-8"  >
            <readerQuotas maxStringContentLength="2147483647"/>
          </textMessageEncoding>
          <netMessagingTransport/>
        </binding>
</customBinding>

<endpoint name="endpoint1"
           address="sb://on-permises/Namespace/topic1"
                   listenUri="sb://on-permises/Namespace/topic1/subscriptions/sub"
                   binding="customBinding"
                   bindingConfiguration="messagingBinding"
                   contract="WCFService.IService1"
                   behaviorConfiguration="securityBehavior" />

        <endpoint name="endpoint2"
           address="sb://on-permises/Namespace/topic2"
                   listenUri="sb://on-permises/Namespace/topic2/subscriptions/sub"
                   binding="customBinding"
                   bindingConfiguration="messagingBinding"
                   contract="WCFService.IService2"
                   behaviorConfiguration="securityBehavior" />

一旦我 运行 应用程序,我得到错误: System.ArgumentException:无法将值添加到集合中,因为集合中已包含相同类型的项目:'Microsoft.ServiceBus.TransportClientEndpointBehavior'。此集合仅支持每种类型的一个实例。 参数名称:item

我尝试定义两个不同的端点行为,但得到了同样的错误。 这里的任何帮助都会有所帮助。

找到解决方案,问题是服务主机试图在 WSDL/Metadata 中添加这两个服务端点。这是没有必要的。因此,在 ServiceMetadataContractBehavior (IContractBehavior) 的帮助下,停止公开 WSDL/Metadata .

任何更好的方法或更正请告诉我。

public class DisableContractMetadata : Attribute, IContractBehavior

    {

        public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)

        {

        }


        public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)

        {



        }


        public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)

        {

            /// Here ServiceMetadataContractBehavior type is derived from IContractBehavior

            /// MetadataGenerationDisabled property of ServiceMetadataContractBehavior type = flase disables disables exposing WSDL 

            contractDescription.ContractBehaviors.Add(new ServiceMetadataContractBehavior() { MetadataGenerationDisabled = true });

        }


        public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)

        {



        }

    }

请注意,上述答案不完整,因为它实际上并未实现 IContractBehavior

由于是托管多个服务造成的,您也可以在主机中进行:

ContractDescription contractDescription = ContractDescription.GetContract(typeof(MyService));
contractDescription.ContractBehaviors.Add(new ServiceMetadataContractBehavior() { MetadataGenerationDisabled = true });

或者,如果您在一个类型上有多个合同,请使用:

private static void DisableMetadataGeneration(Type serviceType)
{
    // prevent this error due to hosting multiple services:
    // System.ArgumentException: The value could not be added to the collection, as the collection already contains an item of the same type: 'Microsoft.ServiceBus.TransportClientEndpointBehavior'. This collection only supports one instance of each type.
    foreach (Type contractType in GetContracts(serviceType))
    {
        ContractDescription contractDescription = ContractDescription.GetContract(contractType, serviceType);
        contractDescription.ContractBehaviors.Add(new ServiceMetadataContractBehavior() { MetadataGenerationDisabled = true });
    }
}

private static Type[] GetContracts(Type serviceType)
{
    System.Diagnostics.Debug.Assert(serviceType.IsClass);

    Type[] interfaces = serviceType.GetInterfaces();

    List<Type> contracts = new List<Type>();

    foreach (Type type in interfaces)
    {
        if (type.GetCustomAttributes(typeof(ServiceContractAttribute), false).Any())
        {
            contracts.Add(type);
        }
    }

    return contracts.ToArray();
}