Get SQL Server CE path form multiple projects - c#

To learn ServiceStack, I'm developing an API based in Northwind database (a SQL Server CE sdf file). My solution has 3 projects:
Northwind.Data. Database and POCO classes
Northwind.ServiceModel. DTO classes
Northwind.ServiceInstance. Service classes
What's the best way to access data? Currently the database is in Northwind.Data /App_Data folder. Can I access database path from Web.config and read it in AppHost class to create IDbConnection factory?
Thanks in advance.

What's the best way to access data?
I don't think OrmLite has support for SQL Server CE but there is this. Best way might be to just use SqlCeConnection within your Services.
Can I access database path from Web.config and read it in AppHost class to create IDbConnection factory?
You should be able to add the connection string to the Web.config file.
<add name="Test" connectionString="Data Source=C:\Northwind.sdf" />
If I'm correct about OrmLite not supporting SQL CE and you want IDbConnectionFactory like syntax in your Services you could look into using DBProviderFactories.
The simplest (not the best) thing I can think of would be doing something like below.
Create a 'bare bones' factory for SqlCEConnection. This assumes you have the connection string in your Web.config file
public class SqlCeFactory
{
public SqlCeConnection OpenConnection()
{
var conn = new SqlCeConnection(ConfigurationManager.ConnectionStrings["Test"].ToString());
try
{
conn.Open();
return conn;
}
catch (Exception ex)
{
throw ex;
}
}
}
Register it the SqlLCeFactory in your AppHost
public override void Configure(Funq.Container container)
{
container.Register<SqlCeFactory>(new SqlCeFactory());
}
Inject it into your Service(s)
public class SourceService : ServiceStack.ServiceInterface.Service
{
public SqlCeFactory DbFactory { get; set; }
public object Get(SomeRequest request)
{
using (var con = DbFactory.OpenConnection())
{
//use SqlCeConnection()
}
//more code
}
}

Related

Change DB name for Entity Framework DbContext

I have inherited an application which is using Entity Framework to access a SQL Server database. The DbContext class has the constructor as shown below, where BuildingPermits is the name of the initial catalog.
I would like to be able to switch between databases (with the same connection) via a config file instead of changing the code.
How can I accomplish this?
public BuildingPermitsDbContext() : base("BuildingPermits")
{
Database.SetInitializer<BuildingPermitsDbContext>(null);
}
You can try this.
using System.Configuration;
public BuildingPermitsDbContext() : base(DatabaseName())
{
Database.SetInitializer<BuildingPermitsDbContext>(null);
}
private static string DatabaseName()
{
var db = ConfigurationManager.AppSettingss["desiredDbName"];
return db;
}

Change Database on the fly in Entity Framework same scheme

I have a context which I derive my entity I have 5 databases these database are off the same scheme that I need to switch from at run time. The user would be selecting at the launch of the application which database they would be connecting to.
The database that is of the same scheme is SMBASchedulerEntities its just the catalogue name that is different
public class SourceContext : ContextBase
{
public SMBASchedulerEntities _sourceEntities = new SMBASchedulerEntities();
public SystemDa _systemDB = new SystemDa();
public void AddToPatient(Patient newPatient)
{
_sourceEntities.Patients.Add(newPatient);
SaveChanges();
}
public void AddToAppointmentTypes(AppointmentType AppointmentTypes)
{
_sourceEntities.AppointmentTypes.Add(AppointmentTypes);
SaveChanges();
}
}
As you can see there I reference the entities within my context so I would like to have a property that I can call such as changeDatabase and that it would take affect without restarting the application is that at all possible.
You can pass the name of the connection string you want to connect to, when instantiating your DbContext. First, you declare your DbContext like so:
public class SMBASchedulerEntities : DbContext
{
public SMBASchedulerEntities(string connectionString): base(connectionString)
{
}
}
You keep all your connection strings in your Web.config or App.config (depending on the type of project):
<connectionStrings>
<add name="DefaultConnection1" connectionString="server=localhost;user id=MyAppUser;password=SecretPass;database=MyDatabase1" providerName="System.Data.SqlClient" />
<add name="DefaultConnection2" connectionString="server=localhost;user id=MyAppUser;password=SecretPass;database=MyDatabase2" providerName="System.Data.SqlClient" />
<add name="DefaultConnection3" connectionString="server=localhost;user id=MyAppUser;password=SecretPass;database=MyDatabase3" providerName="System.Data.SqlClient" />
<add name="DefaultConnection4" connectionString="server=localhost;user id=MyAppUser;password=SecretPass;database=MyDatabase4" providerName="System.Data.SqlClient" />
<add name="DefaultConnection5" connectionString="server=localhost;user id=MyAppUser;password=SecretPass;database=MyDatabase5" providerName="System.Data.SqlClient" />
</connectionStrings>
Then you use it like this:
using (var db = new SMBASchedulerEntities("DefaultConnection1"))
{
// use MyDatabase1 through connection string "DefaultConnection1"
}
using (var db = new SMBASchedulerEntities("DefaultConnection2"))
{
// use MyDatabase2 through connection string "DefaultConnection2"
}
Dispose your DbContext
It's recommended to dispose the DbContext after using it. If you still want to use your idea with SourceContext, you could implement something like this:
public class SourceContext : ContextBase, IDisposable
{
public SMBASchedulerEntities _sourceEntities;
public SystemDa _systemDB = new SystemDa();
public SourceContext(string connectionString)
{
_sourceEntities = new SMBASchedulerEntities(connectionString);
}
public void AddToPatient(Patient newPatient)
{
_sourceEntities.Patients.Add(newPatient);
SaveChanges();
}
public void ChangeDatabaseTo(string connectionString)
{
if (_sourceEntities != null)
_sourceEntities.Dispose();
_sourceEntities = new SMBASchedulerEntities(connectionString);
}
public void AddToAppointmentTypes(AppointmentType AppointmentTypes)
{
_sourceEntities.AppointmentTypes.Add(AppointmentTypes);
SaveChanges();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_sourceEntities != null)
{
_sourceEntities.Dispose();
}
}
}
}
...then finally use it like this:
using(var context = new SourceContext("DefaultConnection1"))
{
context.AddPatient(patient); // add to Database1
context.ChangeDatabaseTo("DefaultConnection2");
context.AddPatient(patient); // add to Database2
context.ChangeDatabaseTo("DefaultConnection4");
context.AddPatient(patient); // add to Database4
}
By making your SourceContext an IDisposable, you have the opportunity to properly dispose the DbContext instance. Take note I took care of disposing the existing DbContext before changing it.
So, turns out the easiest way to do this is to put all of the DB names and connection strings in the appsettings.json file.
You can make it very complex, of course, but what I did was make a select drop down, let the user select the DB they want to use, then fire the onclick method to pull the connection string out of the app settings.json file, create an instance of the DBCONTEXT with that name’s connection string and use that DB context throughout whatever you need from there.
Public static class AppSettings
{
public static string GetConnectionString(string sDBinstanceName)
{
IConfigurationRoot Configuration;
IConfigurationBuilder builder = new ConfigurationBuilder().SetpathName(<wherever your appsettings.json file is>,”appsettings.json”).ReadJsonFile();
Configuration = builder.Build();
var tmpSettings = Configuration.GeyAppSettings();
string dbConstr = tmpSettings[“ConnectionStrings”][sDBinstanceName];
return dbConstr;
}
}
This is not MY snippet, but a derivative of what I found online. As it is from memory, it is not 100% correct, but I will fix it on Monday. I will update with author when I find it again(Monday).
Once you get the connection string you treat the DBCONTEXT like any other object, create it, use the tables (MEF) and whatever else you need, then destroy it correctly or let the garbage collection clean it up.
I got this working yesterday and please note: There are ZERO DBCONTEXTs registered in the Program.cs file as they are not needed.
This system is simple, lets you allow the user control to which Database they need based on a simple selection mechanism and answers the question.
At our shop we have MULTIPLE databases with exact same schema because we segregate data based on the timeframe for that data, but I can envision situations where you could use different schemas depending on the selection, we just do not do that.
For instance we have a Production and Development DB that are EXACTLY the same schema (different data) so the one DBCONTEXT is used for both in MEF.
With the method above we can let the user see the data in either at their command, it’s just getting there is a whole lot easier.

.net core 1 adding read only DB connection for 1 query

I have a DB that is used by another web api. I need to make one DB select query to this database in my application against one table and two fields. I see I can create a database first DB context with some tools in .net core 1 by this link. However it seems heavy handed to create this entire DBContext for a database that could change as the web api changes. In addition I should not be writing to it. So I can change the access in SQL server for the user to select only. In addition I want to put my sql connection string in my appsettings.json file with all my other connection strings.
Question: Is it possible to set up an sqlconnection in my controller similar to:
private readonly SqlConnection dbCon = new SQLConnection(Configuration.GetConnectionString("DBCon"));
Where my DBCon is defined in my appsettings.json file. When I try to use the above I get the error:
The name Configuration does not exist in the current context.
So apparently Configuration isn't the answer to getting the setting from appsettings.json.
I need to set up a quick sql connection for a simple query that doesn't take any user input without a lot of configuration. Any help would be appreciated.
In 4.6 in console apps I could use ConfigurationManager to get the connectionstrings from app.config. Not sure how to get it out of appsettings.json. It may be getting it in Startup.cs but not sure how to get it in there and make it avaialable to the controller.
Update:
AppSettings.json is as follows:
{
"ConnectionStrings": {
"DefaultConnection": "valid Connection String",
"DBCon": "valid Connection String"
}, ....
You can (and should) use dependency injection to achieve this.
I would create a simple service that has a method to execute your query. The service class can have the connection string injected via an IOptions instance. Alternatively, you can inject the options directly into the controller.
OtherDbOptions
public class OtherDbOptions
{
public string ConnectionString { get; set; }
}
OtherDbService
public class OtherDbService
{
private readonly string _connectionString;
public OtherDbService(IOptions<OtherDbOptions> options)
{
_connectionString = options.Value.ConnectionString;
}
public object GetData()
{
// create your database connection and return data
}
}
Startup
public void ConfigureServices(IServiceCollection services)
{
// add options services
services.AddOptions();
// configure OtherDbOptions using code
services.Configure<OtherDbOptions>(options =>
{
options.ConnectionString = "value from appsettings.json";
});
// register OtherDbService for DI
services.AddTransient<OtherDbService>();
// other configurations
...
}
Controller (option 1 - inject service)
public OtherDbController(OtherDbService service)
{
_service = service;
}
Controller (option 2 - inject options)
public OtherDbController(IOptions<OtherDbOptions> options)
{
_options = options.Value;
}

System.data.SQLite entity framework code first programmatic providername specification

I've spent a while on this now and have only found a workaround solution that I'd rather not do...
I have a context as shown below. Is there a programmatic way to specify the database to connect to via the constructor, and get it to use the System.Data.SQLite entity framework provider to connect to a SQLite database? This is working via the app.config (with a connectionstring called "Context"), but not via any programmatic way I can find of supplying it. I have tried using an entity connectionstring builder and that produces the following string:
provider=System.Data.SQLite;provider connection string='data
source="datafile.db"'
When the context is first queried with this string I get a message "Keyword not supported: 'provider'."
public class Context : DbContext
{
public IDbSet<Test> Tests { get; set; }
public Context()
: base("Context")
{
}
}
*Edit.
I may have solved this by implementing my own connectionfactory:
public class ConnectionFactory : IDbConnectionFactory
{
public DbConnection CreateConnection(string nameOrConnectionString)
{
return new SQLiteConnection(nameOrConnectionString);
}
}
Then setting:
Database.DefaultConnectionFactory = new ConnectionFactory();
However, it seems like there should be a built in way to do this, and also one that does not involve overriding the global default connection factory.

Entity Framework in Asp.Net MVC

My ASP.Net MVC application has to connect to multiple databases at run time. I can overload my class to accept the connection string at run time as shown below
class MyClassDBContext:DbContext
{
public MyClassDBContext(string str) : base(str)
{
this.Database.Connection.ConnectionString = str;
}
}
Currently, I am retrieving this connection string from a database table. My workflow is as follows
Website connects to default database using credentials stored in
web.config
Website queries default database to get connection strings for
other databases.
Websites connects to other databases by supplying the connection
string at run time
The problem I facing right now is in keeping my code clean. Every time I need the connection string for database number 2, I have to look it up in the default database. Is there any cleaner way of doing this? I considered storing the connection string in the profile data but I am not sure if this is a good idea. Every user of my website will need to connect to at most 2-3 different databases depending on their credentials.
I would personally put all connection strings in your App.Config file and use a simple IOC implementation.
Actually the ninject package off Nuget might be perfect for your needs.
Here's what I mean though. Hopefully this makes your code clean. I used this exact same pattern for a previous project and it worked out well.
You could take it a step further and make a Service Locator and register services in your global.asax. Let me know if that interests you. Also check out ninject.
public interface IService()
{
string GetConnectionString();
void DoStuff();
}
public class DBServiceOne : DbContext, IService
{
protected string GetConnectionString()
{
return ConfigurationManager.AppSettings["DBServiceOneConnectionString"]
}
public DBServiceOne(string str) : base(str)
{
this.Database.Connection.ConnectionString = GetConnectionString()
}
public void DoStuff() { //logic goes here }
}
public class DBServiceTwo : DbContext, IService
{
public DBServiceTwo(string str) : base(str)
{
this.Database.Connection.ConnectionString = GetConnectionString();
}
protected string GetConnectionString()
{
return ConfigurationManager.AppSettings["DBServiceTwoConnectionString"]
}
public void DoStuff() { //logic goes here }
}
public class DBServiceThree : DbContext, IService
{
public DBServiceThree(string str) : base(str)
{
this.Database.Connection.ConnectionString = GetConnectionString();
}
protected string GetConnectionString()
{
return ConfigurationManager.AppSettings["DBServiceThreeConnectionString"]
}
public void DoStuff() { //logic goes here }
}
Now for the implementation -- Use Constructor Injection on your controllers
//This could be in your home controller
public class HomeController : AsyncController
{
private IService DBOneService;
private IService DBTwoService;
private IService DBThreeService;
public HomeController(IService one, IService two, IService three)
{
DBOneService= one;
DBTwoService = two;
DBThreeService = three;
}
public HomeController() : this(new DBServiceOne(), new DBServiceTwo(), new DBServiceThree()) {}
public ActionResult Index() {
DBOneService.DoStuff(); //here you'd want to return a list of data and serialize down with json or populate your razor template with it. Hope this helps!
}
I had a slightly different problem. The DB I connect to depends on the state of a product import. During the import databases get attached and detached. The currently available db is stored in a "default database".
The main problem I had was that I had to switch off connection pooling, otherwise invalid connection states existed after detaching databases and attaching them again.
This is might not be a problem for you.
Apart from that I store the current Connectionstring in the application state. Only after each 60 seconds I query the "default database" again. You have to watch out for multithreading issues by using locking.

Categories