2012-11-26 14 views
6

HttpContext.Current üzerinde yoğun olarak kullanılan eski bir kitaplık kullanması gereken bir dizi ASP.NET barındırılan WebAPI hizmeti oluşturuyorum. Bir uyumsuz çağrıya katılan tüm yöntemlerde bağlamın korunmasını sağlamakta sorun yaşıyorum. Aşağıdaki kodda beklemeyle/Task.Wait ve TaskScheduler.FromCurrentSynchronizationContext() ile çeşitli varyasyonları denedim. Ben istiyorumWebAPI (Orta Güven) ile uyumsuz hale geldiğinde HttpContext'i koruyun

[HttpGet] 
    public Task<IEnumerable<string>> ContinueWith() 
    { 
     Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR"); //or another culture that is not the default on your machine 
     Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture; 

     var output = new List<string> { TestOutput("Action start") }; 

     var task = Task.Factory.StartNew(() => 
      { 
       Thread.Sleep(1000); 
       return TestOutput("In Task"); 
      }).ContinueWith(slowString => 
      { 
       output.Add(slowString.Result); 

       output.Add(TestOutput("Action end")); 
       return output as IEnumerable<string>; 
      }); 

     output.Add(TestOutput("Action Mid")); 

     return task; 
    } 

    private string TestOutput(string label) 
    { 
     var s = label + " ThreadID: " + Thread.CurrentThread.ManagedThreadId.ToString(CultureInfo.InvariantCulture); 
     s += " " + Thread.CurrentThread.CurrentCulture.EnglishName; 
     s += HttpContext.Current == null ? " No Context" : " Has Context"; 
     Debug.WriteLine(s); 
     return s; 
    } 

CurrentCulture fr-FR olmasını sağlamak mümkün olacak ve HttpContext.Current o TestOutput denir her noktada boş değil hiç. Yaptığım şeyle "Görevde" araması için bunu yapmayı başaramadım. Ayrıca bazı test ipliklerimde, hiçbir zaman, yöntemin uyumsuzluğunu etkin bir şekilde kaldırdığımı gösteren hiçbir değişiklik gösterilmiyor. Kültür ve HttpContext.Current TestOutput her aramada korunur ve kodun farklı iş parçacığı üzerinde çalıştırmak için ücretsiz olmasını nasıl sağlayabilirim?

Bir kapakta HttpContext.Current yakalama ve daha sonra basit bir şekilde yeniden ayarlama benim için işe yaramaz, çünkü HttpContext.Current setter çağrılırken bir güvenlik istisnası atacak olan Medium Trust'ı desteklemem gerekiyor.

cevap

6

await görevlerinizin her birinde içerik korunur. Gördüğün ne

parçacığı havuzu görevler için hiçbir bağlam var olmasıdır (Task.Run, TaskFactory.StartNew, ya da bu konuda BackgroundWorker veya Thread veya Delegate.BeginInvoke için). Bu normal ve bekleniyor.

Bu nedenle, iş parçacığı havuzu görevini kullanmayın. Örnek kodunuz, HttpContext'a sahip birden fazla iş parçacığı ile paralel işlem yapmak istiyor gibi görünüyor, ki bu da mümkün değil.

İsterseniz eşzamanlı async yöntemleri yapabilir, ama bu Thread.Sleep aslında yerine işlemci tabanlı yöntemin bir async yöntem olabilir gerektirir: Eski kütüphane sizin kontrolünüz dışındaysa

[HttpGet] 
public async Task<IEnumerable<string>> Test() 
{ 
    Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR"); 
    Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture; 

    var output = new List<string> { TestOutput("Action start") }; 

    var task = SlowStringAsync(); 
    output.Add(TestOutput("Action Mid")); 
    output.Add(await task); 
    output.Add(TestOutput("Action end")); 
    return output; 
} 

public async Task<string> SlowStringAsync() 
{ 
    await Task.Delay(1000); 
    return TestOutput("In Task"); 
} 

ve async yapamazsınız, sonra senkronize olarak adlandırmanız gerekir. Böyle durumlarda bir async yönteminden bir senkron yöntemi çağırmak için kabul edilebilir:

[HttpGet] 
public async Task<IEnumerable<string>> Test() 
{ 
    Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR"); 
    Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture; 

    var output = new List<string> { TestOutput("Action start") }; 

    output.Add(TestOutput("Action Mid")); 
    Thread.Sleep(1000); 
    output.Add(TestOutput("Not Really In Task")); 
    output.Add(TestOutput("Action end")); 
    return output; 
} 
+0

AspNetSynchronizationContext'in başka bir iş parçacığında çalıştırıldığında HttpContext gibi şeyleri korumak için özel olarak benim anlayışım vardı. Yanlış anlama mı yoksa AspNetSynchronizationContext bu durumda geçerli değil mi? – ScottS

+0

'AspNetSynchronizationContext'' HttpContext' korur, ancak aynı anda yalnızca bir iş parçacığı istek bağlamında olabilir. Bağlamı diğer konulara koyamazsınız, ancak 'AspNetSynchronizationContext', içeriği 'bekletme' yöntemini bekledikten sonra yeniden başlatan iş parçacığı havuzu iş parçacığına eklemekten sorumludur. –

+0

@StephenCleary - Cehaletimi bağışla ama 'Task.Factory.StartNew()' yöntemini kullanması durumunda 'CurrentCulture' iş parçacığı boyunca korunur. 'i bekliyoruz Task.Factory.StartNew (() => {doSomething();}; ' –

7

Biraz fark gerçek, HttpContext.Current yazılabilir olduğunu.

+0

Simon, bilinen bir gerçektir, ancak soruda belirtildiği gibi desteklemem gereken Medium Trust'ta çalışırken bir güvenlik istisnasına neden olacaktır. – ScottS

+0

Aynı zamanda çok sayıda iş parçacığına sahip olduğunuz için de çok tehlikelidir, çünkü çok işlemcili erişim için tasarlanmış olan * HttpContext.Current' ile aynıdır. –

+2

Anladığım kadarıyla, bu en iyi yaklaşım değil, ancak iş parçacıkları yüzünden tehlikeli olmayla ilgili olarak, etrafına bir kilit koyar mı? Kilit değişkeni kilit sırasında atanabilir mi, yoksa okunana kadar bekler mi? –