Using RabbitMQ with a cluster of nodes, I set up my factory and connection like this (using the .NET client):
var factory = new ConnectionFactory()
{
UserName = Properties.Settings.Default.RabbitMQUser,
Password = Properties.Settings.Default.RabbitMQPassword,
HostnameSelector = new RandomHostNameSelector(),
AutomaticRecoveryEnabled = true
};
connection = factory.CreateConnection(Properties.Settings.Default.RabbitMQServers.Split(';'));
Where Properties.Settings.Default.RabbitMQServers is use a semi-colon delimited list of servers:
clust01;clust02;clust03
After connecting, is there a way to see which host it actually picked and is there a way to detect when that might change (because the particular node crashed, was stopped, or rebooted)? factory.HostName just returns localhost.
Edit: It seems connection.Endpoint.HostName does give you the actual host name as #Evk and #wally have both stated (thank you). But is there a way to detect a change? It seems that IConnection has a ConnectionShutdown event which I guess might be called as part of switching hosts, but there isn't a corresponding start up or restart event (so I'm assuming it wouldn't know the new host yet). There are also ConnectionBlocked and ConnectionUnblocked events, but they are undocumented so I have no idea what they do...
So how to get host name you already found out, as for how to detect when it changes: when you set AutomaticRecoveryEnabled for your factory, CreateConnection will really return instance of AutorecoveringConnection. This class implements special IRecoverable interface, which has event you need. So to detect when automatic recovery happens, subscribe to it like this:
var connection = factory.CreateConnection();
((IRecoverable)connection).Recovery += (sender, args) =>
{
// recovery happened
};
I've not got an environment in which I can test this, so it might be completely wrong.
It looks like you can use the endpoint of the connection object (IConnection) returned:
(string) connection.Endpoint.HostName
Cite: https://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v1.4.0/rabbitmq-dotnet-client-1.4.0-net-2.0-htmldoc/type-RabbitMQ.Client.IConnection.html
Related
Based on the documentation wildcards support does exist, but I can't seem to find any other info on whether it's just supposed to work or if it's configured on the server or whether the producers or consumers need to configure it.
I'm assuming as a publisher I would just send messages to a topic named /patient/2/goal/ and when a consumer subscribed to a topic called /patient/*/goal/ it would still receive the message, however nothing shows up. What am I missing?
Please note that if I publish a message to /patient/*/goal/ and subscribe to /patient/*/goal/ then I receive the message. However, that only confirms my message bus is working, not that wildcard support is working.
Producer test:
var connectUri = new Uri("...");
var factory = new NMSConnectionFactory(connectUri);
var connection = factory.CreateConnection();
session = connection.CreateSession();
var destination = session.GetTopic("/patient/1/goal/");
producer = session.CreateProducer(destination);
...
Consumer:
var topic = _session.GetTopic("/patient/*/goal/");
var consumer = _session.CreateConsumer(topic);
...
Using / as the the path separator needs to be configured through a plugin. Switching to . made it work as expected.
Caching behavior of the last Dynamics SDK is driving me crazy.
First, if you want to use CrmServiceClient to access different environments you have to use the parameter RequireNewInstance=True; in the connection string. If not, every instance of CrmServiceClient will use the same connection, even if you create and dispose instances to different environments.
Now, even if you use the RequireNewInstance=True; in the connection string I found that cache still occurs in some scenarios.
var client1 = new CrmServiceClient("RequireNewInstance=True;
Url=https://myCompany.crm.dynamics.com;
Username=myUser#myCompany.onmicrosoft.com; Password=myPassowrd;
AuthType=Office365");
//Now, client 2 points to a url that doesn’t exists:
var client2 = new CrmServiceClient("RequireNewInstance=True;
Url=https://xxx.crm.dynamics.com; Username=myUser#myCompany.onmicrosoft.com;
Password=myPassowrd; AuthType=Office365");
The client2 keeps using the first connection string, so you cannot determine if the new connection string is correct.
Any ideas how to test Dynamics Crm connections strings correctly in my asp.net application?
Late reply, but the behavior you're seeing is because when you're specifying an erroneous URL the discovery service is used to ascertain which instance to connect to.
To prevent this specify SkipDiscovery=True in your connection string:
var connectionString2 = #"AuthType=Office365;Url=https://FAKE.crm.dynamics.com;Username=USERNAME;Password=PASSWORD;RequireNewInstance=True;SkipDiscovery=True;";
Edit: SkipDiscovery is true by default starting with 9.0.7, kudos to #mwardm
I think I found the problem. It seems to only happens on Dynamics 365 online trials, that was the reason we were getting inconsistent results depending on the environment.
Apparently, the url doesn't need to be completely valid to establish a connection to a CRM online trial environment, as long as the credentials are valid and the url structure is kept.
Let's consider the following example:
var client1 = new CrmServiceClient("RequireNewInstance=True;
Url=https://fake.crm.dynamics.com;
Username=myUser#myCompany.onmicrosoft.com; Password=myPassowrd;
AuthType=Office365");
In this case I can substitute the "fake" part of the url with whatever I want, but still execute requests correctly using the CrmServiceClient service.
If I try to do this with another environment (e.g. 2015, on premise, not-trial crm online, etc.), the IsReady property of the CrmServiceClient would return false and I would get an error in the LastCrmError property.
Very weird behavior, and difficult to pinpoint.
Now that I think I understand the inconsistent behavior I know that finally it will not affect our clients, so I will mark this response as the answer even if I still do not know why we have different behavior between a trial and a normal environment..
I agree choosing to reuse the existing connection if you don't include RequireNewInstance=true seems counter-intuitive, but I can't reproduce what you're seeing. If I try the following from LinqPad crmSvcClient2 will print out errors and then throw a null ref on the Execute call (8.2.0.2 version of the SDK). With this version of the SDK you'll want to always check LastCrmError after connecting to see if the connection failed.
var connectionString = #"AuthType=Office365;Url=https://REAL.crm.dynamics.com;Username=USERNAME;Password=PASSWORD;RequireNewInstance=True;";
var connectionString2 = #"AuthType=Office365;Url=https://FAKE.crm.dynamics.com;Username=USERNAME;Password=PASSWORD;RequireNewInstance=True;";
using (var crmSvcClient = new CrmServiceClient(connectionString))
{
"crmSvcClient".Dump();
crmSvcClient.LastCrmError.Dump();
((WhoAmIResponse)crmSvcClient.Execute(new WhoAmIRequest())).OrganizationId.Dump();
crmSvcClient.ConnectedOrgFriendlyName.Dump();
}
using (var crmSvcClient2 = new CrmServiceClient(connectionString2))
{
"crmSvcClient2".Dump();
crmSvcClient2.LastCrmError.Dump();
((WhoAmIResponse)crmSvcClient2.Execute(new WhoAmIRequest())).OrganizationId.Dump();
crmSvcClient2.ConnectedOrgFriendlyName.Dump();
}
GetServer is gone for good. How do i check if the server is connected or even exists?
Example code:
// This server exists
var exists = new MongoClient("mongodb://192.168.2.109:27017");
// This server does not exist
var doesNotExist = new MongoClient("mongodb://194.168.200.129:27017");
// Both states return "Discennected"
var connStateExisting = exists.Cluster.Description.State;
var connStateNotExisting = doesNotExist.Cluster.Description.State;
// GetDatabase("name") works for both without errors.
How can i check if a server can be connected?
The Cluster.Description.State does not update immediately. When i checked, it was updated after roughly 100+ milliseconds. The driver contains a connection pool and it seems to do quite a lot asynchronous.
However, the Cluster-property has a "DescriptionChanged"-event that is fired once the connection is done.
If someone else has any knowledge about connections and timeouts, please share it.
I have implemented the following javascript code:
var comHub = $.hubConnection();
var comHubProxy = comHub.createHubProxy("chatHub");
registerClientMethods(comHubProxy);
comHubProxy.on("onConnected", function (userName, userList, friendList, groupHistory, groupList, clanList, roomId) {
});
comHub.start().done(function () {
registerEvents(comHubProxy);
});
Where registerClientMethods(..) and registerEvents(..) just declare all my server and client methods. It all works perfectly, but my issue is I have two hubs. This one, and my super secret admin one. oh, super secret I wish.
My issue is I was doing a little checking, and I decided I'd inspect this hub connection. And oh, the horror.
$.connection.hub.proxies
That one line, and hello super secret hub name. Of course, then you can connect and boom hello functions. Now then, yeah they cant just use them, since I have further security measures and checks. But I am uneasy they can even /see/ them! Is there a way to configure my hub setup to only connect to certain hubs depending on the proxy generated? I started attempting it but I'm pretty muddled...
var hubConfig = new HubConfiguration();
hubConfig.EnableDetailedErrors = false;
hubConfig.EnableJavaScriptProxies = true;
app.MapSignalR("/signalr", hubConfig);
app.MapSignalR("/secret", hubConfig);
GlobalHost.HubPipeline.RequireAuthentication();
My application is a C# Windows service that consumes a WCF service. When the first "Expectation failed (417)" error occurs, I change both ServicePointManager.Expect100Continue and ServicePoint.Expect100Continue to false:
try
{
//ServicePointManager.Expect100Continue = false; // If uncomment all work
var svc = new ServiceClient();
svc.GetData(); // first error
}
catch (ProtocolException pex)
{
if (pex.Message.Contains("(417)"))
{
ServicePointManager.Expect100Continue = false;
var sp = ServicePointManager.FindServicePoint(new Uri(#"http://addr.to.service/service.svc"));
sp.Expect100Continue = false;
var svc = new ServiceClient();
svc.GetData(); // second same error
}
}
However, the second call to the service also fails. But if I set Expect100Continue to false before any connection, communication with the service works correctly.
Is this way correctly to handle Expect100Continue errors? I need the application adapts automatically without user action. What am I forgetting to do this work?
Most of the settings on ServicePointManager are treated as the default values applied on all NEW ServicePoints that are created after that point in the application's life. In the case where you change the setting after seeing the error, you are not actually changing anything on existing ServicePoint instances, including the instance associated with the connection used by WCF in this case.
In your Sample code you are calling ServicePointManager.FindServicePoint to try to find the correct ServicePoint. However, FindServicePoint has several overloads and it is easy to use that API incorrectly. For instance, FindServicePoint will try to take into account things http/https, the host you are connecting to, your proxy configuration, etc. If you are not providing the correct parameters to FindServicePoint, you can easily end up getting the wrong ServicePoint returned to you and your settings will not be applied to the ServicePoint you intended to change.
I would recommend that you use the FindServicePoint overload that takes an IWebProxy object to ensure that you get the right ServicePoint. In most cases, you should be able to pass in WebRequest.DefaultWebProxy as the IWebProxy object.
From the MSDN documentation of ServicePointManager.Expect100Continue,
Changing the value of this property does not affect existing ServicePoint objects. Only new ServicePoint objects created after the change are affected. Therefore changing the value on the existing WCF client will have no effect. You need to create a new WCF client, then call GetData()