How to use Connection String in Azure functions for EF Core 2.1 - entity-framework-6

When using Entity Framework 6+ I can have a class inherit form DbContext like this
MyContext : DbContext
Then I could use the code like this
using (var context = new MyContext())
{
...
}
As long as I had a configuration file with connection string settings with the same name this would be picked up by Entity Framework. Quite nice for different environments.
Now I am working with Azure Functions running on .NET CORE, .NET STANDARD and Entity Framework Core 2.1
But I cant figure out how to achieve the same. Even though there is a dedicated section for ConnectionStrings in Azure Function app and i would expect the local.seeting.json with an input like this
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"AzureWebJobsDashboard": "UseDevelopmentStorage=true",
},
"ConnectionStrings": {
"MyContext": "Server=(localdb)\\mssqllocaldb;Database=MyContext;Trusted_Connection=True;ConnectRetryCount=0"
}
}
should do the same. But no.
All the samples I can find is where you have to inject the DbContextOptionsBuilder or a connection string into the constructor.
But since it is Azure Function and DI framework dont play that well with it I rather avoid to pass the connection string or db context all the way down the layers.
In short: Can EF Core not pick up the settings from a file itself?

Related

Handling DB transactions/ DbContext with ASP.NET MVC with Entity Framework, UnityConfig and Multi-Tenancy

I am getting the error "System.Data.SqlClient.SqlException: New transaction is not allowed because there are other threads running in the session." when we hit 2 or more simultaneous users conducting the same DB action.
It doesn't matter whether its a query or we are making actual data changes using the entity framework, we continue to get this issue when multiple users hit the same web functions.
From looking at other posts it is my understanding we should ensure the DbContext is initialized/unique for each web request which should ensure the transaction issue is resolved.
We are using ASP.NET MVC 4 w/ UnityConfig, EntityFramework and a Multi-Tenancy architecture connecting to Azure SQL from an Azure Web App.
The DB gets initialized in Unity here:
container.RegisterType<IStorageUnitOfWork, StorageElasticScaleUoW<int>>(new InjectionConstructor(sharding.ShardMap, tenantId, connStrBldr.ConnectionString));
and this IStorageUnitOfWork is setup like:
public class StorageElasticScaleUoW<T> : DbContext, IStorageUnitOfWork
{
public StorageElasticScaleUoW()
{
this.Database.CommandTimeout = 0;
}
protected internal StorageElasticScaleUoW(string connectionString)
: base(SetInitializerForConnection(connectionString))
{
this.Database.CommandTimeout = 0;
}
I am unclear on the best approach to move this to a per web request architecture (assuming that is the be the appropriate solution).
I have seen some posts talking about using TransientLifetimeManager and PerThreadLifetimeManager on initializing the unitofWork but I am not clear how that will work with multi-tenancy. In case it helps, our multi-tenancy/sharding setup mirrors the one Microsoft suggest here: https://learn.microsoft.com/en-nz/azure/sql-database/saas-tenancy-elastic-tools-multi-tenant-row-level-security
Thanks!
The tenant ID is (or should be) simply another parameter you should be passing into your DbContext constructor that you then use to define query filters (different depending on version you're using). You want each request to your application to have their own instance of that DbContext, so you'd use PerRequestLifetimeManager (see this answer).

Where does an MVC Controller get it's database context at run time

Given this code:
namespace Eisk.Controllers
{
public class EmployeesController : Controller
{
DatabaseContext _dbContext;
public EmployeesController(DatabaseContext databaseContext)
{
_dbContext = databaseContext;
}
public ViewResult Index()
{
var employees = _dbContext.EmployeeRepository;
return View(employees.ToArray());
}
Note that the constructor doesn't new up a database.
When accessed from a unit test I can inject a databaseContext and the controller will use that for the duration of the test. What I can't figure out is where this code is getting the database context it's using at run time. If I could find that out I might be able to figure out how to circumvent that behavior and have it use a mocked/in memory DB instead.
More explanation:
I don't have access to a legacy database for this application right now so I'm trying to Mock up an in memory data source that gets filled from xml files. That's why I need to be able to circumvent the default database context creation.
More Information:
Thanks for all the help so far you wonderful people you.
Steven seems to have directed me down the correct path.
In the Global.asax file is this call:
DependencyInjectorInitializer.Init();
Following that through the code I get to:
public static void Initialize()
{
_container = new UnityContainerFactory().CreateConfiguredContainer();
var serviceLocator = new UnityServiceLocator(_container);
ServiceLocator.SetLocatorProvider(() => serviceLocator);
DependencyResolver.SetResolver(new UnityDependencyResolver(_container));
}
At least that gets me headed in the right direction. Now I have to figure out how Unity is going about creating the context so I can do my intervention.
Let me plug the EISK MVC Employee Info Starter Kit here. It's a well thought out system developed by Mohammad Ashraful Alam Et al. that includes a well fledged example of how many of the new technologies fit together. MVC 5, Entity Framework 6, Unity, Authentication, OpenAuth, DI, Moq, and a couple of other things. Can be used as a template, general learning, or training.
Employee Info Starter Kit
With the default configuration of ASP.NET MVC, a controller should have a default constructor (i.e. a public constructor with no parameters). If not ASP.NET MVC will throw the following exception:
Type 'Eisk.Controllers.EmployeesController' does not have a default
constructor
If this however works, this means that you (or another developer) overwrote the default configuration by either using a custom IControllerFactory or custom IDependencyResolver. Most developers do this by using an open source Dependency Injection library (such as Simple Injector, Autofac or Castle Windsor). If you pull in the NuGet MVC integration packages for such library, it will usually do this configuration for you. So somebody on your team might have done this for you.
My advice is: talk to your team and ask them how they did this and which container they used and where you can find the configuration for that.

Automatically updating database with multiple DbContexts

I'm using EF6 in ASP.NET 5 project. Where I'm using ASP.NET Identity as the authentication mechanism. As anyone would do, I have modeled my domain objects in a separate dll project and for data access logic I have a separate project. This data project contains EF migrations, DbContext for domain models, repositories and Unit of work.
And I have a service layer which is contacted by ASP.NET controllers and this service layer will communicate with data layer and do required operations.
In the main ASP.NET web project I have the default DbContext which is related to Identity and it's migrations.
Having two DbContexts somehow prevents me from updating database automatically. If I had only one DbContext after I create migrations for model changes, it will automatically run on the first time I try to access the website. This doesn't happen anymore, always I have to run the "update-database" command manually.
One solution I have right now is to add a reference to "Microsoft.AspNet.Identity.EntityFramework" in my data project and use Identity context contain my domain tables. But adding an ASP.NET reference in my data project is something I don't want to do unless I have no other options. Because data layer is not even communicating directly with web layer.
Even though this video by Scott Allen discuss about this issue, a solution is not proposed.
You can kick in migrations explicitly by using database initializer and using MigrateDatabaseToLatestVersion. This initializer allows you explicitly state the context and configuration you want to use. Something like:
SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Configuration>());
You can also call all the logic manually, effectively doing the same as Update-Database cmdlet, when you want during app start. Look at DbMigrator class.
You can run migration inside each DbContext constructor separately.
public class DataContext: DbContext
{
static DaraContext()
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<DataContext, Configuration>());
}
}
public class ApplicationDbContext : IndetityDbContext
{
static ApplicationDbContext()
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<ApplicationDbContext, Configuration>());
}
}

Is it possible to connect an Asp.net MVC web application with more than one databases

I want to develop a new asp.net MVC web application but this application should be able to :-
perform CRUD operations on an already existing web application Database that is deployed on the same server as the asp.net mvc.
Also the asp.net MVC web application should have its own database .
All the MVC projects I have implemented so far were either, using their own database or were build on existing database.
But will it be possible to build a new asp.net mvc application on existing database to retrieve data, insert data and delete data; But at the same time to have its own database.
Baring in mind that I am using the entity framework as the data access layer.
BR
It is possible. You will need to create a Entity Framework model for each database.
Yes, it's entirely possible regardless of the framework you use to connect to the databases, ADO.NET, EF, etc.
I would have a separate DAL project containing all the DAL logic and some kind of DBFactory class returning the specific DBContext according to where the data is going to be retrieved from.
Example:
public static IEnumerable<User> GetAllUsers()
{
using(var dbContext = DBFactory.GetContext(EDbConnecion.SQLSERVER) )
{
//regular LINQ code here
}
}
And the only job of the DBFactory.GetContext method is something like:
public static DbContext DBFactory.GetContext(EDbConnection connType)
{
switch(connType)
{
case EDbConnecion.SQLSERVER:
return new SqlServerContext("WhatHaveYou");
case EDbConnecion.ORACLE:
return new OracleContext("WhatHaveYou");
//and so on
}
}

Entity Framework is trying to create a database, but its not what I want

I have a small asp.net mvc4 application (working fine in my local machine), that uses entity framework v4.1.0.0 with ADO.net DbContext Generator.(SQL Server 2008 r2)
I am adding newer versions of dlls required through the "Add Deployable Dependencies..." context menu in Visual Studio 2010.
I have a shared hosting with godaddy.com, I have uploaded the files to server and created the database, now here comes the problem.When I try to browse my site I get the following error:
CREATE DATABASE permission denied in database 'master'.
I looked this up around and found out that this error was caused by EF code first trying to create database.but i do not want EF code first to recreate the database, how do i turn off this automatic database creation altogether? I have no intentions of using the code-first feature whatsoever.
Please help.
put this code into the Application_Start() method of Global.asax or constructor on your DbContext class
Database.SetInitializer<MyContext>(null);
If you want to recreate database when POCO domains are changed, use following code instead of above
Database.SetInitializer<MyContext>(new DropCreateDatabaseIfModelChanges<MyContext>());
If you are using EF Migrations, this is what you set for it:
public sealed class DbConfiguration : DbMigrationsConfiguration<DatabaseContext>
{
public DbConfiguration()
{
AutomaticMigrationsEnabled = false;
}
}
But this doesn't answer the question on EF Code First itself. If the database already exists, then EF will not try to create it. So you just need to point it to an existing database. And to make sure the connection string name is the same as the name of the database context. If it is not, you need to provide it to it with some overrides:
public class DatabaseContext : DbContext
{
public DatabaseContext()
: base(ApplicationParameters.ConnectionStringName)
{
}
public DatabaseContext(string connectionStringName)
: base(connectionStringName)
{
}
}

Resources