Akka.NET Configuration settings for remoting - c#

I am using the example on the Akka.NET github to play with some basic remoting.
In the remoting example available from GitHub there is the following section in the configuration string for Akka.NET.
deployment {
/localactor {
router = round-robin-pool
nr-of-instances = 5
}
/remoteactor {
router = round-robin-pool
nr-of-instances = 5
remote = ""akka.tcp://system2#localhost:666""
}
}
remote {
dot-netty.tcp {
port = 1234
hostname = localhost
}
What does the forward slash / indicate? is this a comment or is this just the format of the files?
What does the router option 'round-robin-pool' control? I can see that it maps to the following class but I am hoping someone can explain what akka.routing actually means in the context of a remoting scenario? I am assuming this has something to do with how urls or ips are mapped?
Any clarification would be appreciated.

Consider the following snippet from the example:
/localactor {
router = round-robin-pool
nr-of-instances = 5
}
What does the forward slash / indicate? is this a comment or is this just the format of the files?
The forward slash is not a comment; it indicates the name of an actor. The code in the example refers to the actor named localactor in the following way:
var local = system.ActorOf(Props.Create(() => new SomeActor("hello", 123)).WithRouter(FromConfig.Instance), "localactor");
What does the router option 'round-robin-pool' control? I can see that it maps to the following class but I am hoping someone can explain what akka.routing actually means in the context of a remoting scenario? I am assuming this has something to do with how urls or ips are mapped?
round-robin-pool is used to define a router. localactor in the above configuration snippet is a router actor that creates a pool of five routee instances to which it routes messages in round-robin order. A router has no special meaning in a remoting context; it is essentially no different from a router in a non-remoting scenario. You can read more about routers in the linked documentation.

Related

Set Custom Host Name as part of changing the Endpoint Address of a Soap Client

I am presently in a scenario where I need to have multiple servers that live behind a Load Balancer talk to each other directly, and I need to communicate with specific servers for PUSH notifications. This is for a chat tool that requires users that have been moved to different servers by a load balancer to still be able to talk to one another live.
The actual pushes are being handled with Signal-R, and I have all of that working. So here is the actual complication:
Normally, this would be simple enough to do by targeting them via IP Address to bypass the load balancer. However, this is complicated because the servers expects a specific Host name or it will reject the request.
I know it is possible to do this with a WebRequest, but would like to avoid having to build a proxy if I can help it.
Here is the piece I have where I'm trying to send a global push to tell everyone across all connected servers to update their buddy lists because someone logged in or out.
private void NotifyUsersChangedGlobal()
{
List<string> addressesToNotify = ChatUsers.Select(x => x.ServerIP).Distinct().ToList();
foreach (string address in addressesToNotify)
{
ChatUplinkSoapClient client = BuildClient(address);
client.NotifyUsersChanged();
}
}
And this is the Client Builder where (I assume) I need to handle assigning the custom Host name to ride on top of the IP Address
private ChatUplinkSoapClient BuildClient(string endpointIP)
{
string relativeUrl = "/WebServices/ChatUplink.asmx";
//Turn on HTTPS
HttpBindingBase binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
//Link together the IP Address and the asmx route
EndpointAddress endpoint = new EndpointAddress(endpointIP + relativeUrl);
//Make the Client
ChatUplinkSoapClient client = new ChatUplinkSoapClient(binding, endpoint);
//Need to set Host header to "HostHeaderName", or the server will reject the request.
return client;
}
Ideas?

Sending to Azure Event Hub Error

I'm completely brand new to C#, Microsoft Azure, and basically everything. I'm trying to set up an Azure Event Hub that I can send data to. Right now I'm just following the tutorial that can be found here.
It builds just fine, but I receive the same exception every time. The message is the following: An existing connection was forcibly closed by the remote host. This question has been asked before but never answered.
Just to be sure I'm doing this right I'm attaching pictures with where I obtained the values for the Event Hub Connection String and the Hub Name.
Where I got the Event Hub Connection String from.
This one is within the namespace - not the hub itself.
Where I got the Hub Name from.
The code goes as follows:
private const string EventHubConnectionString = "<Connection String>";
private const string EventHubName = "eventhubtest";
Does the Hub Name have to be simply that or a path? Any ideas or help would be greatly appreciated. Thanks.
#Jamie Penzien, I had been stuck with this exact same error for days and my colleague asked me to change the following part and it worked.
var connectionStringBuilder = new EventHubsConnectionStringBuilder(EventHubConnectionString)
{
EntityPath = EventHubName,
TransportType = TransportType.AmqpWebSockets
};
I am still trying to understand the reason, and it may have something to do with the company's firewall settings.
Eventhub name or Entity Path would be simply the name of EventHub found under an EventHub namespace.
You can use below code to create client:
EventHubClient eventHubClient;
var connectionStringBuilder = new EventHubsConnectionStringBuilder(EventHubConnectionString)
{
EntityPath = EventHubName
};
eventHubClient = EventHubClient.CreateFromConnectionString(connectionStringBuilder.ToString());
EventHubsConnectionStringBuilder can be found under Microsoft.Azure.EventHubs package.
I answered my own questions. First, I needed to change the connection string and make sure it contained the entity path within it. Then when establishing the hub client I did this:
eventHubClient = EventHubClient.CreateFromConnectionString(EventHubConnectionString);
HOWEVER, I was getting this exception specifically because of a firewall issue. I have to open ports (working on it right now) to allow outbound communication to the event hub. I believe these are ports 5671 and 5672.
Thank you to all that answered and #RayX who nailed it on the head.

Finding Connection by UserId in SignalR

I have a webpage that uses ajax polling to get stock market updates from the server. I'd like to use SignalR instead, but I'm having trouble understanding how/if it would work.
ok, it's not really stock market updates, but the analogy works.
The SignalR examples I've seen send messages to either the current connection, all connections, or groups. In my example the stock updates happen outside of the current connection, so there's no such thing as the 'current connection'. And a user's account is associated with a few stocks, so sending a stock notification to all connections or to groups doesn't work either. I need to be able to find a connection associated with a certain userId.
Here's a fake code example:
foreach(var stock in StockService.GetStocksWithBigNews())
{
var userIds = UserService.GetUserIdsThatCareAboutStock(stock);
var connections = /* find connections associated with user ids */;
foreach(var connection in connections)
{
connection.Send(...);
}
}
In this question on filtering connections, they mention that I could keep current connections in memory but (1) it's bad for scaling and (2) it's bad for multi node websites. Both of these points are critically important to our current application. That makes me think I'd have to send a message out to all nodes to find users connected to each node >> my brain explodes in confusion.
THE QUESTION
How do I find a connection for a specific user that is scalable? Am I thinking about this the wrong way?
I created a little project last night to learn this also. I used 1.0 alpha and it was Straight forward. I created a Hub and from there on it just worked :)
I my project i have N Compute Units(some servers processing work), when they start up they invoke the ComputeUnitRegister.
await HubProxy.Invoke("ComputeUnitReqisted", _ComputeGuid);
and every time they do something they call
HubProxy.Invoke("Running", _ComputeGuid);
where HubProxy is :
HubConnection Hub = new HubConnection(RoleEnvironment.IsAvailable ?
RoleEnvironment.GetConfigurationSettingValue("SignalREndPoint"):
"http://taskqueue.cloudapp.net/");
IHubProxy HubProxy = Hub.CreateHubProxy("ComputeUnits");
I used RoleEnviroment.IsAvailable because i can now run this as a Azure Role , a Console App or what ever in .NET 4.5. The Hub is placed in a MVC4 Website project and is started like this:
GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromSeconds(50);
RouteTable.Routes.MapHubs();
public class ComputeUnits : Hub
{
public Task Running(Guid MyGuid)
{
return Clients.Group(MyGuid.ToString()).ComputeUnitHeartBeat(MyGuid,
DateTime.UtcNow.ToEpochMilliseconds());
}
public Task ComputeUnitReqister(Guid MyGuid)
{
Groups.Add(Context.ConnectionId, "ComputeUnits").Wait();
return Clients.Others.ComputeUnitCameOnline(new { Guid = MyGuid,
HeartBeat = DateTime.UtcNow.ToEpochMilliseconds() });
}
public void SubscribeToHeartBeats(Guid MyGuid)
{
Groups.Add(Context.ConnectionId, MyGuid.ToString());
}
}
My clients are Javascript clients, that have methods for(let me know if you need to see the code for this also). But basicly they listhen for the ComputeUnitCameOnline and when its run they call on the server SubscribeToHeartBeats. This means that whenever the server compute unit is doing some work it will call Running, which will trigger a ComputeUnitHeartBeat on javascript clients.
I hope you can use this to see how Groups and Connections can be used. And last, its also scaled out over multiply azure roles by adding a few lines of code:
GlobalHost.HubPipeline.EnableAutoRejoiningGroups();
GlobalHost.DependencyResolver.UseServiceBus(
serviceBusConnectionString,
2,
3,
GetRoleInstanceNumber(),
topicPathPrefix /* the prefix applied to the name of each topic used */
);
You can get the connection string on the servicebus on azure, remember the Provider=SharedSecret. But when adding the nuget packaged the connectionstring syntax is also pasted into your web.config.
2 is how many topics to split it about. Topics can contain 1Gb of data, so depending on performance you can increase it.
3 is the number of nodes to split it out on. I used 3 because i have 2 Azure Instances, and my localhost. You can get the RoleNumber like this (note that i hard coded my localhost to 2).
private static int GetRoleInstanceNumber()
{
if (!RoleEnvironment.IsAvailable)
return 2;
var roleInstanceId = RoleEnvironment.CurrentRoleInstance.Id;
var li1 = roleInstanceId.LastIndexOf(".");
var li2 = roleInstanceId.LastIndexOf("_");
var roleInstanceNo = roleInstanceId.Substring(Math.Max(li1, li2) + 1);
return Int32.Parse(roleInstanceNo);
}
You can see it all live at : http://taskqueue.cloudapp.net/#/compute-units
When using SignalR, after a client has connected to the server they are served up a Connection ID (this is essential to providing real time communication). Yes this is stored in memory but SignalR also can be used in multi-node environments. You can use the Redis or even Sql Server backplane (more to come) for example. So long story short, we take care of your scale-out scenarios for you via backplanes/service bus' without you having to worry about it.

WP7 Mango - How to get an IP address for a given hostname

I need to get an IP address for a given hostname from a DnsEndPoint, and convert it to an IPEndPoint. How would I go about doing this? WP7 lacks a Dns.GetHostEntry function, so is there any way to do this without creating a Socket, sending data to the host, then receiving a ping from the host and reading the RemoteEndPoint property to get the IP address of the host?
Try using DeviceNetworkInformation.ResolveHostNameAsync in the Microsoft.Phone.Net.NetworkInformation namespace, like this:
public void DnsLookup(string hostname)
{
var endpoint = new DnsEndPoint(hostname, 0);
DeviceNetworkInformation.ResolveHostNameAsync(endpoint, OnNameResolved, null);
}
private void OnNameResolved(NameResolutionResult result)
{
IPEndPoint[] endpoints = result.IPEndPoints;
// Do something with your endpoints
}
There is no way to do this built into the framework. You could use a socket assumming that the host supports ping. It will depend on the network you are running in (I'd assume you can't control this) and the exact requirements of the application.
It may be easier to get your app to work with IP addresses and not require a hostname if all you have is an IP address.
I think Im dealing with the same problem. I also have a dynamic IP updating the dns with No-ip.
For what I know the System.Net.Dns is not available in this version of Windows Phone.
Maybe in next releases.
http://msdn.microsoft.com/en-us/library/system.net.dns.aspx
At the start of my app Im going to create a web service call to the host (to the webserver in it) asking for the IPAddress. I think I'll solve the problem in the meantime.
This could be the WCF service
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetIpAddress(string value);
}
public class Service1 : IService1
{
public string GetIpAddress()
{
// Add the proper error handling and collection matching of course
IPAddress s = Dns.GetHostAddresses("www.mysite.com")[0];
return s.ToString();
}
}
If you guys find a direct approach please let me know

Why does Request["host"] == "dev.testhost.com:1234" whereas Request.Url.Host == "localhost"

Hi all, I seem to have found a discrepancy when testing ASP.NET applications locally on the built-in web server with Visual Studio 2008 (Cassini).
I've set up a host on my local machine associating dev.testhost.com with 127.0.0.1, since I have an application that needs to change its appearance depending on the host header used to call it.
However, when I request my test application using http://dev.testhost.com:1234/index.aspx, the value of Request.Url.Host is always "localhost". Whereas the value of Request.Headers["host"] is "dev.testhost.com:1234" (as I would expect them both to be).
I'm NOT concerned that the second value includes the port number, but I am mighty confused as to why the HOST NAMES are completely different! Does anyone know if this is a known issue, or by design? Or am I being an idiot?!
I'd rather use Request.Url.Host, since that avoids having to strip out the port number when testing... - Removed due to possibly causing confusion! - Sam
Request.Headers["host"] is the value received from the application that connects to the server, while the other value is the one the server gets when it tries to get the domain name.
The browser uses in the request the domain name entered because that is used in the case of virtual domains. The server reports the one set in the server preferences, or the first one it finds.
EDIT: Looking at the code of Cassini to see if it uses some particular settings, I noticed the following code:
public string RootUrl {
get {
if (_port != 80) {
return "http://localhost:" + _port + _virtualPath;
}
else {
return "http://localhost" + _virtualPath;
}
}
}
//
// Socket listening
//
public void Start() {
try {
_socket = CreateSocketBindAndListen(AddressFamily.InterNetwork, IPAddress.Loopback, _port);
}
catch {
_socket = CreateSocketBindAndListen(AddressFamily.InterNetworkV6, IPAddress.IPv6Loopback, _port);
}
// …
}
The explanation seems to be that Cassini makes explicit reference to localhost, and doesn't try to make a reverse DNS lookup. Differently, it would not use return "http://localhost" + _virtualPath;.
The Request.Headers["host"] is the host as specified in the http header from the browser. (e.g. this is what you'd see if you examined the traffic with Fiddler or HttpWatch)
However, ASP.NET loasds this (and other request info) into a System.Uri instance, which parses the request string into its constituent parts. In this case, "Host" refers to literally the host machine part of the original request (e.g. with the tcp port being in the Port) property.
This System.Uri class is a very useful helper class that takes all the pain out of splitting your request into it's parts, whereas the "Host:" (and for that matter the "GET") from the http header are just raw request data.
Although they both have the same name, they are not meant to be the same thing.
It's a matter of what the w3 specs say versus what the Microsoft Uri.Host property is supposed to contain. The naming does not imply an attempt by MS to provide identical functionality. The function that does include port numbers is Uri.Authority.
With the update you posted, you're still facing the same problem, just examining a different aspect of it. The Uri.Host property is not explicity or implicity stated to perform the same function as the headers that are defined in the w3 specs. In long form, here are some quotes from the Uri.Host MSDN page:
Uri.Host Property
Gets the host component of this instance.
Property Value
Type: System.String
A String that contains the host name. This is usually the DNS host name or IP address of the server.
There's no guarantee that this will match what is in the headers, just that it represents the host name in some form.

Categories