I'm developing a web application and I would like to implement Identity. I've done a couple of tests and it's pretty easy to implement when using a Code First approach.
My issue is that I can't get it to work with a Model First approach. I would like to define my models in the .edmx file, and generate my database using the "Generate database from model" option.
Here's what I've done:
I started from the default ASP .NET Web Application template, including the "Individual User Account" authentication. Then I registered a user in order for entity framework to generate the needed tables in the default database.
Then I added the "ADO .NET Entity Data Model" to my project, and chose the "EF Designer from Database" option. It has been generated successfully with the existing tables created by Identity. I changed the connection string in the IdentityModels:
public ApplicationDbContext()
: base("MyConnectionStringName", throwIfV1Schema: false)
{
}
But after this, when I try to register a user, I get the following error:
"Unable to load the specified metadata resource."
Previously, I also had an error: "The entity type ApplicationUser is not part of the model for the current context."
Is it actually possible to use Identity with a Model First approach ? If yes, what am I doing wrong ?
I said I'll post something in order to explain how I managed to get this working. I struggled to find some documentation and tutorials about using Identity with a Model First approach, so here it comes.
Firstly, I found this genius article from Ben Foster: http://benfoster.io/blog/aspnet-identity-stripped-bare-mvc-part-1
This article discuss about how to implement an "Identity Stripped Bare". Reading it and following the steps allowed me understand how to use identity from scratch (you can see at the beggining that he generates an MVC 5 project with no authentication system).
If you want the code of this "Naked Identity", here it is: https://github.com/benfoster/NakedIdentity
The first step was to generate the database. In the Naked Identity code, the v1.0 of Identity is used. Some things are different (a couple table properties for example), but it stays mostly identical.
To create a database usable by Identity, I simply ran the template MVC 5 project, registered a user for the table to be created with the Code First approach, and then copied those tables needed by Identity in my empty database.
Once this was done, I generated my .edmx using the freshly created database. A connection string is added to the web.config. A connection string may already exist as "DefaultConnection". You need to keep this one as well.
Basically, those 2 connection strings are needed because, Identity is gonna use the default one, and the .edmx is gonna use the other one. It is not possible to use the same one for both as the .edmx connection string needs metadata, that are not supported by identity. Thus, those 2 connection strings are different, but I modified them so they can refer to the same database.
<connectionStrings>
<add name="DefaultConnectionString" connectionString="Data Source=(LocalDb)\v11.0; Initial Catalog=DatabaseName; Integrated Security=True" providerName="System.Data.SqlClient" />
<add name="EntitiesConnectionString" connectionString="metadata=res://*/Models.WebAppModel.csdl|res://*/Models.WebAppModel.ssdl|res://*/Models.WebAppModel.msl;provider=System.Data.SqlClient;provider connection string="data source=(LocalDb)\v11.0;initial catalog=DatabaseName;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
The first connection string is the one you're gonna use with entity. So here is how the IdentityDbContext is initialized:
``
public class AppDbContext : IdentityDbContext
{
public AppDbContext() : base("QualityWebAppDbEntitiesDefault", throwIfV1Schema: false)
{
}
public static AppDbContext Create()
{
return new AppDbContext();
}
}
``
(you can find the AppUser definition in the NakedIdentity sources)
And for my .edmx, the initialization looks like this:
public partial class QualityWebAppDbEntities : DbContext
{
public QualityWebAppDbEntities()
: base("name=QualityWebAppDbEntities")
{
}
}
Hope this will help people that want to use a Model First approach with Identity.
Related
I am creating a Web Api in C#.Net. I have implemented Dependency Injection in it using Unity.Mvc5 and using Db First approach. Since then i'm facing some issues in connection strings. There is a default AccountController in it and I have created a TestController to test my Api's.
There are two connection strings in my Web.config file (one of them is commented but just to show here i have uncommented it).
<add name="DDEXEntities" connectionString="Data Source=DESKTOP-CSB6551;initial catalog=DDEX;integrated security=True" providerName="System.Data.SqlClient" />
<add name="DDEXEntities" connectionString="metadata=res://*/Models.Model1.csdl|res://*/Models.Model1.ssdl|res://*/Models.Model1.msl;provider=System.Data.SqlClient;provider connection string="data source=DESKTOP-CSB6551;initial catalog=DDEX;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
Now the problem is when I use the first string my test controller Api's don't work. The exception given is:
The context is being used in Code First mode with code that was generated from an EDMX file for either Database First or Model First development. This will not work correctly. To fix this problem do not remove the line of code that throws this exception. If you wish to use Database First or Model First, then make sure that the Entity Framework connection string is included in the app.config or web.config of the start-up project. If you are creating your own DbConnection, then make sure that it is an EntityConnection and not some other type of DbConnection, and that you pass it to one of the base DbContext constructors that take a DbConnection. To learn more about Code First, Database First, and Model First see the Entity Framework documentation here: http://go.microsoft.com/fwlink/?LinkId=394715
And when I use the second connection string, my Account controller doesn't work and produces exception:
An error occurred when trying to create a controller of type 'AccountController'. Make sure that the controller has a parameterless public constructor.
My UnityConfig.cs is as follows:
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<DbContext, DDEXEntities>(new PerResolveLifetimeManager());
// register all your components with the container here
// it is NOT necessary to register your controllers
container.RegisterType<AccountController>(new InjectionConstructor());
// e.g. container.RegisterType<ITestService, TestService>();
container.RegisterType<IGenreService, GenreService>(new TransientLifetimeManager());
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
}
}
Can anyone let me know what I have done wrong. This is getting on my nerves now.
Thanks in advance.
Edit + Solution:
Based on Roman's answer, I named my first connection string as DefaultConnection and in ApplicationDbContext class constructor I gave this DefaultConnection. Now my AccountController uses this connection string and all other controllers use second connection string.
I hope it helps someone.
That's because AccountController uses your DbContext in CodeFirst mode. I think it's better to use separate DbContext: first one just for authentication and authorization(in CodeFirst mode) and second one for other stuff(in DatabaseFirst mode).
Also you can try to configure AccountController to use DbContext in DatabaseFirst mode.
My project is set up as follows..
MainProject
DataAccess its a Class Library
EntityFramework Database tables its a Class Library
EntityFramework Identity tables its a Class Library
In my main projects webconfig I have 2 connectionstrings, one is for the normal database tables and the other is for the Identity tables. The connectionstring for the normal database tables is an entity framework connectionstring
<add name="HWCEntities" connectionString="metadata=res://*/HWCEF.csdl|res://*/HWCEF.ssdl|res://*/HWCEF.msl;provider=System.Data.SqlClient;provider connection string="data source=****;initial catalog=****;persist security info=True;user id=****;password=****;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient"/>
The identity entityframework connectionstring is this
<add name="HWCIdentityEntities" connectionString="metadata=res://*/HWCIdentityEF.csdl|res://*/HWCIdentityEF.ssdl|res://*/HWCIdentityEF.msl;provider=System.Data.SqlClient;provider connection string="data source=****;initial catalog=****;persist security info=True;user id=****;password=****;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
however if I place that connectionstring in the main project's webconfig, and try to log into the web app, I get this error
The entity type ApplicationUser is not part of the model for the current context.
and its pointing at line 78 of AccountController
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
So instead of using the Identity connectionstring, I use this one
<add name="HWCIdentityEntities" connectionString="Data Source=****;Initial Catalog=****;User ID=****;password=****;Integrated Security=false;" providerName="System.Data.SqlClient"/>
using that connectionstring doesn't throw any error, and I would be fine with using that connectionstring but when I try and query the Identity database, I get this error
An exception of type 'System.Data.Entity.Infrastructure.UnintentionalCodeFirstException' occurred in HWC.Identity.dll but was not handled in user code
Additional information: The context is being used in Code First mode with code that was generated from an EDMX file for either Database First or Model First development. This will not work correctly. To fix this problem do not remove the line of code that throws this exception. If you wish to use Database First or Model First, then make sure that the Entity Framework connection string is included in the app.config or web.config of the start-up project. If you are creating your own DbConnection, then make sure that it is an EntityConnection and not some other type of DbConnection, and that you pass it to one of the base DbContext constructors that take a DbConnection. To learn more about Code First, Database First, and Model First see the Entity Framework documentation here: http://go.microsoft.com/fwlink/?LinkId=394715
and this error is thrown in my HWCIdentityEF.Context.csdl|res
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
How can I fix this so I can query the Identity database? I am assuming that I need to use the Identity connectionstring in the main application?
This works for me:
1) Make sure your context looks similar:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("myConnectString", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
2) Should be only 1 connect string in web.config
3) Tell Identity to use that context instead of IdentityDbContext. Search for IdentityDbContext and replace it with ApplicationDbContext (or whatever you called it). For example:
A) Startup.cs: app.CreatePerOwinContext<ApplicationDbContext>((options, context)=>new ApplicationDbContext());
B) IndentityConfig.cs (user manager and role manager): var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
var manager = new ApplicationRoleManager(new RoleStore<IdentityRole>(context.Get<ApplicationDbContext>()));
After reading solution after solution, and thanks to Steve Greene, I finally figured out what the issue was. I had to change the name of one of the connectionstrings, and changed its context. Now I can login and my queries run.
I am using MVC 5 and sql server 2012.I have created DB with name TestDB its doest not contain any table.Now i am trying to use Identity which is default given in AccountController in MVC project. I have change in AccountController "Defaultconnection" to my TestDBEntities connection but i am getting error
System.InvalidOperationException: The entity type ApplicationUser is not part of the model for the current context. How i can created Identity with exist Database.
<connectionStrings>
<add name="TestDBEntities" connectionString="metadata=res://*/DAL.TestModel1.csdl|res://*/DAL.TestModel1.ssdl|res://*/DAL.TestModel1.msl;provider=System.Data.SqlClient;provider connection string="data source=xxxxx;initial catalog=TestDB;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("TestDBEntities", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
As per my understanding, the possible ways to solve your problem is:
1.Cross check that have you added the ApplicationDbContext to the UserStore constructor
Ex: https://stackoverflow.com/a/23894335/3397630
2.Also check that do you have any other connection string in the webconfig file. This may also cause the problem.
Finally if both above points doesn’t work, kindly follow the below article:
http://www.codeguru.com/csharp/.net/net_asp/mvc/securing-asp.net-mvc-applications-with-asp.net-identity.htm
It was really good, I personally used and created a identity tables for my projects without any issues.
In the articles, it was explained each , every points very well and easy understandable.
Hope the above information will be useful , kindly let me know your thoughts or feedbacks
Thanks
Karthik
I was working at an asp.net MVC project with the IdentityDbContext.
The code for the context:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("ApplicationDb")
{
}
}
And in my web.config a connectionstring named after the context:
<add name="ApplicationDb" connectionString="Data Source="..." providerName="System.Data.SqlClient" />
Strange thing is when I call the Update-Database command to create the database with Entity Framework, my database is created. So far so good.
But: the authorisation code from Owin is also creating a second upon running the application. This one is named DefaultConnection and is copy from the other one.
So my question: does Identity Framework always need a connection string named "DefaultConnection", even if you point the context to another connectionstring?
In the end I managed to solve this by adding the DefaultConnection connectionstring in web.config so I end up with two connectionstring:
ApplicationDb
DefaultConnection
Is this really the way to go? Because if that's the case it doesn't make much sense to put a custom connectionstring name in the base constructor?!
Btw, I also tried the context like so:
public ApplicationDbContext()
{
}
Which in theory should effectively do the same. But still DefaultConnection is created upon running the app. Doesn't make sense to me.
I'm build my webapi project based on this article: A simple POC using ASP.NET Web API, Entity Framework, Autofac, Cross Domain Support
However, I need to pass a connection string to the DbContext because a user that connects to the webapi can select a different database to work with.
Where and what is that best way to implement this? In the controller, having a separate 'service' or a singleton?
I'm currently building a website that requires multiple databases also. This is the basics (for now). It may not be the best/efficient way, but it does the job so that I can continue working on the site.
Let's say you have this connection and everything there is correct, except the database name can change.
<add name="MyDbContext" connectionString="Server=SomeConnection;Database=SomeDatabase;"providerName="System.Data.SqlClient" />
You can create a connection string on the fly with this
public MyDbContext CreateDbContext(string databaseName)
{
SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder(System.Configuration.ConfigurationManager.ConnectionStrings["MyDbContext"].ConnectionString); // Gets the default connection
sqlBuilder.InitialCatalog = databaseName; // Update the database name
return new MyDbContext(sqlBuilder.ToString());
}
Also, unless you want to automatically create a database if it doesn't exist, possibly from incorrect database name, you need to set the initializer. Simply pass the initializer null to prevent ef from automatically creating one. I set this in the constructor of MyDbContext
public class MyDbContext : DbContext
{
/* some other constructors */
public MyDbContext(string nameOrConnectionString, bool createDb)
: base(nameOrConnectionString)
{
if(!createdDb)
{
System.Data.Entity.Database.SetInitializer<MyDbContext>(null);
}
}
}
One way would be to have multiple ConnectionStrings in your web config. You could then select which ConnectionString to use depending on a parameter passed to your webapi:
In your web config:
<connectionStrings>
<add name="dataBase1" connectionString="/*db info here*/" providerName="System.Data.SqlClient" />
<add name="dataBase2" connectionString="/*db info here*/" providerName="System.Data.SqlClient" />
</connectionStrings>
Then in your code:
public someobject GetData(/*arguments*/, string dbType)
{
var connectionString = dbType == 'dataBase1'
? ConfigurationManager.ConnectionString['dataBase1'].toString()
: ConfigurationManager.ConnectionString['dataBase2'].toString()
/*then pass connectionString to dbContext*/
var dbContext = new DbContext(connectionString);
}