Microsoft.Xrm.Tooling.Connector High Memory Allocation - c#

I am currently going through the process of upgrading our product CRM SDK and the main change I have encountered is that instead of connecting to the Xrm service and creating my IOrganizationService using the tried and trusted method of:
var connection = CrmConnection.Parse(connectionString);
var service = new OrganizationService(connection);
I am now having to utilise the CrmServiceClient from the Tooling namespace:
CrmServiceClient conn = new Microsoft.Xrm.Tooling.Connector.CrmServiceClient(connectionString).OrganizationServiceProxy;
Now this is all fine except from one major issue...memory.
Using the older Xrm.Client method you were able to specify the Service Configuration Instance Mode (which defaulted to ServiceConfigurationInstanceMode.PerName). What this meant is that the service was reused if the same application called the create multiple times. This kept the memory footprint low. The below image show the amount of allocated memory after calling to create a service instance 100 times
However, using the newer method you cannot set this instance mode anywhere and it seems that a brand new connection is created every time whether you want it or not. Here are the results of the same test:
As you can see, with every new connection, more and more memory is allocated. I can;t see anywhere that i can tell it to reuse the service.
So what I'm basically asking is, am I going about this in the wrong way? Should I be creating and caching everything myself? Are there hidden classes/methods that I am missing? Any help would be greatly appreciated.

The latest SDK (8.2.0.1) caches and resuses the connection as long as the connectionstring does not inclue RequireNewInstance=true.
One thing worth noting is even if you new up another CrmServiceClientwith a unique connection string (pointing to a different CRM organization), but the connection string does not include RequireNewInstance=true, the CrmServiceClient will reuse the previous cached connection.
So
var connectionString = $#"Url=https://ORG1.crm.dynamics.com;AuthType=Office365;UserName=USER#DOMAIN.com;Password=PASSWORD";
var connectionString2 = $#"Url=https://ORG2.crm.dynamics.com;AuthType=Office365;UserName=USER#DOMAIN.com;Password=PASSWORD";
var crmSvcClient = new CrmServiceClient(connectionString);
((WhoAmIResponse)crmSvcClient.Execute(new WhoAmIRequest())).OrganizationId.Dump();
crmSvcClient.ConnectedOrgFriendlyName.Dump();
var crmSvcClient2 = new CrmServiceClient(connectionString2);
((WhoAmIResponse)crmSvcClient2.Execute(new WhoAmIRequest())).OrganizationId.Dump();
crmSvcClient2.ConnectedOrgFriendlyName.Dump();
Prints out the guid and ORG1 friendly name both times. If you pass RequireNewInstance=true in connectionstring2 then you will see ORG2 printed out.

Related

Same machine, different app domains, same GUIDs coming up

I'm fairly certain I'm either doing something wrong, or understanding something wrong. It's hard to give a piece of code to show my problem, so I'm going to try explaining my scenario, with the outcome.
I'm starting up several instances of a DLL, in the same console application, but in it's own app domain. I then generated a Guid.NewGuid() that I assign to a class in the instance, and set the application's folder to a new folder. This works great so far. I can see everything works great, and my instances are seperated. However... when I started changing my app's folder to the same name as the unique GUID generated for that class I started picking up anomolies.
It works fine, when I instantiate the new instances slowly, but when I hammer new ones in, the application started picking up data in its folder, when it started up. After some investigation, I found that its because that folder already exist, due to that GUID already being instantiated. On further investigation, I can see that the machine takes a bit of a pause, and then continues to generated the new instances, all with the same GUID.
I understand that the GUID generating algorithm uses the MAC as part of it, but I was under the impression that even if the same machine, at the same exact moment generates two GUIDs, it would still be unique.
Am I correct in that statement? Where am I wrong?
Code :
Guid guid = Guid.NewGuid();
string myFolder = Path.Combine(baseFolder, guid.ToString());
AppDomain ad = AppDomain.CurrentDomain;
Console.WriteLine($"{ad.Id} - {guid.ToString()}");
string newHiveDll = Path.Combine(myFolder, "HiveDriveLibrary.dll");
if (!Directory.Exists(myFolder))
{
Directory.CreateDirectory(myFolder);
}
if (!File.Exists(newHiveDll))
{
File.Copy(hiveDll, newHiveDll);
}
Directory.SetCurrentDirectory(myFolder);
var client = ServiceHelper.CreateServiceClient(serviceURL);
ElementConfig config = new ElementConfig();
ElementConfig fromFile = ElementConfigManager.GetElementConfig();
if (fromFile == null)
{
config.ElementGUID = guid;
config.LocalServiceURL = serviceURL;
config.RegisterURL = registerServiceURL;
}
else
{
config = fromFile;
}
Directory.SetCurrentDirectory is a thin wrapper atop the Kernel 32 function SetCurrentDirectory.
Unfortunately, the .NET documentation writers didn't choose to copy the warning from the native function:
Multithreaded applications and shared library code should not use the SetCurrentDirectory function and should avoid using relative path names. The current directory state written by the SetCurrentDirectory function is stored as a global variable in each process, therefore multithreaded applications cannot reliably use this value without possible data corruption from other threads that may also be reading or setting this value
It's your reliance on this function that's creating the appearance that multiple threads have magically selected exactly the same GUID value.

Connecting to mongodb sing C# quick tour not creating db or collection

I'm going through the mongoDB Driver Documentation Quick Tour for the first time. Specifically the 2.4 version.
I've created a fresh mongodb instance at the 192.168.1.50 address, and it appears to be running correctly.
The MongoDB documentation gives the following example:
var client = new MongoClient("mongodb://192.168.1.50:27017");
#It's ok if the database doesn't yet exist. It will be created upon first use
var database = client.GetDatabase("testDB");
#It’s ok if the collection doesn’t yet exist. It will be created upon first use.
var collection = database.GetCollection<BsonDocument>("testCollection");
However, when I go on my server, and I enter the mongo console
mongo
And I list the databases using
show dbs
The output is only
admin 0.000GB
local 0.000GB
Is there anything else I should have done to make this work? I'm getting no errors on try/catch, and it appears to be running fine.
Troubleshooting
So far I've confirmed that mongodb is running by using the following:
netstat -plntu
Shows mongod running on 27017 in the LISTEN state.
I'd also be interested in knowing if there's a way on the mongodb server to view live connections, so I could see if it were actually successfully connecting.
Well the problem is that you need to create almost one collection in order to persist the created database (weird right?) i tested it with robomongo and works in that way.
The problem is that GetCollection method is not creating the target collection, you can try with this code:
static void Main(string[] args)
{
var client = new MongoClient("mongodb://192.168.1.50:27017");
//# It's ok if the database doesn't yet exist. It will be created upon first use
var database = client.GetDatabase("test");
//# It’s ok if the collection doesn’t yet exist. It will be created upon first use.
string targetCollection = "testCollection";
bool alreadyExists = database.ListCollections().ToList().Any(x => x.GetElement("name").Value.ToString() == targetCollection);
if (!alreadyExists)
{
database.CreateCollection(targetCollection);
}
var collection = database.GetCollection<BsonDocument>(targetCollection);
}
It turns out that a method I had found on how to set multiple bindIp's was incorrect. The problem wasn't with the C# at all. I found the solution here
In case that ever goes away, here's the current settings I had to follow for multiple ip's
edit file /etc/mongod.conf
Wrap the comma-separated-Ips with brackets
bindIp = [127.0.0.1, 192.168.184.155, 96.88.169.145]
My original code worked fine, I just didn't have the brackets on the bindIp.

MongoDB C# driver: connection string for sharding over replica set

I need to setup sharding over replica set as recommended in MongoDB reference for high availability & scalability. I have few questions about connection string and its behavior for C# driver in that scenario (code snippet below):
Is the connection string below looks right for connecting to mongos instances: mongos1, mongos2 & mongos3?
What happens to client if one of the mongos instance crashes? Will the failed call handled gracefully by retrying to second mongos instance? Does the client blacklist the failed mongos instance and try after sometime?
If I want to set readpreference, will the driver be aware of replica set existence and honor setting ReadPreference?
Code snippet:
MongoUrlBuilder bldr = new MongoUrlBuilder();
List<MongoServerAddress> servers = new List<MongoServerAddress>();
servers.Add(new MongoServerAddress("mongos1:27016"));
servers.Add(new MongoServerAddress("mongos2:27016"));
servers.Add(new MongoServerAddress("mongos3:27016"));
bldr.Username = "myuser";
bldr.Password = "mypwd";
bldr.Servers = servers;
bldr.DatabaseName = "mydb";
bldr.ReadPreference = ReadPreference.Primary;
var server = MongoServer.Create(bldr.ToMongoUrl());
1) Yes, this is just fine. Note that all of this could be put in an actual connection string as well. mongodb://myuser:mypwd#mongos1:27016,mongos2:27016,mongos3:27016/mydb/?readPreference=primary
2) The way your connection string is built, you'll be load balancing across the 3 mongos. If one goes down, then the other two will simply begin to receive more traffic. Errors, however, will happen and nothing gets retried automatically. You'll need to handle the errors and make decisions based on each query/write whether it is safe to retry.
3) The driver, when talking to a sharded system, will simply forward the read preference to mongos. Note that mongos version 2.2 had some difficulty with read preferences. I'd advise you to be on the 2.4 line.

SQL Server perform backup with C#

I've investigated the possibilities of creating database backups through SMO with C#.
The task is quite easy and code straightforward. I've got only one question: how can I check if the backup was really created?
SqlBackup.SqlBackup method returns no parameters and I don't even know if it throws any exceptions. (the only thing that I know is that it is blocking, because there's also SqlBackupAsync method)
I would appreciate any help.
you can and its very possible to do what you asked for,
but doing the backup it self using SMO its not very hard, but the hard part is managing the backup and the restore.
it would be hard to put all the code here, but its wont fit. so I will try my best to put the lines you need.
SqlBackup.SqlBackup doesn't return any value, its a void function.
but it takes one parameter which is "Server", try out the following code:
Server srvSql;
//Connect to Server using your authentication method and load the databases in srvSql
// THEN
Backup bkpDatabase = new Backup();
bkpDatabase.Action = BackupActionType.Database;
bkpDatabase.Incremental = true; // will take an incemental backup
bkpDatabase.Incremental = false; // will take a Full backup
bkpDatabase.Database = "your DB name";
BackupDeviceItem bDevice = new BackupDeviceItem("Backup.bak", DeviceType.File);
bkpDatabase.Devices.Add(bDevice );
bkpDatabase.PercentCompleteNotification = 1;// this for progress
bkpDatabase.SqlBackup(srvSql);
bkpDatabase.Devices.Clear();
I've investigated the problem using Reflector.NET (I suppose this is legal since RedGate is Ms Gold Certified Partner and Reflector.NET opens .NET libraries out of the box). As I found out the method throws two types of exceptions:
FailedOperationException - in most cases, other exceptions are "translated" (I suppose translating means creating new FailedOperationException and setting InnerException to what was actually thrown)
UnsupportedVersionException - in one case when log truncation is set to TruncateOnly and server major version is more or equal to 10 (which is sql server 2008?)
This solves my problem partially, because I'm not 100% sure that if something goes wrong those exceptions will actually be thrown.

How do I Programmatically change Connection String un LINQ C# Winforms

This question may be redundant, but i could not totally understand how to do this.
I need to be able to, when the users Run my Winforms app, can search for the instance of SQL if the previous one are not available. I already have the check for the DB existence, and also made a dialog wich search for all the available instance, and bulding the connection string isn't a problem. The point here is that, I need to be able to everytime the users open the app it loads the CN from a external file, and if the external file doesn't exist or the instance isn't available, i can use the app in another instance (asuming, offcourse, that the required DB is in that Instance).
The point is that, i don't know how to Programmatically change Connection String, using LINQ in winforms.
Thanks in advance
You should be to pass the connection string to the DataContext constructor.
var db = new MyDataContext(myconnectionstring);
var someConnectionString = "This is my connection String";
using (var db = new SomeConcreteDataContext(someConnectionString)){
//...Do whatever...
}
A DataContext is created per 'unit of work'.
As ichiban says pass the required connection string into the constructor when creating the DC

Categories