Модульное тестирование и множественные параметры для конструкторов в Asp.Net Core MVC, передача токена на каждый запрос - PullRequest
0 голосов
/ 19 мая 2018

Я пытаюсь добавить еще один параметр в мои конструкторы в своем приложении Asp.Net Core MVC, но сталкиваюсь с некоторыми трудностями при этом.Вот как выглядит моя реализация.

Действие входа:

[HttpPost, AllowAnonymous, ValidateAntiForgeryToken]
public IActionResult Login(LoginViewModel loginModel, string returnUrl = null)
{
   returnUrl = string.IsNullOrWhiteSpace(returnUrl) ? ApiConstants.Dashboard : returnUrl;
   ViewData["ReturnUrl"] = returnUrl;
   if (!ModelState.IsValid) return View(loginModel);
   var token = Service.Login(loginModel);
   if (string.IsNullOrWhiteSpace(token)) return View(loginModel);
   TempData["token"] = token;
   AddCookie(token);
   return RedirectToAction("Index", "Dashboard");
}

private void AddCookie(string token)
{
   HttpContext.Response.Cookies.Append("token", token,new CookieOptions()
   {
      Expires = DateTimeOffset.Now.AddDays(-1)
   });
}

Контроллер:

private readonly INozzleService _nozzleService;
public NozzleController(INozzleService nozzleService)
{
  var token = HttpContext.Request.Cookies["token"];
  _nozzleService = nozzleService;
}

Обслуживание форсунок:

private static INozzleAdapter Adapter { get; set; }
public NozzleService(INozzleAdapter adapter)
{
  Adapter = adapter;
}

Адаптер форсунки:

private readonly string _token;
public NozzleAdapter(string token)
{
   _token = token;
}

Как только я получу токен в адаптере, я добавлю токен в заголовок HttpClient.

client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token);

Настройка служб при запуске:

public void ConfigureServices(IServiceCollection services)
{
   services.AddSingleton<ITempDataProvider, CookieTempDataProvider>();
   services.AddDistributedMemoryCache();
   services.AddSession();
   services.AddTransient<IAccountService, AccountService>();
   services.AddTransient<IAccountAdapter, AccountAdapter>();
   services.AddTransient<INozzleService, NozzleService>();
   services.AddTransient<INozzleAdapter, NozzleAdapter>();
   services.AddMvc();
}

Не могли бы вы, пожалуйстадайте мне знать, что может быть лучшим способом для достижения этой цели в приложении Asp.Net core 2.0 MVC?Я прочитал пост о том, что использование нескольких конструкторов не является хорошей идеей в приложении Asp.Net Core MVC, поэтому я не хочу использовать несколько конструкторов.

В то же время я хочу удостовериться, что все мои классы можно тестировать с помощью DI.Какой должен быть лучший подход здесь?

Пожалуйста, дайте мне знать, если кому-то нужна дополнительная информация.

Обновление:

В соответствии с решением Shyju, я смог реализовать cookie, однакоМне все еще нужно передать два параметра одному из моих контроллеров.

private readonly IAccountService _service;
private readonly ITokenProvider _tokenProvider;
public AccountController(IAccountService service, ITokenProvider tokenProvider)
{
  _service = service;
  _tokenProvider = tokenProvider;
}

Чтобы я мог, используйте метод AddToken, как показано ниже.

_tokenProvider.AddToken(token);

1 Ответ

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

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

public interface ITokenProvider
{
    /// <summary>
    /// Gets the token
    /// </summary>
    /// <returns></returns>
    string GetToken();
}

Теперь создайте реализацию этого, которая будет считывать токен из куки.Вот простая реализация, которая считывает токен из коллекции куки

public class CookieTokenProvider : ITokenProvider
{
    private readonly IHttpContextAccessor httpContextAccessor;

    public CookieTokenProvider(IHttpContextAccessor httpContextAccessor)
    {
        this.httpContextAccessor = httpContextAccessor;
    }
    public string GetToken()
    {
        if (httpContextAccessor.HttpContext.Request.Cookies
                                           .TryGetValue("token", out string tokenValue))
        {
            return tokenValue;
        }
        return null;
    }
}

Теперь вы можете внедрить реализацию ITokenProvider в любое место и вызвать метод GetToken, чтобы получить значение токена.Например, вы можете внедрить это в конструктор класса NozzleAdapter.

private readonly ITokenProvider tokenProvider;
public NozzleAdapter(ITokenProvider tokenProvider)
{
   tokenProvider=tokenProvider;
}
public string SomeOtherMethod()
{
   var token = this.tokenProvider.GetToken();
   //Do null check and use it
}

Убедитесь, что вы зарегистрировали это в методе ConfigureServices в классе запуска

services.AddTransient<ITokenProvider, CookieTokenProvider>();

Относительно вашего комментарияо получении токена и его сохранении, это зависит от вас, где вы хотите это сделать.Вы можете сделать это в реализации CookieTokenProvider.Прочитайте значение и сохраните его где-нибудь (локальная БД, в кеше памяти и т. Д.) И получите его оттуда, если оно существует (в следующий раз)

Теперь для ваших модульных тестов вы можете создать MockTokenProvider, который не используетHttpContext, но просто верните фиктивное значение для вашего тестирования,

public class MockTokenProvider : ITokenProvider
{
    public string GetToken() => "FakeToken";
}
...