Entityframework code based config - entity-framework

I'm trying to get rid of the App.config with its EntityFramework (v6) settings and move it into code (Don't want to deploy the config with connection string and password).
Following exception is thrown on opening: System.Data.Entity.Core.EntityException: The underlying provider failed on Open.
I'm using sqlite3 db with encryption and database first entity model.
[DbConfigurationType(typeof(DatabaseConfiguration))]
public partial class TestEntities : DbContext
{
public TestEntities () :
base((DatabaseConfiguration.GetConnectionString("TestEntities", #"\\\\ABT\01_Tools\Test\DB\test.db", "someDummyPw")))
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<Employee> Employees { get; set; }
}
public class SQLiteConnectionFactory:IDbConnectionFactory
{
public DbConnection CreateConnection(string nameOrConnectionString)
{
return new SQLiteConnection(nameOrConnectionString);
}
}
public class DatabaseConfiguration:DbConfiguration
{
public DatabaseConfiguration()
{
SetDefaultConnectionFactory(new SQLiteConnectionFactory());
SetProviderFactory("System.Data.SQLite", SQLiteFactory.Instance);
SetProviderFactory("System.Data.SqlClient", SqlClientFactory.Instance);
SetProviderFactory("System.Data.SQLite.EF6", SQLiteProviderFactory.Instance);
//SetProviderFactory("System.Data.EntityClient", EntityProviderFactory.Instance);
SetProviderServices("System.Data.SQLite.EF6", (DbProviderServices)SQLiteProviderFactory.Instance.GetService(typeof(DbProviderServices)));
}
public static string GetConnectionString(string efModelName, string databaseFilePath, string password)
{
// Initialize the connection string builder for the underlying provider.
SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder
{
DataSource = databaseFilePath,
Password = password
};
// Initialize the EntityConnectionStringBuilder.
EntityConnectionStringBuilder entityBuilder = new EntityConnectionStringBuilder();
entityBuilder.Provider = "System.Data.SQLite.EF6";
// Set the provider-specific connection string.
entityBuilder.ProviderConnectionString = sqlBuilder.ToString();
// Set the Metadata location.
entityBuilder.Metadata = string.Format(#"res://*/Model.{0}.csdl|res://*/Model.{0}.ssdl|res://*/Model.{0}.msl", efModelName);
return entityBuilder.ConnectionString;
}
}
Any Ideas?

Related

How to use dynamic connection string in mongodbcontext in C#

I would like to connect to the database specified in the connection string. I have multiple connection sting for different client
public MongoContext(IConfiguration configuration)
{
_configuration = configuration;
// Every command will be stored and it'll be processed at SaveChanges
_commands = new List<Func<Task>>();
}
private void ConfigureMongo()
{
if (MongoClient != null)
{
return;
}
// Configure mongo (You can inject the config, just to simplify)
MongoClient = new MongoClient(_configuration["MongoSettings:Connection"]);
Database = MongoClient.GetDatabase(_configuration["MongoSettings:DatabaseName"]);
}
public IMongoCollection<T> GetCollection<T>(string name)
{
ConfigureMongo();
return Database.GetCollection<T>(name);
}
}
My Repository Class is
public abstract class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected readonly IMongoContext Context;
protected IMongoCollection<TEntity> DbSet;
protected BaseRepository(IMongoContext context, int parentID)
{
Context = context;
DbSet = Context.GetCollection<TEntity>(typeof(TEntity).Name);
}
}
For each request, i want to set connection string dynamically based on UserID
Not sure I've got what you're asking, but if you need connecting to more than one cluster, you should create a separate mongo client for each separate cluster

Get current logged in user in DbContext

For audit purposes I'm trying to get the current logged in user in my DbContext. However I'm having some issues with this. A few things to take into account:
In Blazor Server we have to use AddDbContextFactory
IHttpContextAccessor returns no result in deployed website (might be because IHttpContextAccessor is not thread safe?)
I created a custom DbContext that injects AuthenticationStateProvider.
public partial class CustomDbContext : DbContext
{
private AuthenticationStateProvider _authenticationStateProvider;
#region construction
public CustomDbContext ()
{
}
public CustomDbContext (AuthenticationStateProvider stateProvider)
{
_authenticationStateProvider = stateProvider;
}
[ActivatorUtilitiesConstructor]
public CustomDbContext (DbContextOptions<CustomDbContext> options, AuthenticationStateProvider stateProvider) : base(options)
{
_authenticationStateProvider = stateProvider;
}
public CustomDbContext(DbContextOptions<CustomDbContext> options) : base(options)
{
}
#endregion
...
In this DbContext, when overwriting the SaveChanges I get the User and their claims:
var state = await _authenticationStateProvider.GetAuthenticationStateAsync();
var userIdClaim = state.User.Claims.FirstOrDefault(c => c.Type == "userId")?.Value;
userId = userIdClaim != null && !string.IsNullOrEmpty(userIdClaim ) ? userIdClaim : string.Empty;
...
However when I call .CreateDbContext(); on the injected DbContextFactory, I get the following exception:
'Cannot resolve scoped service
'Microsoft.AspNetCore.Components.Authorization.AuthenticationStateProvider'
from root provider.'
I've found some topics about this, but the suggested solution there is to create a custom DbContextFactory that is scoped. But then you lose the reason why you are using the DbContextFactory, no?
Any ideas on how to solve this?
Thank you
The DBContextFactory is a singleton registered in the root application DI container, while the AuthenticationStateProvider is a scoped service that is registered in the Hub session DI container. You can't access a lower order service from a higher order service.
You need to rethink your design and provide the user information from whatever scoped service is making whatever call to need a DbConbtext.
Additional Information
I'm not sure what your data pipeline looks like so this example uses the Blazor template weather forecast.
First a View Service that components inject and use.
This injects the AuthenticationStateProvider. It gets the current user for each request and passes it to the data pipeline in a request object.
public class WeatherForecastViewService
{
private AuthenticationStateProvider _authenticationStateProvider; // scoped service
private WeatherForecastService _weatherForecastService; //Singleton Service
public WeatherForecastViewService(AuthenticationStateProvider authenticationStateProvider, WeatherForecastService weatherForecastService)
{
_authenticationStateProvider = authenticationStateProvider;
_weatherForecastService = weatherForecastService;
}
public async ValueTask SaveWeatherForecast(WeatherForecast record)
{
var user = await GetCurrentUser();
var request = new RecordRequest<WeatherForecast>(record, user );
await _weatherForecastService.SaveRecord(request);
}
private async ValueTask<ClaimsPrincipal> GetCurrentUser()
{
var state = await _authenticationStateProvider.GetAuthenticationStateAsync();
return state.User ?? new ClaimsPrincipal();
}
}
Here are the request and result objects:
public readonly struct RecordRequest<TRecord>
{
public TRecord Record { get; init; }
public ClaimsPrincipal Identity { get; init; }
public RecordRequest(TRecord record, ClaimsPrincipal identity)
{
this.Record = record;
this.Identity = identity;
}
}
public record RecordResult
{
public bool SuccessState { get; init; }
public string Message { get; init; }
private RecordResult(bool successState, string? message)
{
this.SuccessState = successState;
this.Message = message ?? string.Empty;
}
public static RecordResult Success(string? message = null)
=> new RecordResult(true, message);
public static RecordResult Failure(string message)
=> new RecordResult(false, message);
}
And here's the singleton data service
public class WeatherForecastDataService
{
// This is a singleton
private readonly IDbContextFactory<DbContext> _factory;
public WeatherForecastDataService(IDbContextFactory<DbContext> factory)
=> _factory = factory;
public async ValueTask<RecordResult> SaveRecord(RecordRequest<WeatherForecast> request)
{
if (!request.Identity.IsInRole("SomeRole"))
return RecordResult.Failure("User does not have authority");
// simulates some async DB activity
await Task.Delay(100);
// Get your DbContext from the injected Factory
// using var dbContext = this.factory.CreateDbContext();
// do your db stuff
return RecordResult.Success();
}
}
PS I haven'y actually run this code so there may be some typos!
IHttpContextAccessor returns no result in deployed website (might be because IHttpContextAccessor is not thread safe?)
Nothing to do with whether IHttpContextAccessor is not thread safe... It's simply because the HttpContext object is not available in Blazor Server App, as communication between the client side (browser) and server side is done through the SignalR protocol, not HTTP. But there is a way how to access the HttpContext object before the Blazor App is rendered, as the initial call to the app is always made through HTTP request; that is, when you enter a url into the address bar of your browser and hit the enter button. See here how to do that...
The following code snippet describes how to inject an AuthenticationStateProvider into the ApplicationDbContext object created by default when you select Individual Accounts in Blazor Server App.
Copy and test. It should work...
Data/ApplicationDbContext.cs
public class ApplicationDbContext : IdentityDbContext
{
public DbSet<Employee> Employees { get; set; }
private AuthenticationStateProvider _authenticationStateProvider;
public ApplicationDbContext(DbContextOptions<ApplicationDbContext>
options, AuthenticationStateProvider stateProvider)
: base(options)
{
_authenticationStateProvider = stateProvider;
}
public override async Task<int>
SaveChangesAsync(CancellationToken cancellationToken)
{
var stateProvider = await
_authenticationStateProvider.GetAuthenticationStateAsync();
if (stateProvider.User.Identity.IsAuthenticated)
{
Console.WriteLine("Authenticated User name: " +
stateProvider.User.Identity.Name);
}
// Delegate the saving action to the base class
return await base.SaveChangesAsync(cancellationToken);
}
}
Create an Employee Repository class service:
EmployeeRepository.cs
using <put here the namespace of your app>.Data;
using <put here the namespace of your app>.Models;
using Microsoft.EntityFrameworkCore;
public class EmployeeRepository
{
private readonly ApplicationDbContext ApplicationDbContext;
public EmployeeRepository(ApplicationDbContext
applicationDbContext)
{
ApplicationDbContext = applicationDbContext;
}
public async Task<Employee> CreateEmployee(Employee employee)
{
CancellationTokenSource cancellationTokenSource = new
CancellationTokenSource();
CancellationToken token = cancellationTokenSource.Token;
await ApplicationDbContext.Employees.AddAsync(employee);
await ApplicationDbContext.SaveChangesAsync(token);
return employee;
}
}
Index.razor
#inject EmployeeRepository EmployeeRepository
#using <Put here....>.Models
<button type="button" #onclick="SaveEmployee">Save Employee</button>
#if (emp != null)
{
<div>#emp.ID.ToString()</div>
<div>#emp.FirstName</div>
<div>#emp.LastName</div>
<div>#emp.City</div>
}
#code
{
private Employee emp;
private async Task SaveEmployee()
{
Employee employee = new Employee { FirstName = "Joana", LastName = "Brown", City = "London" };
emp = await EmployeeRepository.CreateEmployee(employee);
}
}
Create model class Employee:
Models/Employee.cs
public class Employee
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string City { get; set; }
}
Note: To test this code, you'll have to create A Blazor Server App with Individual Accounts, create the database, including the Employees table
Last but not least: Startup
// Created by the default template
//services.AddDbContext<ApplicationDbContext>(options =>
// options.UseSqlServer(
// Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(options =>
options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddDbContextFactory<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")),
ServiceLifetime.Scoped);
// This is your code...
services.AddScoped<ApplicationDbContext>(p =>
p.GetRequiredService<IDbContextFactory<ApplicationDbContext>>
().CreateDbContext());
services.AddScoped<EmployeeRepository>();
services.AddScoped<AuthenticationStateProvider,
RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddSingleton<WeatherForecastService>();
UPDATE:
but does that no against the the recommendations of Microsoft? They ae suggesting to always use using
var context = DbFactory.CreateDbContext();
You mean:
using var context = DbFactory.CreateDbContext();
No, it is not against the recommendations of Microsoft. It's another way to instantiate the DbContext. I did it that way in order to stick to this code by you:
services.AddScoped<ApplicationDbContext>(p => p.GetRequiredService<IDbContextFactory<ApplicationDbContext>>().CreateDbContext());
Anyhow, these are the changes you should make in order to reflect "Microsoft's recommendations"
Change:
services.AddScoped<ApplicationDbContext>(p => p.GetRequiredService<IDbContextFactory<ApplicationDbContext>>().CreateDbContext());
To:
services.AddScoped<ApplicationDbContext>();
Change:
private readonly ApplicationDbContext ApplicationDbContext;
public EmployeeRepository(ApplicationDbContext
applicationDbContext)
{
ApplicationDbContext = applicationDbContext;
}
To:
private readonly IDbContextFactory<ApplicationDbContext>
DbFactory;
public EmployeeRepository(IDbContextFactory<ApplicationDbContext>
_DbFactory)
{
DbFactory = _DbFactory;
}
And change:
await ApplicationDbContext.Employees.AddAsync(employee);
await ApplicationDbContext.SaveChangesAsync(token);
To:
await context.Employees.AddAsync(employee);
await context.SaveChangesAsync(token);
Also add:
using var context = DbFactory.CreateDbContext();
at the beginning of the EmployeeRepository.CreateEmployee method
Run and test.
Hope this work...
New Version
Data/ApplicationDbContext.cs
public class ApplicationDbContext : IdentityDbContext
{
public DbSet<Employee> Employees { get; set; }
private AuthenticationStateProvider _authenticationStateProvider;
public ApplicationDbContext(DbContextOptions<ApplicationDbContext>
options, AuthenticationStateProvider stateProvider)
: base(options)
{
_authenticationStateProvider = stateProvider;
}
public override async Task<int>
SaveChangesAsync(CancellationToken cancellationToken)
{
var stateProvider = await
_authenticationStateProvider.GetAuthenticationStateAsync();
if (stateProvider.User.Identity.IsAuthenticated)
{
Console.WriteLine("Authenticated User name: " +
stateProvider.User.Identity.Name);
}
// Delegate the saving action to the base class
return await base.SaveChangesAsync(cancellationToken);
}
}
Create an Employee Repository class service:
EmployeeRepository.cs
using <put here the namespace of your app>.Data;
using <put here the namespace of your app>.Models;
using Microsoft.EntityFrameworkCore;
public class EmployeeRepository
{
private readonly IDbContextFactory<ApplicationDbContext> DbFactory;
public EmployeeRepository(IDbContextFactory<ApplicationDbContext> _DbFactory)
{
DbFactory = _DbFactory;
}
public async Task<Employee> CreateEmployee(Employee
employee)
{
using var context = DbFactory.CreateDbContext();
// CancellationTokenSource provides the token and have authority to cancel the token
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationToken token = cancellationTokenSource.Token;
await context.Employees.AddAsync(employee);
await context.SaveChangesAsync(token);
return employee;
}
}
Index.razor
#inject EmployeeRepository EmployeeRepository
#using <Put here....>.Models
<button type="button" #onclick="SaveEmployee">Save Employee</button>
#if (emp != null)
{
<div>#emp.ID.ToString()</div>
<div>#emp.FirstName</div>
<div>#emp.LastName</div>
<div>#emp.City</div>
}
#code
{
private Employee emp;
private async Task SaveEmployee()
{
Employee employee = new Employee { FirstName = "Joana", LastName = "Brown", City = "London" };
emp = await EmployeeRepository.CreateEmployee(employee);
}
}
Create model class Employee:
Models/Employee.cs
public class Employee
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string City { get; set; }
}
Note: To test this code, you'll have to create A Blazor Server App with Individual Accounts, create the database, including the Employees table
Last but not least: Startup
public void ConfigureServices(IServiceCollection services)
{
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddDbContextFactory<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")),
ServiceLifetime.Scoped);
services.AddScoped<ApplicationDbContext>();
services.AddScoped<EmployeeRepository>();
services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddSingleton<WeatherForecastService>();
}

Dbcontext not able to migrate because schema does not exist?

I am currently writing some integrations test which affect the database just in a different schema.
I am following this guide
https://www.thinktecture.com/en/entity-framework-core/isolation-of-integration-tests-in-2-1/
My problem is with this abstract class used for creating DbContext?
public abstract class IntegrationTestsBase<T> : IDisposable
where T : DbContext
{
private readonly string _schema;
private readonly string _historyTableName;
private readonly DbContextOptions<T> _options;
protected T DbContext { get; }
protected IntegrationTestsBase()
{
_schema = Guid.NewGuid().ToString("N");
_historyTableName = "__EFMigrationsHistory";
_options = CreateOptions();
DbContext = CreateContext();
DbContext.Database.Migrate();
}
protected abstract T CreateContext(DbContextOptions<T> options,
IDbContextSchema schema);
protected T CreateContext()
{
return CreateContext(_options, new DbContextSchema(_schema));
}
private DbContextOptions<T> CreateOptions()
{
return new DbContextOptionsBuilder<T>()
.UseNpgsql($"Server=(local);Database=Demo;...",
builder => builder.MigrationsHistoryTable(_historyTableName, _schema))
.ReplaceService<IMigrationsAssembly, DbSchemaAwareMigrationAssembly>()
.ReplaceService<IModelCacheKeyFactory, DbSchemaAwareModelCacheKeyFactory>()
.Options;
}
public void Dispose()
{
DbContext.GetService<IMigrator>().Migrate("0");
DbContext.Database.ExecuteSqlCommand(
(string)$"DROP TABLE [{_schema}].[{_historyTableName}]");
DbContext.Database.ExecuteSqlCommand((string)$"DROP SCHEMA [{_schema}]");
DbContext?.Dispose();
}
}
DbContext is being created, but once the migrations is being called i get an error stating that the schema, does not exist?
which I am not sure why because i in my ensure the in my configuration
public class SchemaContext : DbContext, IDbContextSchema
{
public virtual DbSet<Schema>? SchemaModel { get; set; }
public SchemaContext()
{
}
public SchemaContext(DbContextOptions<SchemaContext> options, IDbContextSchema schema = null)
: base(options)
{
Schema = schema.Schema;
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema(Schema);
//base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
}
public string Schema { get; }
}
I would assume that modelBuilder.HasDefaultSchema(Schema); would have created the schema?
which does not seem to be case, hence migration fails? what am I missing? why is the schema not being created in the actual database?
In your could you are configure Context with method - UseSqlServer which is used only for MS SQL, you have to use Npgsql.EntityFrameworkCore.PostgreSql package and configure you context with UseNpgsql extension method:
.UseNpgsql("Host=localhost;Port=5432;Database=my_db;Username=postgres;Password=password");

EF migration control logging SQL

I have some code for creating a database and applying migrations:
public static (Server Server, string ConnectionString) InitializeServerAndDatabase(string databaseName, string defaultConnectionConnectionString, DbMigrationsConfiguration migrationsConfiguration)
{
var sqlConnection = new SqlConnection(defaultConnectionConnectionString);
var serverConnection = new ServerConnection(sqlConnection);
var server = new Server(serverConnection);
var database = new Database(server, databaseName);
database.Create();
// Build database with migrations and seed data
var sqlConnectionStringBuilder = new SqlConnectionStringBuilder(defaultConnectionConnectionString);
sqlConnectionStringBuilder.InitialCatalog = databaseName;
var connectionString = sqlConnectionStringBuilder.ToString();
migrationsConfiguration.TargetDatabase = new DbConnectionInfo(connectionString, "System.Data.SqlClient");
var migrator = new DbMigrator(migrationsConfiguration);
var logger = new MigratorLoggingDecorator(migrator, new MinimalMigrationLogger());
logger.Update();
// Set environment variable so the DbContext will establish a connection to the right database
Environment.SetEnvironmentVariable("DefaultConnection", connectionString);
return (server, connectionString);
}
Since running migrations logged a lot more SQL than I wanted, I attempted minimize the logging by writing MinimalMigrationsLogger, which is used in the method above:
public class MinimalMigrationLogger : MigrationsLogger
{
public override void Info(string message)
{
// Ignore it; there's too much of it clogging up CI
}
public override void Verbose(string message)
{
// The SQL text and other info comes here
// Ignore it; there's too much of it clogging up CI
}
public override void Warning(string message)
{
Console.WriteLine(message);
}
}
However, I'm still getting SQL in my logs for creating the table and the seed data. Why does my setup not avoid this? How can I change it so that it will not log table creation and seed data SQL?
Try the following full example and see what's the difference with yours.
All you have to do ,is create the migrations on the same project
using Microsoft.SqlServer.Management.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Migrations;
using System.Data.Entity.Migrations.Infrastructure;
namespace EntityFramework.ConsoleExample
{
using Microsoft.SqlServer.Management.Smo;
class Program
{
public static string ServerName = "localhost";
public static string DbName = "EntityFramework.ConsoleExample.MyContenxt";
public static string ConnectionString = #"Server=" + ServerName + "; Database=" + DbName + #";Integrated Security = True;MultipleActiveResultSets=true";
static void Main(string[] args)
{
var conf = new EntityFramework.Console.Migrations.Configuration
{
MigrationsAssembly = typeof(Customer).Assembly
};
InitializeServerAndDatabase(DbName, ServerName, Program.ConnectionString, conf);
System.Console.ReadLine();
}
public static void InitializeServerAndDatabase(string databaseName, string serverName, string defaultConnectionConnectionString, DbMigrationsConfiguration migrationsConfiguration)
{
ServerConnection sqlConnection = new ServerConnection(serverName);
Server sqlServer = new Server(sqlConnection);
Database newDB = new Database(sqlServer, databaseName);
newDB.Create();
migrationsConfiguration.TargetDatabase = new DbConnectionInfo(defaultConnectionConnectionString, "System.Data.SqlClient");
var migrator = new DbMigrator(migrationsConfiguration);
var logger = new MigratorLoggingDecorator(migrator, new MinimalMigrationLogger());
logger.Update();
}
}
public class Customer
{
public int CustomerId { get; set; }
public int Age { get; set; }
public string Name { get; set; }
public string Name2 { get; set; }
public string Name3 { get; set; }
}
public class MyContenxt : DbContext
{
public DbSet<Customer> Customers { get; set; }
}
public class MinimalMigrationLogger : MigrationsLogger
{
public override void Info(string message)
{
System.Console.WriteLine("Info::::" + message);
}
public override void Verbose(string message)
{
//System.Console.WriteLine("Verbose::::" + message);
}
public override void Warning(string message)
{
System.Console.WriteLine("Warning::::" + message);
}
}
}

WebApi Switch Connectionstring related on HeaderValue - Request is null

We have different Customers and each of them own a Database.
the client send an Request with an HttpHeader DatabaseOwner:Samsung
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("DatabaseOwner", "Samsung");
In my ApiController i would like that my Context is based on that Value and connects to the correct Database
public class AuthController : ApiController
{
public CmpContext db { get; set; }
public AuthController(): base()
{
db = new CmpContext(VcsCmpConnectionstring.GetCMPConnectionString(this.Request));
}
// GET api/Auth
public IQueryable<DealerModel> GetDealer()
{
return db.Dealer;
}
public static string GetCMPConnectionString(HttpRequestMessage request)
{
string returnvalue;
if (request.Headers.Contains("DatabaseOwner"))
{
SqlConnectionStringBuilder ConnStringBuilder = new SqlConnectionStringBuilder(ConfigurationManager.ConnectionStrings["CMPContext"].ConnectionString);
ConnStringBuilder.InitialCatalog = "vcs_cmp_" + request.Headers.GetValues("DatabaseOwner").First();
returnvalue = ConnStringBuilder.ToString();
}
else
{
throw new MissingFieldException("Header DatabaseOwneris null");
}
return returnvalue;
}
When i try to get this.Request it is always null
When is Request access able or is there a better way to switch between Databases?
Greetings from Bavaria
Patrick
Request object is only initialized after APIController's Initialize function is called. So you cannot access Request before base.initialize is called. Try doing this:
public class AuthController : ApiController
{
protected override void Initialize(
System.Web.Http.Controllers.HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
db = new CmpContext(
VcsCmpConnectionstring.GetCMPConnectionString(this.Request));
}
}