Как получить аутентифицированного пользователя из отдельной библиотеки классов в .Net Core - PullRequest
0 голосов
/ 24 мая 2018

У меня есть ядро ​​MVC, которое ссылается на библиотеку классов .NET Core.Весь доступ к данным и бизнес-логика находятся в библиотеке классов.Как я могу получить доступ к аутентифицированному пользователю из библиотеки классов?

В прошлом при использовании .NET Framework вы могли использовать

string UserName = System.Web.HttpContext.Current.User.Identity.Name

Чтобы получить имя пользователя из метода в классебиблиотека.В .NET Core кажется, что HttpContext больше не имеет свойства Current или User.

Вот простой пример использования.Предположим, у меня есть сущность данных и служба, которая «маркирует» сущности датой и именем пользователя перед сохранением их в базе данных.

Это будет во внешней библиотеке классов:

public interface IAuditable{
    DateTime CreateDate{get;set;}
    string UserName{get;set;}
}

public class MyEntity:IAuditable{
    public int ID{get;set;}
    public string Name{get;set;}
    public string Information{get;set;}
}

public static class Auditor{
    public static IAuditable Stamp(IAuditable model){            
        model.CreateDate=DateTime.UtcNow;
        model.CreatedBy=System.Web.HttpContext.Current.User.Identity.Name;
        return model;
    }
}

public sealed class MyService:IDisposable{
    MyDb db=new MyDb();
    public async Task<int> Create(MyEntity model){
        Auditor.Stamp(model);
        db.MyEntities.Add(model);
        return await db.SaveAsync();
    }
    public void Dispose(){
        db.Dispose();
    }
}

Тогда в моем контроллере MVC будет действие post, которое вызывает службу:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(MyEntity model)
{
    await service.Create(model);
    return RedirectToAction("Index")
}

Я хотел бы найти способ заменить эту строку в Auditor.Stamp, поскольку в .NET Core, по-видимому, нет HttpContext.Current.

В этом посте приведен пример того, как получить имя пользователя вCore:

public class UserResolverService  
{
    private readonly IHttpContextAccessor _context;
    public UserResolverService(IHttpContextAccessor context)
    {
        _context = context;
    }

    public string GetUser()
    {
       return await _context.HttpContext.User?.Identity?.Name;
    }
}

Но у меня осталась другая версия той же проблемы: как получить объект IHttpContextAccessor из библиотеки классов?

Большинство результатов моего поискаЕдинственное, что касается вопроса о том, как получить имя пользователя из метода контроллера MVC.Раньше я передавал объект User в каждый метод для каждого сервиса, но это было много дополнительной типизации - я бы предпочел что-то, что я мог бы набрать один раз (может быть, в Startup?), А потом забыть об этом.

Мне нужно что-то, что я могу смоделировать для модульных тестов, но, честно говоря, я думаю, что оборачивать System.Web.HttpContext.Current.User.Identity.Name во что-то, что можно смоделировать, было чертовски легко.

1 Ответ

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

В этой версии все еще сохраняется такая же гибкость.

Внедрение IHttpContextAccessor и у вас есть доступ к тому, что вам нужно.

рефакторинг статического Auditor, чтобы сделать его более инъекционным

public interface IAuditor {
    IAuditable Stamp(IAuditable model);
}

public class Auditor : IAuditor {
    private readonly IHttpContextAccessor accessor;

    public Auditor(IHttpContextAccessor accessor) {
        this.accessor = accessor;
    }

    public IAuditable Stamp(IAuditable model){            
        model.CreateDate = DateTime.UtcNow;
        model.CreatedBy = accessor.HttpContext.User?.Identity?.Name;
        return model;
    }
}

В таком случае служба будет зависеть от новой абстракции

public interface IMyService : IDisposable {
    Task<int> Create(MyEntity model);
}

public sealed class MyService : IMyService {
    MyDb db = new MyDb();
    private readonly IAuditor auditor;

    public MyService(IAuditor auditor) {
        this.auditor = auditor;
    }

    public async Task<int> Create(MyEntity model) {
        auditor.Stamp(model);
        db.MyEntities.Add(model);
        return await db.SaveAsync();
    }

    public void Dispose() {
        db.Dispose();
    }
}

На самом деле вы также должны вводить MyDb, но это выходит за рамки текущего вопроса.

Наконец, вы настраиваете свою библиотеку, чтобы иметь возможность настраивать службы при запуске

public static IServiceCollection AddMyLibrary(this IServiceCollection services) {

    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    services.AddSingleton<IAuditor, Auditor>();  
    services.AddScoped<IMyService, MyService>();

    //...add other services as needed

    return services.  
}

, а затем вы можете вызвать ее при запуске из корневого проекта

public void ConfigureServices(IServiceCollection services) {

    //...

    services.AddMyLibrary();

    //...
}

С помощью этой абстракции и использования DI части приложения развязаны и могут тестироваться изолированно.

...