pilotboba wrote:
Otis wrote:
You then should use adapter, selfservicing isn't suitable for that situation. To 'serve itself' it has to be able to do things without using some sort of adapter/session/context object.
Sure, but currently you have the utility class that allows you to set the connection string programatically. I assume you are storing it somewhere global like in the application object?
No in a static variable in DbUtils: DbUtils.ActualConnectionString.
As DbUtils contains solely static methods, it's a bit complicated to transform this to what you want, however I do think it's possible.
I would like to be able to set it in perhaps the BeginRequest event of the application object and you could store it either in HttpContext or in the Thread or even session? This would allow me to do what I do.
It still is "self-serving" it is just getting a connection string from a thread / session specific place rather than an app global location like config or such?
Or you could use the provider model pattern (a la membership, profile in 2.0) to get the connection string, and I could create a provider that would return the connection string from the users profile. Just a thought.
All code of selfservicing uses instances, except for DbUtils, as they're a set of utility methods, like produce a connection, produce a dataadapter etc.
The dbUtils template isnt big so you should be able to alter it pretty easily and use your copy in a custom template set.
In HelperClasses\DbUtils.cs you'll find a method called CreateConnection(). In there, it checks if the static variable ActualConnectionString is set, if not, it reads from the config file and sets the variable with that value.
You should do the following:
1) add a new private static member variable which will be the lock object for the critical section:
private static object _semaphore = new object();
2) alter the CreateConnection() in this way or similar:
public static SqlConnection CreateConnection()
{
lock(_semaphore)
{
string connectionStringToUse = HttpContext.Current.Session["userConnectionString"];
return CreateConnection(connectionStringToUse);
}
}
As this change is very small, you can first try it in a generated code project you already have and see how it behaves. Due to the lock, it might be that that routine will be a bottleneck under heavy load, though it should be relatively minor as creating a connection from the pool is very fast.
Keep in mind that connection pooling will be different: if every user has his own connection string, the connection pool has to be bigger than expected as pooling is done on connection string.
I wonder if it's possible to use windows authentication and impersonation, as the users are known in the db anyway. Either way, IF possible, try to implement a role based security system yourself which authenticates the users against a table row in the DB, places the user in a role and using that set of credentials offers things to the user. This is much more scalable, however requires some more work, and of course a 'different' application to manage users and passwords, which can be a problem if the customer wants everything integrated in Active Directory (for example), in which case you can fall back on windows authentication and impersonation (which requires 1 connection string and thus not a problem)
To recap:
IF possible avoid multiple connection strings with many users, it's not performing because you can't use connection pooling or you need a large pool. This is an ADO.NET thing. Also, if you need dynamic database/user selection no matter what, consider adapter, as that's designed for this, not selfservicing. In a winforms app, running on a desktop: no problem, as you have a single user, so you can use selfservicing there, but in a webapp, IF you need custom connection strings per user, use the trick above to modify selfservicing to handle this for you, though if possible, use different ways to manage multi-user applications, as multiple connection strings is mitigating the usage of a connection pool.