# Full Duplex > [!NOTE] > [Sagas](/nservicebus/sagas/index.md) is a better approach when responses must be correlated to requests as they provide message-to-state correlation out of the box. Run the solution. Two console applications start-up, `Client` and `Server.` ## Code walk-through ### Messages Look at the messages in the `Shared` project: ```cs public class RequestDataMessage : IMessage { public Guid DataId { get; set; } public string String { get; set; } } ``` ```cs public class DataResponseMessage : IMessage { public Guid DataId { get; set; } public string String { get; set; } } ``` The two classes here implement the NServiceBus `IMessage` interface, indicating they are messages. These classes only have properties, each with get and set access. The `RequestDataMessage` is sent from the client to the server, and the `DataResponseMessage` replies from the server to the client. ### Client The client console has an input loop: ```cs while (true) { var key = Console.ReadKey(); Console.WriteLine(); if (key.Key != ConsoleKey.Enter) { break; } var guid = Guid.NewGuid(); Console.WriteLine($"Requesting to get data by id: {guid:N}"); var message = new RequestDataMessage { DataId = guid, String = "String property value" }; await messageSession.Send("Samples.FullDuplex.Server", message); } ``` This code sends a message with a new `Guid` and a string value every time the 'Enter' key is pressed. ### Server When a `RequestDataMessage` arrives in the server queue, the bus dispatches it to the message handler found in the `RequestDataMessageHandler.cs` file in the `Server` project. The bus knows which classes to call based on the interface they implement. ```cs public class RequestDataMessageHandler () : IHandleMessages ``` At start-up, the bus scans all assemblies and builds a dictionary indicating which classes handle which messages. So when a given message arrives in a queue, the bus knows which class to invoke. The `Handle` method of this class contains this: ```cs var response = new DataResponseMessage { DataId = message.DataId, String = message.String }; await context.Reply(response); ``` Finally, the bus replies with the response message. The bus knows to send the responses to where the message was sent from, every time it receives a message from the queue. Open `DataResponseMessageHandler.cs` in the `Client` project and find a class whose signature looks similar to the message handler on the server: ```cs class DataResponseMessageHandler() : IHandleMessages ```