2014-06-24 32 views
20

Tôi sử dụng OWIN + Microsoft.AspNet.Identity.Owin (v.2.0.0.0) trong ứng dụng Web. Tôi đăng ký UserManager/DbContext theo yêu cầu web, theo khuyến cáo rộng rãi:Rò rỉ bộ nhớ trong Owin.AppBuilderExtensions

app.CreatePerOwinContext(ApplicationDbContext.Create); 
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); 

nhưng không phải là bao giờ xử lý. Tôi liếc nhìn vào gương và nó có vẻ như một lỗi trong phương pháp khuyến nông:

public static IAppBuilder CreatePerOwinContext<T>(this IAppBuilder app, Func<IdentityFactoryOptions<T>, IOwinContext, T> createCallback) where T: class, IDisposable 
{ 
    if (app == null) 
    { 
     throw new ArgumentNullException("app"); 
    } 
    if (createCallback == null) 
    { 
     throw new ArgumentNullException("createCallback"); 
    } 
    object[] args = new object[1]; 
    IdentityFactoryOptions<T> options = new IdentityFactoryOptions<T> { 
     DataProtectionProvider = app.GetDataProtectionProvider() 
    }; 
    IdentityFactoryProvider<T> provider = new IdentityFactoryProvider<T> { 
     OnCreate = createCallback 
    }; 
    options.Provider = provider; 
    args[0] = options; 
    app.Use(typeof(IdentityFactoryMiddleware<T, IdentityFactoryOptions<T>>), args); 
    return app; 
} 

IdentityFactoryProvider có hai callbacks - tạo và định đoạt, nhưng xử lý gọi lại không được đăng ký tại đây. Tôi cũng xác nhận sự nghi ngờ của tôi với bộ nhớ hồ sơ.

Tôi không thấy Owin trên codeplex/github (thực ra tôi nghĩ nó là mã nguồn mở), vì vậy tôi không biết hỏi câu hỏi ở đâu: ai có thể xác nhận đây là rò rỉ bộ nhớ không? Tôi không chắc chắn vì google không nói gì về nó, tôi hy vọng nó sẽ được thảo luận ở khắp mọi nơi, nếu đây là một lỗi.

+1

Tôi đã tự do chuyển tiếp điều này cho nhóm Microsoft xử lý mã này. –

+0

Thật tuyệt khi nghe phản ứng của họ, nếu có. –

+0

Cuối cùng tôi nghe nói, đã có điều tra vấn đề. Vấn đề chính là mã Identity không phải là mã nguồn mở và thật khó để tạo ra một yêu cầu kéo để sửa chữa nó. Có một trình giữ chỗ trên codeplex vào lúc này nhưng ... không có gì. Nó có thể là một gợi ý rằng nó sẽ được mở nguồn cuối cùng. –

Trả lời

6

Tôi cũng có vấn đề của mình, không có gì được đăng ký với CreatePerOwinContext được xử lý. Tôi đang sử dụng v2.1.

Đây là bản sửa lỗi tạm thời đang hoạt động tốt cho tôi khi hoạt động xung quanh cho đến khi thư viện này được sửa. Về cơ bản bạn phải tự đăng ký mỗi loại sử dụng đăng ký với CreatePerOwnContext trong lớp sau, và sau đó ở phần cuối của quy trình Startup của bạn, bạn đăng ký lớp tùy chỉnh này:

public sealed class OwinContextDisposal : IDisposable 
{ 
    private readonly List<IDisposable> _disposables = new List<IDisposable>(); 

    public OwinContextDisposal(IOwinContext owinContext) 
    { 
     if (HttpContext.Current == null) return; 

     //TODO: Add all owin context disposable types here 
     _disposables.Add(owinContext.Get<MyObject1>()); 
     _disposables.Add(owinContext.Get<MyObject2>()); 

     HttpContext.Current.DisposeOnPipelineCompleted(this); 
    } 

    public void Dispose() 
    { 
     foreach (var disposable in _disposables) 
     { 
      disposable.Dispose(); 
     } 
    } 
} 

Vào cuối quá trình Startup của bạn đăng ký lớp này:

app.CreatePerOwinContext<OwinContextDisposal>(
     (o, c) => new OwinContextDisposal(c)); 

Bây giờ mọi thứ sẽ được xử lý ở cuối đường ống yêu cầu đúng cách.

1

Bạn có thể đặt logic để xử lý các trường hợp bạn tạo bằng CreatePeOwinContext() trong cùng một cuộc gọi lại mà bạn sử dụng để tạo ra các thông số này. Đó là:

public class Startup 
{ 
    public void Configuration(IAppBuilder app) 
    { 
     app.CreatePerOwinContext<ClassIWantOneInstancePerContext>(ClassIWantOneInstancePerContext.Create); 

     //other code... 
    } 
} 

Sau đó, bạn chỉ nên quan tâm để bao gồm một cuộc gọi đến DisposeOnPipelineCompleted() trong callback sử dụng để nhanh chóng lớp học của bạn. Đó là:

public class ClassIWantOneInstancePerContext 
{ 
    //other code... 

    public static ClassIWantOneInstancePerContext Create() 
    { 
     ClassIWantOneInstancePerContext TheInstance = new ClassIWantOneInstancePerContext(); 
     HttpContext.Current.DisposeOnPipelineCompleted(TheInstance); 

     return TheInstance; 
    } 
} 

Cũng đừng quên đưa phương thức Dispose() vào định nghĩa lớp học của bạn!

+0

Điều này có thể giống như lý do kỳ lạ, nhưng tôi muốn ở trong OWIN trừu tượng và không muốn tham chiếu System.Web ... –

+0

Điều này không giới thiệu một dependenct trên System.Web, nhưng nó chắc chắn hoạt động! – ilikeprogramming

0

Cách sử dụng: app.CreatePerRequest<AuthorizationContext>();

Phương pháp mở rộng:

public static IAppBuilder CreatePerRequest<T>(this IAppBuilder builder)where T:IDisposable 
     { 
      builder.Use(async (context, next) => 
      { 
       var resolver = context.Get<IDependencyScope>(); 

       using (var instance = (T) resolver.GetService(typeof (T))) 
       { 
        context.Set<T>(instance); 
        if (next != null) 
        { 
         await next(); 
        } 
       } 

      }); 

      return builder; 
     } 

để sử dụng Dependency Injection bạn phải cấu hình owin: app.UseScopePerOwinRequest(_dependencyResolver); - Đây nên là trung đầu tiên ..

public static IAppBuilder UseScopePerOwinRequest(this IAppBuilder builder,IDependencyResolver resolver) 
     { 
      builder.Use(async (context, next) => 
      { 
       using (var instance = resolver.BeginScope()) 
       { 
        context.Set<IDependencyScope>(instance); 
        if (next != null) 
        { 
         await next(); 
        } 
       } 

      }); 

      return builder; 
     } 

Và đối với ở trên mã để làm việc, bạn phải triển khai IDepedencyResolver với bất kỳ vùng chứa nào.

  • Yêu cầu đi vào và phạm vi mới cho yêu cầu được tạo ra
  • Trong phạm vi mà bạn tạo ra đối tượng khác.
  • Sử dụng các đối tượng đó trong phần mềm trung gian khác
  • và khi phạm vi kết thúc, nó sẽ được xử lý.
  • bất kỳ đối tượng nào trong phạm vi đó không được xử lý cũng bị xử lý.
5

Vụ rò rỉ bộ nhớ trong AppBuilderExtensions lớp đã được đã được cố định trong phiên bản mới nhất của Microsoft.AspNet.Identity.Owin thư viện (2.2.1).

Tôi đã kiểm tra mã bằng cách sử dụng Phản xạ và cũng bằng cách đặt điểm ngắt vào Dispose() các phương pháp đối tượng được tạo bởi AppBuilderExtensions.CreatePerOwinContext().