SignalR + RabbitMQ Backplane: SignalR client receives same message repeatedly - c#

https://github.com/mdevilliers/SignalR.RabbitMq/issues/43
I'm having real difficulty getting this to work, can someone please glance at this and see if something is wrong in the setup?
Here's my test:
I spin up two self hosted servers, configured to the same RabbitMqScaleoutConfiguration
[Test]
public void BasicBackplaneTest()
{
SubsciberTestServerNode nodeA = null;
SubsciberTestServerNode nodeB = null;
string messageA = null;
string messageB = null;
try
{
Log("Given I have a WorkCenter Dispatch Publisher");
var publisher = new WcDispatchPublisher(ConnectionString);
Log("And I have multiple server nodes subscribed to the backplane");
nodeA = new SubsciberTestServerNode("nodeA").Start().Result;
nodeB = new SubsciberTestServerNode("nodeB").Start().Result;
Log("And I wait 5 seconds");
Thread.Sleep(5000);
Log("When I publish a message: {0}", TestPayload);
publisher.Publish(TestPayload);
Log("And I wait 60 seconds");
Thread.Sleep(TimeSpan.FromSeconds(60));
messageA = nodeA.Message;
messageB = nodeB.Message;
}
catch (AggregateException exception)
{
Log("Exception Occurred: {0}", exception.Flatten().Message);
Exception = exception;
}
catch (Exception exception)
{
Log("Exception Occurred: {0}", exception.Message);
Exception = exception;
}
finally
{
nodeA?.Dispose();
nodeB?.Dispose();
Log("Then no exceptions should have been thrown.");
Exception.Should().BeNull();
Log("Then the message should have been added to the Message Queue");
messageA.Should().NotBeNullOrWhiteSpace();
messageB.Should().NotBeNullOrWhiteSpace();
}
Server:
internal class SubsciberTestServerNode : IDisposable
{
private readonly string _nodeName;
private readonly string _url;
private WcDispatchSubscriber _subscriber;
private IDisposable _webApp;
public SubsciberTestServerNode(string nodeName)
{
_nodeName = nodeName;
_url = $"http://localhost:9999/{nodeName}";
MessageList = new List<string>();
}
public string Message { get; set; }
public List<string> MessageList { get; set; }
public void Dispose()
{
if (_webApp != null)
{
_webApp.Dispose();
_webApp = null;
_subscriber.Dispose();
_subscriber = null;
}
}
public async Task<SubsciberTestServerNode> Start()
{
_webApp = WebApp.Start(_url, app =>
{
new Startup(_nodeName).Configuration(app);
Thread.Sleep(TimeSpan.FromSeconds(5));
//Place this code into your Application_Start() method.
var factory = new ConnectionFactory
{
UserName = "guest",
Password = "guest",
HostName = "localhost"
};
var exchangeName = "WC_LeadDispatch_Exchange";
var configuration = new RabbitMqScaleoutConfiguration(factory, exchangeName);
GlobalHost.DependencyResolver.UseRabbitMq(configuration);
GlobalHost.Configuration.TransportConnectTimeout = TimeSpan.FromSeconds(10);
Thread.Sleep(TimeSpan.FromSeconds(5));
});
_subscriber = new WcDispatchSubscriber();
await _subscriber.Subscribe(_url, msg =>
{
string message = $"Message received at Node: {_nodeName}. Message: {msg}.";
Console.WriteLine(message);
Message = message;
MessageList.Add(message);
});
return this;
}
}
Subscriber:
public class WcDispatchSubscriber : IDisposable
{
private const string HubName = "DispatchUpdateHub";
private const string MessageEventName = "addMessage";
private readonly int _connectionLimitInt;
private IDisposable _hubProxySubscription;
public WcDispatchSubscriber()
{
string connectionLimit = ConfigurationManager.AppSettings.Get("SignalRConnectionLimit");
int.TryParse(connectionLimit, out _connectionLimitInt);
_connectionLimitInt = _connectionLimitInt == 0 ? 100 : _connectionLimitInt;
}
public void Dispose()
{
_hubProxySubscription.Dispose();
}
public async Task Subscribe(string hubConnectionString, Action<string> messageReceived)
{
var hubConnection = new HubConnection(hubConnectionString);
IHubProxy dispatchHubProxy = hubConnection.CreateHubProxy(HubName);
_hubProxySubscription = dispatchHubProxy.On(MessageEventName, messageReceived);
ServicePointManager.DefaultConnectionLimit = _connectionLimitInt;
await hubConnection.Start();
}
}
Publisher:
public class WcDispatchPublisher
{
private const string ExchangeName = "WC_LeadDispatch_Exchange";
private readonly IHubContext _hubContext;
public WcDispatchPublisher(string connectionString)
{
//actual string will look like this. we may need to overload the other constructors in the Rabbit/SigR.
//_rabbitConnectionString =
// "host=cprmqsrvt02vn01:5672;publisherConfirms=true;username=unittest;password=Un1t735t;virtualhost=UnitTest-NotificationService";
var configuration = new RabbitMqScaleoutConfiguration(connectionString, ExchangeName);
GlobalHost.DependencyResolver.UseRabbitMq(configuration);
_hubContext = GlobalHost.ConnectionManager.GetHubContext<DispatchUpdateHub>();
}
/// <summary>
/// </summary>
/// <param name="payload"></param>
public void Publish(string payload)
{
Task.Factory.StartNew(() =>
{
_hubContext.Clients.All.addMessage(payload);
}).Wait();
}
}
this will work every say 12th run or so, normally here's what I get:
Given I have a WorkCenter Dispatch Publisher
And I have multiple server nodes subscribed to the backplane
And I wait 5 seconds
When I publish a message: test-payload
And I wait 60 seconds
Message received at Node: nodeA. Message: test-payload.
Message received at Node: nodeB. Message: test-payload.
Message received at Node: nodeB. Message: {"LeadId":37252,"DispatchId":153595,"NotificationTypeId":1,"NotificationTitle":" Leads Dispatch","DispatchDateTime":"2016-06- 16T17:16:26.187","AlertMessage":"Lead number 37252 dispatched 6/16/2016 at 7:16 AM CST","DispatchedToFranchise":5576,"FranchiseOpsId":130}.
Message received at Node: nodeB. Message: {"LeadId":37252,"DispatchId":153595,"NotificationTypeId":1,"NotificationTitle":" Leads Dispatch","DispatchDateTime":"2016-06- 16T17:16:26.187","AlertMessage":"Lead number 37252 dispatched 6/16/2016 at 7:16 AM CST","DispatchedToFranchise":5576,"FranchiseOpsId":130}.
Message received at Node: nodeB. Message: {"LeadId":37252,"DispatchId":153595,"NotificationTypeId":1,"NotificationTitle":" Leads Dispatch","DispatchDateTime":"2016-06- 16T17:16:26.187","AlertMessage":"Lead number 37252 dispatched 6/16/2016 at 7:16 AM CST","DispatchedToFranchise":5576,"FranchiseOpsId":130}.
Message received at Node: nodeB. Message: {"LeadId":37252,"DispatchId":153595,"NotificationTypeId":1,"NotificationTitle":" Leads Dispatch","DispatchDateTime":"2016-06- 16T17:16:26.187","AlertMessage":"Lead number 37252 dispatched 6/16/2016 at 7:16 AM CST","DispatchedToFranchise":5576,"FranchiseOpsId":130}.
Message received at Node: nodeB. Message: {"LeadId":37252,"DispatchId":153595,"NotificationTypeId":1,"NotificationTitle":"Leads Dispatch","DispatchDateTime":"2016-06-16T17:16:26.187","AlertMessage":"Lead number 37252 dispatched 6/16/2016 at 7:16 AM CST","DispatchedToFranchise":5576,"FranchiseOpsId":130}.
Message received at Node: nodeB. Message: {"LeadId":37252,"DispatchId":153595,"NotificationTypeId":1,"NotificationTitle":"Leads Dispatch","DispatchDateTime":"2016-06-16T17:16:26.187","AlertMessage":"Lead number 37252 dispatched 6/16/2016 at 7:16 AM CST","DispatchedToFranchise":5576,"FranchiseOpsId":130}.
... CONTINUES LIKE THIS FOREVER

Off the top of my head, I would say try:
nodeA = new SubsciberTestServerNode("nodeA").Start().Wait();
nodeB = new SubsciberTestServerNode("nodeB").Start().Wait();
or
nodeA = await new SubsciberTestServerNode("nodeA").Start();
nodeB = await new SubsciberTestServerNode("nodeB").Start();
Result is a thread blocking call, so its likely blocking nodeA from firing.

Related

SSIS Script Task using client.GetAsync(url) not waiting for response

I have an API call using client.GetAsync(url) within a SSIS script task but for some reason its not waiting for response from API and jumping back to the entry point for the script task which is public void Main(). Done some reading and found out that it might result in a deadlock for some reason but tried all the variations I could find to get it to work but with no luck. Something else that I don't understand is the exact same code is running on a webpage and that works perfect and waits for response from the api and continuing the flow.
Script Task entry point
The response here for payload is: ID =5, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}"
Here if in debug mode and moving the process back to go through the process again I noticed there 2 threads one current executing and the old one with the response I was expecting on the first call but not too sure what this means.
public void Main() {
// TODO: Add your code here
try {
PackageDetails packageInfo = new PackageDetails {
PackageNumber = 1234567891, Env = "Development", UserName = "USER"
};
var payload = API.ListHeadByPackAsync(packageInfo);
//var test = GetResponse();
Dts.TaskResult = (int) ScriptResults.Success;
} catch (Exception ex) {
System.Console.Write(ex.Message);
Dts.TaskResult = (int) ScriptResults.Failure;
}
}
API Call
public static class API {
public static async Task<PackageDetails> ListHeadByPackAsync(PackageDetails package) {
PackageDetails packageInfo = new PackageDetails();
try {
using(var client = new ApiClient(requestUrl, authToken)) {
var response = await client.GetAsync(); //-> not waiting for response
}
} catch (Exception err) {
switch (err.Message) {
//TODO:
}
}
return packageInfo;
}
}
Client
public class ApiClient: IDisposable {
private readonly TimeSpan _timeout;
private HttpClient _httpClient;
private HttpClientHandler _httpClientHandler;
private readonly string _baseUrl;
private readonly string _credentials;
//private const string MediaTypeXml = "application/csv";
public ApiClient(string baseUrl, string authToken, TimeSpan ? timeout = null) {
_baseUrl = baseUrl;
_credentials = Base64Encode(authToken);
_timeout = timeout ?? TimeSpan.FromSeconds(90);
}
public async Task < string > GetAsync() {
EnsureHttpClientCreated();
using(var response = await _httpClient.GetAsync(_baseUrl).ConfigureAwait(continueOnCapturedContext: false))
//-> after executing above line it will go straight to public void Main(), dose not wait for response
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
public void Dispose() {
_httpClientHandler?.Dispose();
_httpClient?.Dispose();
}
private void CreateHttpClient() {
_httpClientHandler = new HttpClientHandler {
AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip
};
_httpClient = new HttpClient(_httpClientHandler, false) {
Timeout = _timeout
};
if (!string.IsNullOrWhiteSpace(_baseUrl)) {
_httpClient.BaseAddress = new Uri(_baseUrl);
}
_httpClient.DefaultRequestHeaders.Add("Authorization", "Basic" + " " + _credentials);
}
private void EnsureHttpClientCreated() {
if (_httpClient == null) {
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
CreateHttpClient();
}
}
public static string Base64Encode(string token) {
var tokenBytes = System.Text.Encoding.UTF8.GetBytes(token);
return System.Convert.ToBase64String(tokenBytes);
}
}

C# Grpc System.InvalidOperationException: 'Cannot write message after request is complete.'

At runtime I get the following error:
System.InvalidOperationException: 'Cannot write message after request
is complete.'
I'm using Grpc and reactive X to get data.
public class SensorService: Protos.Vehicule.VehiculeBase
{
private readonly ILogger<SensorService> _logger;
private DataProvider _dataProvider;
private CarSim.Vehicule _vehicule;
public SensorService(ILogger<SensorService> logger)
{
_dataProvider = new DataProvider(new CarSim.Vehicule());
_vehicule = _dataProvider.getVehicule();
_logger = logger;
_dataProvider.Start();
}
public System.IObserver<CarSim.Vehicule> GetData { get; private set; }
public override async Task Status(All request, IServerStreamWriter<StatusVehicule> responseStream, ServerCallContext context)
{
while (!context.CancellationToken.IsCancellationRequested)
{
_vehicule.VehiculeChangedState.Subscribe(onNext: new Action<CarSim.Vehicule>(async (t) =>
{
await responseStream.WriteAsync(new StatusVehicule()
{
Camera = t.Camera,
FuelLevel = t.FuelLevel,
GunStatus = true,
Light = t.Light,
OilLevel = t.OilLevel,
Peed = t.Speed,
Tempature = t.Tempature
}
);
; }));
}
}
}
This is likely not a bug. The exception means that you're trying to send a response after the RPC has actually finished. Usually this happens when the RPC deadline is exceeded (at which point the RPC is automatically cancelled) or when it was cancelled by the client. Both of these situations can happen at any time (from the server side handler's perspective) and they are basically an inherent race condition (the RPC could have been cancelled just before you decide to send the response).
The exception is just gRPC's way of informing you that the response could not be sent (and there is really no way to send a response AFTER the RPC has finished).
You must register SensorService in your gRpc Server code:
like this:
app.UseEndpoints(endpoints => { endpoints.MapGrpcService<SensorService >(); .....
I have found a solution that works. But i still have the same error.
public override async Task Status(All request, IServerStreamWriter<StatusVehicule> responseStream, ServerCallContext context){
try
{
var eventLoop = new EventLoopScheduler();
await _vehicule.VehiculeChangedState.ObserveOn(eventLoop).ForEachAsync<CarSim.Vehicule>(t =>
{
try
{
responseStream.WriteAsync(new StatusVehicule()
{
Camera = t.Camera,
FuelLevel = t.FuelLevel,
GunStatus = true,
Light = t.Light,
OilLevel = t.OilLevel,
Peed = t.Speed,
Status = t.GetState().ToString(),
StatusDoors = t.StatusDoors.ToString(),
Tempature = t.Tempature
}
).Wait();
}
catch (Exception)
{
// ignored
}
},
context.CancellationToken);
}
catch (Exception e)
{
_logger.LogError(e.Message);
}
}

WCF service server throws an exception Cannot access a disposed object

So my service is a simple chat application between two wcf clients. Event callback works when I call events. After I close my client and run it again, and write a message again (to call the event) it throws me exception:
An exception of type 'System.ObjectDisposedException' occurred in
RussianRouletteServiceLibrary.dll but was not handled in user code
Additional information: Cannot access a disposed object.
The code for my service callback is as follows:
private static Action<User, UMessage> gameChat = delegate { };
public void Play()
{
IGameCallback subscriber =
OperationContext.Current.GetCallbackChannel<IGameCallback>();
gameChat += subscriber.PlayerSentMessage;
}
This is the event trigger:
public void SendMessage(User user, UMessage message)
{
try
{
gameChat(user, message);
}
catch (Exception ex)
{
throw ex;
}
}
I get this error every time I .ChannelFactory.Close(); .Close(); the client while closing form event is happening.
Is there anyone that knows how to fix this and is willing to share his knowledge?
Thank you in advance!
EDIT #1
This is the code of the client when it opens:
ConcurrencyMode.Multiple,
UseSynchronizationContext = false)]
public partial class GameForm : Form, IGameCallback
{
#region IGame Callbacks
public void PlayerSentMessage(User user, UMessage message)
{
string nickname = user.NickName == clientUser.NickName ? "You" : user.NickName;
this.Invoke(new MethodInvoker(() => lb_ChatBox.Items.Add(nickname + " : " + message.MessageContent)));
}
#endregion
private GameClient _gameClient = null;
private InstanceContext _instance = null;
private User clientUser = new User(){ Email = "zigm4s#gmail.com", Id = 0, FirstName = "Zigmas", LastName = "Slusnys", NickName = "Ziggy", Password = "test123"};
public GameForm()
{
string state;
if (_gameClient != null)
{
MessageBox.Show("nelygu null");
MessageBox.Show(_gameClient.State.ToString());
//_gameClient = new GameClient(new InstanceContext(this));
}
else
{
_gameClient = new GameClient(new InstanceContext(this));
MessageBox.Show(_gameClient.State.ToString());
}
InitializeComponent();
try
{
_gameClient.Open();
_gameClient.Play();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
This is when the client form is closing.
private void GameForm_FormClosing(object sender, FormClosingEventArgs e)
{
try {
if (_gameClient.State != System.ServiceModel.CommunicationState.Faulted)
{
MessageBox.Show("Closing client");
_gameClient.ChannelFactory.Close();
_gameClient.Close();
}
else
{
MessageBox.Show("Aborting client");
_gameClient.Abort();
}
}
catch(Exception ex)
{ MessageBox.Show(ex.ToString());}
}
EDIT #2
I found the mistake, on the service side i had delegates that were static. It doesn't throw this error when it's not static.

ServerSentEvents, HttpTaskAsyncHandler and waiting

I'm trying to create a quite simple notifications system (don't want to use SignalIR or something else). I have the following testing code:
Client side:
var source = new EventSource('/notifications.axd');
source.onopen = function () {
Console.log("Connection open");
};
source.onerror = function () {
Console.log("Connection error");
};
source.onmessage = function (event) {
Console.log("Message: " + event.data);
};
Server side:
public class NotificationMessage {
public NotificationMessage() {
Id = Guid.NewGuid().ToString();
}
public string Id { get; private set; }
}
public class NotificationsHandler : HttpTaskAsyncHandler {
private const string CONTENT_TYPE = "text/event-stream";
private sealed class NotificationItem {
public ConcurrentQueue<NotificationMessage> Messages;
public CancellationTokenSource CancellationTokenSource;
}
private static readonly ConcurrentDictionary<string, NotificationItem> _tasks =
new ConcurrentDictionary<string, NotificationItem>();
public static void Notify(string hostId, string userId, NotificationMessage message) {
NotificationItem item;
if (!_tasks.TryGetValue(string.Format("{0}|{1}", hostId, userId), out item)) {
return;
}
var tokenSource = item.CancellationTokenSource;
item.Messages.Enqueue(message);
item.CancellationTokenSource = new CancellationTokenSource();
tokenSource.Cancel();
}
public override async Task ProcessRequestAsync(HttpContext context) {
HttpRequest request = context.Request;
NotificationItem item = _tasks.GetOrAdd(
string.Format("{0}|{1}", request.Url.Host, CsSession.Data.CurrentUser.Id),
k => new NotificationItem {
Messages = new ConcurrentQueue<NotificationMessage>(),
CancellationTokenSource = new CancellationTokenSource()
}
);
HttpResponse response = context.Response;
response.ContentType = CONTENT_TYPE;
response.CacheControl = "no-cache";
response.ContentEncoding = Encoding.UTF8;
response.AppendHeader("connection", "keep-alive");
response.BufferOutput = false;
bool supportsAsyncFlush = response.SupportsAsyncFlush;
bool shouldPing = true;
while (response.IsClientConnected) {
try {
NotificationMessage message = null;
if ((!item.Messages.IsEmpty && item.Messages.TryDequeue(out message)) || shouldPing) {
response.Write(string.Format("data:{0}\n\n", message == null ? "{}" : JsonMapper.Serialize(message)));
if (supportsAsyncFlush) {
await Task.Factory.FromAsync(response.BeginFlush, response.EndFlush, null);
} else {
response.Flush();
}
}
} catch (Exception) {
break;
}
var delay = Task.Delay(15000, item.CancellationTokenSource.Token);
await delay;
shouldPing = delay.Status == TaskStatus.RanToCompletion;
}
}
}
The problem is: the above doesn't works. I have two issues:
1) When the client connects, I receive an empty packet (that's ok). Then, if I don't enqueue any messages, after awaiting the Task.Delay, the loop tries to write an empty message again, but I don't know where. The response.Write line never returns (and nothing is being received on the client).
2) If I write to the queue, for some reason the connection is dropped. If I put a breakpoint on the line after the await delay, that line is never executed (while my logic says otherwise :) ). If I cancel the token, the delay task should quit, but it seems it is aborting the whole handler??

How can I find the message I added in my msmq

I wet through this except that I added it to a windows service like this
public partial class TriggerHostProcesses : ServiceBase
{
private const string MESSAGE_QUEUE = #".\Private$\Sample Queue";
private MessageQueue _queue;
public TriggerHostProcesses()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
SendMessage("Hope This Works");
}
protected override void OnStop()
{
}
internal void start()
{
OnStart(null);
}
private void SendMessage(string message)
{
_queue = new MessageQueue(MESSAGE_QUEUE);
Message msg = new Message();
msg.Body = message;
msg.Label = "Testing " + DateTime.Now.ToString();
_queue.Send(msg,new MessageQueueTransaction());
}
}
and to get the message
partial class HostListener : ServiceBase
{
private const string MESSAGE_QUEUE = #".\Private$\Sample Queue";
private MessageQueue _queue;
public HostListener()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
var myTransaction = new MessageQueueTransaction();
var queue = new MessageQueue(MESSAGE_QUEUE);
var message = queue.Receive(new TimeSpan(0, 0, 20),myTransaction);
message.Formatter = new XmlMessageFormatter(
new String[] { "System.String,mscorlib" });
Console.WriteLine(message.Body.ToString());
}
catch(Exception ex)
{
Console.WriteLine("No Message");
}
}
protected override void OnStop()
{
// TODO: Add code here to perform any tear-down necessary to stop your service.
}
internal void start()
{
OnStart(null);
}
}
in my main I added this
var ServiceToRun1 = new TriggerHostProcesses();
var ServiceToRun2 = new HostListener();
if (Environment.UserInteractive)
{
// This used to run the service as a console (development phase only)
ServiceToRun1.start();
ServiceToRun2.start();
Console.WriteLine("Press Enter to terminate ...");
Console.ReadLine();
ServiceToRun1.Stop();
ServiceToRun2.Stop();
}
else
{
ServiceBase.Run(ServiceToRun1);
}
I get the exception Timeout for the requested operation has expired.
Can someone please check if they can see what the problem is?
I don't believe you are using transactions correctly. For example, when sending a message you use:
_queue.Send(msg,new MessageQueueTransaction());
However, this does not begin or commit a transaction. Looking in MSDN the example uses the following code (edited by me):
var myTransaction = new MessageQueueTransaction();
myTransaction.Begin();
myQueue.Send("hello world", myTransaction);
myTransaction.Commit();
I don't believe your message is getting sent, and so your Receive times out.
Similarly your receive logic doesn't seem to correctly use transactions:
myTransaction.Begin();
var myMessage = myQueue.Receive(myTransaction);
var body myOrder = (string)myMessage.Body;
myTransaction.Commit();
You should Rollback in the event of an exception processing your messages so they can be placed back on the queue.
Here is my final product. I'm using this in a windows service. 20 s at a time to see if I have a message then do my processes.
public class MSMQueue:IQueue
{
public MSMQueue(string queueName)
{
Message_Queue = queueName;
}
public string Message_Queue { get; private set; }
public string Pop()
{
MessageQueue queue = new MessageQueue(Message_Queue);
if (queue.Transactional)
return popTransactionalQueue(queue, new TimeSpan(0, 0, 1));
else
return popNormalQueue(queue, new TimeSpan(0, 0, 1));
}
public string Pop(TimeSpan timeSpan)
{
MessageQueue myQueue = new MessageQueue(Message_Queue);
if (myQueue.Transactional)
return popTransactionalQueue(myQueue, timeSpan);
else
return popNormalQueue(myQueue, timeSpan);
}
public void Add(string message)
{
// Connect to a queue on the local computer.
MessageQueue myQueue = new MessageQueue(Message_Queue);
// Send a message to the queue.
if (myQueue.Transactional)
{
var myTransaction = new MessageQueueTransaction();
myTransaction.Begin();
myQueue.Send(message, myTransaction);
myTransaction.Commit();
}
else
myQueue.Send(message);
}
#region private methods
private string popNormalQueue(MessageQueue queue, TimeSpan timeOut)
{
var message = queue.Receive(timeOut);
message.Formatter = new XmlMessageFormatter(
new String[] { "System.String,mscorlib" });
return message.Body.ToString();
}
private string popTransactionalQueue(MessageQueue queue, TimeSpan timeOut)
{
// Set the formatter.
queue.Formatter = new XmlMessageFormatter(new Type[]
{typeof(String)});
// Create a transaction.
MessageQueueTransaction myTransaction = new
MessageQueueTransaction();
String message=string.Empty;
try
{
myTransaction.Begin();
Message myMessage = queue.Receive(timeOut, myTransaction);
message = (String)myMessage.Body;
myTransaction.Commit();
}
catch (MessageQueueException e)
{
myTransaction.Abort();
throw e;
}
return message;
}
#endregion
}

Categories