Search code examples
c#wcfrabbitmqmessage-queuecorewcf

CoreWCF - RabbitMQ: Contract requires TwoWay Binding


I am following the code in the Launch Announcement Blog for RabbitMQ support in CoreWCF and am not sure what to do with this exception:

System.InvalidOperationException
  HResult=0x80131509
  Message=Contract requires TwoWay (either request-reply or duplex), but Binding 'RabbitMqBinding' doesn't support it or isn't configured properly to support it.
  Source=System.ServiceModel.Primitives
  StackTrace:
   at System.ServiceModel.Channels.ServiceChannelFactory.BuildChannelFactory(ServiceEndpoint serviceEndpoint, Boolean useActiveAutoClose)
   at System.ServiceModel.ChannelFactory.OnOpening()
   at System.ServiceModel.Channels.CommunicationObject.<System-ServiceModel-IAsyncCommunicationObject-OpenAsync>d__88.MoveNext()
   at System.ServiceModel.Channels.CommunicationObject.<OpenAsyncInternal>d__87.MoveNext()
   at System.ServiceModel.ChannelFactory.EnsureOpened()
   at System.ServiceModel.ChannelFactory`1.CreateChannel(EndpointAddress address, Uri via)

I created my Service following the CoreWCF Reademe:

dotnet new --install CoreWCF.Templates 
dotnet new corewcf --name MyService

and this is my Contract:

    [ServiceContract]
    public interface IService
    {
        [OperationContract]
        string GetData(int value);

        [OperationContract]
        CompositeType GetDataUsingDataContract(CompositeType composite);
    }

    // Use a data contract as illustrated in the sample below to add composite types to service operations.
    [DataContract]
    public class CompositeType
    {
        bool boolValue = true;
        string stringValue = "Hello ";

        [DataMember]
        public bool BoolValue
        {
            get { return boolValue; }
            set { boolValue = value; }
        }

        [DataMember]
        public string StringValue
        {
            get { return stringValue; }
            set { stringValue = value; }
        }
    }

How do I change my Contract to support RabbitMQ Bindings?

I did try changing the contract so it had only void methods, and therefor doesn't need two-way communication, but I'm still getting the exception.


For additional context, this is the code that fails to create the Channel:

public static TContract CreateChannelOnRabbitMq<TContract>()
{
    var endpointAddress = new System.ServiceModel.EndpointAddress(Uri);
    var rabbitMqBinding = new CoreWCF.ServiceModel.Channels.RabbitMqBinding
    {
        SslOption = new SslOption
        {
            ServerName = Uri.Host,
            Enabled = true
        },
    };
    var factory = new ChannelFactory<TContract>(rabbitMqBinding, endpointAddress);
    
    factory.Credentials.UserName.UserName = Credentials.UserName;
    factory.Credentials.UserName.Password = Credentials.Password;

    var channel = factory.CreateChannel();
    
    (channel as System.ServiceModel.Channels.IChannel)?.Open();

    return channel;
}

Solution

  • Turns out, I needed to mark the Operation Contracts as oneway:

        System.ServiceModel.ServiceContract]
        [CoreWCF.ServiceContract]
        public interface IService
        {
            [System.ServiceModel.OperationContract(IsOneWay = true)]
            [CoreWCF.OperationContract(IsOneWay = true)]
            void SendData(int value);
        }
    

    Once marked up correctly I can send messages from the client and receive them on the server.