使用 Identity Core 在 ASP.NET MVC 框架中标识 [英] Identity in ASP.NET MVC Framework using Identity Core

查看:28
本文介绍了使用 Identity Core 在 ASP.NET MVC 框架中标识的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法部分切换到 .NET Standard.

我正在将一个类库迁移到 .NET Standard,在这个库中我有存储库和数据库通信.我已经成功地将其迁移到使用 AspNetCore.Identity.EntityFrameworkCore.我试图实现的是最终让 1 个 .NET Standard 项目负责数据库,其中 1 个 MVC .NET Framework、1 个 API .NET Framework 和 1 个新的 .NET Core 应用程序将使用它.除此之外,还有一些其他 .NET Framework 类库依赖于它.基本上 .NET Core 应用程序已经制作完成,但后端尚未合并"以实现重叠功能.

简要概述:

不将 MVC/API 转换为 .Core 的原因是目前有太多其他库依赖于 .NET Framework,有些还不能转换,但对数据库使用相同的库是一个根本性的变化,将避免双重实现一些存储库.

我也已经转换了实现 Microsoft.AspNetCore.Identity.IdentityUserMicrosoft.AspNetCore.Identity.IdentityRole 等的实体.所以我的 DbContext 类看起来像这样:

public class DatabaseContext : IdentityDbContext{私有 IConfiguration _config;公共 DatabaseContext(IConfiguration config) : base(){_config = 配置;}//所有的DbSet, OnModelCreating}

我已成功运行 EFCore Code First 迁移.

现在我正在尝试在我的 MVC 应用程序中配置身份(然后也在 API 项目中).

我只有标准的IdentityConfig.csStartup.Auth.cs,所有配置都在这里完成.我曾尝试查看此文档

创建 UserStore 不是问题,但是尝试创建 UserManager 比较困难,我也尝试在我的 UserRepository 中使用它,就像我以前所做的一样,我现在不能再使用了:(.

旧用户存储库

private readonly UserManager_userManager = null;private readonly RoleManager_roleManager = null;内部静态 IDataProtectionProvider DataProtectionProvider { get;私人订制;}public UserRepository(DatabaseContext dbContext) : base(dbContext, c => c.contactId, m => m.ContactId){var userStore =new UserStore(dbContext);var roleStore = new RoleStore(dbContext);_userManager = new UserManager(userStore);_roleManager = new RoleManager(roleStore);_userManager.UserValidator = new UserValidator(_userManager) { AllowOnlyAlphanumericUserNames = false };if (DataProtectionProvider == null){DataProtectionProvider = new MachineKeyProtectionProvider();}_userManager.UserTokenProvider = new DataProtectorTokenProvider(DataProtectionProvider.Create("Identity"));}

在创建 UserManager 时再次尝试执行上述操作会出现问题,因为它询问了 9 个参数,所以我有点觉得这不应该这样做......可能会这样做这样的事情当然我首先想修复根本问题.

最后但并非最不重要的一点:请记住,这些应用程序都已经投入生产,所以特别是在用户周围,我需要确保所有登录仍然有效.在发布此版本时,由于其他一些迁移问题,我需要将数据迁移到新数据库.

解决方案

好吧,这是一个很长的答案,准备好第二天花在从头上拔出头发:).

首先是 IApplicationUser 的接口,它由 2 个不同的类实现:

公共接口 IApplicationUser{字符串 ID { 获取;放;}///<summary>获取或设置该用户的用户名.</summary>字符串用户名 { 获取;放;}}

实现1,这是我的数据库实体的一部分:

public class ApplicationUser : IdentityUser, IApplicationUser{公共日期时间?LockoutEndDateUtc { 获取;放;}public bool RequiresPasswordCreation { get;放;}公共字符串 TemporaryToken { 获取;放;}}

实现 2,对于我的 .NET Framework 项目:

public class ApplicationUserMvc : IdentityUser, IApplicationUser{公共异步任务GenerateUserIdentityAsync(UserManager manager){//注意 authenticationType 必须与 CookieAuthenticationOptions.AuthenticationType 中定义的匹配var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);//在此处添加自定义用户声明返回用户身份;}...所有其他事情}

然后我创建了自己的身份管理器(界面)

公共接口IIdentityManager{//用户管理方法任务CreateAsync(IApplicationUser 用户);//..所有需要的方法}公共接口 IIdentityResult{布尔成功{得到;放;}列表<字符串>错误 { 得到;放;}}

然后是我的实际实现,所以这是我的 .NET Core 项目.

公共类 IdentityManagerCore : IIdentityManager{private 只读 UserManager_userManager;private readonly RoleManager_角色管理器;公共 IdentityManagerCore(UserManager userManager, RoleManager roleManager){_userManager = 用户管理器;_roleManager = 角色管理器;}公共异步任务CreateAsync(IApplicationUser 用户){ApplicationUser realUser = new ApplicationUser(){Id = user.Id,TemporaryToken = user.TemporaryToken,AccessFailedCount = user.AccessFailedCount,ConcurrencyStamp = user.ConcurrencyStamp,电子邮件 = user.Email,EmailConfirmed = user.EmailConfirmed,LockoutEnabled = user.LockoutEnabled,LockoutEnd = user.LockoutEnd,NormalizedEmail = user.NormalizedEmail,NormalizedUserName = user.NormalizedUserName,PasswordHash = user.PasswordHash,PhoneNumber = user.PhoneNumber,PhoneNumberConfirmed = user.PhoneNumberConfirmed,RequiresPasswordCreation = user.RequiresPasswordCreation,SecurityStamp = user.SecurityStamp,TwoFactorEnabled = user.TwoFactorEnabled,用户名 = 用户.用户名};var 结果 = await _userManager.CreateAsync(realUser);返回 ConvertToInterface(结果);}私有 IIdentityResult ConvertToInterface(IdentityResult 结果){IIdentityResult realResult = new IdentityResultCore();realResult.Succeeded = result.Succeeded;realResult.Errors = result.Errors?.Select(x => x.Description).ToList();返回真实结果;}}公共类 IdentityResultCore : IdentityResult, IIdentityResult{私有 IEnumerable_错误;私人布尔_succeed;public new bool 成功{得到 =>base.Succeeded ||_成功;设置 =>_succeed = 值;}公共新列表错误{得到 =>base.Errors?.Select(x => x.Description).ToList() ??_errors?.ToList();设置 =>_errors = 值;}}

UserManagerRoleManager 在启动时注入如下:

services.AddTransient();

.NET Framework 实现:

公共类 IdentityManagerMvc : IIdentityManager{private readonly UserManager_userManager = null;private readonly RoleManager_roleManager = null;内部静态 IDataProtectionProvider DataProtectionProvider { get;私人订制;}公共 IdentityManagerMvc(DatabaseContextMvc dbContext){var userStore =new UserStore(dbContext);var roleStore = new RoleStore(dbContext);_userManager = new UserManager(userStore);_roleManager = new RoleManager(roleStore);_userManager.UserValidator = new UserValidator(_userManager) { AllowOnlyAlphanumericUserNames = false };if (DataProtectionProvider == null){DataProtectionProvider = new MachineKeyProtectionProvider();}_userManager.UserTokenProvider = new DataProtectorTokenProvider(DataProtectionProvider.Create("Identity"));}公共异步任务CreateAsync(IApplicationUser 用户){ApplicationUserMvc realUser = new ApplicationUserMvc(){Id = user.Id,TemporaryToken = user.TemporaryToken,AccessFailedCount = user.AccessFailedCount,ConcurrencyStamp = user.ConcurrencyStamp,电子邮件 = user.Email,EmailConfirmed = user.EmailConfirmed,LockoutEnabled = user.LockoutEnabled,LockoutEnd = user.LockoutEnd,NormalizedEmail = user.NormalizedEmail,NormalizedUserName = user.NormalizedUserName,PasswordHash = user.PasswordHash,PhoneNumber = user.PhoneNumber,PhoneNumberConfirmed = user.PhoneNumberConfirmed,RequiresPasswordCreation = user.RequiresPasswordCreation,SecurityStamp = user.SecurityStamp,TwoFactorEnabled = user.TwoFactorEnabled,用户名 = 用户.用户名};var 结果 = await _userManager.CreateAsync(realUser);返回 ConvertToInterface(结果);}私有 IIdentityResult ConvertToInterface(IdentityResult 结果){IIdentityResult realResult = new IdentityResultMvc();realResult.Succeeded = result.Succeeded;realResult.Errors = result.Errors?.ToList();返回真实结果;}}公共类 IdentityResultMvc : IdentityResult, IIdentityResult{私有 IEnumerable_错误;私人布尔_succeed;public new bool 成功{得到 =>base.Succeeded ||_成功;设置 =>_succeed = 值;}公共新列表错误{得到 =>base.Errors?.ToList() ??_errors?.ToList();设置 =>_errors = 值;}}

最后但并非最不重要的一点是,您的 .NET Framework 项目需要一个单独的 DatabaseContext,这个将仅用于身份"目的,因此不会实际查询任何数据,仅用于身份验证, 授权.

public class DatabaseContextMvc : IdentityDbContext{public DatabaseContextMvc() : base("DatabaseContext"){Configuration.LazyLoadingEnabled = false;Configuration.ProxyCreationEnabled = false;//Database.SetInitializer(null);}public void SetTimeout(int 分钟){this.Database.CommandTimeout = 分钟 * 60;}公共静态 DatabaseContextMvc Create(){返回新的 DatabaseContextMvc();}}

此时您应该拥有在任何地方使用它所需的所有类.例如,在您的 .NET Framework 项目中,您可以像这样设置 ApplicationUserManager:

public class ApplicationUserManager : UserManager{public ApplicationUserManager(IUserStore store):基地(商店){//看看我在哪里使用了applicationUserMvc}public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context){var userStore =new UserStore(context.Get());//ApplicationUserLogin,UserRole,UserClaim 是自己创建的,但只是覆盖了 IdentityUserLogin(例如).var manager = new ApplicationUserManager(userStore);}...}

无论您在 .NET Framework 中使用什么依赖注入,请确保同时注册您的 DatabaseContextDatabaseContextMvc.

这是我的 DatabaseContext,它位于 .NET Standard 库中并在 .NET Core 和 .NET Framework 中使用:

public class DatabaseContext : IdentityDbContext{私有 IConfiguration _config;公共字符串 ConnectionString { 获取;}公共数据库上下文(IConfiguration 配置):基础(){_config = 配置;var connectionString = config.GetConnectionString("DatabaseContext");连接字符串 = 连接字符串;}public void SetTimeout(int 分钟){Database.SetCommandTimeout(分钟 * 60);}公共虚拟 DbSet<地址>地址 { 得到;放;}公共静态 DatabaseContext 创建(IConfiguration 配置){返回新的 DatabaseContext(config);}protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){//设置 DbContextOptions 的代码选项生成器.UseSqlServer(ConnectionString,providerOptions =>providerOptions.CommandTimeout(60)).UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);base.OnConfiguring(optionsBuilder);}

在这篇长文章或实施之后,您的注意力可能已经消失了,但再多说几句:

  • 我可以保证,有了这个,你就能让它发挥作用,它在过去半年里非常有效.
  • 因此 .NET Standard(以及 EntityFrameworkCore)是进行数据库操作的主要方式,大多数代码是为了应对 .NET Framework.
  • 您将努力安装正确的依赖项.它会导致运行时异常,您将很快遇到这些异常但很容易解决,.NET Framework 只需要为自己安装依赖项.确保版本一致,使用 Manage NuGet packages for Solution 下的 Consolidate 版本(右键单击解决方案).
  • 您将必须以 netcore 方式进行设置:因此您的 .NET Framework 项目中也需要 appsettings.json.此外,您仍然需要在 Web.Config 中使用它,这主要用于身份验证的一小部分.

    私有 IConfiguration GetConfiguartion(){var path = Server.MapPath("~/");var builder = new ConfigurationBuilder().SetBasePath(路径).AddJsonFile("appsettings.json");return builder.Build();//在你的DI中注入返回的IConfiguration}

  • 祝你好运.如果您认为这很困难并且会造成很多麻烦:正确,如果您有一个小型应用程序,最好将所有内容都转换为 .NET Core/.NET Standard.

I am having trouble with switching partially to .NET Standard.

I am in the process of migrating a class library to .NET Standard, in this library I have the repositories and the database communication. I already migrated this successfully to use AspNetCore.Identity.EntityFrameworkCore. What I try to achieve is eventually having 1 .NET Standard project taking care of the database, where 1 MVC .NET Framework, 1 API .NET Framework and 1 new .NET Core application will be using it. Besides that a few other .NET Framework class libraries depend on it. Basically the .NET Core application has been made already but the back-end has not been 'merged' for overlapping functionalities.

Little overview:

Reason for not converting MVC/API to .Core is that too many other libraries currently depend on .NET Framework, some are not yet convertible, but using the same library for the database is a fundamental change which will avoid double implementations of some repositories.

I have also already converted my entities that implement Microsoft.AspNetCore.Identity.IdentityUser, Microsoft.AspNetCore.Identity.IdentityRole, etc. So my DbContext class looks like this:

public class DatabaseContext : IdentityDbContext<ApplicationUser, ApplicationRole, string, ApplicationUserClaim, ApplicationUserRole, ApplicationUserLogin, ApplicationRoleClaim, ApplicationUserToken>
{
    private IConfiguration _config;
    public DatabaseContext(IConfiguration config) : base()
    {
        _config = config;
    }
    //all DbSet, OnModelCreating
}

I have successfully ran the EFCore Code First Migrations.

Now I am trying to configure the Identity in my MVC application (and then in the API project as well).

I just have the standard IdentityConfig.cs, Startup.Auth.cs where all the configuration is done. I have tried looking at this documentation (migration identity). All I could do is add this, where AddMvc() does not exist so that throws an compile error:

Startup.cs

using System;
using System.IO;
using Babywatcher.Core.Data.Database;
using Babywatcher.Core.Data.Entities;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Owin;
using Owin;

[assembly: OwinStartupAttribute(typeof(MyProject.MVC.Startup))]
namespace MyProject.MVC
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            var services = new ServiceCollection();
            ConfigureAuth(app);
            ConfigureServices(services);
        }

        public void ConfigureServices(IServiceCollection services)
        {
            // Add EF services to the services container.
            services.AddDbContext<DatabaseContext>(options =>
                options.UseSqlServer(""));//Configuration trying to refer to above method: Configuration.GetConnectionString("DefaultConnection")

            services.AddIdentity<ApplicationUser, ApplicationRole>()
                .AddEntityFrameworkStores<DatabaseContext>()
                .AddDefaultTokenProviders();

            services.AddMvc();
        }
    }
}

Well I guess this doesn't really do much, Also I am using SimpleInjector throughout both .NET Framework projects which I would prefer to keep using if possible in stead of going to use the default dependency injector.

By adding above I don't really know what to do with the ConfigureAuth method and where to put all the configuration.

When I try to adjust the IdentityManager, to try and reference the same types within AspNetCore.Identity I start to get issues when trying to change the ApplicationUserManager:

Creating the UserStore is not a problem, but trying to create the UserManager is more difficult, I also have tried to use this in my UserRepository, like I did before, which I can't use now anymore :(.

Old UserRepository

private readonly UserManager<ApplicationUser, string> _userManager = null;
private readonly RoleManager<ApplicationRole, string> _roleManager = null;

internal static IDataProtectionProvider DataProtectionProvider { get; private set; }
public UserRepository(DatabaseContext dbContext) : base(dbContext, c => c.contactId, m => m.ContactId)
{
    var userStore =
        new UserStore<ApplicationUser, ApplicationRole, string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>(dbContext);
    var roleStore = new RoleStore<ApplicationRole, string, ApplicationUserRole>(dbContext);
    _userManager = new UserManager<ApplicationUser, string>(userStore);
    _roleManager = new RoleManager<ApplicationRole, string>(roleStore);
    _userManager.UserValidator = new UserValidator<ApplicationUser>(_userManager) { AllowOnlyAlphanumericUserNames = false };
    if (DataProtectionProvider == null)
    {
        DataProtectionProvider = new MachineKeyProtectionProvider();
    }
    _userManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser, string>(DataProtectionProvider.Create("Identity"));
}

Attempting to do above again gives issues when creating the UserManager because of the 9 arguments it asks so I kind-of felt that this shouldn't be done this way... Probably going to do something like this to get them there of course I first want to fix the root problem.

Last but not least: Keep in mind that these applications are all in production already, so especially around the users I need to make sure that the logins all still work. When bringing this version live I will need to migrate the data to a new database because of some other migration issues.

解决方案

Alright so this is a long answer, be prepared to spent the next day on pulling your hair out of your head :).

First an interface of IApplicationUser which is implemented by 2 different classes:

public interface IApplicationUser
{
    string Id { get; set; }

    /// <summary>Gets or sets the user name for this user.</summary>
    string UserName { get; set; }
}

Implementation 1, this one is part of my database entities:

public class ApplicationUser :  IdentityUser<string>, IApplicationUser
{
    public DateTime? LockoutEndDateUtc { get; set; }
    public bool RequiresPasswordCreation { get; set; }
    public string TemporaryToken { get; set; }
}

Implementation 2, for my .NET Framework projects:

public class ApplicationUserMvc : IdentityUser<string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>, IApplicationUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUserMvc, string> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here

        return userIdentity;
    }
 ...all the other things
}

I then created my own Identity Manager (interface)

public interface IIdentityManager
{
    //User manager methods
    Task<IIdentityResult> CreateAsync(IApplicationUser user);
    //..all methods needed
}

public interface IIdentityResult
{
    bool Succeeded { get; set; }
    List<string> Errors { get; set; }
}

Then my actual implementations of this, so this one is for my .NET Core projects.

public class IdentityManagerCore : IIdentityManager
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly RoleManager<ApplicationRole> _roleManager;

    public IdentityManagerCore(UserManager<ApplicationUser> userManager, RoleManager<ApplicationRole> roleManager)
    {
        _userManager = userManager;
        _roleManager = roleManager;
    }

    public async Task<IIdentityResult> CreateAsync(IApplicationUser user)
    {
        ApplicationUser realUser = new ApplicationUser()
        {
            Id = user.Id,
            TemporaryToken = user.TemporaryToken,
            AccessFailedCount = user.AccessFailedCount,
            ConcurrencyStamp = user.ConcurrencyStamp,
            Email = user.Email,
            EmailConfirmed = user.EmailConfirmed,
            LockoutEnabled = user.LockoutEnabled,
            LockoutEnd = user.LockoutEnd,
            NormalizedEmail = user.NormalizedEmail,
            NormalizedUserName = user.NormalizedUserName,
            PasswordHash = user.PasswordHash,
            PhoneNumber = user.PhoneNumber,
            PhoneNumberConfirmed = user.PhoneNumberConfirmed,
            RequiresPasswordCreation = user.RequiresPasswordCreation,
            SecurityStamp = user.SecurityStamp,
            TwoFactorEnabled = user.TwoFactorEnabled,
            UserName = user.UserName
        };
        var result = await _userManager.CreateAsync(realUser);
        return ConvertToInterface(result);
    }

    private IIdentityResult ConvertToInterface(IdentityResult result)
    {
        IIdentityResult realResult = new IdentityResultCore();
        realResult.Succeeded = result.Succeeded;
        realResult.Errors = result.Errors?.Select(x => x.Description).ToList();
        return realResult;
    }
}

public class IdentityResultCore : IdentityResult, IIdentityResult
{
       private IEnumerable<string> _errors;
    private bool _succeed;
    public new bool Succeeded
    {
        get => base.Succeeded || _succeed;
        set => _succeed = value;
    }

    public new List<string> Errors
    {
        get => base.Errors?.Select(x => x.Description).ToList() ?? _errors?.ToList();
        set => _errors = value;
    }
}

The UserManager and RoleManager are injected on startup like so:

services.AddTransient<IIdentityManager, IdentityManagerCore>();

The .NET Framework implementation:

public class IdentityManagerMvc : IIdentityManager
{
    private readonly UserManager<ApplicationUserMvc, string> _userManager = null;
    private readonly RoleManager<ApplicationRoleMvc, string> _roleManager = null;

    internal static IDataProtectionProvider DataProtectionProvider { get; private set; }
    public IdentityManagerMvc(DatabaseContextMvc dbContext)
    {
        var userStore =
            new UserStore<ApplicationUserMvc, ApplicationRoleMvc, string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>(dbContext);
        var roleStore = new RoleStore<ApplicationRoleMvc, string, ApplicationUserRole>(dbContext);
        _userManager = new UserManager<ApplicationUserMvc, string>(userStore);
        _roleManager = new RoleManager<ApplicationRoleMvc, string>(roleStore);
        _userManager.UserValidator = new UserValidator<ApplicationUserMvc>(_userManager) { AllowOnlyAlphanumericUserNames = false };
        if (DataProtectionProvider == null)
        {
            DataProtectionProvider = new MachineKeyProtectionProvider();
        }
        _userManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUserMvc, string>(DataProtectionProvider.Create("Identity"));
    }

    public async Task<IIdentityResult> CreateAsync(IApplicationUser user)
    {
        ApplicationUserMvc realUser = new ApplicationUserMvc()
        {
            Id = user.Id,
            TemporaryToken = user.TemporaryToken,
            AccessFailedCount = user.AccessFailedCount,
            ConcurrencyStamp = user.ConcurrencyStamp,
            Email = user.Email,
            EmailConfirmed = user.EmailConfirmed,
            LockoutEnabled = user.LockoutEnabled,
            LockoutEnd = user.LockoutEnd,
            NormalizedEmail = user.NormalizedEmail,
            NormalizedUserName = user.NormalizedUserName,
            PasswordHash = user.PasswordHash,
            PhoneNumber = user.PhoneNumber,
            PhoneNumberConfirmed = user.PhoneNumberConfirmed,
            RequiresPasswordCreation = user.RequiresPasswordCreation,
            SecurityStamp = user.SecurityStamp,
            TwoFactorEnabled = user.TwoFactorEnabled,
            UserName = user.UserName
        };
        var result = await _userManager.CreateAsync(realUser);
        return ConvertToInterface(result);
    }

    private IIdentityResult ConvertToInterface(IdentityResult result)
    {
        IIdentityResult realResult = new IdentityResultMvc();
        realResult.Succeeded = result.Succeeded;
        realResult.Errors = result.Errors?.ToList();
        return realResult;
    }
}


public class IdentityResultMvc : IdentityResult, IIdentityResult
{
    private IEnumerable<string> _errors;
    private bool _succeed;
    public new bool Succeeded
    {
        get => base.Succeeded || _succeed;
        set => _succeed = value;
    }

    public new List<string> Errors
    {
        get => base.Errors?.ToList() ?? _errors?.ToList();
        set => _errors = value;
    }
}

Last but not least you would need a seperate DatabaseContext for your .NET Framework project, this one will only be used for "identity" purposes, so not to actually query any data, just for authentication, authorization.

public class DatabaseContextMvc : IdentityDbContext<ApplicationUserMvc, ApplicationRoleMvc, string, ApplicationUserLogin,
    ApplicationUserRole, ApplicationUserClaim>
{
    public DatabaseContextMvc() : base("DatabaseContext")
    {
        Configuration.LazyLoadingEnabled = false;
        Configuration.ProxyCreationEnabled = false;

        //Database.SetInitializer<DatabaseContextMvc>(null);
    }

    public void SetTimeout(int minutes)
    {
        this.Database.CommandTimeout = minutes * 60;
    }

    public static DatabaseContextMvc Create()
    {
        return new DatabaseContextMvc();
    }
}

At this moment you should have all the classes necessary to use it everywhere. So for example, in your .NET Framework project, you can have your ApplicationUserManager like so:

public class ApplicationUserManager : UserManager<ApplicationUserMvc, string>
{
    public ApplicationUserManager(IUserStore<ApplicationUserMvc, string> store)
        : base(store)
    {//look at where i used applicationUserMvc
    }

    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) 
    {
        var userStore =
            new UserStore<ApplicationUserMvc, ApplicationRoleMvc, string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>(context.Get<DatabaseContextMvc>());
        //ApplicationUserLogin,UserRole,UserClaim are self created but just override IdentityUserLogin (for example).
        var manager = new ApplicationUserManager(userStore);
    }
  ...
}

In whatever Dependency Injection you use in .NET Framework, make sure to Register both your DatabaseContext and DatabaseContextMvc.

Here is my DatabaseContext which is inside the .NET Standard library and used across .NET Core and .NET Framework:

public class DatabaseContext : IdentityDbContext<ApplicationUser, ApplicationRole, string, ApplicationUserClaim, ApplicationUserRole, ApplicationUserLogin, ApplicationRoleClaim, ApplicationUserToken>
{
    private IConfiguration _config;
    public string ConnectionString { get; }
    public DatabaseContext(IConfiguration config) : base()
    {
        _config = config;
        var connectionString = config.GetConnectionString("DatabaseContext");
        ConnectionString = connectionString;
    }

    public void SetTimeout(int minutes)
    {
        Database.SetCommandTimeout(minutes * 60);
    }

    public virtual DbSet<Address> Addresses { get; set; }

    public static DatabaseContext Create(IConfiguration config)
    {
        return new DatabaseContext(config);
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        //setup code for the DbContextOptions
        optionsBuilder
            .UseSqlServer(ConnectionString, 
                providerOptions => providerOptions.CommandTimeout(60))
            .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
        base.OnConfiguring(optionsBuilder);
    }

your focus is probably already gone after this long post or after implementing, but A few more words:

  • I can guarantee that with this you will make it work, it works perfect for the last half year.
  • So .NET Standard (and thus EntityFrameworkCore) is the primary way of doing database operations, most code is to cope with .NET Framework.
  • You will fight with installing the correct dependencies. It will cause runtime exceptions that you will encounter very quickly but easy resolvable, .NET Framework just needs to install the dependencies for itself. Make sure that the versions are aligned, use the Consolidate version under Manage NuGet packages for Solution (right-click on solution).
  • You will have to do it the-netcore-way for settings: so you need appsettings.json in your .NET Framework project as well. Also you still need it in the Web.Config, this is mostly for the small part of authentication.

    private IConfiguration GetConfiguartion()
    {
        var path = Server.MapPath("~/");
        var builder = new ConfigurationBuilder()
                         .SetBasePath(path)
                         .AddJsonFile("appsettings.json");
    
        return builder.Build();//inject the return IConfiguration in your DI
    }
    

  • Good luck. If you think this is difficult and causes a lot of trouble: correct, if you have a small application you are better of converting everything to .NET Core / .NET Standard.

这篇关于使用 Identity Core 在 ASP.NET MVC 框架中标识的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆