The Problem
One of the requirements for a Silverlight 4/WCF RIA Service application that I am working on is that the connection string is stored encrypted within the web.config file. This left me with the problem that I would need to somehow unencrypt the connection string and manually set it before any database interaction was done.
Fortunately there is a virtual method inside the LinqToEntitiesDomainService class that is created, overriding this allows you to set the connection string before the database is accessed.
The Code
The below code shows an example of overriding the CreateObjectContext() method.
In the code I fetch the encrypted connection string from the web.config file, decrypt it and then return a new EntitySet using this connection string.
using System.Configuration;
[EnableClientAccess()]
public class TestDomainService : LinqToEntitiesDomainService<TestEntities>
{
protected override TestEntities CreateObjectContext()
{
string encConnection = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
string decConnection = encConnection.Decrypt();
return new TestEntities(decConnection);
}
}
Extra Information
There is another method of the LinqToEntitiesDomainService that came in very handy when I was figuring out the above code, this is the OnError method which, when overriden, gives you access to a DomainServiceErrorInfo object, allowing you to see details of any errors that occured.
For example, when I was running this code I had made a spelling mistake in my pre-encrypted connectionString.
Edit
I’ve written a new post about how to put this into a re-usable base class.
[...] my previous post I wrote about overriding the LinqToEntitiesDomainService.CreateObjectContext() method to [...]
Have seen your information pop up in a number of google queries while working with silverlight. Thanks for sharing all the techniques you’ve come up with.
I have a similar problem in that I need to switch the connection information dynamically, however, for a different reason. We have customer data divided into multiple databases to give them additional safety. I can create an EntityFramework model and domain service and then hook them up to a DataGrid on the client side very easily for one database, but would like to be able to do so for all of the databases. Can you think of a way to somehow switch the database within the domain service based on a parameter? Maybe have multiple datasources. Maybe pass in a parameter from the DataGrid that indicates the datasource in the config file? We’d like to do this as dynamically as possible, so a person could be logged in as a super user, choose from a dropdown which customer DB they want to connect to, pass that information to the server side along with the query, and then get results based on that customer’s data in the datagrid.
I tried ignoring the DomainService’s ObjectContext within the query method and constructing a new entity object context right there in the method, but for some reason, I get an error message saying that I’m trying to access an ObjectContext that has already been disposed which is odd because the code is definitely within the using statement. Here is the code:
[Query] public IQueryable GetActiveUsers(string dbName) { // this line is pseudo code, but essentially asks if the user is authorized to access to the DB they requested if( !UserDbs.AuthorizedToAccessDb(dbName, userPrincipal) ) { throw FaultException("Not authorized"); } ConnectionConfig connectionConfig = UserDbs.Configs[dbName]; string customerDbConnectionString = new System.Data.EntityClient.EntityConnectionStringBuilder { Metadata = "res://*/Models.CustomerDbModel.csdl|res://*/Models.CustomerDbModel.ssdl|res://*/Models.CustomerDbModel.msl", Provider = "System.Data.SqlClient", ProviderConnectionString = new System.Data.SqlClient.SqlConnectionStringBuilder { InitialCatalog = connectionConfig.DbName, DataSource = connectionConfig.DbInstance, IntegratedSecurity = connectionConfig.UseWindowsIntegratedLogin, MultipleActiveResultSets = true, UserID = connectionConfig.DbUsername, Password = connectionConfig.DbPassword, ConnectTimeout = DB_CONNECTION_TIMEOUT_PERIOD }.ConnectionString }.ConnectionString; try { using (CustomerEntities customerEntities = new CustomerEntities(customerDbConnectionString)) { ObjectQuery allUsers = customerEntities.Users; return (from user in allUsers where user.Active == true select user); } } catch (Exception e) { logger.Error("Error getting active users", e); return null; } }So that’s the gist of an idea, however, even if we can do that, I wonder how much the recreation of the ObjectContext will slow down connections to the DB. Take a look let me know if you see something we might be able to do. Thanks much in advance.
Very helpful. Thanks!