2. AGENDA 2
• Intro
• Messaging and queues
• Testing
• SOA
• Saga
3. INTRO 4
• Fallacies of distributed computing
• Why NServiceBus?
• Bus vs. Broker
• Service orientation
• Excercises
4. FALLACIES OF DISTRIBUTED COMPUTING 5
1. The network is reliable
2. Latency isn’t a problem
3. Bandwidth isn’t a problem
4. The network is secure
5. The topology won’t change
6. The administrator will know what to do
7. Transport cost isn’t a problem
8. The network is homogeneous
Cant’ assume WHEN the message will arrive,
IF AT ALL
5. WHY NSERVICEBUS 6
1. The network is reliable
2. Latency isn’t a problem NServiceBus addresses the first five directly
3. Bandwidth isn’t a problem
4. The network is secure
5. The topology won’t change
6. The administrator will know what to do
7. Transport cost isn’t a problem
8. The network is homogeneous
The most developer-friendly service bus for SOA on .NET
6. BUS VS. BROKER 7
• Bus is not necessarily physically separate
• Simpler; no routing or service fail over
• No single point of failure
App
App
Buss.dll
Broker
App App
Buss.dll Buss.dll App App
7. TENETS OF SERVICE ORIENTATION 8
• Services are autonomous
• Share contract & schema, not class or type
• Boundaries are explicit
• Compatibitility is base on Policy
8. LAYERS & COUPLING 9
Tight coupling
Loose coupling
Sales Shipping CRM
UI
BL
DAL
DB Referential Integrity
Reintroduces coupling
9. WHEN CAN I WRITE SOME CODE? 10
• Getting started
• New class library
• Install-Package NServiceBus.Host
• Logging
• NServiceBus uses log4net, you can configure logging in app.config
• Default output is console
11. MESSAGING AND QUEUES 12
• Store & forward
• Dangers of store & forward
• Request/Response
• Messaging and NServiceBus
• Exercises
12. STORE & FORWARD 13
SERVER
MSMQ
OUTGOING INCOMING
Store & Forward writes to disk
Resilient in the face of failures
MSMQ
OUTGOING INCOMING
CLIENT
13. DANGERS OF STORE & FORWARD 14
• If target is offline for an extended period of timemessages can fill up the disk
• Can cause a server to crash
• Especially problematic in B2B integration
• 1 MB/message, 100 message/sec = 6GB/minute
• Solution – discard messages after a while
• Use [TimeToBeReceived("00:01:00")] on the message definition
14. REQUEST/RESPONSE 15
SERVER
MSMQ
OUTGOING INCOMING
Client can’t assume
when a response Equivalent to 2
will arrive, if at all one-way messages
MSMQ
OUTGOING INCOMING
CLIENT
15. REQUEST/RESPONSE 16
• Message is sent from the server to the client’s queue
If the client is offline, message sits in the server machine’s outgoing queue
• Client is not blocked until response arrives
• If two requests were sent, responses may arrive out of order
16. WARNING! THIS IS NOT RPC 17
• Do NOT try to implement regular request/response patterns on top of messaging
• The client should be designed so that it can continue operating if a response never
comes
Differences from RPC
• RPC is easy to code
• After invoking a web service
• Next line of code assumes we’ve got a response
• RPC problems
• Can’t reason about the time between one line of code and another
• Messaging makes this all explicit
17. MESSAGING AND NSERVICEBUS 18
SERVER
MSMQ
OUTGOING INCOMING
Transaction
MSMQ
OUTGOING INCOMING
CLIENT
18. DEFINE A MESSAGE 19
• Preferably inherit from IEvent or ICommand
• Use IMessage when replying using Bus.Reply()
• Also possible to define your own convention
• Configure.DefiningMessagesAs(t=>MyOwnConvention(t))
• Add properties like a regular class/interface
• Keep contract definintions in their own assembly/project
public class MyEvent: IEvent {}
19. INSTANTIATE A MESSAGE 20
• var myMessage = new MyMessage();
• var myMessage = Bus.CreateInstance<MyMessage>();
20. SEND A MESSAGE 21
Bus.Send(messageObject);
Can instantiate and send together (useful for interfaces):
Bus.Send<IMessage>((message) =>
{
message.Prop1 = value1;
message.Prop2 = value2;
});
21. SPECIFY DESTINATION 22
1. Bus.Send(destination, messages);
Requires that application manages routing
2. Configure destination for message type.
In <UnicastBusConfig>, under <MessageEndpointMappings> specify one of
the following:
- <add Messages="assembly" Endpoint="destination"/>
- <add Messages="type" Endpoint="destination"/>
3. Specify destination using
- QueueName@ServerName , or
- Just QueueName for the same machine
22. HANDLE A MESSAGE 23
Write a class that implements IHandleMessages<T> where T is a message type
public class MyHandler : IHandleMessages<MyMessage>
{
public void Handle(MyMessage message)
{
}
}
Remember to specify in <UnicastBusConfig>, under
<MessageEndpointMappings> one of the following:
- <add Messages="assembly" Endpoint="source"/>
- <add Messages="type" Endpoint="source"/>
23. CONFIGURING AN ENDPOINT 24
When configuring an endpoint inherit from
1. Using AsA_Client will
- use non-transactional MsmqTransport
- purge its queue of messages on startup
- processes messages using its own permissions, not those of the message sender
2. Using AsA_Server will
- use transactional MsmqTransport
- not purge its queue of messages on startup, hence fault-tolerant
- processes messages using the permissions of the sender (impersonation)
3. Using AsA_Publisher will
- extends AsA_Server
- indicates to the infrastructure that a storage for subscription request is to be set up
25. UNIT TESTING MESSAGE HANDLERS 26
Available from NuGet using
Install-Package NServiceBus.Testing
Provides the ability to set expectations around how message handlers handle messages
• Expect: Send, Reply, Publish, etc...
Test.Initialize();
Test.Handler<MyHandler>()
.ExpectPublish<MyMessage>(message => message.Prop1 == value1)
.OnMessage<SomeEvent>(someEvent =>
{
someEvent.Prop1 = inputValue1;
});
28. SAGA - DEFINITION 29
A Saga:
• Is a pattern for implementing long-lived transaction by using a series of
shorter transactions
• Holds relevant state to needed to process mulitple messages in a ”saga entity”
• Are initiated by a message (event/command)
29. SAGA - DECLARATION 30
public class MyPolicy : Saga<MyPolicyData>,
IAmStartedByMessages<MyMessage1>,
IHandleMessages<MyMessage2>
{
public void Handle(MyMessage1 order)
public void Handle(MyMessage2 order)
}
• Methods are like regular message handling logic
• Sagas can be started by multiple messages (IAmStartedByMessages<T>)
• First messages should start saga, following messages should be processed by
the same one
30. SAGA – DECLARATION CONT. 31
public class MyPolicyData : ISagaEntity
{
public Guid Id { get; set; }
public string Originator { get; set; }
public string OriginalMessageId { get; set; }
}
31. ENDING A SAGA 32
MarkAsComplete();
• Can call this from any method
• Causes the saga to be deleted
• Any data that you want retained should be sent on (or published) via a message
34. EXTRA EXERCISES 35
TIMEOUT
CUSTOM XML NAMESPACE
CONFIGURABLE ROUTING
DEPENDENCY INJECTION
WEB-APP HOSTING
FULL DUPLEX
DISTRIBUTION GROUP EXERCISE
Editor's Notes
The Fallacies of Distributed Computing are a set of assumptions that Peter Deutsch and others at Sun Microsystems originally asserted programmers new to distributed applications invariably make. These assumptions ultimately prove false, resulting either in the failure of the system, a substantial reduction in system scope, or in large, unplanned expenses required to redesign the system to meet its original goals.Self explanatoryLocal vs. globalLocal vs. globalThis is just false.Your network topology might change for some reasonMore like trial and errorCost in resources to serialize/deserialize data and cost in network trafficUse standard technologies. Maybe not relevant for Nservicebus since you must run on windows.
Services are autonomous – changes on one services should not affect another service through encapsulationContract & schema – don’t share implementation as contract, framework is fine to shareBoundaries – to communicate over boundaries should be an explicit actCompatibility – security, signing etc. is not defined in main code but as policies
But do you really need referential integrity? What if you didn’t delete data, and modeled the business lifecycle of data instead?Products no longer for sale, though previous orders can continue processing, inventory liquidated, etc.
Consider overriding ConfigureHowToFindSaga to be able to get the correct saga for processing messages