Create role using entity framework core migrations - asp.net-core

I'm creating my 4th migrations script with EF Core (2.0.0). In there I want to add a few roles to the database.
The problem is, is that I'm not really sure how to do this. Currently I have this:
protected override void Up(MigrationBuilder migrationBuilder)
{
// todo: Pass connection string somehow..?
var opt = new DbContextOptions<ApplicationContext>();
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new ApplicationContext(opt)));
//if (!roleManager.RoleExists("ROLE NAME"))
//{
// todo: create the role...
//}
}
But creating the RoleManager like that gives me the following error:
There is no argument given that corresponds to the required formal
parameter 'roleValidators' of
'RoleManager.RoleManager(IRoleStore,
IEnumerable>, ILookupNormalizer,
IdentityErrorDescriber, ILogger>)'
I'm not sure how to solve this problem. I couldn't find any info on how to do this properly in .NET Core using migrations.
I'm facing two issues in this code:
I'm trying to create an instance of the DbContext somehow. Shouldn't I be able to get the DbContext from within my migrations code?
Instantiating the RoleManager like this doesn't work and needs to be resolved.
How can I solve these problems?

The Up method is basically an instruction file that tells EF's database migrator how to generate a database upgrade script. The method is executed when the script is generated. Doing any data manipulation there is absolutely out of place. EF core doesn't support seeding yet, so you have to add missing roles when the application starts, for example by something like this.

Related

Unable to create a View in ASP.NET Core MVC

I am working on an ASP.NET Core 7.0 MVC app. I have created a data access layer using EF Core 7.0 with a database-first approach. I was trying to create a Razor view through the "AddView" option from the controller for the "Create" process.
However, I am getting this error:
This is how I inject my DbContext:
builder.Services.AddDbContext<NorthwindContext>(options => options.UseSqlServer(
builder.Configuration.GetConnectionString("DefaultConnection")));
I am new to ASP.NET Core. It looks like I have to pass additional options in the Program.cs file. I did a Google search, but couldn't find any help!
If I create the view manually it might work. However, I would like to create it through the scaffolding process.
This is my NorthwindContext code:
After removing the parameterless constructor as per Neil I am getting the new error:
More specifically to my comment, the AddDbContext registers the context class in the asp.net core DI container so it can be provided whenever any class or process wants an instance of the DbContext.
The view generator will want that. However, if the DI container find a parameterless constructor it will use that first, and therefore not use the constructor that passes in the options.
The outcome is a context is provided that does not have the "UseSqlServer" options set.
Hence the error that a database provider has not been configured.
Remove that parameterless constructor from the DbContext and you should be good to go.
The latest error indicates the constructor requires an object of type DbContextOptions.But the injector cannot create the instance.
You could try with the parameterless constructor and configure the options in OnConfiguring method
And the picture you've shown indicates you've seprated Modes from your MVC projects,Make sure you've setted the right startup project(right click on your solution -- Set startup projects) and configrue which projects would contain the migration classes
public class SomeDbContext : DbContext
{
public SomeDbContext()
{
}
public DbSet<SomeEntity> SomeEntity { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("connectionstring", b => b.MigrationsAssembly("MVCProj"));
}
}
Regist it as below:
services.AddDbContext<SomeDbContext>();
If you still got the error,please upload the minimal codes that could reproduce the error

Get service from WebApplicationFactory<T> in ASP.NET Core integration tests

I want to set up my tests using WebApplicationFactory<T> as detailed in
Integration tests in ASP.NET Core.
Before some of my tests I need to use a service configured in the real Startup class to set things up.
The problem I have is that I can't see a way to get a service from the factory.
I could get a service from factory.Server using factory.Host.Services.GetRequiredService<ITheType>(); except that factory.Server is null until factory.CreateClient(); has been called.
Is there any way that I am missing to get a service using the factory?
Thanks.
You need to create a scope from service provider to get necessary service:
using (var scope = AppFactory.Server.Host.Services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<MyDatabaseContext>();
}
Please pardon me. I know you ask for Net Core 2.1, but since v3.1+ people got here as well...
My project uses Net Core 3.1. When I use AppFactory.Server.Host.Services.CreateScope() like Alexey Starchikov's suggestion, I encounter this error.
The TestServer constructor was not called with a IWebHostBuilder so IWebHost is not available.
Noted here, by designs.
So I use the below approach. I put database seeding in the constructor of the test class. Note that, I do not have to call factory.CreateClient(). I create client variables in test methods as usual.
using (var scope = this.factory.Services.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<YourDbContext>();
// Seeding ...
dbContext.SaveChanges();
}
In APS.NET 6 I had to use _factory.Services.CreateScope():
using var scope = _factory.Services.CreateScope();
var sender = scope.ServiceProvider.GetRequiredService<IEmailSender>();
await sender.SendAsync("Hello");

Where should I put my NHibernate SchemaExport method?

Where should I put my NHibernate SchemaExport method and how should I call it when I decide to recreate the database?
Should I leave this in my startup project (an asp.net mvc project)? Should I create a seperate console project just for exporting my schema?
I think these questions all originate from the fact that I don't want schema export to run every time the web app starts.
I'm using fluent nhibernate if that makes a difference.
I would factor this out into a seperate assembly; you could then use this from a variety of places (console app, integration test setup, installer, etc).
As an idea: you could place it in a ProjectInstaller that optionally takes a command line argument. So you wouldn't have to have an extra console app just for that.
Personally I use two Tests (using Nunit in this case) to create or update the database. In both cases, I only generate the script, as I want full control as to when the database gets created or updated.
[Test]
[Ignore]
public void Create_Database_Schema_From_MappingFiles()
{
Configuration cfg = new Configuration();
cfg.Configure();
var schema = new SchemaExport(cfg);
schema.Create(true, false);
}
[Test]
[Ignore]
public void Update_an_existing_database_schema()
{
Configuration cfg = new Configuration();
cfg.Configure();
var update = new SchemaUpdate(cfg);
update.Execute(true, false);
}

Single website multiple connection strings using asp mvc 2 and nhibernate

In my website i use ASP MVC 2 + Fluent NHibernate as orm, StructureMap for IoC container.
There are several databases with identical metadata(and so entities and mappings are the same). On LogOn page user fiils in login, password, rememberme and chooses his server from dropdownlist (in fact he chooses database).
Web.config contains all connstrings and we can assume that they won't be changed in run-time.
I suppose that it is required to have one session factory per database.
Before using multiple databases, i loaded classes to my StructureMap ObjectFactory in Application_Start
ObjectFactory.Initialize(init => init.AddRegistry<ObjectRegistry>());
ObjectFactory.Configure(conf => conf.AddRegistry<NhibernateRegistry>());
NhibernateRegistry class:
public class NhibernateRegistry : Registry
{
public NhibernateRegistry()
{
var sessionFactory = NhibernateConfiguration.Configuration.BuildSessionFactory();
For<Configuration>().Singleton().Use(
NhibernateConfiguration.Configuration);
For<ISessionFactory>().Singleton().Use(sessionFactory);
For<ISession>().HybridHttpOrThreadLocalScoped().Use(
ctx => ctx.GetInstance<ISessionFactory>().GetCurrentSession());
}
}
In Application_BeginRequest i bind opened nhibernate session to asp session(nhibernate session per request) and in EndRequest i unbind them:
protected void Application_BeginRequest(
object sender, EventArgs e)
{
CurrentSessionContext.Bind(ObjectFactory.GetInstance<ISessionFactory>().OpenSession());
}
Q1: How can i realize what SessionFactory should i use according to authenticated user?
is it something like UserData filled with database name (i use simple FormsAuthentication)
For logging i use log4net, namely AdoNetAppender which contains connectionString(in xml, of course).
Q2: How can i manage multiple connection strings for this database appender, so logs would be written to current database? I have no idea how to do that except changing xml all the time and reseting xml configuration, but its really bad solution.
I suppose that it is required to have one session factory per database.
No; you can do just fine with one session factory for both databases.
You just supply an opened IDbConnection as a param to the OpenSession() method of ISessionFactory.
By doing so, you'll lose the possibility for a second level cache, but that might not be a problem.
If you want the second level cache, you need to implement you're own DriverConnectionProvider and supply it via fluent nh's Provider<TYourDriverConnectionProvider>() method.

Tracking changes in Entity Framework 4.0 using POCO Dynamic Proxies across multiple data contexts

I started messing with EF 4.0 because I am curious about the POCO possibilities... I wanted to simulate disconnected web environment and wrote the following code to simulate this:
Save a test object in the database.
Retrieve the test object
Dispose of the DataContext associated with the test object I used to retrieve it
Update the test object
Create a new data context and persist the changes on the test object that are automatically tracked within the DynamicProxy generated against my POCO object.
The problem is that when I call dataContext.SaveChanges in the Test method above, the updates are not applied. The testStore entity shows a status of "Modified" when I check its EntityStateTracker, but it is no longer modified when I view it within the new dataContext's Stores property. I would have thought that calling the Attach method on the new dataContext would also bring the object's "Modified" state over, but that appears to not be the case. Is there something I am missing? I am definitely working with self-tracking POCOs using DynamicProxies.
private static void SaveTestStore(string storeName = "TestStore")
{
using (var context = new DataContext())
{
Store newStore = context.Stores.CreateObject();
newStore.Name = storeName;
context.Stores.AddObject(newStore);
context.SaveChanges();
}
}
private static Store GetStore(string storeName = "TestStore")
{
using (var context = new DataContext())
{
return (from store in context.Stores
where store.Name == storeName
select store).SingleOrDefault();
}
}
[Test]
public void Test_Store_Update_Using_Different_DataContext()
{
SaveTestStore();
Store testStore = GetStore();
testStore.Name = "Updated";
using (var dataContext = new DataContext())
{
dataContext.Stores.Attach(testStore);
dataContext.SaveChanges(SaveOptions.DetectChangesBeforeSave);
}
Store updatedStore = GetStore("Updated");
Assert.IsNotNull(updatedStore);
}
As you stated later, you were using the POCO generator, not the self-tracking entities generator.
I've tried it as well, and became quite perplexed. It seems that the proxy classes don't quite work as expected, and there might be a bug. Then again. none of the examples on MSDN try something like this, and when they reference updates in different tiers of an app (something like we're doing here) they use self-tracking entities, not POCO proxies.
I'm not sure how these proxies work, but they do seem to store some kind of state (I managed to find the "Modified" state inside the private properties). But it seems that this property is COMPLETELY ignored. When you attach a property to a context, the context adds an entry to the ObjectStateManager, and it stores further state updates in there. At this point if you make a change - it will be registered, and applied.
The problem is that when you .Attach an entity - the Modified state from the proxy is not transferred to the state manager inside the context. Furthermore, if you use context.Refresh() the updates are override, and forgotten! Even if you pass RefreshMode.ClientWins into it. I tried setting the object state's state property to modified, but it was overridden anyway, and the original settings were restored..
It seems that there's a bug in the EF right not, and the only way to do this would be to use something like this:
using (var db = new Entities())
{
var newUser = (from u in db.Users
where u.Id == user.Id
select u).SingleOrDefault();
db.Users.ApplyCurrentValues(user);
db.SaveChanges();
}
One more thing here
Entitity Framework: Change tracking in SOA with POCO approach
It seems that POCO just doesn't support the approach you're looking for, and as I expected the self-tracking entities were created to tackle the situation you were testing, while POCO's proxies track changes only within the context they created.. Or so it seems...
Try
db.ObjectStateManager.ChangeObjectState(user, System.Data.EntityState.Modified);
Before calling SaveChanges
After playing around with the self-tracking entities, I realised what was your mistake.
Instead of trying to attach the entity to the data context, you should instead instruct that you want the data context to apply the new changes you have made to it to the database.
In this case, change the "saving" code to this:
using (var dataContext = new DataContext())
{
dataContext.Stores.ApplyChanges(testStore);
dataContext.SaveChanges();
}
At least I have tested it on my local machine, and it worked after this update :)
Hope this helps!
I think the root of your problem is your management of the Context object.
With POCO disposing the context does not notify the entities on that context that they are no longer associated with a context. The change tracking with POCO is all managed by the context so you get into some fun problems where the POCO will act like it is still attached to a context but in reality it is not and re-attaching to another context should throw an error about attaching to multiple contexts.
there is a small post about this you may want to read here:
http://social.msdn.microsoft.com/forums/en-US/adodotnetentityframework/thread/5ee5db93-f8f3-44ef-8615-5002949bea71/
If you switch to self tracking I think you'll find your entities work the way you're wanting.
another option is to add a property to a partial class of your poco to track changes manually after detaching the POCO from the context you used to load it.