WebApi에서 HttpContext.Current를 사용하는 것은 비동기로 인해 위험합니다.
내 질문은 이것과 약간 관련이 있습니다 : 의존성 주입이있는 HttpContext.Items에 대한 WebApi 동등합니다 .
Ninject를 사용하여 WebApi 영역에서 HttpContext.Current를 사용하여 클래스를 주입하려고합니다.
내 우려는 WebApi에서 ( 모든 것이? ) 비동기 이므로 매우 위험 할 수 있습니다 .
이 점에서 내가 틀렸다면 저를 수정하십시오. 이것이 지금까지 조사한 것입니다.
HttpContext.Current는 Thread에서 현재 컨텍스트를 가져옵니다 (구현을 직접 살펴 봤습니다).
다른 스레드에서 실행될 수 있기 때문에 비동기 작업 내에서 HttpContext.Current를 사용할 수 없습니다.
WebApi는 메소드와 함께 IHttpController를 사용합니다
Task<HttpResponseMessage> ExecuteAsync
=> 모든 요청은 비동기입니다 => 액션 메소드 내에서 HttpContext.Current를 사용할 수 없습니다. 심지어 같은 스레드에서 더 많은 요청이 동시화에 의해 실행될 수도 있습니다.생성자에 물건을 주입 한 컨트롤러를 만들기 위해 IHttpControllerActivator는 sync 메서드 와 함께 사용됩니다
IHttpController Create
. 이것은 ninject가 모든 종속성을 가진 Controller를 생성하는 곳입니다.
이 4 가지 요점 모두에서 옳다면, 액션 메서드 나 그 아래의 레이어 내에서 HttpContext.Current를 사용하는 것은 매우 위험하며 예상치 못한 결과가 발생할 수 있습니다. 나는 이것을 정확하게 제안하는 많은 받아 들여진 답변을 보았습니다. IMHO 이것은 잠시 동안 작동 할 수 있지만 부하가 걸리면 실패합니다.
그러나 DI를 사용하여 컨트롤러와 그 종속성을 생성 할 때는 하나의 분리 된 스레드에서 실행되기 때문에 괜찮습니다. 생성자의 HttpContext에서 값을 얻을 수 있으며 안전할까요? . IIS의 모든 스레드가 소비 될 수있는 과부하 상태에서 문제가 발생할 수 있으므로 각 컨트롤러가 모든 요청에 대해 단일 스레드에서 생성되는지 궁금합니다.
HttpContext 항목을 삽입하려는 이유를 설명하기 위해 :
- 한 가지 해결책은 컨트롤러 작업 메서드에서 요청을 가져오고 필요한 값을 코드의 깊숙한 곳에서 사용될 때까지 매개 변수로 모든 계층에 전달하는 것입니다.
우리가 원하는 솔루션 : 그 사이의 모든 레이어는 이것에 영향을받지 않으며, 삽입 된 요청을 코드 깊숙한 곳에서 사용할 수 있습니다 (예 : URL에 의존하는 일부 ConfigurationProvider에서)
이 주제가 매우 복잡해 보이므로 내가 완전히 틀렸거나 내 제안이 맞다면 의견을 보내주십시오. 미리 Thx!
HttpContext.Current는 Thread에서 현재 컨텍스트를 가져옵니다 (구현을 직접 살펴 봤습니다).
HttpContext
스레드에 적용되는 것이 더 정확할 것입니다 . 또는 스레드가 HttpContext
.
다른 스레드에서 실행될 수 있기 때문에 비동기 작업 내에서 HttpContext.Current를 사용할 수 없습니다.
전혀; async
/ 의 기본 동작은 await
임의의 스레드에서 다시 시작되지만 해당 스레드는 async
메서드 를 다시 시작하기 전에 요청 컨텍스트에 들어갑니다 .
이것의 핵심은 SynchronizationContext
. 당신이 그것에 익숙하지 않은 경우 주제에 대한 MSDN 기사 가 있습니다. A SynchronizationContext
는 플랫폼에 대한 "컨텍스트"를 정의하며 일반적인 것은 UI 컨텍스트 (WPF, WinPhone, WinForms 등), 스레드 풀 컨텍스트 및 ASP.NET 요청 컨텍스트입니다.
ASP.NET 요청 컨텍스트는 HttpContext.Current
문화 및 보안과 같은 몇 가지 다른 것들을 관리합니다 . UI를 컨텍스트 모두 단단히 단일 스레드 (과 관련된 UI 스레드)하지만, ASP.NET 요청 컨텍스트는 특정 스레드에 연결되어 있지 않습니다. 그러나 요청 컨텍스트 에서 한 번 에 하나의 스레드 만 허용 합니다 .
솔루션의 다른 부분은 방법 async
과 await
작동입니다. async
내 블로그에 그들의 행동을 설명 하는 소개가 있습니다 . 요약하면 await
기본적으로 현재 컨텍스트 (이 SynchronizationContext.Current
아닌 경우 null
) 를 캡처하고 해당 컨텍스트를 사용하여 async
메서드 를 다시 시작합니다 . 따라서 await
자동으로 ASP.NET을 캡처하고 해당 요청 컨텍스트 내 SynchronizationContext
에서 async
메서드 를 다시 시작합니다 (따라서 문화, 보안 및 HttpContext.Current
).
이면 컨텍스트를 캡처 하지 말라고await
ConfigureAwait(false)
명시 적으로 말하는 await
것 입니다.
ASP.NET은 / 를 사용하여 SynchronizationContext
깔끔하게 작동 하도록 변경해야했습니다 . 응용 프로그램이 .NET 4.5에 대해 컴파일되고 web.config에서 명시 적으로 4.5를 대상 으로하는지 확인해야합니다 . 이것은 새 ASP.NET 4.5 프로젝트의 기본값이지만 ASP.NET 4.0 또는 이전 버전에서 기존 프로젝트를 업그레이드 한 경우 명시 적으로 설정해야합니다.async
await
.NET 4.5에 대해 애플리케이션을 실행하고 .NET Framework를 관찰하여 이러한 설정이 올바른지 확인할 수 있습니다 SynchronizationContext.Current
. 만약 AspNetSynchronizationContext
그렇다면 당신은 좋은 것입니다. 이면 LegacyAspNetSynchronizationContext
설정이 잘못된 것입니다.
만큼 설정이 올바른지 (그리고 당신이 ASP.NET 4.5을 사용하는 것처럼 AspNetSynchronizationContext
), 당신은 안전하게 사용할 수있는 HttpContext.Current
애프터 await
그것에 대해 걱정하지 않고.
async / await 방법론을 사용하는 웹 API를 사용하고 있습니다.
또한 사용
1) HttpContext.Current.Server.MapPath
2) System.Web.HttpContext.Current.Request.ServerVariables
이것은 코드 변경없이 갑자기 중단 된 상당한 시간 동안 잘 작동했습니다.
이전 버전으로 되돌 리면서 많은 시간을 보내면서 누락 된 키가 문제를 일으키는 것을 발견했습니다.
< httpRuntime targetFramework="4.5.2" /> under system.web
나는 기술적으로 전문가가 아닙니다. 그러나 웹 구성에 키를 추가하고 GO를 제공하는 것이 좋습니다 .
이 문제를 정확히 설명하는 아주 좋은 기사를 찾았습니다. http://byterot.blogspot.cz/2012/04/aspnet-web-api-series-part-3-async-deep.html?m=1
저자는 WebApi 프레임 워크에서 ExecuteAsync 메서드가 어떻게 호출되는지 자세히 조사하여 다음과 같은 결론에 도달했습니다.
ASP.NET Web API 작업 (및 모든 파이프 라인 메서드)은 Task 또는 Task <T>를 반환하는 경우에만 비동기 적으로 호출됩니다. 이것은 분명하게 들릴 수 있지만 Async 접미사가있는 파이프 라인 메서드는 자체 스레드에서 실행되지 않습니다. 담요 Async를 사용하는 것은 잘못된 이름 일 수 있습니다. [업데이트 : ASP.NET 팀은 실제로 Async가 Task를 반환하는 메서드를 나타내는 데 사용되며 비동기 적으로 실행할 수 있지만 반드시 그럴 필요는 없음을 확인했습니다.]
이 기사에서 이해 한 것은 Action 메서드가 동 기적으로 호출되지만 호출자 결정이라는 것입니다.
이 목적을 위해 다음과 같은 작은 테스트 앱을 만들었습니다.
public class ValuesController : ApiController
{
public object Get(string clientId, string specialValue)
{
HttpRequest staticContext = HttpContext.Current.Request;
string staticUrl = staticContext.Url.ToString();
HttpRequestMessage dynamicContext = Request;
string dynamicUrl = dynamicContext.RequestUri.ToString();
return new {one = staticUrl, two = dynamicUrl};
}
}
하나의 비동기 버전 반환 async Task<object>
jquery로 약간의 DOS 공격을 시도했지만를 사용할 때까지 어떤 문제도 확인할 수 없었 await Task.Delay(1).ConfigureAwait(false);
습니다. 이는 실패 할 것이 분명합니다.
What I took from the article is, that the problem is very complicated and Thread switch can happen when using async action method, so it is definetly NOT a good idea to use HttpContext.Current anywhere in the code called from the action methods. But as the controller is created synchronously, using HttpContext.Current in the constructor and as well in dependency injection is OK.
When somebody has another explanation to this problem please correct me as this problem is very complicated an I am still not 100% convinced.
diclaimer:
- I ignore for now the problem of self-hosted Web-Api withoud IIS, where HttpContext.Current would not work probably anyway. We now rely on IIS.
'Development Tip' 카테고리의 다른 글
IE8을 사용하는 첫 번째 자식 및 마지막 자식 (0) | 2020.12.04 |
---|---|
504 시간 초과 오류 증가 (0) | 2020.12.04 |
docker를 사용할 때 virtualenv가 (프로덕션에서) 목적을 제공합니까? (0) | 2020.12.04 |
PropertyDefinition이 일치하지 않습니다. (0) | 2020.12.04 |
Visual Studio에서 이전에 실행 된 몇 줄이 무엇인지 확인하기 위해 뒤로 물러 설 방법이 있습니까? (0) | 2020.12.04 |