2012-06-29 3 views
5

AsyncController를 종속성 주입과 혼합하려고합니다. 문제의 MVC 응용 프로그램은 비동기 웹 서비스 호출을 통해 거의 모든 데이터를 가져옵니다. TPL에서 Tasks의 비동기 작업을 래핑하고 이러한 작업이 완료되면 컨트롤러의 AsyncManager에 알립니다.AsyncManager.Sync없이 안전하게 ASP.NET 동기화 컨텍스트를 통해 작업 실행

때로는 쿠키를 추가하는 등의 작업을 계속 수행하면서 HttpContext를 눌러야합니다. Using an Asynchronous Controller in ASP.NET MVC에 따라이 작업을 수행하는 올바른 방법은 AsyncManager.Sync 메서드를 호출하는 것입니다. 그러면 HttpContext를 비롯한 ASP.NET 스레드 컨텍스트가 현재 스레드에 전파되고 콜백이 실행 된 다음 이전 컨텍스트가 복원됩니다.

그러나 그 기사는 말한다 :

동작을 보증되지 ASP.NET의 통제하에 이미 스레드에서 동기화()를 호출.

컨트롤러에서 작업을 모두 수행하면 문제가되지 않습니다. 일반적으로 연속에서 사용해야 할 스레드를 알고 있기 때문입니다. 하지만 내가하려는 것은 비동기 데이터 액세스와 비동기 컨트롤러 사이에 중간 계층을 만드는 것입니다. 그래서 이것도 비동기입니다. 모든 것은 DI 컨테이너에 의해 배선되어 있습니다.

이전과 같이 호출 체인의 일부 구성 요소는 "현재"HttpContext를 사용해야합니다. 예를 들어 로그온 후에 싱글 사인온 (SSO) 서비스에서 얻은 "세션"토큰을 저장하려고합니다. 그 일을하는 추상화는 ISessionStore입니다. 응답에 쿠키를 넣거나 요청에서 쿠키를 가져 오는 CookieSessionStore를 생각해보십시오. 나는이 함께 볼 수있는

두 가지 문제 :

  1. 구성 요소는 AsyncManager에 액세스 할 수 또는 그들이 컨트롤러에서 사용하고 모른다.
  2. 구성 요소는 호출되는 스레드를 알지 못하므로 AsyncManager.Sync 또는 이와 동등한 기능은 이론적으로 문제가됩니다.

내가 기본적으로 요청의 시작 부분에 TaskScheduler.FromCurrentSynchronizationContext()을 잡고 객체를 주입하고, # 1를 해결하기 위해, 그리고 작업이 인수로 HttpContextBase 복용, 그 스케줄러 시작을 통해 작업을 호출 할 수 있습니다.

즉, 내 구성 요소에서, 나는 비슷한 호출 할 수 있습니다 : 나는 아직이 어떤 문제를 발견하지 않은

MySyncObject.Sync(httpContext => /* Add a cookie or something else */); 

을,하지만 난 문제 # 2에 대한 걱정. Reflector에서 AsyncManagerSynchronizationContextTaskScheduler을 모두 보았고 비슷하게 작동하여 ASP.NET SynchronizationContext에서 콜백을 실행합니다. 그리고 그게 날 무서워 :)

인라인 경우 동기화 작업을 수행하는 대신 작업 스케줄러 구현이 직접 호출하는 것을 보았을 때 조금의 희망이있었습니다. 그러나 유감스럽게도 이것은 보통 Task.Start(scheduler) 코드 경로를 통해 발생하지 않는 것 같습니다. 오히려, 작업은 시작하기 전에 기다리는 것과 같은 다른 상황에서 인라인 될 수 있습니다.

그래서 내 질문은 : 나는이 방법으로 여기 문제로 실행하는 것

  1. 건가요?
  2. 더 좋은 방법이 있습니까?
  3. 스레드 안전성이없는 HttpContext에 대한 액세스를 직렬화하기 만하면이 시나리오에서 동기화의 유용성이 있습니까? 즉, 대신 스레드로부터 안전한 HttpContextBase 래퍼 (ick)를 사용할 수 있습니까?
+0

'Task.Start (scheduler)'를 사용하면, 충분히 빨리'Wait()'하면 인라인 될 수 있습니다. 물론 우리는 멀티 스레딩에 대해 이야기하고 있습니다. 따라서 "즉시"는 "충분히 빠르지"않을 수도 있습니다. – svick

+0

흠 나는 그것을 보지 못한다. 물론 .NET 4.5를 지금 설치 했으므로 누가 알 수 있습니까? :) –

답변

1

스레드 로컬 통계에 의존하는 것이 좋습니다. HttpContext.Current은 그 메커니즘에 의존하고 있으며 수년간 작업 해 왔지만 이제 비동기식으로 바뀌어 가고 있으며 그 접근법은 빠르게 악화되고 있습니다. 이 정적 변수의 값을 로컬 변수로 가져 와서 비동기 작업으로 전달하면 항상 유용합니다.

확실하게
public async Task<ActionResult> MyAction() { 
    await Task.Yield(); 
    var item = this.HttpContext.Items["something"]; 
    await Task.Yield(); 
    return new EmptyResult(); 
} 

, 미들웨어 비즈니스 로직, 특히 HttpContext를 또는 무엇에 의존해서는 안 : 그래서, 예를 들면 : 당신이 MVC에 있다면

public async Task<ActionResult> MyAction() { 
    var context = HttpContext.Current; 
    await Task.Yield(); 
    var item = context.Items["something"]; 
    await Task.Yield(); 
    return new EmptyResult(); 
} 

또는 더 나은, 모두 HttpContext.Current을 피하기 ASP.NET 라이브러리에서. 따라서 쿠키를 설정하기 위해 미들웨어가 콜백, 인터페이스 등을 통해 컨트롤러로 다시 콜된다고 가정하면 해당 컨텍스트에 액세스하기 위해 this.HttpContext을 사용할 수 있습니다.

관련 문제