创建类库工程RequestResponse.Messages:
namespace RequestResponse.Messages { public class MyMessage { public string Text { get; set; } } }
创建类库工程RequestResponse.Server:
using System; using log4net; using log4net.Config; using Shuttle.Core.Host; using Shuttle.Core.Infrastructure; using Shuttle.Core.Infrastructure.Log4Net; using Shuttle.ESB.Core; using Shuttle.ESB.Modules.ActiveTimeRange; namespace RequestResponse.Server { public class ServiceBusHost : IHost, IDisposable { private static IServiceBus bus; public void Start() { Log.Assign(new Log4NetLog(LogManager.GetLogger(typeof(ServiceBusHost)))); bus = ServiceBus.Create().Start(); Console.WriteLine("#########server-end bus instance has started"); } public void Dispose() { bus.Dispose(); LogManager.Shutdown(); } } }
using System; using System.Text; using RequestResponse.Messages; using Shuttle.Core.Infrastructure; using Shuttle.ESB.Core; namespace RequestResponse.Server { public class ServerMessageHandler : IMessageHandler<MyMessage> { private int received; public void ProcessMessage(HandlerContext<MyMessage> context) { //服务器端接受到消息 Console.WriteLine("【SERVER-END RECEIVE A MSG,Content:"+ context.Message.Text+ "】"); //服务器端发送回应消息 context.Bus.SendReply(new MyMessage { Text = "I have recwived your msg" }); } public bool IsReusable { get { return true; } } } }
<?xml version="1.0"?> <configuration> <configSections> <section name="serviceBus" type="Shuttle.ESB.Core.ServiceBusSection, Shuttle.ESB.Core"/> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/> </configSections> <serviceBus> <control workQueueUri="msmq://./requestresponse-server-control-inbox-work" errorQueueUri="msmq://./shuttle-samples-error" durationToSleepWhenIdle="250ms*25,500ms*10,1s" threadCount="1"/> <inbox workQueueUri="msmq://./requestresponse-server-inbox-work" errorQueueUri="msmq://./shuttle-samples-error" durationToSleepWhenIdle="250ms,1s" durationToIgnoreOnFailure="1s" threadCount="1"/> </serviceBus> <log4net> <appender name="ConsoleAppender" type="log4net.Appender.ColoredConsoleAppender"> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%d [%t] %-5p %c - %m%n"/> </layout> </appender> <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"> <file value="logs\request-response-server"/> <appendToFile value="true"/> <rollingStyle value="Date"/> <maxSizeRollBackups value="10"/> <maximumFileSize value="100000KB"/> <datePattern value="-yyyyMMdd.'log'"/> <param name="StaticLogFileName" value="false"/> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%d [%t] %-5p %c - %m%n"/> </layout> </appender> <root> <level value="TRACE"/> <appender-ref ref="ConsoleAppender"/> <appender-ref ref="RollingFileAppender"/> </root> </log4net> <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
创建控制台应用程序RequestResponse.Client:
using System; using log4net; using RequestResponse.Messages; using Shuttle.Core.Infrastructure; using Shuttle.Core.Infrastructure.Log4Net; using Shuttle.ESB.Core; namespace RequestResponse.Client { internal class Program { private static void Main() { Log.Assign(new Log4NetLog(LogManager.GetLogger(typeof(Program)))); var bus = ServiceBus.Create().Start(); Console.WriteLine("###### Client bus started. Press CTRL+C to stop."); Console.WriteLine(); Console.WriteLine("@Press enter to send a message to the server."); Console.WriteLine(); while (true) { Console.ReadLine(); //将消息发送出去 bus.Send(new MyMessage{Text = "Client Massage"}); } } } }
using System; using RequestResponse.Messages; using Shuttle.Core.Infrastructure; using Shuttle.ESB.Core; namespace RequestResponse.Client { public class ClientMessageHandler : IMessageHandler<MyMessage> { public void ProcessMessage(HandlerContext<MyMessage> context) { //客户端接收到消息 Console.WriteLine("【Client-END RECEIVE A MSG, Content:"+ context.Message.Text +"】"); } public bool IsReusable { get { return true; } } } }
<?xml version="1.0"?> <configuration> <configSections> <section name="serviceBus" type="Shuttle.ESB.Core.ServiceBusSection, Shuttle.ESB.Core"/> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/> </configSections> <serviceBus> <messageRoutes> <messageRoute uri="msmq://./requestresponse-server-inbox-work"> <add specification="StartsWith" value="RequestResponse"/> </messageRoute> </messageRoutes> <inbox workQueueUri="msmq://./requestresponse-client-inbox-work" journalQueueUri="msmq://./requestresponse-client-inbox-journal" errorQueueUri="msmq://./shuttle-samples-error"/> <outbox workQueueUri="msmq://./requestresponse-client-outbox-work" errorQueueUri="msmq://./shuttle-samples-error"/> </serviceBus> <log4net> <appender name="ConsoleAppender" type="log4net.Appender.ColoredConsoleAppender"> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%d [%t] %-5p %c - %m%n"/> </layout> </appender> <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"> <file value="logs\request-response-server"/> <appendToFile value="true"/> <rollingStyle value="Date"/> <maxSizeRollBackups value="10"/> <maximumFileSize value="100000KB"/> <datePattern value="-yyyyMMdd.'log'"/> <param name="StaticLogFileName" value="false"/> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%d [%t] %-5p %c - %m%n"/> </layout> </appender> <root> <level value="TRACE"/> <appender-ref ref="ConsoleAppender"/> <appender-ref ref="RollingFileAppender"/> </root> </log4net> <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
一切就绪。
然后设置解决方案的启动顺序,将server放在client前面。
然后右击项目RequestResponse.Server,生成,再右击其属性,在启动外部程序中选择host.exe
然后便可以运行这个解决方案了。
三个问题:
1 内部运行原理?
2 适用场景?
If there is one thing that a service bus should never be used for it is querying. A service bus is geared towards instructing systems what to do (command message); notifying systems of events that have taken place using a publish / subscribe mechanism (event message); and, less frequently, transferring data (document message).
It is perfectly valid to send a command to a system to perform some calculation. The result could then be stored a result store and a notification sent that the calculation has been completed. This is quite different from sending a request for data.
With any system it is advisable to isolate tasks and decouple them. In this way each can be implemented independently and versioned independently. By using a specific endpoint / queue to handle a particular message type you have the ability to send a relevant message for processing at any time.
For example, in a tightly-coupled system you may have a process that registers a new user. So after gathering the user information from some front-end the information is submitted for processing:
If this is done in a synchronous fashion the user presses thesubmitbutton and waits. Let's assume our mail server has gone down. Now the user cannot register. What's more is that sending e-mail by using our shared smtp server takes a couple of seconds so during periods of heavy traffic this process takes quite some time.
We could change this process to gather the user information from the front-end and submit it for registration by sending aRegisterUserCommandto our user service. The call returns immediately informing the user that there registration request has been received and they will be contact with the result via e-mail. Now our process will be as follows (autonomous components indicated byAC):
In this way each component can be developed, versioned, and deployed in isolation. Stopping any of the services for deployment would not result in any process breaking since the queues will continue receiving work. Even if the entire machine is brought down Shuttle ESB will still store message on the sending machine when using anoutbox.
3 与MSMQ In WCF的异同?
Web Services / WCF
Some may argue that they use web services and therefore have a service oriented architecture. They would be correct in that they have exposed a service of some sort. There are however many properties of a SOA that are not present when using only web services:
These are not necessarily bad but do represent some of the properties of a WS.
This does not mean that web services have no place in a SOA. In fact, there are instances where we definitely need them. For external integration they are fine; serving as an entry point into our systems.
这里是NServiceBus与WCF的对比:http://support.nservicebus.com/customer/portal/articles/861164-nservicebus-and-wcf
(转载请注明出处)