.NET API에서 HttpContext에 액세스하는 방법

9881 단어 csharpdotnet
웹에 노출되는 애플리케이션을 구축하는 경우 현재 HTTP 요청에서 일부 데이터를 읽거나 HTTP 응답에서 일부 값을 설정해야 할 수 있습니다.

.NET API에서 HTTP 요청 및 HTTP 응답과 관련된 모든 정보는 HttpContext 라는 전역 개체에 저장됩니다. 어떻게 액세스할 수 있습니까?

이 문서에서는 오래된 코드HttpContext.Current를 제거하는 방법과 더 테스트 가능한 코드를 작성하기 위해 수행할 수 있는 작업에 대해 알아봅니다.

HttpContext를 직접 사용하지 않는 이유



몇 년 전에는 코드에서 직접 HttpContext에 액세스했습니다.

예를 들어 Cookies 컬렉션에 액세스해야 하는 경우

var cookies = HttpContext.Current.Request.Cookies;


효과가 있었습니다. 그러나 이 접근 방식에는 큰 문제가 있습니다. 테스트를 설정하기 어렵게 만듭니다.

사실 우리는 클라이언트 클래스와 HttpContext 사이에 직접적인 종속성을 추가한 정적 인스턴스를 사용하고 있었습니다.

이것이 .NET 팀이 해당 클래스의 검색을 추상화하기로 결정한 이유입니다. 이제 IHttpContextAccessor 를 사용해야 합니다.

IHttpContextAccessor 추가



이제 HTTP 헤더 "데이터 위치"에 이름이 저장되어 있는 특정 도시의 현재 날씨를 반환하는 엔드포인트/WeatherForecast를 노출하는 이 .NET 프로젝트가 있습니다.

실제 계산(음, 진짜... 모든 것이 가짜입니다. 😅)은 WeatherService에서 수행합니다. 특히 GetCurrentWeather 방법으로.

public WeatherForecast GetCurrentWeather()
{
    string currentLocation = GetLocationFromContext();

    var rng = new Random();

    return new WeatherForecast
    {
        TemperatureC = rng.Next(-20, 55),
        Summary = Summaries[rng.Next(Summaries.Length)],
        Location = currentLocation
    };
}


현재 위치를 검색해야 합니다.

우리가 말했듯이, 우리는 더 이상 이전HttpContext.Current.Request에 의존할 수 없습니다.

대신 생성자에 IHttpContextAccessor를 주입하고 이를 사용하여 Request 개체에 액세스해야 합니다.

public WeatherService(IHttpContextAccessor httpContextAccessor)
{
    _httpContextAccessor = httpContextAccessor;
}

IHttpContextAccessor 인스턴스가 있으면 이를 사용하여 현재 HttpContext 헤더에서 정보를 검색할 수 있습니다.

string currentLocation = "";

if (_httpContextAccessor.HttpContext.Request.Headers.TryGetValue("data-location", out StringValues locationHeaders) && locationHeaders.Any())
{
    currentLocation = locationHeaders.First();
}

return currentLocation;


쉽죠? 거의 끝났습니다.

시작 클래스 구성



이런 방식으로 애플리케이션을 실행하면 현재 HTTP 요청에 액세스할 수 없습니다.

애플리케이션에서 서비스로 추가IHttpContextAccessor를 지정하지 않았기 때문입니다.

이를 위해 다음 명령어를 추가하여 ConfigureServices 클래스를 업데이트해야 합니다.

services.AddHttpContextAccessor();

Microsoft.Extensions.DependencyInjection 네임스페이스에서 가져온 것입니다.

이제 프로젝트를 실행할 수 있습니다!
data-location 헤더에서 도시를 지정하는 끝점을 호출하면 반환된 WeatherForecast 개체의 Location 필드에서 해당 값을 볼 수 있습니다.



추가 개선 사항



충분한가?



이런 식으로 사용하면 HTTP 컨텍스트에 액세스해야 하는 모든 클래스는 여러 객체를 모의해야 하기 때문에 설정하기 매우 어려운 테스트를 갖게 됩니다.

실제로 HttpContext.Request.Headers 를 모의하기 위해 HttpContext , Request , Headers 에 대한 모의를 만들어야 합니다.

이것은 테스트를 작성하고 이해하기 어렵게 만듭니다.

따라서 제 제안은 HttpContext 액세스를 별도의 클래스로 래핑하고 실제로 필요한 메서드만 노출하는 것입니다.

예를 들어 GetValueFromRequestHeader 서비스의 IHttpContextWrapper에서 HTTP 요청 헤더에 대한 액세스를 래핑할 수 있습니다.

public interface IHttpContextWrapper
{
    string GetValueFromRequestHeader(string key, string defaultValue);
}



이는 IHttpContextAccessor 인스턴스에 액세스하는 유일한 서비스입니다.

public class HttpContextWrapper : IHttpContextWrapper
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public HttpContextWrapper(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public string GetValueFromRequestHeader(string key, string defaultValue)
    {
        if (_httpContextAccessor.HttpContext.Request.Headers.TryGetValue(key, out StringValues headerValues) && headerValues.Any())
        {
            return headerValues.First();
        }

        return defaultValue;
    }
}


이러한 방식으로 HttpRequest 빌드에 집중하여 HttpContextWrapper 클래스와 WeatherService 클래스 모두에 대해 더 나은 테스트를 작성할 수 있으므로 복잡한 구조 설정에 대한 걱정 없이 테스트를 작성할 수 있습니다. 값을 검색하기 위해서만.

그러나 종속성 수명 범위에 주의하십시오! HTTP 요청 정보는 내부에 있습니다. 무엇을 추측하세요? - 그들의 HTTP 요청. 따라서 Startup 클래스에서 종속성을 정의할 때 IHttpContextWrapper를 Transient 또는 Scoped로 주입해야 합니다. 차이점이 기억나지 않는다면 제가 도와드리겠습니다here !

마무리



이 문서에서는 IHttpContextAccessor 를 사용하여 현재 HTTP 요청에 액세스할 수 있음을 배웠습니다. 물론 예를 들어 HTTP 헤더를 추가하여 응답을 업데이트하는 데 사용할 수도 있습니다.

즐거운 코딩하세요!

🐧

좋은 웹페이지 즐겨찾기