[C#.NET][WCF] 實作 雙向 MSMQ @self-host for NetMsmqBinding

  • 6684
  • 0
  • WCF
  • 2016-01-21

[C#.NET][WCF] 實作 雙向 MSMQ @self-host for NetMsmqBinding

MSMQ 基本上是屬於單相通訊,在合約裡面必須要定義 IsOneWay 且 不能返回資料,若要實現雙向通訊就得經過一些技巧處理

 

實作架構如下圖所示:

image

 

簡單來講 Service 和 Client 都有自己的 ServiceHost

Service 監聽自己的 MSMQ


internal class service
{
    public const String QueueName = @".\private$\Two-way/request";

    private static void Main(string[] args)
    {
        // Get MSMQ queue name from app settings in configuration
        // Create the transacted MSMQ queue if necessary.
        if (!MessageQueue.Exists(QueueName))
            MessageQueue.Create(QueueName, true);

        string hostName = Dns.GetHostName();
        var serviceBinding = new NetMsmqBinding()
        {
            Security = new NetMsmqSecurity() { Mode = NetMsmqSecurityMode.None },
        };

        ServiceHost serviceHost = null;
        try
        {
            // Create a ServiceHost for the OrderProcessorService type.
            serviceHost = new ServiceHost(typeof(RequestService));
            serviceHost.AddServiceEndpoint(typeof(IRequestService), serviceBinding, "net.msmq://" + hostName + "/private/Two-way/request");

            // Open the ServiceHost to create listeners and start listening for messages.
            serviceHost.Open();

            // The service can now be accessed.
            Console.WriteLine("The service is ready.");
            Console.WriteLine("Press <ENTER> to terminate service.");
            Console.WriteLine();
            Console.ReadLine();
        }
        finally
        {
            if (serviceHost != null)
            {
                serviceHost.Close();
            }
        }
    }
}

Client 監聽自己 MSMQ,並調用 Service 的 SendUser 方法


internal class client
{
    //public const String QueueName = @".\private$\serviceQueue";
    public const String QueueName = @".\private$\Two-way/response";

    private static void Main(string[] args)
    {
        // Get MSMQ queue name from app settings in configuration
        // Create the transacted MSMQ queue if necessary.
        if (!MessageQueue.Exists(QueueName))
            MessageQueue.Create(QueueName, true);

        string hostName = Dns.GetHostName();
        var serviceBinding = new NetMsmqBinding()
        {
            Security = new NetMsmqSecurity() { Mode = NetMsmqSecurityMode.None },
        };

        ServiceHost serviceHost = null;
        var responseName = "net.msmq://" + hostName + "/private/Two-way/response";

        try
        {
            serviceHost = new ServiceHost(typeof(ResponseService));
            serviceHost.AddServiceEndpoint(typeof(IResponseService), serviceBinding, responseName);
            // Open the ServiceHost to create listeners and start listening for messages.
            serviceHost.Open();

            ChannelFactory<IRequestService> proxy = new ChannelFactory<IRequestService>(
                new NetMsmqBinding()
                {
                    Security = new NetMsmqSecurity() { Mode = NetMsmqSecurityMode.None },
                },
                new EndpointAddress("net.msmq://" + hostName + "/private/Two-way/request"));

            proxy.Open();
            IRequestService channel = proxy.CreateChannel();

            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
            {
                channel.SendUser(new User() { Name = "yy", Age = 12, ID = Guid.NewGuid() }, responseName);
                proxy.Close();
                // Complete the transaction.
                scope.Complete();
            }

            Console.WriteLine();
            Console.WriteLine("Press <ENTER> to terminate client.");
            Console.ReadLine();
        }
        finally
        {
            if (serviceHost != null)
            {
                serviceHost.Close();
            }
        }
    }
}

 

當 Service 收到 Client 調用 SendUser 方法時,則再送資料給 Client 的 MSMQ


internal class RequestService : IRequestService
{
    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
    public void SendUser(User user, string returnAddress)
    {
        Console.WriteLine("接收用戶端訊息 : " + user);

        var serviceBinding = new NetMsmqBinding()
        {
            Security = new NetMsmqSecurity() { Mode = NetMsmqSecurityMode.None },
        };

        ChannelFactory<IResponseService> proxy = new ChannelFactory<IResponseService>(serviceBinding, returnAddress);
        proxy.Open();
        IResponseService channel = proxy.CreateChannel();
        using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
        {
            channel.SendUserResult(user.ID);
            scope.Complete();
        }
        proxy.Close();
    }
}

 

 

 

Note.本篇範例全部採用 hard code來處理 binding / endpoint,所以看起來程式碼很多,相對的也比較沒彈性,也就是說該範例只能在本機執行,無法使用兩台不同的電腦測試..

運行結果如下:

image

 


本文出自:http://www.dotblogs.com.tw/yc421206/archive/2013/10/24/125435.aspx
飯粒下載:https://dotblogsfile.blob.core.windows.net/user/yc421206/1310/2013102414642430.zip

 

 

 

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo