.Net Core - внедрение зависимостей IUserInfo из промежуточного программного обеспечения API на уровень хранилища - PullRequest
0 голосов
/ 03 июля 2018

Предположим, у меня есть следующий слой структурированного проекта, такой как Репозиторий -> Сервис -> API снизу вверх, Пример кода:

Repository:

public interface IUserInfo
{
    int UID{ get; set; }
}
public class UserInfo : IUserInfo
{
    public int UID { get; set; }
}
public class ProductionRepository : Repository, IProductionRepository {
    public ProductionRepository(IUserInfo userInfo, StoreDbContext dbContext) : base(userInfo, dbContext)
    {}
    //...
}

Услуги:

public class ProductionService : Service, IProductionService {
        public ProductionService(IUserInfo userInfo, StoreDbContext dbContext)
            : base(userInfo, dbContext)
        {
        }
//...
}
public abstract class Service {        
    protected IProductionRepository m_productionRepository;
    public Service(IUserInfo userInfo, StoreDbContext dbContext)
    {
        UserInfo = userInfo;
        DbContext = dbContext;
    }
    protected IProductionRepository ProductionRepository
            => m_productionRepository ?? (m_productionRepository = new ProductionRepository(UserInfo, DbContext));
}

API:

  public class ProductionController : Controller {
        private readonly IUserInfo userInfo;
        protected IProductionService ProductionBusinessObject;
        public ProductionController(IUserInfo _userInfo, IProductionService productionBusinessObject)
        {
            userInfo = _userInfo;
            ProductionBusinessObject = productionBusinessObject;
        }
  }

Теперь в моем файле Startup.cs я использую токен JWT с событием " OnTokenValidated " для получения информации UserInfo из токена:

services.AddAuthentication(options =>
{
     options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
     options.Events = new JwtBearerEvents
     {
         #region Jwt After Validation Authenticated
         OnTokenValidated = async context =>
         {
              #region Get user's immutable object id from claims that came from ClaimsPrincipal
              var userID = context.Principal.Claims.Where(c => c.Type == ClaimTypes.NameIdentifier)
              services.Configure<UserInfo>(options =>
              {
                    options.UID = userID;
              });
              #endregion
          },
          #endregion
       }
};

Я использую services.Configure и пытаюсь назначить UID для объекта IUserInfo, но когда я отлаживаю в своем контроллере, IUserInfo всегда представляет нулевой объект, как в конструкторе или методе API. . Я знаю, что, вероятно, неправильно использую Внедрение зависимостей в ядре .Net, поэтому, пожалуйста, не стесняйтесь указывать мне, как правильно вставить этот IUserInfo в мой Controller -> Service -> Repository , поэтому все из них можно получить актуальную информацию UserInfo!

Ответы [ 2 ]

0 голосов
/ 03 июля 2018

Вы можете ввести IUserInfo, зарегистрировав его в качестве службы при запуске.

services.AddScoped<IUserInfo>(provider =>
{
    var context = provider.GetService<IHttpContextAccessor>();

    return new UserInfo
    {
        UID = context.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier)
    };
});
0 голосов
/ 03 июля 2018

Позднее вы не сможете зарегистрировать вещи в коллекции сервисов, особенно не динамически для какого-либо запроса. Набор услуг настраивается один раз (в течение ConfigureServices) и затем замораживается; Вы не можете изменить его впоследствии. Если вы хотите сделать вещи доступными в области запроса, вы можете либо поделиться ими как состоянием в зависимости от области запроса, либо поместить его в HttpContext.

Это кажется плохим дизайном, хотя передавать такие пользовательские данные, как зависимость DI. Вы должны передать эту информацию явно в вызовах методов.

Кроме того, вы действительно должны принять претензии и использовать , что напрямую. Вы можете легко создать некоторые методы расширения для ClaimsPrincipal, которые позволяют вам сделать User.GetUserId(), чтобы получить идентификатор пользователя из заявки, без необходимости помещать его в какой-то пользовательский объект, о котором вам нужно позаботиться. Принципал пользователя уже доступен во всей среде, поэтому просто используйте его.


Btw. обратите внимание, что использование services.Configure<UserInfo>() в общем случае не зарегистрирует зависимость UserInfo (особенно не зависимость IUserInfo!), а вместо этого настроит IOptions<UserInfo>. Но опять же: в вашем случае это не сработает, поскольку к моменту вызова Configure() коллекция сервисов уже создана.

...