대기 후 HttpContext.Current가 null 인 이유는 무엇입니까?


90

다음 테스트 WebAPI 코드가 있으며 프로덕션에서 WebAPI를 사용하지 않지만이 질문에 대한 토론 때문에 만들었습니다. WebAPI 비동기 질문

어쨌든 문제가되는 WebAPI 메서드는 다음과 같습니다.

public async Task<string> Get(int id)
{
    var x = HttpContext.Current;
    if (x == null)
    {
        // not thrown
        throw new ArgumentException("HttpContext.Current is null");
    }

    await Task.Run(() => { Task.Delay(500); id = 3; });

    x = HttpContext.Current;
    if (x == null)
    {
        // thrown
        throw new ArgumentException("HttpContext.Current is null");
    }

    return "value";
}

두 번째 예외는 await완료 될 때 HttpContext.Current스레드 정적 변수가 더 이상 적절한 값으로 해석되지 않는 다른 스레드에있을 가능성이 높기 때문에 두 번째 예외가 예상됩니다 . 이제 동기화 컨텍스트를 기반으로 실제로 대기 후 동일한 스레드로 다시 돌아 가야 할 수 있지만 테스트에서 멋진 작업을 수행하지 않습니다. 이것은 단지 평범하고 순진한 await.

다른 질문에 대한 의견에서 나는 HttpContext.Current기다림 후에 해결해야한다고 들었습니다 . 이 질문에 대해 같은 것을 나타내는 또 다른 의견이 있습니다. 그래서 무엇이 사실입니까? 해결해야합니까? 난 더 생각하지,하지만 난이 때문에 권위있는 대답 싶어 async하고 await나는 확실한 아무것도 찾을 수없는 새로운 충분히이입니다.

요약 : HttpContext.Current잠재적 null으로 await?


3
귀하의 질문은 명확하지 않습니다. 예상 한 일을 말했고, 그 의견 그것이 일어나고 있음을 나타냅니다 ... 그래서 무엇이 당신을 혼란스럽게합니까?
Jon Skeet

@ user2674389, 이것은 오해의 소지가 있습니다. 그건 AspNetSynchronizationContext그 돌봐 HttpContext하지 await. 또한 awaitWeb API 실행 모델에 대한 다른 스레드에서 발생할 수 있습니다.
noseratio

간결 질문을 제기하는 편집
welegan

1
@JoepBeusenberg 특정 웹 스택의 HTTP 요청 컨텍스트 내에서 실행되는 어셈블리에서 호출 될 때만 작동하는 별도의 어셈블리를 만드는 것은 테스트, 유지 관리 및 재사용이 어려울 수 있습니다.
Darrel Miller

1
@DarrelMiller 오히려 그 반대입니다. 실제 웹 프로젝트에서 비즈니스 로직을 분리했습니다. 의존성 주입을 사용하여 비즈니스 로직 위에 webapi 인식 라이브러리를 추가 할 수 있습니다. 그러나이 라이브러리는 비즈니스 로직이 .ConfigureAwait(false)어딘가에서 끝났을 때 중단됩니다 . 웹을 인식하지 못하기 때문에 비즈니스 계층을 통해 명시 적으로 전달 된 요청이나 컨트롤러가 없습니다. 이는 비즈니스 로직이 일반 .NET을 작성할 때 요청 세부 정보를 삽입 할 수있는 로깅 모듈에 유용합니다 TraceInformation.
Joep Beusenberg 2007

답변:


148

ASP.NET 4.5 애플리케이션을 작성하고 4.5 를 대상으로하고 있는지 확인하십시오 . async그리고 await당신은 4.5에서 실행되지 않는 ASP.NET에 정의되지 않은 동작을 하고 새로운 "작업 친화적 인"동기화 컨텍스트를 사용하고 있습니다.

특히 다음 중 하나를 수행해야합니다.

  • 설정 httpRuntime.targetFramework하기 위해 4.5, 또는
  • 에서 appSettings로 설정 aspnet:UseTaskFriendlySynchronizationContext합니다 true.

자세한 정보는 여기에서 확인할 수 있습니다 .


2
방금 새 ASP.NET 4.5 WebAPI 프로젝트를 만들고 코드를 복사 / 붙여 넣기 한 다음 테스트를 수행했습니다. 그것은 나를 위해 완벽하게 작동했습니다 (두 예외가 발생하지 않았습니다). 4.5 에서 실행 중이고 타겟팅 하는지 다시 확인하세요 .
Stephen Cleary

3
Target framework : .NET Framework 4.5가 설정되어 있습니다. 나는 당신에게 무엇을 말해야할지 모르겠습니다. 그것은 내 로컬 컴퓨터에서 확실히 null입니다.
welegan

24
<httpRuntime targetFramework="4.5" />명확히 위해, 덕분에 그것을 해결하는 것이다.
welegan

1
@Vince : 4.5.1이 제대로 작동합니다. targetFramework4.5.1 또는 4.5로 설정해야하는지 / 설정할 수 있는지 잘 모르겠지만 4.5.1에서 비동기로 작동해야합니다.
Stephen Cleary

1
자체 관리 핸들러를 작성한 경우 어떻게됩니까? web.config에 이러한 항목을 추가 한 후에도 HttpContext.Current = null이 계속 표시됩니다.
Brain2000

28

@StephenCleary가 올바르게 지적했듯이 web.config에 다음이 필요합니다.

<httpRuntime targetFramework="4.5" />

이 문제를 처음 해결할 때 위의 솔루션 전체 검색을 수행하고 모든 웹 프로젝트에 있는지 확인하고 신속하게 범인으로 무시했습니다. 결국 그 검색 결과를 전체 컨텍스트에서 살펴 보게되었습니다.

<!--
  For a description of web.config changes for .NET 4.5 see http://go.microsoft.com/fwlink/?LinkId=235367.

  The following attributes can be set on the <httpRuntime> tag.
    <system.Web>
      <httpRuntime targetFramework="4.5" />
    </system.Web>
-->

도.

레슨 : 웹 프로젝트를 4.5로 업그레이드하는 경우에도 해당 설정을 수동으로 가져와야합니다.


22
또 다른 문제는 이것이 <compilation targetFramework "4.5"/>와 다르다는 것입니다
Andrew

3

내 테스트에 결함이 있거나 여기에 누락 된 web.config 요소가있어 HttpContext.Current가 대기 후 올바르게 해결됩니까?

당신의 테스트는 결함이없고 HttpContext.Current는 당신이 기다릴 때 ASP.NET Web API에서 기다릴 때이 기다림을 따르는 코드가 기다림 전에 존재했던 올바른 HttpContext를 전달하도록 보장하기 때문에 기다림 후에 null이되어서는 안됩니다.


WebAPI에 대해 동일한 연속 스레드에 대해 확신합니까? 나는 그것이 다른 실인 경우를 다루었 다 .
noseratio

4
ASP.NET은 모든 스레드 풀 스레드에서 다시 시작되지만 올바른 요청 컨텍스트를 사용합니다.
Stephen Cleary

2
예, 맞습니다. 스레드는 동일하지 않을 수 있지만 HttpContext.Current는 대기 전과 동일합니다. 내 질문을 업데이트했습니다.
Darin Dimitrov

4
HttpContext.Current는 내 코드에서 대기 후 null이며 .net 4.6.1을 대상으로합니다.
Triynko

1
나를 위해 HttpContext.Current는 대기 함수 전에 null입니다
JobaDiniz

2

최근에이 문제를 만났습니다. Stephen이 명시 적으로 설정하지 않으면 대상 프레임 워크가이 문제를 일으킬 수 있다고 지적했듯이.

제 경우에는 웹 API가 버전 4.6.2로 마이그레이션되었지만 런타임 대상 프레임 워크가 웹 구성에 지정되지 않았기 때문에 기본적으로 <system.web> 태그 내에 누락되었습니다.

실행중인 프레임 워크 버전에 대해 의문이있는 경우이 방법이 도움이 될 수 있습니다. 웹 API 메서드에 다음 줄을 추가하고 중단 점을 설정하여 런타임에 현재로드 된 유형을 확인하고 레거시 구현이 아닌지 확인합니다.

다음이 표시되어야합니다 (AspNetSynchronizationContext).

여기에 이미지 설명 입력

LegazyAspNetSynchronizationContext (대상 프레임 워크를 추가하기 전에 확인한 내용) 대신 :

여기에 이미지 설명 입력

소스 코드 ( https://referencesource.microsoft.com/#system.web/LegacyAspNetSynchronizationContext.cs )로 이동하면이 인터페이스의 레거시 구현에 비동기 지원이 없음을 알 수 있습니다.

여기에 이미지 설명 입력

문제의 원인을 찾는 데 많은 시간을 보냈고 Stephen의 답변이 많은 도움이되었습니다. 이 답변이 문제에 대한 추가 정보를 제공하기를 바랍니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.