I have a .Net core app that I have installed the cosmos nuget package into:
Install-Package Microsoft.Azure.DocumentDB.Client
I am attempting to follow the instructions given here from MS that details how to create a database and the collections.
Using dependency injection, I have registered IDocumentClient. However, when I attempt to use this in a setup class to create the database and collections, the following methods are not listed as avaialable:
public void Setup(IDocumentClient client)
{
await client.CreateDatabaseIfNotExistsAsync(new Database() { Id = databaseId });
await client.CreateDocumentCollectionIfNotExistsAsync(UriFactory.CreateDatabaseUri(databaseId), new DocumentCollection { Id = "Identity" });
}
In both cases, the methods flag up as not known, and the IDE prompts me to create them. This happens even with the Microsoft.Azure.Documents.Client namespace defined in the file.
Whilst these methods exist on the DocumentClient class, they are not actually part of the IDocumentClient interface.
In this manner, you will need to pass the concrete DocumentClient class into the setup method, rather than the IDocumentClient interface.
public void Setup(DocumentClient client)
{
await client.CreateDatabaseIfNotExistsAsync(new Database() { Id = databaseId });
await client.CreateDocumentCollectionIfNotExistsAsync(UriFactory.CreateDatabaseUri(databaseId), new DocumentCollection { Id = "Identity" });
}
Once you do this, the methods are available as normal.
Whilst Dependency Injection/IoC generally prefers the use of Interfaces over concrete classes, it is probably ok in this instance, since the class purpose is specifically to set up and configure the database: a certain knowledge of the underlying technology here is to be expected.
Related
I have a Web Api project which relies heavily on Azure Cosmos DB. Until now, having one Cosmos DB account (one connection string) was sufficient. Now a new requirement is to be able to connect to a different Cosmos (two connection strings) depending on an incoming parameter.
For customerId X we should fetch documents from Cosmos DB 1 and for another customer Y we have to look in Cosmos DB 2.
Until now my Startup.cs file registered a singleton instance of CosmosClient. Which in turn gets instantiated like this
cosmosClient = new CosmosClient(endpointUrl, primaryKey);
And this worked really well. The Web Api was easily able to process all requests. But now that we have to new up a CosmosClient per request, performance is really bad.
So my question is; Is there a way to have multiple instances of the same singleton? As in; can we create a single instance of the combination Class+EndPointUrl? (Would that still be a singleton?)
Right now, we are newing up thousands of CosmosClients every minute. And we really need just one more compared to what we had earlier.
There's multiple ways to do this, but an easy implementation would be to create a wrapper around each CosmosClient you use. The only use of the wrapper will be to allow you to use various instances of the CosmosClient and differentiate them by their types.
//Create your own class for each client inheriting the behaviour of CosmosClient
public class ContosoCosmosClient : CosmosClient
{
public ContosoCosmosClient(string connectionString, CosmosClientOptions clientOptions = null) : base(connectionString, clientOptions)
{
}
public ContosoCosmosClient(string accountEndpoint, string authKeyOrResourceToken, CosmosClientOptions clientOptions = null) : base(accountEndpoint, authKeyOrResourceToken, clientOptions)
{
}
public ContosoCosmosClient(string accountEndpoint, TokenCredential tokenCredential, CosmosClientOptions clientOptions = null) : base(accountEndpoint, tokenCredential, clientOptions)
{
}
}
//In Startup.up add a Singleton for each client
services.AddSingleton(new ContosoCosmosClient(...));
services.AddSingleton(new FabrikamCosmosClient(...));
Then in your business logic you can add both clients and depending on your logic choose which client you want to use:
public class MyService
{
public MyService(ContosoCosmosClient contosoClient, FabrikamCosmosClient fabrikamClient)
{
//...
}
}
Thanks for all comments and answers.
In the end, is this case, the best solution was the approach that was suggested by Mr. T. https://devblogs.microsoft.com/cosmosdb/httpclientfactory-cosmos-db-net-sdk/
I'm now still using one CosmosClient, Scoped. Which allows dynamic use of endpoints.
By injecting the IHttpClientFactory and setting the CosmosClientOptions like this;
{
HttpClientFactory = () => _httpClientFactory.CreateClient("cosmos")
});
we are now making full use of the HttpClient and its ability to reuse ports.
I have the (almost) worst of multi tenancy. I'm building a asp.net core website that I'm porting a bunch of pokey little intranet sites to. Each subsite will be an asp.net Area. I have an IdentityContext for the Identity stuff. I have multiple copies of vendor databases, each of those with multiple tenants. The ApplicationUserclass has an OrgCode property that I want to use to switch the db context.
I can see myself needing something that maps User.OrgCode and Area to a Connection string
There are many partial examples of this on Stack Overflow. I am very confused after an afternoons reading. The core of it seams to be:
remove DI dbcontext ref from the constructor args.
Instantiate the dbcontext in the controller constructor.
Use dbcontext as before.
Am I on the right track?
Any coherent examples?
Edit 2020/07/09
This has unfortunately become more pressing.
The Identity database is tenant agnostic. Every user in Identity has an OrgCode identifier. (Custom user property).
Each server has multi tenancy built in through the use of 'cost centers'. The server has a collection of databases named the same on every server.
core vendor database
custom database where we store our extensions
logs database for our job output
There are also small application specific databases that already use an Org Code to identify a user
Server A - 1 Org Code
Server B - 4 Org Codes
Server C - 3 Org Codes engaged in project, 50+ not yet (mostly small)
Server D - No Org Codes engaged as of now. 80+ on server. (soon)
It is not possible to consolidate all the organisations onto one server. There are legal and technical ramifications. Each server has hundreds of remote transponders reporting to them that would need updating. The data these supply is what our custom jobs work with.
The dream is to continue to use DI in each page, passing in the contexts as required. The context would then be smart enough to pick the correct underlying connection details based on the OrgCode of the username.
I hesitate to use the word proxy because it seems heavily loaded in this space.
Hell, even using a switch statement would be fine if I knew where to put it
Desired effect User from Org XYZ loads page that requires Vendor database, they get the one from the server that XYZ maps to.
Edit 2020/07/13
To tidy up referenceing, I've switched the OrgCode and Server to Enums. The context inheritance is as follows
DbContext
CustLogsContext
public virtual ServerEnum Server
{
get
{
return ServerEnum.None;
}
}
DbSet (etc)
CustLogsServerAContext
public override ServerEnum Server
{
get
{
return ServerEnum.ServerA;
}
}
CustLogsServerBContext (etc)
CustLogsServerCContext (etc)
CustLogsServerDContext (etc)
VendorContext
VendorServerAContext
VendorServerBContext (etc)
VendorServerCContext (etc)
VendorServerDContext (etc)
I've also created a static class OrgToServerMapping that contains a dictionary mapping OrgCodes to Servers. Currently hardcoded, will change eventually to load from config, and add a reload method.
Currently thinking I need a class that collects the contexts Would have a Dictionary<serverEnum, dbcontext> and be registered as a service. Pretty sure I'd need a version of the object for each inherited dbcontext, unless someone knows ome polymorphic trick I can use
I work on a similar system with thousands of databases, but with LinqToSql instead of EF (I know...). Hopefully the general ideas translate. There are connection pool fragmentation issues that you have to contend with if you end up with many databases, but for just your four databases you won't have to worry about that.
I like these two approaches - they both assume that you can set up the current ApplicationUser to be injected via DI.
Approach #1: In Startup, configure the DI that returns the data context to get the current user, then use that user to build the correct data context. Something like this:
// In Startup.ConfigureServices
services.AddScoped<ApplicationUser>((serviceProvider) =>
{
// something to return the active user however you're normally doing it.
});
services.AddTransient<CustLogsContext>((serviceProvider) =>
{
ApplicationUser currentUser = serviceProvider.GetRequiredService<ApplicationUser>();
// Use your OrgToServerMapping to create a data context
// with the correct connection
return CreateDataContextFromOrganization(currentUser.OrgCode);
});
Approach #2: Rather than injecting the CustLogsContext directly, inject a service that depends on the active user that is responsible for building the data context:
// In Startup.ConfigureServices
services.AddScoped<ApplicationUser>((serviceProvider) =>
{
// something to return the active user however you're normally doing it.
});
services.AddTransient<CustLogsContextWrapper>();
// In its own file somewhere
public class CustLogsContextWrapper
{
private ApplicationUser currentUser;
public CustLogsContextWrapper(ApplicationUser currentUser)
{
this.currentUser = currentUser;
}
public CustLogsContext GetContext()
{
// use your OrgToServerMapping to create a data context with the correct connection;
return CreateDataContextFromOrganization(user.OrgCode);
}
}
Personally I prefer the latter approach, because it avoids a call to a service locator in Startup, and I like encapsulating away the details of how the data context is created. But if I already had a bunch of code that gets the data context directly with DI, the first one would be fine.
I have created a multitenancy implementation as follows (which could scale endlessly in theorie). Create a multitenancy database (say tenantdb). Easy. But the trick is to store connectionstring details for each tenant (your target databases). Along side your user orgCode etc.
I can see myself needing something that maps User.OrgCode and Area to a Connection string
So the way to map it in code is to feed your dbcontext whith your target tenant connectionstring, which you get from your tenantdb. So you would need anohter dbcontext for you tenantdb. So first call your tenantdb get the correct tenant connectionstring by filtering with your user orgcode. And then use it to create a new target dbcontext.
The dream is to continue to use DI in each page, passing in the contexts as required. The context would then be smart enough to pick the correct underlying connection details based on the OrgCode of the username.
I have this working with DI.
I created UI elements for crud operations for this tenantdb, so I can update delete add connection string details and other needed data. The Password is encrypted on save and decrypted on the get just before passing to your target dbcontext.
So I have two connection strings in my config file. One for the tenantdb and one for a default target db. Which can be an empty/dummy one, as you probably encounter application startup errors thrown by your DI code if you don't have one, as it will most likely auto search for a connectionstring.
I also have switch code. This is where a user can switch to anohter tenant. So here the user can choose from all the tenants it has rights to (yes rights are stored in tenantdb). And this would again trigger the code steps described above.
Cheers.
Took this Razor Pages tutorial as my starting point.
This way you can have very lousily coupled target databases. The only overlap could be the User ID. (or even some token from Azure,Google,AWS etc)
Startup.
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddDbContext<TenantContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("TenantContext")));
//your dummy (empty) target context.
services.AddDbContext<TargetContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("TargetContext")));
}
IndexModel (Tenant pages).
public class IndexModel : PageModel
{
private readonly ContosoUniversity.Data.TenantContext _context;
private ContosoUniversity.Data.TargetContext _targetContext;
public IndexModel(ContosoUniversity.Data.TenantContext context, ContosoUniversity.Data.TargetContext targetContext)
{
_context = context;
//set as default targetcontext -> dummy/empty one.
_targetContext = targetContext;
}
public TenantContext Context => _context;
public TargetContext TargetContext { get => _targetContext; set => _targetContext = value; }
public async Task OnGetAsync()
{
//get data from default target.
var student1 = _targetContext.Students.First();
//or
//switch tenant
//lets say you login and have the users ID as guid.
//then return list of tenants for this user from tenantusers.
var ut = await _context.TenantUser.FindAsync("9245fe4a-d402-451c-b9ed-9c1a04247482");
//now get the tenant(s) for this user.
var SelectedTentant = await _context.Tenants.FindAsync(ut.TenantID);
DbContextOptionsBuilder<TargetContext> Builder = new DbContextOptionsBuilder<TargetContext>();
Builder.UseSqlServer(SelectedTentant.ConnectionString);
_targetContext = new TargetContext(Builder.Options);
//now get data from the switched to database.
var student2 = _targetContext.Students.First();
}
}
Tenant.
public class Tenant
{
public int TenantID { get; set; }
public string Name { get; set; }
//probably could slice up the connenctiing string into props.
public string ConnectionString { get; set; }
public ICollection<TenantUser> TenantUsers { get; set; }
}
TenantUser.
public class TenantUser
{
[Key]
public Guid UserID { get; set; }
public string TenantID { get; set; }
}
Default connstrings.
{ "AllowedHosts": "*",
"ConnectionStrings": {
"TenantContext": "Server=(localdb)\mssqllocaldb;Database=TenantContext;Trusted_Connection=True;MultipleActiveResultSets=true",
"TargetContext": "Server=(localdb)\mssqllocaldb;Database=TargetContext;Trusted_Connection=True;MultipleActiveResultSets=true"
}
NOTE: This example has been simplified
I have got a Client's Contact table and wanted to retrieve specific client contact information from DB. The code I typed belove brings me all contact details. I wanted to use a parameter to only bring me specific client contacts.
I used IClientContactRepository interface like this
public interface IClientContactRepository
{
IQueryable<ClientContactModel> ClientContacts { get; }
}
And i used this class to retrive data from database with dapper
public class ClientContactRepository : IClientContactRepository
{
private readonly IConfiguration configuration;
private List<ClientContactModel> ClientContactList {get;set;}
public ClientContactRepository(IConfiguration config)
{
configuration = config;
SqlConnection conn = new SqlConnection(configuration["ConnectionString"]);
using (var connection = conn)
{
ClientContactList = connection.Query<ClientContactModel>("Select * FROM ContactTable ").ToList();
}
}
public IQueryable<ClientContactModel> ClientContacts => ClientContactList;
}
In my Startup class
services.AddTransient<IClientContactRepository, ClientContactRepository>();
My QUESTION is: can I pass the client's id parameter to the constructor.
I tried this: add a parameter to the constructor
public ClientContactRepository(IConfiguration config, int clientId)
and tried to start up class.
services.AddTransient<IClientContactRepository, ClientContactRepository(int,i)>()
Didn't work....
Can someone help me how to pass parameter please?
Yes, but where are you getting the client ID from - is it a configured value that will be static for the lifetime of the application? If so, you can use the AddTansient method overload that accepts a factory delegate to create the objects.
The better way (will cover all use cases) is registering the type that can provide that information (create one if no such type exists) with the DI container and use that as a parameter in the constructor of your repo.
As an example, let’s say you get your client ID from a claim, so the type you need to inject is IPrincipal:
services.AddScoped<IPrincipal>(
provider => provider.GetService<IHttpContextAccessor>()
.HttpContext
.User);
You would then inject the IPrincipal into your repo constructor and retrieve the client ID. An even better way would be to create your own type “ClientIdAccessor” which is responsible for providing the client ID. You would then not have a dependency on IPrincipal when testing your repo and the implementation of this new type would only depend on external libraries for your asp.net core implementation.
Side note: are you certain you want to use AddTransient for your repo? Usually you’d want to use the same repo object for the lifetime of the request (I.e. AddScoped).
It seems to me that it's a bad idea to have a domain service require an instance of IOptions<T> to pass it configuration. Now I've got to pull additional (unnecessary?) dependencies into the library. I've seen lots of examples of injecting IOptions all over the web, but I fail to see the added benefit of it.
Why not just inject that actual POCO into the service?
services.AddTransient<IConnectionResolver>(x =>
{
var appSettings = x.GetService<IOptions<AppSettings>>();
return new ConnectionResolver(appSettings.Value);
});
Or even use this mechanism:
AppSettings appSettings = new AppSettings();
Configuration.GetSection("AppSettings").Bind(appSettings);
services.AddTransient<IConnectionResolver>(x =>
{
return new ConnectionResolver(appSettings.SomeValue);
});
Usage of the settings:
public class MyConnectionResolver
{
// Why this?
public MyConnectionResolver(IOptions<AppSettings> appSettings)
{
...
}
// Why not this?
public MyConnectionResolver(AppSettings appSettings)
{
...
}
// Or this
public MyConnectionResolver(IAppSettings appSettings)
{
...
}
}
Why the additional dependencies? What does IOptions buy me instead of the old school way of injecting stuff?
Technically nothing prevents you from registering your POCO classes with ASP.NET Core's Dependency Injection or create a wrapper class and return the IOption<T>.Value from it.
But you will lose the advanced features of the Options package, namely to get them updated automatically when the source changes as you can see in the source here.
As you can see in that code example, if you register your options via services.Configure<AppSettings>(Configuration.GetSection("AppSettings")); it will read and bind the settings from appsettings.json into the model and additionally track it for changes. When appsettings.json is edited, and will rebind the model with the new values as seen here.
Of course you need to decide for yourself, if you want to leak a bit of infrastructure into your domain or pass on the extra features offered by the Microsoft.Extensions.Options package. It's a pretty small package which is not tied to ASP.NET Core, so it can be used independent of it.
The Microsoft.Extensions.Options package is small enough that it only contains abstractions and the concrete services.Configure overload which for IConfiguration (which is closer tied to how the configuration is obtained, command line, json, environment, azure key vault, etc.) is a separate package.
So all in all, its dependencies on "infrastructure" is pretty limited.
In order to avoid constructors pollution of IOptions<>:
With this two simple lines in startup.cs inside ConfigureServices you can inject the IOptions value like:
public void ConfigureServices(IServiceCollection services)
{
//...
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
services.AddScoped(cfg => cfg.GetService<IOptions<AppSettings>>().Value);
}
And then use with:
public MyService(AppSettings appSettings)
{
...
}
credit
While using IOption is the official way of doing things, I just can't seem to move past the fact that our external libraries shouldn't need to know anything about the DI container or the way it is implemented. IOption seems to violate this concept since we are now telling our class library something about the way the DI container will be injecting settings - we should just be injecting a POCO or interface defined by that class.
This annoyed me badly enough that I've written a utility to inject a POCO into my class library populated with values from an appSettings.json section. Add the following class to your application project:
public static class ConfigurationHelper
{
public static T GetObjectFromConfigSection<T>(
this IConfigurationRoot configurationRoot,
string configSection) where T : new()
{
var result = new T();
foreach (var propInfo in typeof(T).GetProperties())
{
var propertyType = propInfo.PropertyType;
if (propInfo?.CanWrite ?? false)
{
var value = Convert.ChangeType(configurationRoot.GetValue<string>($"{configSection}:{propInfo.Name}"), propInfo.PropertyType);
propInfo.SetValue(result, value, null);
}
}
return result;
}
}
There's probably some enhancements that could be made, but it worked well when I tested it with simple string and integer values. Here's an example of where I used this in the application project's Startup.cs -> ConfigureServices method for a settings class named DataStoreConfiguration and an appSettings.json section by the same name:
services.AddSingleton<DataStoreConfiguration>((_) =>
Configuration.GetObjectFromConfigSection<DataStoreConfiguration>("DataStoreConfiguration"));
The appSettings.json config looked something like the following:
{
"DataStoreConfiguration": {
"ConnectionString": "Server=Server-goes-here;Database=My-database-name;Trusted_Connection=True;MultipleActiveResultSets=true",
"MeaningOfLifeInt" : "42"
},
"AnotherSection" : {
"Prop1" : "etc."
}
}
The DataStoreConfiguration class was defined in my library project and looked like the following:
namespace MyLibrary.DataAccessors
{
public class DataStoreConfiguration
{
public string ConnectionString { get; set; }
public int MeaningOfLifeInt { get; set; }
}
}
With this application and libraries configuration, I was able to inject a concrete instance of DataStoreConfiguration directly into my library using constructor injection without the IOption wrapper:
using System.Data.SqlClient;
namespace MyLibrary.DataAccessors
{
public class DatabaseConnectionFactory : IDatabaseConnectionFactory
{
private readonly DataStoreConfiguration dataStoreConfiguration;
public DatabaseConnectionFactory(
DataStoreConfiguration dataStoreConfiguration)
{
// Here we inject a concrete instance of DataStoreConfiguration
// without the `IOption` wrapper.
this.dataStoreConfiguration = dataStoreConfiguration;
}
public SqlConnection NewConnection()
{
return new SqlConnection(dataStoreConfiguration.ConnectionString);
}
}
}
Decoupling is an important consideration for DI, so I'm not sure why Microsoft have funnelled users into coupling their class libraries to an external dependency like IOptions, no matter how trivial it seems or what benefits it supposedly provides. I would also suggest that some of the benefits of IOptions seem like over-engineering. For example, it allows me to dynamically change configuration and have the changes tracked - I've used three other DI containers which included this feature and I've never used it once... Meanwhile, I can virtually guarantee you that teams will want to inject POCO classes or interfaces into libraries for their settings to replace ConfigurationManager, and seasoned developers will not be happy about an extraneous wrapper interface. I hope a utility similar to what I have described here is included in future versions of ASP.NET Core OR that someone provides me with a convincing argument for why I'm wrong.
I can't stand the IOptions recommendation either. It's a crappy design to force this on developers. IOptions should be clearly documented as optional, oh the irony.
This is what I do for my configuraition values
var mySettings = new MySettings();
Configuration.GetSection("Key").Bind(mySettings);
services.AddTransient(p => new MyService(mySettings));
You retain strong typing and don't need need to use IOptions in your services/libraries.
You can do something like this:
services.AddTransient(
o => ConfigurationBinder.Get<AppSettings>(Configuration.GetSection("AppSettings")
);
Using Net.Core v.2.2, it's worked for me.
Or then, use IOption<T>.Value
It would look something like this
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
I would recommend avoiding it wherever possible. I used to really like IOptions back when I was working primarily with core but as soon as you're in a hybrid framework scenario it's enough to drive you spare.
I found a similar issue with ILogger - Code that should work across frameworks won't because I just can't get it to bind properly as the code is too dependent on the DI framework.
I hope somebody is able to help me, because it seems I'm totally stuck.
For upcoming projects in our company we'd like to use Entity Framework 5 with an code first approach. I played around a little while and everytime I try to use EF with our existing libraries, I fail because it seems EF heavily relies on an existing app.config.
In our company, we have an inhouse database library that allows us to connect to various data sources and database technologies taking the advantages of MEF (managed extensibility framework) for database providers. I just have to pass some database settings, such as host (or file), catalog, user credentials and a database provider name, the library looks for the appropriate plugin and returns me a custom connection string or IDbConnection.
We'd like to use this library together with EF because it allows us to be flexible about which database we use also change the database at runtime.
So. I saw that a typical DbContext object takes no parameters in the constructor. It automatically looks for the appropriate connection string in app.config. We don't like such things so I changed the default constructor to take a DbConnection object that get's passed to the DbContext base class. No deal.
Problems occur when the code first model changes. EF automatically notices this and looks for migration classes / configuration. But: A typical migration class requires a default parameterless constructor for the context! What a pity!
So we build our own migration class using the IDbContextFactory interface. But again, it seems that also this IDbContextFactory needs a parameterless constructor, otherwise I'm not able to add migrations or update the database.
Further, I made my own data migration configurator where I pass the context, also the target database. Problem is here: It doesn't find any migration classes, no matter what I try.
I'm completely stuck because it seems the only way to use EF is when connection strings are saved in app.config. And this is stupid because we need to change database connections at runtime, and app.config is read-only for default users!
How to solve this?
The answer is provided here
https://stackoverflow.com/a/15919627/941240
The trick is to slightly modify the default MigrateDatabaseToLatestVersion initializer so that:
the database is always initialized ...
... using the connection string from current context
The DbMigrator will still create a new data context but will copy the connection string from yours context according to the initializer. I was even able to shorten the code.
And here it goes:
public class MasterDetailContext : DbContext
{
public DbSet<Detail> Detail { get; set; }
public DbSet<Master> Master { get; set; }
// this one is used by DbMigrator - I am NOT going to use it in my code
public MasterDetailContext()
{
Database.Initialize( true );
}
// rather - I am going to use this, I want dynamic connection strings
public MasterDetailContext( string ConnectionString ) : base( ConnectionString )
{
Database.SetInitializer( new CustomInitializer() );
Database.Initialize( true );
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
public class CustomInitializer : IDatabaseInitializer<MasterDetailContext>
{
#region IDatabaseInitializer<MasterDetailContext> Members
// fix the problem with MigrateDatabaseToLatestVersion
// by copying the connection string FROM the context
public void InitializeDatabase( MasterDetailContext context )
{
Configuration cfg = new Configuration(); // migration configuration class
cfg.TargetDatabase = new DbConnectionInfo( context.Database.Connection.ConnectionString, "System.Data.SqlClient" );
DbMigrator dbMigrator = new DbMigrator( cfg );
// this will call the parameterless constructor of the datacontext
// but the connection string from above will be then set on in
dbMigrator.Update();
}
#endregion
}
Client code:
static void Main( string[] args )
{
using ( MasterDetailContext ctx = new MasterDetailContext( #"Database=ConsoleApplication801;Server=.\SQL2012;Integrated Security=true" ) )
{
}
using ( MasterDetailContext ctx = new MasterDetailContext( #"Database=ConsoleApplication802;Server=.\SQL2012;Integrated Security=true" ) )
{
}
}
Running this will cause the two databases to be created and migrated according to the migration configuration.
It needs a parameterless constructor in order to invoke it. What you could do is provide your default DbConntectionFactory in the empty constructor, something like:
public DbContext()
{
IDbContextFactory defaultFactory; //initialize your default here
DbContext(defaultFactory);
}
public DbContext(IDbContextFactory factory)
{
}