Creating authentication using own dbcontext - asp.net

I want to create an owin authentication using my own external sql database instead of the base asp context. I can create an edmx model from the database but i dont know how to use it to identify the users.
When i change the base Database connection used by ApplicationUser to my own one i get this exception.
I have already created at least 30 projects to test the solutions i found on google but none of them was worked for me.

[SOLUTION]
The solution is much more easier than i thougth..
All i had to do was inheriting my User table from IdentityUser (AspNetUser is my own table)
public partial class AspNetUser : IdentityUser
and using my custom connectionstring's name (BCTSDb) instead of DefaultConnection in IdentityModels.cs.
public ApplicationDbContext()
: base("BCTSDb", throwIfV1Schema: false)
This is codefirst from database, database first is not working with this solution (i dont know why).
This solved the FIRST problem. After this i couldn't scaffold any controllers with views because of missing keys and ambiguous references.
[WHATTODO]
1. Ambiguous references
In my AspNetUser.cs class i made all ORIGINAL attributes override:
for example UserName:
public override string UserName { get; set; }
Its possible that this is not necessary, i haven't tried without this, maybe this solve the ambiguous references between my dbcontext and ApplicationDbContext.
2. Missing keys
I dont know where i left my keys but there is the solution:
At the end of my OnModelCreating function (in my dbcontext) i wrote the following lines:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// your table operations, references
// ...
modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id);
modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId });
base.OnModelCreating(modelBuilder);
}
After this i could do anything i want.

Related

EntityFramework dependency injection of DatabaseContext on Asp.Net

i have not much knowledge about Asp and Entity Framework so i really cant figure out what i have to do.
My problem is accessing database context out of main asp method -
There is how db context created and used in Program.cs (Main)
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<DatabaseContext>(
options => options.UseSqlite(builder.Configuration.GetConnectionString("DefaultDataSource"))
);
var app = builder.Build();
using (var scope = app.Services.CreateScope())
{
var context = services.GetRequiredService<DatabaseContext>();
context.Database.EnsureCreated();
}
so my problem is kinda that i making "options" for DatabaseContext constructor out of "builder.Configuration"
But what do i do when i need to acces db from other script? DatabaseContext requires config but i just dont know how to get it outside of that builder.
one guy suggested me to use Dependency Injection, i have looked but i just cant get how to do it properly, like i make a class where i initialize db context, but i still need to somehow make a config here and i really have no clue how.
It could be really stupid question but i really cant figure it out for a couple of days :D
I`ve tried to make DbContext without a config but it gives error
I don't know what you tried, but I think this might be what you want.
Assuming your DatabaseContext class is the most basic, and defines a table
Users in it:
public class DatabaseContext : DbContext
{
public DatabaseContext(DbContextOptions<DatabaseContext> options)
: base(options)
{
}
public DbSet<Models.User> Users { get; set; }
}
Then you register it in Program.cs:
builder.Services.AddDbContext<DatabaseContext>(
options => options.UseSqlite(builder.Configuration.GetConnectionString("DefaultDataSource"))
);
You can generate your database by migrating and updating the database(Of course you can also manually create):
Add-Migration InitialCreate
Update-Database
Then you can access your database in other classes through dependency injection, such as in the controller:
public class HomeController : Controller
{
private readonly DatabaseContext _databaseContext;
public HomeController(DatabaseContext databaseContext)
{
_databaseContext = databaseContext;
}
public IActionResult Index()
{
var user = _databaseContext.Users.ToList();
return View();
}
}
For more details about dependency injection, you can refer to this document.

Implement Authentication using ASP Identity With 2 Tables

Instead of the default 5 tables, I would like to use just UserLoginsTable and UserTable. Because I just have one 'User' type (Admin) and there's no point of having the other tables.
I'm using ASP MVC 5 framework and Entity Framework 6 (Code First approach).
How can I achieve this in my application?
when you run add-migration "ApplicationDbContext", its give you the code of migration file which contains all the queries, what you need here is write the code to delete other 4 tables like:
enable-migrations
add-migration "drop tables" //selected specific context
write down the below code inside the migration code class
DropTable("dbo.AspNetUserClaims");
DropTable("dbo.AspNetUserLogins");
DropTable("dbo.AspNetUserRoles");
DropTable("dbo.AspNetRoles");
finally run the below command
update-database
You create your own User inheriting IdentityUser like this:
public class User : IdentityUser
{
}
Then you ignore the other classes in your DbContext, including the original IdentityUser, including your Users DbSet:
public class MyDbContext : IdentityDbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// avoid some base class sets...
modelBuilder.Ignore<IdentityUser>();
modelBuilder.Ignore<IdentityUserRole>();
modelBuilder.Ignore<IdentityRole>();
modelBuilder.Ignore<IdentityUserClaim>();
// keep identity's original configurations for AspNetUsers and AspNetUserLogins
EntityTypeConfiguration<User> configuration = modelBuilder.Entity<User>().ToTable("AspNetUsers");
configuration.HasMany<IdentityUserLogin>(u => u.Logins).WithRequired().HasForeignKey(ul => ul.UserId);
IndexAttribute indexAttribute = new IndexAttribute("UserNameIndex")
{
IsUnique = true
};
configuration.Property((Expression<Func<User, string>>)(u => u.UserName)).IsRequired().HasMaxLength(0x100).HasColumnAnnotation("Index", new IndexAnnotation(indexAttribute));
configuration.Property((Expression<Func<User, string>>)(u => u.Email)).HasMaxLength(0x100);
modelBuilder.Entity<IdentityUserLogin>().HasKey(l => new { LoginProvider = l.LoginProvider, ProviderKey = l.ProviderKey, UserId = l.UserId }).ToTable("AspNetUserLogins");
}
}
The reason why I ignored the original IdentityUser and created my own User is because of this exception:
The navigation property 'Roles' is not a declared property on type
'IdentityUser'. Verify that it has not been explicitly excluded from
the model and that it is a valid navigation property.
I tried using modelBuilder.Entity<IdentityUser>().Ignore(u => u.Roles); but it didn't solve, though if someone knows how to solve this, we could keep things simpler, I would appreciate any suggestions.

EF7 + ASP.NET5 beta8 - Database initializers

I'm working on multitenant application (ASP.NET 5 + EF7). Each tenant will have separate database. I will have one separate database for tenant account data. I have registered service for EF in startup class for this separate database. I have problem with migrations. I cant create EF migration, until tenantDbContext is registered as service with specific connection string. But this conection string must be dynamic for each tenant... Any idea please? What is the best option to manage DbContexts for tenants?
Future edit - protected override void OnConfiguring was the key how to do: Is this good solution please?
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<TenantDbContext>();
public class TenantDbContext : IdentityDbContext<ApplicationUser>
{
public TenantDbContext() //development database with no connectionString in constructor
{
this._connectionString = "Connection String";
}
public TenantDbContext(string ConnectionString)
{
this._connectionString = ConnectionString;
}
private string _connectionString { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(_connectionString);
}
...etc
As I mentioned in comments I have not tried multi-tenant/multi-db myself but try the following:
You can use DbContext CreateIfNotExists() method. https://msdn.microsoft.com/en-us/library/system.data.entity.database.createifnotexists(v=vs.113).aspx
If you have a Migrations/Configuration.cs you can set AutomaticMigrationsEnabled property to false
Setting the initializer off is probably needed as well: Database.SetInitializer<DatabaseContext>(null);
Sorry without knowing more details like workflow of creating a new tenant (automatic from DB or is a screen filled out with the connection string and name etc.) I can't make more detailed suggestions. I would suggest that your data layer be quite abstracted from the context. It seems like a bad idea for developers to have to select the correct context. Hence the use of a factory.
An option is always requiring a tenant id to be passed into all service or repository methods. I'm guessing this would be in some kind of user claim available in the controller.

I'm getting a cryptic error connecting a new MVC app to an Azure DB created by mobile services

Like the title says, I am trying to connect a new MVC 5 app created by Visual Studio 2013 to an existing database table created by and Azure Mobile Service.
I realized that the issue was with the schema of the tables that were created by the mobile service. Instead of using the default "dbo" schema, the tables used <mobile_service_name> as the schema. My MVC project was looking for dbo.<Table_Name> instead of <mobile_service_name>.<Table_Name> and was throwing an error as a result. To fix this, you need to add some mappings in you DB Context class to tell it where exactly to find the tables it is looking for. These mappings are done in an overridden method called OnModelCreating. It ends up looking like this:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext() : base("DefaultConnection")
{
}
public System.Data.Entity.DbSet<MyObject> MyObjects { get; set; }
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<MyObject>().ToTable("<mobile_service_name>.<Table_Name>");
}
}

Attach additional ObjectSets to ObjectContext from separate project

I hope this makes sense. I have a ASP.NET web application that uses Entity Framework. I have added a couple of custom tables to the db and created a separate project to handle the CRUD operations for those tables. I chose the separate project because I don't want future upgrades to the application to overwrite my custom features.
My problem is this. How do I attach/combine my custom ObjectContext to the ObjectContext of the application? I want to use the same UnitOfWorkScope (already in the application) to maintain the one ObjectContext instance per HTTP request. Again, I don't want to add my ObjectSets to the application's ObjectContext for my reason listed above.
Here is some code:
Widget.cs
public partial class Widget
{
public Widget()
{
}
public int WidgetId {get;set;}
public string WidgetName {get;set;}
}
WidgetObjectContext.cs
public partial class WidgetObjectContext : ObjectContext
{
private readonly Dictionary<Type, object> _entitySets;
public ObjectSet<T> EntitySet<T>()
where T : BaseEntity
{
var t = typeof(T);
object match;
if(!_entitySets.TryGetValue(t, out match))
{
match = CreateObjectSet<T>();
_entitySets.Add(t, match);
}
return (ObjectSet<T>)match;
}
public ObjectSet<Widget> Widgets
{
get
{
if((_widgets == null))
{
_widgets = CreateObjectSet<Widget>();
}
return _widget;
}
}
private ObjectSet<Widget> _widgets;
In my WidgetManager class if I was using the application's ObjectContext I would query my tables like this:
var context = ObjectContextHelper.CurrentObjectContext;
var query = from c in context.ObjectSet .... etc
What I want would be to do something like this:
var context = ObjectContextHelper.CurrentObjectContext.Attach(WidgetObjectContext);
I know this won't work but that is the gist of what I am trying to accomplish. Hope this is clear enough. Thanks.
I don't think it is possible. ObjectContext creates entity connection which connects to metadata describing mapping and database. But you have to different sets of metadata - one for ASP.NET application and one for separate project. Simply you need two connection to work with these models => you need two ObjectContexts.
FYI: The previous answer was correct at the time of the answer. It is now possible to do this using the DbContext available in EF 4.1. The caveat is that you must use the code-first strategy in order to build your custom context. In other words, you won't be able to use EDMX files to accomplish this.

Resources