Shuttle Bus之Request/Response模式簡單示例
建立類庫工程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.
Autonomous Components
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:
- check if the user is blacklisted
- register the user in the database
- send an activation e-mail
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):
- User Registration Service (AC) - handlesRegisterUserCommand
- check blacklisting
- if user blacklisted sendSendEMailCommandto then e-mail service (AC) to notify user that the details provided (user name / e-mail address / contact numbers) have been blacklisted.
- if not blacklisted register user in database and sendSendEMailCommandto the e-mail server (AC) and publishesUserRegisteredEvent.
- check blacklisting
- E-Mail Service (AC) - handlesSendEMailCommand
- sends the requested e-mail via our smtp server; if the server is down the message will simply be retried until it goes through
- CRM User Registration Service (AC) - subscribes toUserRegisteredEvent
- registers the new user in our CRM
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:
- Noevent driven architecture(EDA)
- WS / WCF cannot subscribe to events
- No durability of messages
- A message goes across the wire and is not stored anywhere
- No recoverability
- Once a message is lost it is gone
- No lowtemporal coupling
- A WS must be running in order to invoke it
- No lowbehavioural coupling
- We have to know what the service will do in order to invoke it
- Nomessage routing
- We send messages to a specific WS to invoke some action
- No queuing
- Calls are synchronous and blocking
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
(轉載請註明出處)
相關文章
- Shuttle Bus體系架構的特徵架構特徵
- Request和Response物件物件
- 從零開始實現簡單 RPC 框架 8:網路通訊之 Request-Response 模型RPC框架模型
- Servlet第三篇【request和response簡介、response的常見應用】Servlet
- java基礎學習:JavaWeb之request和responseJavaWeb
- ASP.NET常見物件之Request與ResponseASP.NET物件
- struts之Action中獲取request、response物件的方法物件
- request和response的區別
- 幾種常用設計模式的簡單示例設計模式
- Android MVP模式--簡單實用示例 BMIAndroidMVP模式
- asp.net 8 Request,Response,ServerASP.NETServer
- JAVA的request和response有效域Java
- request/response解決中文亂碼
- WEB開發2--request&responseWeb
- Response.cookies和Request.cookiesCookie
- Python request簡單使用Python
- 設計模式之簡單工廠模式設計模式
- 工廠模式之簡單工廠模式模式
- SpringBoot中的response和request模擬單元測試Spring Boot
- 使用策略模式和簡單工廠模式重寫支付模組(二)-優化$request模式優化
- javaweb入門-----request與response的作用JavaWeb
- 【JavaWeb】請求和響應Request&ResponseJavaWeb
- request和response——請求響應物件物件
- JSP 中的 Request 和 Response 物件JS物件
- Python如何獲取request response bodyPython
- golang設計模式之簡單工廠模式Golang設計模式
- 使用策略模式和簡單工廠模式重寫支付模組(二)-最佳化$request模式
- AOP的簡單示例
- jsoncpp簡單示例JSON
- Laravel 從 $request 到 $response 的過程解析Laravel
- Java常用設計模式之簡單工廠模式Java設計模式
- Java設計模式之策略模式示例Java設計模式
- Python3之遞迴函式簡單示例Python遞迴函式
- C# superSocket簡單示例C#
- jquery驗證簡單示例jQuery
- oracle審計簡單示例Oracle
- Kafka實戰-簡單示例Kafka
- akka入門-簡單示例