DbContext Errors in Azure Worker Role when using Unity - entity-framework-4

I have an Azure worker role with a UnitOfWork class that looks something like this:
public class UnitOfWork : IUnitOfWork
{
public MyData Db { get; private set; }
public ILoginRepository LoginRepository { get; private set; }
public ISubscriptionRepository SubscriptionRepository { get; private set; }
public UnitOfWork(MyData db,
ILoginRepository loginRepository,
ISubscriptionRepository subscriptionRepository)
{
}
}
The repositories accept a reference to the DbContext as well:
public class LoginRepository : Repository<Login>, ILoginRepository
{
public LoginRepository(MyData db) : base(db) { }
}
I would think this is pretty straight-forward.
Now, I'd like to configure my code-first DbContext in Unity so that each time a UnitOfWork is resolved a new DbContext is created and all subsequently resolved repositories get it too.
I'd think that PerResolveLifetimeManager would do the trick:
container.RegisterType<IUnitOfWork, UnitOfWork>();
container.RegisterType<MyData, MyData>(new PerResolveLifetimeManager());
But it does not. I get all these weird SQL-related errors, such as:
"New transaction is not allowed because there are other threads running in the session."
What gives?

You are talking about PerResolveLifetimeManager but you are using PerThreadLifetimeManager (which is said to be buggy anyways) in your code. May that be the cause of your problems?

Ok, I refactored the solution to do much more explicit Resolve calls instead of .ctor injection and then after all that I realized the main issue was around trying to update an object while iterating over an IQueryable that contained it.
Much ado about nothing, seems to me.
Thanks for the help.

Related

How do i create a class library proejct to handle my migrations and database objects in entity framework core 2.2?

I have created a .net core 2.2 web mvc application. I then created a .net core 2.2 class library to contain all my database models. When attempting to run the initial migration i get the error cannot create object of type 'X'.
I have referenced my class library in the main web project, set it as the startup and in the package manager console i set the default project as the class library.
I expected this to create my migrations but i get this error.
public class ProjectWalesDbContext : DbContext
{
public ProjectWalesDbContext(DbContextOptions<ProjectWalesDbContext> options)
: base(options)
{ }
public DbSet<User> Users { get; set; }
public DbSet<UserCourse> UserCourses { get; set; }
public DbSet<Course> UserCourse { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.Property(b => b.created_at)
.HasDefaultValueSql("getdate()");
modelBuilder.Entity<User>()
.Property(b => b.password_reset_date)
.HasDefaultValueSql("getdate()");
modelBuilder.Entity<User>()
.Property(b => b.password_reset_required)
.HasDefaultValueSql("0");
modelBuilder.Entity<UserCourse>()
.Property(b => b.course_progress)
.HasDefaultValueSql("0");
}
}
this is my db context that i set up ive set it up the same way in other projects so i cant see what ive done wrong if anything. any help would be greatly appreciated
Solved, I needed to add the line:
services.AddDbContext<ProjectWalesDbContext>(item => item.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
to the start-up of the web app so I could create the context.

Entity Framework Core Error: No parameterless constructor defined for this object

At the point of creating a new MVC Controller:
after I click Add button, I get the following Error:
Here is my simple Context class:
public class MainDbContext : DbContext
{
public MainDbContext(DbContextOptions<MainDbContext> options) : base(options)
{
}
public DbSet<Todo> Todo { get; set; }
}
and my simple model:
public partial class Todo
{
public int Id { get; set; }
public string TaskName { get; set; }
}
I have made some search on this issue, most of the posts point to a dropdown list or a SelectList method using MVC, but for my case it is a Controller creation fail, so it seems to be an Entity Framework Core issue
Any help ?
Thanks to #poke comment above, and to this link: "Use Code First with connection by convention", by modifying the context class as follows C# will call base class parameterless constructor by default
public class MainDbContext : DbContext
{
public MainDbContext()
// C# will call base class parameterless constructor by default
{
}
}
It's a tooling error. Most likely, you're running Visual Studio 2015, which doesn't have full .NET Core support. Basically, in previous versions of EF, DbContext had a parameterless constructor, and this version of the scaffold generator is depending on that. In EF Core, DbContext does not have a parameterless constructor, so the generator is choking on that.
If you're using VS2015, upgrade to 2017. It's time. Aside from that, you don't need this anyways, and it's only leading you down a bad path. All the scaffold does is create a new class under Controller, named {Name}Controller that inherits from Controller. Then it creates a folder named {Name} in Views and adds some basic HTML for doing CRUD. You'll end up replacing most of this HTML anyways. Additionally, the scaffold requires you to work with an actual entity class, which is the last thing you should ever be doing. You should always accept user input via a view model and then map that posted data onto your entity class before finally saving the entity. Look at the scaffold being broken as an excellent opportunity to start learning how to create good code.
Here's the solution from Microsoft. It suggest to create a design-time class that instantiates the connection to a database.
A solution
Because DbContext constructor is expecting DbContextOptions, AddDbContext must be set within the Startup Configuration method.
public class MainDbContext : DbContext
{
public MainDbContext(DbContextOptions<MainDbContext> options) : base(options)
{
}
public DbSet<Todo> Todo { get; set; }
}
Within projects startup.cs set AddDbContext
services.AddDbContext<MainDbContext>(o => o.UseSqlServer(#"Data Source=SOURCE;Initial
Catalog=DBCatalog;User ID=ZX;Password=******;Connect
Timeout=30;Encrypt=False;TrustServerCertificate=False;
ApplicationIntent=ReadWrite;MultiSubnetFailover=False"));
ConfigureServices method:
Set database:
UseSqlServer,
UseInMemeoryDatabase,
UseSqlite,
etc...
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MainDbContext>(o => o.UseSqlServer(#"Data Source=SOURCE;Initial
Catalog=DBCatalog;User ID=ZX;Password=******;Connect
Timeout=30;Encrypt=False;TrustServerCertificate=False;
ApplicationIntent=ReadWrite;MultiSubnetFailover=False"));
}
Make sure your project builds and runs without errors before scaffolding.
In Visual Studio 2019, I received this error while attempting to scaffold a new controller because I had a missing comma in my JSON in appsettings.json file.
Eventually I built and tried to run and got a System.FormatException, "Could not parse the JSON file" during runtime.
Since appsettings.json was the only JSON file I was editing recently I knew it had to be appsettings.json.
Scaffolding, code generators, and EF migrations invoke runtime code, this means even if your code compiles, if it throws runtime errors those could cause a problem for such actions.
FYI -
As of EF Core 2.1 parameterized constructors are allowed.
See this Microsoft article for more information.
https://learn.microsoft.com/en-us/ef/core/modeling/constructors
the solution is check the file Startup.cs if you have in the void ConfigureServices the DataContext, for example in SQLServer my Startup.cs is
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<YourDataContext>(options => options.UseSqlServer(Configuration.GetConnectionString("YourConnectionStrings")));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
}
if you not have this services the error is
no parameterless constructor defined for type YourDataContextName
I had the same problem and I add this line to Startup.cs on the ConfigureServices method.
It worked fine for me:
services.AddControllersWithViews();
Just add an empty constructor to your dbcontext and this solves the problem.

Publishing with Multiple Context in Same Database

I encountered a problem with multiple context in EF 6. Recently i had splitted my context into three parts and configured them as had been told here
Everything was fine, until i decided to publish via Visual Studio; because publish wizard detected only one of my context instead of three. And interestingly everytime it detects same context, i couldn't find why, neither first letter of name nor any difference from the others seem cause this.
But i couldn't publish my MVC project because of this. I have to migrate all three contexts while publishing.
After some search, i saw Update-Database command gets connectionstring parameter. This is my last option, if there isn't any way to solve publish wizard i try to update database with this code.
I haven't been able to reproduce this issue. Here are the steps I used (using Visual Studio 2013 Update 2).
Create a new MVC application. Add the following models to the project (two separate Code First models/contexts).
public class CustomerContext : DbContext
{
public DbSet<Customer> Customers { get; set; }
}
public class Customer
{
public int CustomerId { get; set; }
public string Name { get; set; }
}
public class ProductContext : DbContext
{
public DbSet<Product> Products { get; set; }
}
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
Then enable migrations, add a migration and update the local database for both contexts, using the following commands.
Enable-Migrations -ContextTypeName CustomerContext -MigrationsDirectory Migrations\Customer
Enable-Migrations -ContextTypeName ProductContext -MigrationsDirectory Migrations\Product
Add-Migration FirstMigration -ConfigurationTypeName MyWebApp.Migrations.Customer.Configuration
Add-Migration FirstMigration -ConfigurationTypeName MyWebApp.Migrations.Product.Configuration
Update-Database -ConfigurationTypeName MyWebApp.Migrations.Customer.Configuration
Update-Database -ConfigurationTypeName MyWebApp.Migrations.Product.Configuration
Then when I right-click -> Publish the project I get the option to enable migrations on App_Start for both of my contexts (and the ASP.NET Identity context too). If I understand correctly, you are not seeing your additional context(s) in this screen.
I've seen this happen when multiple DbContexts share a common connection string. By this I mean:
public class Context1: DbContext
{
public Context1()
: this("DefaultConnection")
{}
public Context1: (string connectionString)
: base(connectionString)
{}
....
}
public class Context2: DbContext
{
public Context2()
: this("DefaultConnection")
{}
public Context2: (string connectionString)
: base(connectionString)
{}
...
}
When you Publish, only one DbContext will show up under Settings > Databases. If you change "DefaultConnection" to something else then you will see the distinct DbContexts. Like this:
public class Context1: DbContext
{
public Context1()
: this("DefaultConnection")
{}
public Context1: (string connectionString)
: base(connectionString)
{}
....
}
public class Context2: DbContext
{
public Context2()
: this("DefaultConnection2")
{}
public Context2: (string connectionString)
: base(connectionString)
{}
...
}
Maybe this explains the behavior you are seeing.
If both dbContexts are using the same database (and therefore the same database connection string in web.config), how do we get Web Deploy to show them both? Do I have to create a separate (duplicate) connection string that points to the same database just to get it to show up as a separate context in the wizard?
When you want to see all contexts in the Publish dialog, you need to add another connection strings to web.config. They should have different name and be referenced from your context (name in constructor)

Entity Framework -Update-Database- Does not create Database

Visual Studio 2013
I am trying to learn asp.net MVC over at PluralSight. I created a project(dll) called eManagr.Domain with the following classes:
Department / Employee / IDepartmentDatasource
Department.cs
public class Department
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual ICollection<Employee> Employees { get; set; }
}
Employee.cs
public class Employee
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
IDepartmentDataSource
public interface IDepartmentDataSource
{
IQueryable<Employee> Employees { get; }
IQueryable<Department> Departments { get; }
}
I created an infrastructure folder with the following file : DepartmentDb.cs
public class DepartmentDb : DbContext, IDepartmentDataSource
{
public DbSet<Employee> Employees {get; set;}
public DbSet<Department> Departments {get; set;}
IQueryable<Employee> IDepartmentDataSource.Employees
{
get { return Employees; }
}
IQueryable<Department> IDepartmentDataSource.Departments
{
get { return Departments; }
}
}
I then created another project using MVC 4 called eManager.Web with Internet Template during the creation of the project.
When running Enable-Migration it says I have two[eWeb.Domain , eWeb.Model.Users] which then I tell it Enable-Migration with the following command:
Enable-Migration -ContextTypeName DepartmentDb
which creates the migration folder and a file called Configurations.cs
public Configuration()
{
AutomaticMigrationsEnabled = true;
}
protected override void Seed(eManager.Web.Infrastructure.DepartmentDb context)
{
context.Departments.AddOrUpdate(t => t.Name,
new Department() { Name="Engineering"},
new Department() { Name = "Sales" },
new Department() { Name = "Shipping" },
new Department() { Name = "HR" }
);
}
EDIT -- Connection String from Web.Config --
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=aspnet-eManager.Web-20140216202751;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnet-eManager.Web-20140216202751.mdf" providerName="System.Data.SqlClient" />
When I run the following I get the following reponse:
PM> update-database
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
No pending code-based migrations.
Running Seed method.
PM>
After this runs, I suppose to see a database file in my App_Data but it does not exist and when I use SQL Server Object Explorer, the database is not created even though that is what I am trying to do.
Could you provide your connection string from Web.config?
Also, is there a Data Connection (Server Explorer -> Data Connections) named the same as your connection String?
I think, adding a parameter-less constructor to your DepartmentDb context class could solve your problem
public DepartmentDb ()
: base("name=DefaultConnection")
Where name=DefaultConnection has to be your connection string name
I noticed that you enabled your migration in the correct way, have you run:
add-migration "give it a name" ?
once this has been completed you will notice a new file in the migrations folder.
you wont be able to update database with out creating a new migration.
I just ran into something very similar. I encountered it when I was going through the following ASP.NET MVC tutorial:
https://www.asp.net/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application
In my case, the problem seemed to be that I already had a database table of that name. I had gone through the tutorial partway previously about a month ago, but was interrupted and had to abort. Even though I deleted the entire Project, it seemed that the database table name may have been retained.
I say seemed to be, because the problem disappeared with the following solution: after a 2nd delete of the project, I carefully substituted 'Contoso' for 'ContosoUniversity' in every relevant situation.
Before the problem was solved, I was repeatedly getting the (0x80131904-error) in the Package Manager Console when trying to update-database, and a notice that the mdf file could not be connected to the database. However, when I checked the appropriate directory, the mdf file was not even being created.
FYI For beginning MVC-ers in Visual Studio 2012, I do recommend going through the following MVC tutorial before the one above.
https://www.asp.net/mvc/overview/older-versions/getting-started-with-aspnet-mvc4/intro-to-aspnet-mvc-4
A MVC5 Visual Studio 2013 version is also available through that link.
The tutorial of the first paragraph makes a few jumps...
I could not have debugged the issue if I'd started with the EF5 tutorial as my first MVC project.

Multi Tenancy in ASP.NET MVC Application

In the following example, what is an efficient way to implement multitenancy with minimal redundant code? In this scenario, tenant is a student. The students' school has 2 locations and each location is required to have the data (i.e, Courses) stored in a seperate database. When a student logs in, their location determines which database to pull from.
I'm using Entity Framework and Repository Pattern. Currently I have the implementation for accessing Location 1 DB. I've looked into different options to implement Location 2, such as injecting a TenantContext in the HomeController contructor, but I am stuck on how to set the correct database connection and what approach would be most efficient.
Below is the code for Location 1 only.
Example Controller
public class HomeController : Controller
{
ICourseRepository courseRepository;
//How to set the correct repository to use based on location?
public HomeController(ICourseRepository courseRepository)
{
this.courseRepository = courseRepository;
}
//Register for a new class
public ViewResult Register()
{
var courseList = courseRepository.AvailableCourses();
return View(courseList);
}
}
CourseRepository
public class CourseRepository : ICourseRepository
{
private Location1DB context = new Location1DB();
public List<Course> AvailableCourses()
{
//Get available courses from Location 1 Course Table
}
}
Location1Model.Context.cs (This is genereated using EF DbContext Generator)
public partial class Location1DB: DbContext
{
public Location1DB()
: base("name=Location1DB")
{
}
public DbSet<Course> Courses { get; set; }
}
Web.config
<connectionStrings>
<add name="Location1DB" ... />
<add name="Location2DB" ... />
</connectionStrings>
sorry I'll try to edit and provide a more complete answer when I get time tomorrow, but check this SO answer and the castle windsor container doco to get you started (also not sure what container you are using but all the major ones should have this functionality).
The thought would be to read the LocationID out of the cookie, grab the right connection string and have the container pass it as a parameter to your dbcontext.
DbContext is a partial class remember, so you could declare your own partial DbContext class, put an interface on it and pass that as a dependency into your repository.

Resources