This topic resembles this thread and this thread. Also I have read this example
But, in any of this thread I can't find clear example how organize p2p connection across the internet.
All examples good working in local network.
I made a small program, you can see it below. It works good in local network.
Main question: After peer registration how to open Wcf host and wait calls from another peers? In this topic I have read that:
When a peer is resolved on the global cloud, it is typically resolved to an IPv6 address
So I need open my WCF on this IPv6 address? How I can receive it?
Please give me some coding tips.
My program:
namespace FileShare
{
internal class Program
{
private static void Main()
{
Console.WriteLine("Hello enter your username");
IPeerRegistrationRepository peerRegistrationRepository = new PeerRegistrationRepository();
IPeerNameResolverRepository peerNameResolverRepository = new PeerNameResolverRepository();
ServiceHost host = null;
try
{
string username = Console.ReadLine();
int port = PeerUtils.FindFreePort();
peerRegistrationRepository.StartRegistration("Max951Peer", port, PeerNameType.Secured);
string serviceUrl = $"net.tcp://{peerRegistrationRepository.PeerName.PeerHostName}:{port}/Max951P2PService";
IP2PService localService = new P2PService();
host = new ServiceHost(localService, new Uri(serviceUrl));
host.AddServiceEndpoint(typeof(IP2PService), new NetTcpBinding { Security = { Mode = SecurityMode.None } }, serviceUrl);
try
{
host.Open();
Console.WriteLine($"Host opened on { serviceUrl }");
}
catch (Exception e)
{
Console.WriteLine($"Error { e }");
return;
}
Console.WriteLine($"Registered peer. PeerHostName: { peerRegistrationRepository.PeerName.PeerHostName }, Classifier: { peerRegistrationRepository.PeerName.Classifier }");
PeerNameRecordCollection results = peerNameResolverRepository.ResolvePeerName(peerRegistrationRepository.PeerName, Cloud.Global);
Console.WriteLine("{0} Peers Found:", results.Count.ToString());
int i = 1;
foreach (PeerNameRecord peer in results)
{
Console.WriteLine("{0} Peer:{1}", i++, peer.PeerName);
foreach (IPEndPoint ip in peer.EndPointCollection)
{
Console.WriteLine("\t Endpoint: {0}", ip);
string endpointUrl = $"net.tcp://[{ip.Address}]:{ip.Port}/Max951P2PService";
NetTcpBinding binding = new NetTcpBinding { Security = { Mode = SecurityMode.None } };
try
{
IP2PService serviceProxy = ChannelFactory<IP2PService>.CreateChannel(binding, new EndpointAddress(endpointUrl));
serviceProxy.SendMessage("Hello!", username);
}
catch (Exception)
{
// ignored
}
}
}
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
peerRegistrationRepository.StopRegistration();
host?.Close();
}
//serviceModelClient.Stop();
}
}
[ServiceContract]
public interface IP2PService
{
[OperationContract(IsOneWay = true)]
void SendMessage(string message, string from);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class P2PService : IP2PService
{
/// <inheritdoc />
public void SendMessage(string message, string from)
{
Console.WriteLine($"{from} says: { message }");
}
}
}
namespace Utils.PeerToPeer
{
public class PeerNameResolverRepository : IPeerNameResolverRepository
{
private readonly PeerNameResolver peerNameResolver;
public PeerNameResolverRepository()
{
this.peerNameResolver = new PeerNameResolver();
}
/// <inheritdoc />
public PeerNameRecordCollection ResolvePeerName(string name, PeerNameType peerNameType, Cloud cloud)
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentNullException(nameof(name));
}
return this.peerNameResolver.Resolve(new PeerName(name, peerNameType), cloud);
}
/// <inheritdoc />
public PeerNameRecordCollection ResolvePeerName(PeerName peerName, Cloud cloud)
{
return this.peerNameResolver.Resolve(peerName, cloud);
}
}
}
namespace Utils.PeerToPeer
{
public class PeerRegistrationRepository : IPeerRegistrationRepository
{
private PeerNameRegistration peerNameRegistration;
/// <inheritdoc />
public bool IsRegistered => this.peerNameRegistration != null && this.peerNameRegistration.IsRegistered();
/// <inheritdoc />
public string PeerUri => GetPeerUri();
/// <inheritdoc />
public PeerName PeerName { get; set; }
/// <inheritdoc />
public void StartRegistration(string name, int port, PeerNameType peerNameType)
{
this.PeerName = new PeerName(name, peerNameType);
this.peerNameRegistration = new PeerNameRegistration(PeerName, port, Cloud.Global);
this.peerNameRegistration.Start();
}
/// <inheritdoc />
public void StopRegistration()
{
this.peerNameRegistration?.Stop();
this.peerNameRegistration = null;
}
private string GetPeerUri()
{
return this.peerNameRegistration?.PeerName.PeerHostName;
}
}
}
Related
I'm trying to create sample router with two remote actors.
Here's my code
class Program
{
public const string AkkaConfig = #"{
akka {
actor {
provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
deployment {
/remoteecho1 {
remote = ""akka.tcp://Target#my1.lan:8090""
}
/remoteecho2 {
remote = ""akka.tcp://Target#my2.lan:8090""
}
}
remote{
helios.tcp{
port = 0
hostname = localhost
}
}
}
}";
static void Main(string[] args)
{
using (var system = ActorSystem.Create("Deployer", AkkaConfig))
{
var remoteEcho1 = system.ActorOf(Props.Create(() => new EchoActor()), "remoteecho1");
var remoteEcho2 = system.ActorOf(Props.Create(() => new EchoActor()), "remoteecho2");
var roundRobinGroup = new RoundRobinGroup(new[]
{
remoteEcho1,
remoteEcho2
});
var coordinator = system.ActorOf(Props.Empty.WithRouter(roundRobinGroup),"coordinator");
system.ActorOf(Props.Create(() => new HelloActor(coordinator)), "localactor");
system.ActorSelection("/user/localactor").Tell(new SayHelloMessage());
Console.ReadKey();
}
}
}
public class HelloActor:ReceiveActor
{
private readonly IActorRef remoteActor;
public HelloActor(IActorRef remoteActor)
{
this.remoteActor = remoteActor;
Context.Watch(remoteActor);
Receive<HelloMessage>(m =>
{
Console.WriteLine("Pingback from {1}: {0}", m.MessageText, Sender.Path);
});
Receive<SayHelloMessage>(m =>
{
var newMessage = new HelloMessage(Guid.NewGuid().ToString());
remoteActor.Tell(newMessage);
});
}
protected override void PreStart()
{
Context.System.Scheduler.ScheduleTellRepeatedlyCancelable(TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(1), Context.Self, new SayHelloMessage(), ActorRefs.NoSender);
}
}
public class SayHelloMessage
{
}
The problem is that remoteActor.Tell(newMessage) in the code below doesn't send message to my actor
Receive<SayHelloMessage>(m =>
{
var newMessage = new HelloMessage(Guid.NewGuid().ToString());
remoteActor.Tell(newMessage);
});
When I pass remoteEcho actor to HelloActor constructor instead of router instance everything works fine. How to make that example work with Router?
I have several objects in my solution that use the following pattern:
#region Repositories
private RepositoryAccount _account;
private RepositoryInquiry _inquiry;
private RepositoryLoan _loan;
public RepositoryAccount Account { get { return _account ?? (_account = new RepositoryAccount(this)); } }
public RepositoryInquiry Inquiry { get { return _inquiry ?? (_inquiry = new RepositoryInquiry(this)); } }
public RepositoryLoan Loan { get { return _loan ?? (_loan = new RepositoryLoan(this)); } }
#endregion
I created a Generic Class to try to make the Property handling a little cleaner but ran into a snag. The Property Class looks like:
public class Property<T> where T : class, new()
{
private T _value;
public T Value
{
get { return _value ?? (_value = new T()); }
set
{
// insert desired logic here
_value = value;
}
}
public static implicit operator T(Property<T> value)
{
return value.Value;
}
public static implicit operator Property<T>(T value)
{
return new Property<T> { Value = value };
}
}
I replace my property (with backing objects) with the new Generic Property like:
public Property<RepositoryAccount> Account { get; set; }
public Property<RepositoryInquiry> Inquiry { get; set; }
public Property<RepositoryLoan> Loan { get; set; }
However, if you noticed in the original public getter, I need to instantiate each object with another object: this is required and there is no paramaterless constructor for these repository objects.
Any suggestions?
The whole object looks like:
public class UnitOfWorkSymitar : IUnitOfWork
{
#region Properties
internal IPHostEntry IpHostInfo;
internal IPAddress IpAddress;
internal IPEndPoint RemotEndPoint;
internal System.Net.Sockets.Socket Sender;
internal byte[] Bytes = new byte[1024];
internal bool IsAllowedToRun = false;
internal string SymServerIp;
internal int SymPort;
public string State { get; set; }
#endregion
#region Constructor
public UnitOfWorkSymitar() { OpenSymitarConnection(); }
protected UnitOfWorkSymitar(string serverIp, int? port) { OpenSymitarConnection(serverIp, port); }
#endregion
#region Implement IUnitOfWork
public void Commit() { /* No commit on this socket connection */ }
public void Rollback() { /* No rollback on this socket connection */ }
#endregion
#region Implement IDisposable
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose()
{
CloseSymitarConnection();
}
#endregion
#region Private Helpers
/// <summary>
/// Connect to a remote device.
/// </summary>
/// <returns>Success/failure message</returns>
private string OpenSymitarConnection(string serverIp = null, int? port = null)
{
var config = ConfigInfoSymitar.Instance;
SymServerIp = serverIp ?? config.SymServerIp;
SymPort = port ?? config.SymPort;
try
{
// Establish the remote endpoint for the socket.
//IpHostInfo = Dns.GetHostEntry(SymServerIp);
//IpAddress = IpHostInfo.AddressList[0];
IpAddress = Dns.GetHostAddresses(SymServerIp)[0];
RemotEndPoint = new IPEndPoint(IpAddress, SymPort);
// Create a TCP/IP socket.
Sender = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors.
Sender.Connect(RemotEndPoint);
}
catch (Exception ex)
{
State = DetermineError(ex);
return State;
//throw;
}
IsAllowedToRun = true;
State = "Success";
return State;
}
/// <summary>
/// Setup and send the request
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public string SendMessage(string request)
{
try
{
// Encode the data string into a byte array and add the carriage return for SymConnect.
var msg = Encoding.ASCII.GetBytes(request);
if(!request.EndsWith("\n"))
msg = Encoding.ASCII.GetBytes(request + "\n");
// Send the data through the socket.
var bytesSent = Sender.Send(msg);
// Receive the response from the remote device.
var bytesRec = Sender.Receive(Bytes);
var response = Encoding.ASCII.GetString(Bytes, 0, bytesRec);
response = response.Replace("\n", "");
return response;
}
catch (Exception ex)
{
return DetermineError(ex);
}
}
/// <summary>
/// Close the connection to a remote device.
/// </summary>
/// <returns></returns>
private string CloseSymitarConnection()
{
try
{
// Release the socket.
Sender.Shutdown(SocketShutdown.Both);
Sender.Close();
}
catch (Exception ex)
{
return DetermineError(ex);
}
finally
{
IsAllowedToRun = false;
}
return "Success!";
}
/// <summary>
/// Determine if this is an Arguments, Socket or some other exception
/// </summary>
/// <param name="ex">The exception to be checked</param>
/// <returns>String message</returns>
private static string DetermineError(Exception ex)
{
if (ex.GetType() == typeof(ArgumentNullException))
return "Missing Arguments: " + Environment.NewLine + ex.GetFullMessage();
if (ex.GetType() == typeof(SocketException))
return "Socket Error: " + Environment.NewLine + ex.GetFullMessage();
return "Unexpected Error: " + Environment.NewLine + ex.GetFullMessage();
}
#endregion
#region Symitar Samples
private static string ExecSymConnectRequest(string symServerIP, int symPort, string request)
{
// Data buffer for incoming data.
var bytes = new byte[1024];
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
// This example uses port 11000 on the local computer.
var ipHostInfo = Dns.GetHostEntry(symServerIP);
var ipAddress = ipHostInfo.AddressList[0];
var remoteEP = new IPEndPoint(ipAddress, symPort);
// Create a TCP/IP socket.
var sender = new System.Net.Sockets.Socket(AddressFamily.InterNetwork
, SocketType.Stream
, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors.
try
{
sender.Connect(remoteEP);
// Encode the data string into a byte array and add the carriage return for SymConnect.
var msg = Encoding.ASCII.GetBytes(request + "\n");
// Send the data through the socket.
var bytesSent = sender.Send(msg);
// Receive the response from the remote device.
var bytesRec = sender.Receive(bytes);
var response = Encoding.ASCII.GetString(bytes, 0, bytesRec);
// Release the socket.
sender.Shutdown(SocketShutdown.Both);
sender.Close();
response.Replace("\n", "");
return response;
}
catch (ArgumentNullException ane)
{
return "Missing Arguments: " + ane.Message;
}
catch (SocketException se)
{
return "Socket Error: " + se.Message;
}
catch (Exception e)
{
return "Unexpected Error: " + e.Message;
}
}
catch (Exception e)
{
return e.Message;
}
}
#endregion
#region Repositories
private RepositoryAccount _account;
private RepositoryInquiry _inquiry;
private RepositoryLoan _loan;
public RepositoryAccount Account { get { return _account ?? (_account = new RepositoryAccount(this)); } }
public RepositoryInquiry Inquiry { get { return _inquiry ?? (_inquiry = new RepositoryInquiry(this)); } }
public RepositoryLoan Loan { get { return _loan ?? (_loan = new RepositoryLoan(this)); } }
#endregion
}
Might try something like:
class Program {
Property<string> Foo = new Property<string>(() => "FOO!");
}
public class Property<T> where T : class {
private Lazy<T> instance;
public Property(Func<T> generator) {
instance = new Lazy<T>(generator);
}
public T Value {
get { return instance.Value; }
}
public static implicit operator T(Property<T> value) {
return value.Value;
}
public static implicit operator Property<T>(T value) {
return new Property<T>(() => value);
}
}
There is a solution using reflection although it might not be the cleanest OOP one. A method of the FormatterService class in the System.Runtime namespace FormatterServices.GetUninitializedObject() will create an instance without calling the constructor. There is a similar answer to this problem here.
In order to make it work with your solution you have to make some changes to your code. First of all remove the new() from your generic class Property declaration otherwise you will always get an error from the compiler if you try to use a type T with no parameter-less constructor. Second add this method to your Property class:
private T GetInstance()
{
return (T)FormatterServices.GetUninitializedObject(typeof(T)); //does not call ctor
}
It will return an unitialized object but it won't call the constructor.
Here is the full code:
public class Property<T> where T : class
{
private T _value;
public T Value
{
get
{
return _value ?? (_value = GetInstance());
}
set
{
// insert desired logic here
_value = value;
}
}
private T GetInstance()
{
return (T)FormatterServices.GetUninitializedObject(typeof(T)); //does not call ctor
}
public static implicit operator T(Property<T> value)
{
return value.Value;
}
public static implicit operator Property<T>(T value)
{
return new Property<T> { Value = value };
}
}
I created a gist here, you can try the code into LinqPad and see the result.
hope it helps.
I have a WCF service that creates a private message in MSMQ. The messages are being created fine, and I can see the messages that my client application is creating.
I also have a MSMQ listener service that seems to run fine. When I start the service up, it appears to successfully "process" the messages in the queue and they are removed. However, the implementation of my listener service doesn't seem to get executed.
I'm fairly new to MSMQ, and I have no idea why the messages are being removed from the queue, and why the code in my listener method is not getting executed.
Below are my service classes...
[ServiceContract(Namespace = ServiceConstants.NAMESPACE, Name = "IOrderService")]
public interface IOrderQueueProcessingService
{
[OperationContract(IsOneWay = true, Action = "*")]
void ProcessOrderQueue(MsmqMessage<string> message);
}
public abstract class OrderQueueProcessingServiceBase : ServiceBase, IOrderQueueProcessingService
{
#region CONSTRUCTORS
protected OrderQueueProcessingServiceBase() { }
protected OrderQueueProcessingServiceBase(List<EventRecord> existingList) : base(existingList) { }
#endregion //CONSTRUCTORS
#region IOrderQueueProcessingService Members
[OperationBehavior(TransactionScopeRequired = false, TransactionAutoComplete = true)]
public virtual void ProcessOrderQueue(MsmqMessage<string> message)
{
throw new NotImplementedException();
}
#endregion
}
public class OrderQueueProcessingService : OrderQueueProcessingServiceBase
{
#region Constructors
public OrderQueueProcessingService() {}
public OrderQueueProcessingService(List<EventRecord> existingList) : base(existingList) { }
#endregion
/// <summary>
/// Processes any Orders in the Orders Queue
/// </summary>
/// <param name="message"></param>
public override void ProcessOrderQueue(MsmqMessage<string> message)
{
var q = new MessageQueue(#".\private$\msmqdemo/submitorderservice.svc");
q.Send("hey");
/*
using (new Tracer("OrderQueueProcessingService"))
{
// add data context to work with.
using (var unitOfWork = new TLFDataContext())
{
var newOrderLines = new List<OrderLineDataContract>
{
new OrderLineDataContract
{
C = "test",
IC = "msw",
Qty = 1,
T = "volume" ,
ED = DateTime.UtcNow.AddDays(5)
}
};
var newOrder = new OrderDataContract
{
LIs = newOrderLines.AsEnumerable(),
PId = 9323,
POId = 8686,
S = "new"
};
var orderService = new OrderService();
var createdOrder = orderService.CreateOrder(null, null, newOrder);
//unitOfWork.SubmitUnitOfWork();
//return null;
}
}*/
}
}
I commented out the code that I am eventually trying to execute, and replaced it with a simple MSMQ message send, for testing. This seems like it should work fine. Any help would be greatly appreciated.
Config settings below...
<service name="ServiceImplementation.OrderQueueProcessingService">
<host>
<baseAddresses>
<add baseAddress="https://localhost:9000/OrderQueueProcessingService.svc" />
</baseAddresses>
</host>
<endpoint address="net.msmq://localhost/private/testingqueue/OrderQueueProcessingService.svc" binding="netMsmqBinding" bindingConfiguration="MsmqBindingNonTransactionalNoSecurity" contract="IOrderQueueProcessingService" />
</service>
I was able to figure out my issue. I didn't have any event handling for the QueueOnPeekComplted event. I added that to an Initialize method, and was able to successfully process my messages. I also added handling of messages that could not be processed. Below is my new implementation of my OrderQueueProcessingService.
public class OrderQueueProcessingService : OrderQueueProcessingServiceBase, IDisposable
{
#region Constructors
public OrderQueueProcessingService()
{
Initialize(ConfigurationManager.AppSettings["OrderQueueProcessingQueueName"]);
}
public OrderQueueProcessingService(List<EventRecord> existingList) : base(existingList) {}
#endregion
#region Properties
private MessageQueue Queue { get; set; }
#endregion
#region IDisposable Members
public new void Dispose()
{
if (Queue == null) return;
//unsubscribe and dispose
Queue.PeekCompleted -= QueueOnPeekCompleted;
Queue.Dispose();
}
#endregion
private void Initialize(string queueName)
{
Queue = new MessageQueue(queueName, false, true, QueueAccessMode.Receive)
{
Formatter = new XmlMessageFormatter(new[] {typeof (OrderQueueDataContract)})
};
//setup events and start.
Queue.PeekCompleted += QueueOnPeekCompleted;
Queue.BeginPeek();
}
private static void MoveMessageToDeadLetter(IDisposable message)
{
var q = new MessageQueue(ConfigurationManager.AppSettings["OrderProcessingDLQ"], QueueAccessMode.Send)
{
Formatter = new XmlMessageFormatter(new[] {typeof (OrderQueueDataContract)})
};
q.Send(message, MessageQueueTransactionType.Single);
q.Dispose();
}
/// <summary>
/// Processes the specified Order message
/// </summary>
/// <param name="orderMessage"></param>
public override void ProcessOrderQueue(OrderQueueDataContract orderMessage)
{
using (var unitOfWork = new MyDataContext())
{
switch (orderMessage.M.ToLower())
{
case "create":
DataAccessLayer.CreateOrder(unitOfWork, orderMessage.O.TranslateToBe());
break;
default:
break;
}
}
}
private void QueueOnPeekCompleted(object sender, PeekCompletedEventArgs peekCompletedEventArgs)
{
var asyncQueue = (MessageQueue) sender;
using (var transaction = new MessageQueueTransaction())
{
transaction.Begin();
try
{
using (var message = asyncQueue.ReceiveById(peekCompletedEventArgs.Message.Id, TimeSpan.FromSeconds(30), transaction))
{
if (message != null) ProcessOrderQueue((OrderQueueDataContract) message.Body);
}
}
catch (InvalidOperationException ex)
{
transaction.Abort();
}
catch (Exception ex)
{
transaction.Abort();
}
if (transaction.Status != MessageQueueTransactionStatus.Aborted) transaction.Commit();
else
{
using (var message = asyncQueue.ReceiveById(peekCompletedEventArgs.Message.Id, TimeSpan.FromSeconds(30), transaction))
{
if (message != null)
{
MoveMessageToDeadLetter(message);
message.Dispose();
}
}
EventLog.WriteEntry("OrderQueueProcessingService", "Could not process message: " + peekCompletedEventArgs.Message.Id);
}
transaction.Dispose();
}
asyncQueue.EndPeek(peekCompletedEventArgs.AsyncResult);
asyncQueue.BeginPeek();
}
}
Does anyone see any issues with this implementation? I had to fiddle with it quite a bit, but it has passed unit testing, and process testing.
One thing that I noticed is that when my service first starts up, it processes all the messages in the queue; which could potentially hold up the starting of my other services. This may only be an issue when I'm starting them in my console app while testing. To be safe I start this service last.
I have made a WCF publisher Subscriber service which handles 70 to 80 connections per day
If a connection breaks in between ( due to internet connection failure , System shutdown etc.)
the service itself will try to set up a connection itself when the connectivity resumes.
sometime back I am noticed my service is throwing exceptions (operation Timed out)
This request operation sent to net.tcp://localhost:2001/sub did not receive a reply within the configured timeout (00:00:59.9799877). The time allotted to this operation may have been a portion of a longer timeout. This may be because the service is still processing the operation or because the service was unable to send a reply message. Please consider increasing the operation timeout (by casting the channel/proxy to IContextChannel and setting the OperationTimeout property) and ensure that the service is able to connect to the client
and then after some of these Exceptions RM destination time out exceptions are coming up which faults the line for further communication with the service
The request to create a reliable session has been refused by the RM Destination. Server
'net.tcp://localhost:2001/Sub' is too busy to process this request. Try again later. The channel could not be opened.
During this time the the clients already subscribed are responding successfully to the pub sub requests
No new Channels are subscribing to the service
I am using net Tcp binding in the Service
client code
public class Subscriber : IPublishing
{
static int Counter = 0;
ISubscription _proxy;
string _endpoint = string.Empty;
public Subscriber()
{
_endpoint = "net.tcp://localhost:2001/sub";
MakeProxy(_endpoint, this);
}
void MakeProxy(string EndpoindAddress, object callbackinstance)
{
try
{
NetTcpBinding netTcpbinding = new NetTcpBinding(SecurityMode.None);
EndpointAddress endpointAddress = new EndpointAddress(EndpoindAddress);
InstanceContext context = new InstanceContext(callbackinstance);
// Added for Reliable communication
netTcpbinding.ReliableSession.Enabled = true;
netTcpbinding.ReliableSession.Ordered = true;
netTcpbinding.MaxBufferSize = 2147483647;
netTcpbinding.MaxBufferPoolSize = 2147483647;
netTcpbinding.MaxReceivedMessageSize = 2147483647;
netTcpbinding.ReliableSession.InactivityTimeout = TimeSpan.MaxValue;
netTcpbinding.ReceiveTimeout = TimeSpan.MaxValue;
DuplexChannelFactory<ISubscription> channelFactory = new DuplexChannelFactory<ISubscription>(new InstanceContext(this), netTcpbinding, endpointAddress);
_proxy = channelFactory.CreateChannel();
Counter++;
}
catch (Exception ex)
{
//
}
}
public void Subscribe()
{
try
{
_proxy.Subscribe("500");
Counter = 0;
}
catch (Exception ex)
{
((IContextChannel)_proxy).Abort();
}
}
public void Publish(Message e, String ID)
{
}
public void _Subscribe()
{
try
{
//OnUnSubscribe();
Subscribe();
}
catch (Exception ex)
{
}
}
}
Server Code
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
class Subscription : ISubscription
{
#region ISubscription Members
public void Subscribe(string ID)
{
String s = DateTime.Now.ToString(
IPublishing subscriber = OperationContext.Current.GetCallbackChannel<IPublishing>();
Filter.AddSubscriber(KioskID, subscriber);
}
public void UnSubscribe(string ID)
{
IPublishing subscriber = OperationContext.Current.GetCallbackChannel<IPublishing>();
Filter.RemoveSubscriber(KioskID, subscriber);
}
#endregion
}
class Filter
{
static Dictionary<string, List<IPublishing>> _subscribersList = new Dictionary<string, List<IPublishing>>();
static public Dictionary<string, List<IPublishing>> SubscribersList
{
get
{
lock (typeof(Filter))
{
return _subscribersList;
}
}
}
static public List<IPublishing> GetSubscribers(String topicName)
{
lock (typeof(Filter))
{
if (SubscribersList.ContainsKey(topicName))
{
return SubscribersList[topicName];
}
else
return null;
}
}
static public void AddSubscriber(String topicName, IPublishing subscriberCallbackReference)
{
DebugLog.WriteLog("C:\\DevPubSubServiceLogs", topicName + "came for Sub");
lock (typeof(Filter))
{
DebugLog.WriteLog("C:\\DevPubSubServiceLogs",topicName + "inside lock");
if (SubscribersList.ContainsKey(topicName))
{
// Removing any stray subscribers for same topic name
// because only 1 subscriber for 1 topic name should exist
SubscribersList.Remove(topicName);
}
List<IPublishing> newSubscribersList = new List<IPublishing>();
newSubscribersList.Add(subscriberCallbackReference);
SubscribersList.Add(topicName, newSubscribersList);
}
DebugLog.WriteLog("C:\\DevPubSubServiceLogs", topicName + "subscribed");
}
static public void RemoveSubscriber(String topicName, IPublishing subscriberCallbackReference)
{
lock (typeof(Filter))
{
if (SubscribersList.ContainsKey(topicName))
{
//if (SubscribersList[topicName].Contains(subscriberCallbackReference))
//{
// SubscribersList[topicName].Remove(subscriberCallbackReference);
//}
SubscribersList.Remove(topicName);
}
}
}
}
Contracts
[ServiceContract]
public interface IPublishing
{
[OperationContract(IsOneWay = true)]
void Publish(Message e, string ID);
}
[ServiceContract(CallbackContract = typeof(IPublishing))]
public interface ISubscription
{
[OperationContract]
void Subscribe(string topicName);
[OperationContract]
void UnSubscribe(string topicName);
}
Please assist..
I have two apps, app1.cs and app2.cs (codes below). In addition I also have a dll I extracted from refer.cs(code below). When I compile app1.cs(which sends a measurement object) I get the following exception:
Unhandled Exception: RabbitMQ.Client.Exceptions.OperationInterruptioedException
I can't see how the connection is interrupted. Do you see where the problem is caused at?
Regards,
Demi
//refer.cs from which refer.dll is created
using System;
using System.IO;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace refer
{
//start alternate serialization
public static class AltSerialization
{
public static byte[] AltSerialize(Measurement m)
{
using (var ms = new MemoryStream())
{
var bf = new BinaryFormatter();
bf.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
bf.Serialize(ms, m);
return ms.GetBuffer();
}
}
public static Measurement AltDeSerialize(byte[] seriM)
{
using (var stream = new MemoryStream( seriM ))
{
BinaryFormatter bf = new BinaryFormatter();
bf.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
return (Measurement)bf.Deserialize(stream);
}
}
}
//end alternte serialization
[Serializable] //This attribute sets class to be serialized
public class Measurement : ISerializable
{
[NonSerialized] public int id;
public int time; //timestamp
public double value;
public Measurement()
{
id = 1;
time = 12;
value = 0.01;
}
public Measurement(int _id, int _time, double _value)
{
id = _id;
time = _time;
value = _value;
}
//Deserialization constructor
public Measurement(SerializationInfo info, StreamingContext ctxt)
{
//Assign the values from info to the approporiate properties
Console.WriteLine("DeSerialization construtor called.");
time = (int)info.GetValue("MeasurementTime", typeof(int));
value = (double)info.GetValue("MeasurementValue", typeof(double));
}
//Serialization function
public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
{
// Custom name-value pair
// Values must be read with the same name they're written
info.AddValue("MeasurementTime", time);
info.AddValue("MeasurementValue", value);
}
}
}
//MB1.cs
using System;
using System.IO;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using UtilityMeasurement;
public interface IMessageBus
{
string MsgSys // Property 1
{
get;
set;
}
void write (Measurement m1);
Measurement read();
void publish(string queue);
void subscribe(string queue);
}
public class Rabbit : IMessageBus
{
// Implementation of methods for Rabbit class go here
private List<string> publishQ = new List<string>();
private List<string> subscribeQ = new List<string>();
public void write ( Measurement m1 )
{
byte[] body = Measurement.AltSerialize( m1 );
IConnection connection = factory.CreateConnection();
IModel channel = connection.CreateModel();
foreach (string queue in publishQ)
{
channel.BasicPublish("", queue, null, body);
Console.WriteLine("\n [x] Sent to queue {0}.", queue);
}
}
public void publish(string queueName)
{
channel.QueueDeclare(queueName, true, false, false, null); //durable=true
publishQ.Add(queueName); //and, add it the list of queue names to publish to
}
public Measurement read()
{
QueueingBasicConsumer consumer = new QueueingBasicConsumer(channel);
foreach (string queue in subscribeQ)
{
channel.BasicConsume(queue, true, consumer);
}
System.Console.WriteLine(" [*] Waiting for messages." +
"To exit press CTRL+C");
BasicDeliverEventArgs ea =
(BasicDeliverEventArgs)consumer.Queue.Dequeue();
return Measurement.AltDeSerialize(ea.Body);
}
public void subscribe(string queueName)
{
channel.QueueDeclare(queueName, true, false, false, null);
subscribeQ.Add(queueName);
}
public static string MsgSysName;
public string MsgSys
{
get
{
return MsgSysName;
}
set
{
MsgSysName = value;
}
}
public Rabbit(string _msgSys) //Constructor
{
ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "localhost";
System.Console.WriteLine("\nMsgSys: RabbitMQ");
MsgSys = _msgSys;
}
}
public class Zmq : IMessageBus
{
public void write ( Measurement m1 )
{
//
}
public Measurement read()
{
//
return null;
}
public void publish(string queue)
{
//
}
public void subscribe(string queue)
{
//
}
public static string MsgSysName;
public string MsgSys
{
get
{
return MsgSysName;
}
set
{
MsgSysName = value;
}
}
// Implementation of methods for Zmq class go here
public Zmq(string _msgSys) //Constructor
{
System.Console.WriteLine("ZMQ");
MsgSys = _msgSys;
}
}
public class MessageBusFactory
{
public static IMessageBus GetMessageBus(string MsgSysName)
{
switch ( MsgSysName )
{
case "Zmq":
return new Zmq(MsgSysName);
case "Rabbit":
return new Rabbit(MsgSysName);
default:
throw new ArgumentException("Messaging type " +
MsgSysName + " not supported." );
}
}
}
public class MainClass
{
public static void Main()
{
//Asks for the message system
System.Console.WriteLine("\nEnter name of messageing system: ");
System.Console.WriteLine("Usage: [Rabbit] [Zmq]");
string MsgSysName = (System.Console.ReadLine()).ToString();
//Create a new Measurement message
Measurement m1 = new Measurement(2, 2345, 23.456);
//Declare an IMessageBus instance:
//Here, an object of the corresponding Message System
// (ex. Rabbit, Zmq, etc) is instantiated
IMessageBus obj1 = MessageBusFactory.GetMessageBus(MsgSysName);
System.Console.WriteLine("\nA {0} object is now created.", MsgSysName);
System.Console.WriteLine("With Test message:\n ID: {0}", m1.id);
System.Console.WriteLine(" Time: {0}", m1.time);
System.Console.WriteLine(" Value: {0}", m1.value);
// Ask queue name and store it
System.Console.WriteLine("Enter a queue name to publish the message to: ");
string QueueName = (System.Console.ReadLine()).ToString();
obj1.publish( QueueName );
System.Console.WriteLine("Enter another queue name: ");
QueueName = (System.Console.ReadLine()).ToString();
obj1.publish( QueueName );
// Write message to the queue
obj1.write( m1 );
}
}
//MB2.cs
using System;
using System.IO;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using UtilityMeasurement;
public interface IMessageBus
{
string MsgSys // Property 1
{
get;
set;
}
void write (Measurement m1);
Measurement read();
void publish(string queue);
void subscribe(string queue);
}
public class Rabbit : IMessageBus
{
// Implementation of methods for Rabbit class go here
private List<string> publishQ = new List<string>();
private List<string> subscribeQ = new List<string>();
public void write ( Measurement m1 )
{
byte[] body = Measurement.AltSerialize( m1 );
IConnection connection = factory.CreateConnection();
IModel channel = connection.CreateModel();
foreach (string queue in publishQ)
{
channel.BasicPublish("", queue, null, body);
Console.WriteLine("\n [x] Sent to queue {0}.", queue);
}
}
public void publish(string queueName)
{
channel.QueueDeclare(queueName, true, false, false, null); //durable=true
publishQ.Add(queueName); //and, add it the list of queue names to publish to
}
public Measurement read()
{
QueueingBasicConsumer consumer = new QueueingBasicConsumer(channel);
foreach (string queue in subscribeQ)
{
channel.BasicConsume(queue, true, consumer);
}
System.Console.WriteLine(" [*] Waiting for messages." +
"To exit press CTRL+C");
BasicDeliverEventArgs ea =
(BasicDeliverEventArgs)consumer.Queue.Dequeue();
return Measurement.AltDeSerialize(ea.Body);
}
public void subscribe(string queueName)
{
channel.QueueDeclare(queueName, true, false, false, null);
subscribeQ.Add(queueName);
}
public static string MsgSysName;
public string MsgSys
{
get
{
return MsgSysName;
}
set
{
MsgSysName = value;
}
}
public Rabbit(string _msgSys) //Constructor
{
ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "localhost";
System.Console.WriteLine("\nMsgSys: RabbitMQ");
MsgSys = _msgSys;
}
}
public class Zmq : IMessageBus
{
public void write ( Measurement m1 )
{
//
}
public Measurement read()
{
//
return null;
}
public void publish(string queue)
{
//
}
public void subscribe(string queue)
{
//
}
public static string MsgSysName;
public string MsgSys
{
get
{
return MsgSysName;
}
set
{
MsgSysName = value;
}
}
// Implementation of methods for Zmq class go here
public Zmq(string _msgSys) //Constructor
{
System.Console.WriteLine("ZMQ");
MsgSys = _msgSys;
}
}
public class MessageBusFactory
{
public static IMessageBus GetMessageBus(string MsgSysName)
{
switch ( MsgSysName )
{
case "Zmq":
return new Zmq(MsgSysName);
case "Rabbit":
return new Rabbit(MsgSysName);
default:
throw new ArgumentException("Messaging type " +
MsgSysName + " not supported." );
}
}
}
public class MainClass
{
public static void Main()
{
//Asks for the message system
System.Console.WriteLine("\nEnter name of messageing system: ");
System.Console.WriteLine("Usage: [Rabbit] [Zmq]");
string MsgSysName = (System.Console.ReadLine()).ToString();
//Declare an IMessageBus instance:
//Here, an object of the corresponding Message System
// (ex. Rabbit, Zmq, etc) is instantiated
IMessageBus obj1 = MessageBusFactory.GetMessageBus(MsgSysName);
System.Console.WriteLine("\nA {0} object is now created.", MsgSysName);
System.Console.WriteLine("Enter a queue to subscribe to: ");
string QueueName = (System.Console.ReadLine()).ToString();
obj1.subscribe( QueueName );
//Create a new Measurement object m2
Measurement m2 = new Measurement();
//Read message into m2
m2 = obj1.read();
m2.id = 11;
System.Console.WriteLine("\nMessage received from queue {0}:\n ID: {1}",QueueName, m2.id);
System.Console.WriteLine(" Time: {0}", m2.time);
System.Console.WriteLine(" Value: {0}", m2.value);
}
}
I just created a vanilla C# VS2010 Console application project with the Refer.cs and App1.cs in the same project.
I made the following changes:
Added RabbitMQ.Client.dll
Removed the AssemblyVersion attributes
Added string[] args to the Main method in App1.cs
Also, I changed:
factory.HostName = "localhost";
To this:
factory.HostName = "192.168.56.101";
Which is the ip address to my VirtualBox Ubuntu VM running rabbitmq-server. There was no exception thrown, and the message successfully was received on the server.
All signs point to server configuration with what is given. My guess is either your rabbitmq-server is not running at all, it's not running on localhost, or there is some kind of connectivity issue with port 5672.