Connections with many databases - subsonic

We have a webapp where each client has their own db (approx. 700 at the moment).
In SubSonic 2, you had to wrap each call with the SharedDBConnectionScope passing in the right connection string to use, otherwise you ran the risk of one thread or client getting data from another thread or client.
In SubSonic3 is this still needed? Do I need to wrap the calls like I did in 2.x?
There are easy ways of switching the database now, but do I still have thread issues or can I do away with the call to SharedDBConnectionScope?

SubSonic 3 greatly improved the way to create a provider from scratch or just passing a name and a connectionsctring:
Some Examples:
// Linq Templates:
var db = new YourDB("connectionstring goes here", "System.Data.SqlClient");
// SimpleRepository without app.config
IDataProvider provider = SubSonic.DataProviders.ProviderFactory.GetProvider(
connectionString: "Server=localhost;Database=clientdb;Uid=root;",
providerName: "MySql.Data.MySqlClient"
);
IRepository repository = new SimpleRepository(provider,
SimpleRepositoryOptions.RunMigrations);
So basically you can create a provider or repository each time a client connects and use this in your class.

Related

Best practice for connections to CRM in web application

am sorry if this question will be a bit to broad but if this is question about normal ASP.NET MVC 5 Owin based application with default connection to MSSQL server i would not have such hard time but we use CRM as our database.
Ok as i mention am working on ASP.NET MVC5 application and am having hard time finding what is the best practice to create, keep open and to close connection to Dynamics CRM 365?
I found some many posts and blogs but everyone pulling on his side of the road.
Some say it's better for every request to open new connection in using statement so it could be closed right away (that's sounds good but it's a possible that requests will be slow because on every request it needs to open new connection to CRM).
Some say it' better to make singleton object on application scope, keep it open during application lifetime and reuse it on every request.
Normally i would use OrganizationServiceProxy in some simple console app but in this case am not sure should i use OrganizationServiceProxy or CrmServiceClient or something else?
If anyone have or had some similar problem, any hint would be great.
UPDATE:
#Nicknow
I downloaded SDK from SDK 365 and am using this dll-s.
Microsoft.Xrm.Sdk.dll, Microsoft.Crm.Sdk.Proxy.dll, Microsoft.Xrm.Tooling.Connector.dll and Microsoft.IdentityModel.Clients.ActiveDirectory.dll.
You mention
Microsoft.CrmSdk.XrmTooling.CoreAssembly 8.2.0.5.
if am correct this nuget package use official assembly that i downloaded, or there are some modification to this package?
About that test
proof test
if i got it right, no matter if i use using statement, implement Dispose() method or just use static class on application scope for a lifetime of application i will allways get same instance (If i use default settings RequireNewInstance=false)?
For code simplicity, I usually create a static class (a singleton could be used too, but would usually be overkill) to return a CrmServiceClient object. That way my code is not littered with new CrmServiceClient calls should I want to change anything about how the connection is being made.
So it would be good practice to create static class on application scope that lives for application lifetime? That means that every user that makes request would use same instance ? Wouldn't that be i performance issue for that one connection?
All of your method calls will execute to completion or throw an exception thus even if the GC takes a while there is no open connection sitting out there eating up resources and/or blocking other activity.
This one takes me back to section where i allways get same instance of CrmServiceClient and got the part that xrm.tooling handles cached connection o the other side but what happens on this side (web application).
Isn't the connection to CRM (i.e. CrmServiceClient) unmanaged resources, shouldn't i Dispose() it explicitly?
I found some examples with CrmServiceClient and pretty much in all examples CrmServiceClient is casted in IOrganizationService using CrmServiceClient.OrganizationWebProxyClient or CrmServiceClient.OrganizationServiceProxy.
Why is that and what are the benefits of that?
I got so many questions but this is already allot to ask, is there any online documentation that you could point me to it?
First, I'm assuming you are using the latest SDK DLLs from Nuget: Microsoft.CrmSdk.XrmTooling.CoreAssembly 8.2.0.5.
I never wrap the connection in a using statement and I don't think I've ever seen an example where that is done. There are examples from the "old days", before we had tooling library, where calls to create OrganizationServiceProxy were wrapped in a using statement, which caused a lot of inexperienced developers to release code with connection performance issues.
Luckily most of this has been fixed for us through the Xrm.Tooling library.
Create your connection object using CrmServiceClient:
CrmServiceClient crmSvc = new CrmServiceClient(#"...connection string goes here...");
Now if I create an OrganizationServiceContext (or an early-bound equivalent) object I do wrap that in a using so that it is determinedly disposed when I've completed my unit of work.
using (var ctx = new OrganizationServiceContext(crmSvc))
{
var accounts = from a in ctx.CreateQuery("account")
select a["name"];
Console.WriteLine(accounts.ToList().Count());
}
The Xrm.Tooling library handles everything else for you as far the connection channel and authentication. Unless you specify to create a new channel each time (by adding 'RequireNewInstance=true' to the connection string or setting the useUniqueInstance to true when calling new CrmServiceClient) the library will reuse the existing authenticated channel.
I used the following code to do a quick proof test:
void Main()
{
var sw = new Stopwatch();
sw.Start();
var crmSvc = GetCrmClient();
Console.WriteLine($"Time to get Client # 1: {sw.ElapsedMilliseconds}");
crmSvc.Execute(new WhoAmIRequest());
Console.WriteLine($"Time to WhoAmI # 1: {sw.ElapsedMilliseconds}");
var crmSvc2 = GetCrmClient();
Console.WriteLine($"Time to get Client # 2: {sw.ElapsedMilliseconds}");
crmSvc2.Execute(new WhoAmIRequest());
Console.WriteLine($"Time to WhoAmI # 2: {sw.ElapsedMilliseconds}");
}
public CrmServiceClient GetCrmClient()
{
return new CrmServiceClient("...connection string goes here...");
}
When I run this with RequireNewInstance=true I get the following console output:
Time to get Client # 1: 2216
Time to WhoAmI # 1: 2394
Time to get Client # 2: 4603
Time to WhoAmI # 2: 4780
Clearly it was taking about the same amount of time to create each connection.
Now, if I change it to RequireNewInstance=false (which is the default) I get the following:
Time to get Client # 1: 3761
Time to WhoAmI # 1: 3960
Time to get Client # 2: 3961
Time to WhoAmI # 2: 4145
Wow, that's a big difference. What is going on? On the second call the Xrm.Tooling library uses the existing service channel and authentication (which it cached.)
You can take this one step further and wrap your new CrmServiceClient calls in a using and you'll get the same behavior, because disposing of the return instanced does not destroy the cache.
So this will return times similar to above:
using (var crmSvc = GetCrmClient())
{
Console.WriteLine($"Time to get Client # 1: {sw.ElapsedMilliseconds}");
crmSvc.Execute(new WhoAmIRequest());
Console.WriteLine($"Time to WhoAmI # 1: {sw.ElapsedMilliseconds}");
}
using (var crmSvc2 = GetCrmClient())
{
Console.WriteLine($"Time to get Client # 2: {sw.ElapsedMilliseconds}");
crmSvc2.Execute(new WhoAmIRequest());
Console.WriteLine($"Time to WhoAmI # 2: {sw.ElapsedMilliseconds}");
}
For code simplicity, I usually create a static class (a singleton could be used too, but would usually be overkill) to return a CrmServiceClient object. That way my code is not littered with new CrmServiceClient calls should I want to change anything about how the connection is being made.
To fundamentally answer the question about using, we don't need to use it because there is nothing to be released. All of your method calls will execute to completion or throw an exception thus even if the GC takes a while there is no open connection sitting out there eating up resources and/or blocking other activity.

Microsoft Unity - How to register connectionstring as a parameter to repository constructor when it can vary by client?

I am relatively new to IoC containers so I apologize in advance for my ignorance.
My application is a asp.net 4.0 MVC app that uses the Entity Framework with a Repository layer on top of that. It is a multi tenant application so the connection string that is used varies by the logged in client.
The connection string is determined by a 'key' that gets passed in as part of the route which indicates the client. This route data is only present on the first request of the user's session.
The route looks kind of like this: http://{host}/login/dev/
where 'dev' indicates we are using the dev database.
Currently the IoC container is registering all dependencies in the global.asax Application_Start event handler and I have the 'key' hardcoded as follows:
var cnString = CommonServices.GetDBConnection("dev");
container.RegisterType<IRequestMgmtRecipientRepository, RequestMgmtRecipientRepository>(
new InjectionConstructor(cnString));
Is there a way with Unity to dynamically register the repository based on the logged in client using the route data that is supplied initially?
Note: I am not manually resolving the repositories. They are getting constructed by the container when the controllers get instantiated.
I am stumped.
Thanks!
Quick assumption, you can use the host to identify your tenant.
the following article has a slightly different approach http://www.agileatwork.com/bolt-on-multi-tenancy-in-asp-net-mvc-with-unity-and-nhibernate-part-ii-commingled-data/, its using NH, but it is usable.
based on the above this hacked code may work (not tried/complied the following, not much of a unity user, more of a windsor person :) )
Container.RegisterType<IRequestMgmtRecipientRepository, RequestMgmtRecipientRepository>(new InjectionFactory(c =>
{
//the following you can get via a static class
//HttpContext.Current.Request.Url.Host, if i remember correctly
var context = c.Resolve<HttpContextBase>();
var host = context.Request.Headers["Host"] ?? context.Request.Url.Host;
var connStr = CommonServices.GetDBConnection("dev_" + host); //assumed
return new RequestMgmtRecipientRepository(connStr);
}));
Scenario 2 (i do not think this was the case)
if the client identifies the Tenant (not the host, ie http: //host1), this suggests you would already need access to a database to access the client information? in this case the database which holds client information, will also need to have enough information to identify the tenant.
the issue with senario 2 will arise around anon uses, which tenant is being accessed.
assuming senario 2, then the InjectionFactory should still work.
hope this helps

ServiceStack OrmLite Is it a error to use UserAuthRepository.CreateUserAuth inside a transaction

I have a complex workflow where I want to create rows in several tables in one transaction.
One of the operations is to create a new UserAuth (from ServiceStack Authentication feature).
I assume that all the database operations in a transaction should operate on the same connection, and if that is true, then I think it may be a problem to call UserAuthRepository.CreateUserAuth inside a transaction because it looks as if it uses its own connection.
So my question is whether if the creation of a UserAuth will be part of the transaction or not when I have code like shown below. And if not, then how to go about creating new users as part of an transaction?
using (var db = Db.OpenDbConnection()) {
using (var trans = db.OpenTransaction()) {
... do some databae operations via. db ...
var userAuth = UserAuthRepository.CreateUserAuth(
new UserAuth{UserName = "blabla"},
"password"
);
... do some more databae operations via. db ...
trans.Commit();
}
}
Internally whenever ServiceStack requires accessing a database, e.g in the OrmLiteUserAuthRepository.CreateUserAuth it asks for and uses a new connection and immediately disposes of it once it's done.
There is currently no way to make it apart of a custom transaction.

Make SubSonic use existing <connectionstring> instead of new data provider

I am adding SubSonic to a legacy application. This application already defines a ConnectionString. Is there a way I can use this connectionstring instead of creating a new Data Provider entry?
I know that one solution is programmatically setting this in the code (i.e. SubSonic.DataService.GetInstance("Name").SetDefaultConnectionString("ConnString") ). However, is there a more elegant solution?
I think that's the only way to do it. And it might throw an exception if there is no place holder SubSonicService in the config file, I don't remember.
// GetInstance just to initialize subsonic.
DataProvider provider = DataService.GetInstance(subsonicProviderName);
// Set the actual database connection string.
// Overrides config file setting.
provider.DefaultConnectionString = connectionString;
DataService.Provider = provider;

Separate Read/Write Connection for SubSonic

The security policy at our client's production environment requires that we use separate connection to execute writes and read to and from database. We have decided to use SubSonic to generate our DAL. So I am interested in knowing if it is possible and if yes how?
You can specify the provider SubSonic is using at runtime. So you would specify the read provider (using your read connectionstring) when loading from the database and then specify the write provider (using your write connectionstring) when you want to save to it.
The following isn't tested but I think it should give you the general idea:
SqlQuery query = new Select()
.From<Contact>();
query.ProviderName = Databases.ReadProvider;
ContactCollection contacts = query.ExecuteAsCollection<ContactCollection>();
contacts[0].FirstName = "John";
contacts.ProviderName = Databases.WriteProvider;
contacts.SaveAll();

Resources