Добавить отношение к .NET Identity ApplicationUser для сущности на уровне данных - PullRequest
0 голосов
/ 21 мая 2018

Я создаю приложение .NET MVC с удостоверением для входа пользователя.Приложение имеет четыре уровня.

  • Уровень веб / пользовательского интерфейса, имеет ссылку на мой домен и уровни обслуживания
  • Уровень домена, не имеет ссылок
  • Уровень службы, имеетссылка на мои слои данных и доменов
  • слой данных, имеет ссылку на мой слой доменов

Я хочу, чтобы мой класс AppUser имел отношение к одному из моихсущности в моем слое данных, Company .

Класс AppUser находится в слое моего домена и наследуется от IdentityUser .Причина, по которой я разместил свой класс AppUser в своем доменном слое, заключается в том, что мне нужен доступ к нему из моего уровня Web / UI, где IdentityConfig нужен класс.

Но когда я теперь хочу добавить отношение к сущности в моем слое данных, мне стало сложно.

Класс AppUser, как я хочу, чтобы он выглядел:

using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using System.Security.Claims;
using System.Threading.Tasks;

namespace ITKA.Domain.Classes
{
    public class AppUser : IdentityUser
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string ContactNumber { get; set; }
        public int CompanyId { get; set; }
        public Company Company { get; set; }

        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<AppUser> manager)
        {
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            return userIdentity;
        }

        public void Dispose()
        {

        }
    }
}

Класс компании в том виде, как он выглядит:

using ITKA.Data.Interfaces;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace ITKA.Data.Entities
{
    [Table("CompanyTbl")]
    public class Company : IEntity
    {
        [Key]
        public int Id { get; set; }

        [StringLength(100)]
        public string CompanyName { get; set; }

        public virtual ICollection<InventoryItem> InventoryItems { get; set; }
    }
}

Класс IdentityConfig, как он выглядит

using System;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
using Microsoft.Owin.Security;
using ITKA.Domain.Classes;
using ITKA.Domain.Interfaces;

namespace ITKA.Web
{
    public class AppUserManager : UserManager<AppUser>
    {
        public AppUserManager(IUserStore<AppUser> userStore)
            : base(userStore)
        {
        }

        public static AppUserManager Create(IdentityFactoryOptions<AppUserManager> options, IOwinContext context) 
        {
            var userStore = new UserStore<AppUser>((IdentityDbContext<AppUser>)context.Get<IITKAContext>());
            var manager = new AppUserManager(userStore);

            manager.UserValidator = new UserValidator<AppUser>(manager)
            {
                AllowOnlyAlphanumericUserNames = false,
                RequireUniqueEmail = true
            };

            manager.PasswordValidator = new PasswordValidator
            {
                RequiredLength = 8,
                RequireNonLetterOrDigit = false,
                RequireDigit = true,
                RequireLowercase = true,
                RequireUppercase = true
            };

            manager.UserLockoutEnabledByDefault = false;
            manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
            manager.MaxFailedAccessAttemptsBeforeLockout = 5;

            return manager;
        }
    }

    public class AppSignInManager : SignInManager<AppUser, string>
    {
        public AppSignInManager(AppUserManager userManager,
            IAuthenticationManager authManager)
            : base(userManager, authManager) { }

        public static AppSignInManager Create
            (IdentityFactoryOptions<AppSignInManager> options, IOwinContext context)
        {
            return new AppSignInManager(context.Get<AppUserManager>(),
                context.Authentication);
        }
    }

    public class AppRoleManager : RoleManager<IdentityRole>
    {
        public AppRoleManager(RoleStore<IdentityRole> roleStore)
            : base(roleStore) { }

        public static AppRoleManager Create(IOwinContext context)
        {
            var roleStore = new RoleStore<IdentityRole>
                ((IdentityDbContext<AppUser>)context.Get<IITKAContext>());

            return new AppRoleManager(roleStore);
        }
    }
}

Я не знаю, как можно разместить класс AppUser в моем слое данных, чтобы IdentityConfig может быть в состоянии «достичь» его, так как эти слои не имеют ссылок друг на друга.

Я попытался переместить свой класс AppUser на свой уровень данных и заставил его использовать интерфейс iдобавлен к слою моего домена, IAppUser .Я изменил IdentityConfig , чтобы использовать мой интерфейс вместо моего класса, но это дало мне много squiggliez.

Первая проблема, с которой я столкнулся, заключалась в том, что там не было неявного преобразования между IAppUser и IUser , поэтому я сделал мой интерфейс IAppUser наследуемым от IUser , и это решило некоторые проблемы в классе IdentityConfig .

Но в некоторых местах все еще жаловались на то, что неявное преобразование между IAppUser и классом IdentityUser отсутствует.Я не могу заставить свой интерфейс наследовать от класса, поэтому эксперимент завершился.

Я не знаю, есть ли способ добавить отношение к моему классу AppUser к сущности, которая находится в моемслой данных через интерфейс в моем доменном слое, может быть?Такое ощущение, что это не сработает для меня, потому что я думаю, что EF нужно неявно знать, к какому классу / сущности он относится.И так как многие различные классы kan наследуют от интерфейса, это кажется мне невозможным.Я не прав?

Или я могу иметь в своем классе AppUser свойство с интерфейсом, и EF создаст связь?Если мой класс Company будет использовать интерфейс с именем ICompany , а мой класс AppUser будет иметь такое свойство, как:

public ICompany Company { get; set; }

, создаст ли онотношения с компанией?

У меня были проблемы, когда IdentityConfig требовался мой класс DbContext, который также находится на моем уровне данных, но эту проблему я смог решить с помощью интерфейса на уровне моего домена.

Я действительно застрял здесь, и я не знаю, как решить эту проблему.Я благодарен за любую помощь.

1 Ответ

0 голосов
/ 21 мая 2018

Я вижу, что у вас возникла проблема с циклическими ссылками, если вы добавляете слой данных к ссылкам на уровне домена.Вы не хотите, чтобы домен и данные ссылались друг на друга.

Удалите эту ссылку:

  • Уровень данных, имеет ссылку на мой уровень домена

И ссылка на уровень данных в вашем доменном уровне:

  • Доменный уровень, не имеет ссылок

Теперь он должен выглядеть как-товот так.

Web -> Domain  -> Data

    -> Service -> Data
               -> Domain
  1. Веб ссылки на слои Домен и Сервис слои.
  2. Домен ссылается на слой Data .
  3. Сервис слой ссылается на Данные и Домен слои

Обратите внимание, что Уровень данных являетсясамая низкая ссылка, поэтому уровень данных будет , а не иметь какие-либо ссылки.

Сохраните ваш класс AppUser на уровне домена.

Из-за точки # 2Слой домена ссылается на слой данных. Теперь вы можете использовать сущность Company.

AppUser.cs

using ITKA.Data.Entities;
//or just use ITKA.Data.Entities.Company

namespace ITKA.Domain.Classes 
{
    public class AppUser : IdentityUser
    {
        ....
        public virtual Company Company { get; set; }
        ....
    }
}

Теперь для веб-слоя - из-заточка # 1, Веб ссылается на слой Домена, позволяя ему получить доступ к AppUser классу

IdentityConfig.cs

using ITKA.Domain.Classes;
//or just use ITKA.Domain.Classes.AppUser;

namespace ITKA.Web 
{
    public class AppUserManager : UserManager<AppUser>
    {
        ....
        public virtual Company Company { get; set; }
        ....
    }
}

Вам больше всего нужно сохранитьваш IdentityDbContext на уровне домена, а также сохранить сущность DbContext на уровне данных.Однако оба могут указывать на одну и ту же строку подключения.

Надеюсь, это поможет.

...