2017-05-11 29 views
5

Tôi đang thử nghiệm một dự án web bằng cách sử dụng OWIN và kết nối OpenID với Azure AD. Tôi đang sử dụng phần lớn các mã từ mẫu này: https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-openidconnectHttpContext.Current is null trên TokenCache.BeforeAccess

Tôi có một vấn đề mà tôi nhận được một ngoại lệ null trên dòng 27 của tập tin này: https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-openidconnect/blob/master/TodoListWebApp/Utils/NaiveSessionCache.cs

tôi nhận được ngoại lệ vì HttpContext.Current là null.

Tôi có thể thấy rằng Load() được gọi từ BeforeAccessNotification().

Phiên bản khung của tôi là 4.5.2 và tôi có <httpRuntime targetFramework="4.5.2" ... > trong web.config của tôi.

Tại sao HttpContext.Current null trong ngữ cảnh này?


Cập nhật:

Sự khác biệt duy nhất tôi có từ mẫu là ActionResult của tôi trên bộ điều khiển của tôi không phải là async. Tôi gọi AcquireTokenSilentAsync trong một Tác vụ không đồng bộ được gọi với .Wait() từ một ActionResult chuẩn. Tôi đang làm việc trong CMS không cho phép tôi sử dụng ActionResults không đồng bộ.


này được OnAuthorizationCodeReceived:

private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification context) 
    { 
     var code = context.Code; 

     var credential = new ClientCredential(ClientId, AppKey); 

     var userObjectID = 
      context.AuthenticationTicket.Identity.FindFirst(
       "http://schemas.microsoft.com/identity/claims/objectidentifier").Value; 

     var authContext = new AuthenticationContext(Authority, new NaiveSessionCache(userObjectID)); 

     var uri = new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)); 

     var result = await authContext.AcquireTokenByAuthorizationCodeAsync(code, uri, credential, GraphUrl); 
    } 

Đây là stacktrace:

[NullReferenceException: Object reference not set to an instance of an object.] 
    MyTest.NaiveSessionCache.Load() in C:\Workspace\MyTest\src\Website\NaiveSessionCache.cs:26 
    MyTest.NaiveSessionCache.BeforeAccessNotification(TokenCacheNotificationArgs args) in C:\Workspace\MyTest\src\Website\NaiveSessionCache.cs:53 
    Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache.OnBeforeAccess(TokenCacheNotificationArgs args) +94 
    Microsoft.IdentityModel.Clients.ActiveDirectory.<RunAsync>d__55.MoveNext() +3751 
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +14139120 
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 
    Microsoft.IdentityModel.Clients.ActiveDirectory.<AcquireTokenByAuthorizationCodeCommonAsync>d__48.MoveNext() +479 
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +14139120 
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 
    Microsoft.IdentityModel.Clients.ActiveDirectory.<AcquireTokenByAuthorizationCodeAsync>d__30.MoveNext() +386 
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +14139120 
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 
    System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() +31 
    MyTest.<OnAuthorizationCodeReceived>d__12.MoveNext() in C:\Workspace\MyTest\src\Website\Startup.cs:86 
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +14139120 
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 
    System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task) +14139265 
    Microsoft.Owin.Security.OpenIdConnect.<AuthenticateCoreAsync>d__1a.MoveNext() +5965 
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +31 
    Microsoft.Owin.Security.OpenIdConnect.<AuthenticateCoreAsync>d__1a.MoveNext() +7305 
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +14139120 
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 
    Microsoft.Owin.Security.Infrastructure.<BaseInitializeAsync>d__0.MoveNext() +824 
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +14139120 
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 
    Microsoft.Owin.Security.Infrastructure.<Invoke>d__0.MoveNext() +334 
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +14139120 
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 
    Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.<RunApp>d__5.MoveNext() +204 
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +14139120 
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 
    Microsoft.Owin.Security.Infrastructure.<Invoke>d__0.MoveNext() +777 
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +14139120 
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 
    Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.<RunApp>d__5.MoveNext() +204 
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +14139120 
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 
    Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.<DoFinalWork>d__2.MoveNext() +194 
    Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.StageAsyncResult.End(IAsyncResult ar) +96 
    System.Web.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +363 
    System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +157 
+2

Nó thường null khi bạn gọi nó bằng một sợi chỉ bên ngoài của các chủ đề mà khởi xướng cuộc gọi web. Bạn có thể cho chúng tôi biết nếu bạn đã thực hiện một số thay đổi hoặc chia sẻ ngăn xếp cuộc gọi để xem nơi cuộc gọi này có nguồn gốc không? –

+0

Câu hỏi cập nhật –

+0

Tôi đã không thể làm cho nó hoạt động vì vậy tôi đã ngừng sử dụng phiên và hiện đang sử dụng HttpRuntime.Cache. Về cơ bản tôi chỉ thay thế HttpContext.Current.Session [CacheId] bằng HttpRuntime.Cache [CacheId]. Dường như làm việc tốt. –

Trả lời

2

Tôi đã làm việc đó. Bạn phải vượt qua HttpContextBase để tạo đối tượng bộ nhớ cache phiên của bạn. HttpContext.Current trở thành null khi nó thực thi trên một luồng khác.

using Microsoft.IdentityModel.Clients.ActiveDirectory; 
using System.Threading; 
using System.Web; 

namespace AzureADWebApp 
{ 
public class NaiveSessionCache: TokenCache 
{ 
    private static ReaderWriterLockSlim SessionLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); 
    string UserObjectId = string.Empty; 
    string CacheId = string.Empty; 
    HttpContextBase HttpContext = null; 
    public MSALSessionCache(string userId, HttpContextBase httpContext) 
    { 
     UserObjectId = userId; 
     CacheId = UserObjectId + "_TokenCache"; 
     this.HttpContext = httpContext; 
     this.AfterAccess = AfterAccessNotification; 
     this.BeforeAccess = BeforeAccessNotification; 
     Load(); 
    } 

    public void Load() 
    { 
     SessionLock.EnterReadLock(); 
     this.Deserialize((byte[])HttpContext.Session[CacheId]); 
     SessionLock.ExitReadLock(); 
    } 

    public void Persist() 
    { 
     SessionLock.EnterWriteLock(); 

     // Optimistically set HasStateChanged to false. We need to do it early to avoid losing changes made by a concurrent thread. 
     this.HasStateChanged = false; 

     // Reflect changes in the persistent store 
     HttpContext.Session[CacheId] = this.Serialize(); 
     SessionLock.ExitWriteLock(); 
    } 

    // Empties the persistent store. 
    public override void Clear() 
    { 
     base.Clear(); 
     HttpContext.Session.Remove(CacheId); 
    } 

    // Triggered right before ADAL needs to access the cache. 
    // Reload the cache from the persistent store in case it changed since the last access. 
    void BeforeAccessNotification(TokenCacheNotificationArgs args) 
    { 
     Load(); 
    } 

    // Triggered right after ADAL accessed the cache. 
    void AfterAccessNotification(TokenCacheNotificationArgs args) 
    { 
     // if the access operation resulted in a cache update 
     if (this.HasStateChanged) 
     { 
      Persist(); 
     } 
    } 
} 
} 

Và tạo đối tượng NaiveSessionCache của bạn với một tham số bổ sung như dưới đây trong Notification AuthenticationCodeReceived của bạn:

new NaiveSessionCache(userObjectID, notification.OwinContext.Environment["System.Web.HttpContextBase"] as HttpContextBase)); 
1

Tôi không chắc chắn nếu nó trường hợp của bạn, nhưng đôi khi nguyên nhân gốc rễ của HttpContext .Current null là một khóa bị thiếu trong web.config:

<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />

1

Bằng cách thêm thời gian chờ bằng cuộc gọi không đồng bộ, bạn đang quay lên một chuỗi khác trong đó HTTPContext.Current is null. Bạn cần phải điều chỉnh nhà cung cấp dịch vụ bản địa để lấy httpcontext làm tham số hoặc thay đổi luồng chương trình của bạn để sử dụng toán tử chờ đợi để thực hiện công việc này với một chuỗi duy nhất để bạn có thể truy cập các biến thích hợp.

2

ADAL thêm configureAwait (false) cho tất cả phương thức async bắt đầu từ phiên bản 3.13.0, kết quả là HttpContext.Current trong NaiveSession trở thành NULL vì có nhiều khả năng trong một chuỗi mới. Bạn có thể sử dụng phiên bản 3.12.0 của ADAL hoạt động tốt.

Các vấn đề liên quan