Làm cách nào để triển khai Ninject hoặc DI trên các Biểu mẫu Web asp.net?


83

Có rất nhiều ví dụ để làm cho nó hoạt động trên ứng dụng MVC. Nó được thực hiện như thế nào trên Web Forms?

Câu trả lời:


79

Dưới đây là các bước để sử dụng Ninject với WebForms.

Bước1 - Tải xuống

Có hai bản tải xuống bắt buộc - Ninject-2.0.0.0-release-net-3.5 và các phần mở rộng WebForm Ninject.Web_1.0.0.0_With.log4net (có một thay thế NLog).

Các tệp sau cần được tham chiếu trong ứng dụng web: Ninject.dll, Ninject.Web.dll, Ninject.Extensions.Logging.dll và Ninject.Extensions.Logging.Log4net.dll.

Bước 2 - Global.asax

Lớp Global cần lấy từ Ninject.Web.NinjectHttpApplicationvà triển khai CreateKernel(), lớp này tạo ra vùng chứa:

using Ninject; using Ninject.Web;

namespace Company.Web {
    public class Global : NinjectHttpApplication


        protected override IKernel CreateKernel()
        {
            IKernel kernel = new StandardKernel(new YourWebModule());
            return kernel;
        }

Hàm StandardKerneltạo nhận a Module.

Bước 3 - Mô-đun

Trong trường hợp này, Mô-đun YourWebModulexác định tất cả các ràng buộc mà ứng dụng web sẽ cần:

using Ninject;
using Ninject.Web;

namespace Company.Web
{
    public class YourWebModule : Ninject.Modules.NinjectModule
    {

        public override void Load()
        {
            Bind<ICustomerRepository>().To<CustomerRepository>();
        }   

Trong ví dụ này, bất cứ nơi nào ICustomerRepositorygiao diện được tham chiếu, bê tông CustomerRepositorysẽ được sử dụng.

Bước 4 - Trang

Sau khi hoàn tất, mỗi trang cần kế thừa từ Ninject.Web.PageBase:

  using Ninject;
    using Ninject.Web;
    namespace Company.Web
    {
        public partial class Default : PageBase
        {
            [Inject]
            public ICustomerRepository CustomerRepo { get; set; }

            protected void Page_Load(object sender, EventArgs e)
            {
                Customer customer = CustomerRepo.GetCustomerFor(int customerID);
            }

Các InjectAttribute -[Inject]- kể Ninject để bơm ICustomerRepositoryvào tài sản CustomerRepo.

Nếu bạn đã có trang cơ sở, bạn chỉ cần lấy trang cơ sở của mình để lấy từ Ninject.Web.PageBase.

Bước 5 - Trang chính

Chắc chắn, bạn sẽ có các trang chính và để cho phép một Trang chủ truy cập các đối tượng được chèn vào, bạn sẽ cần lấy trang chính của mình từ Ninject.Web.MasterPageBase:

using Ninject;
using Ninject.Web;

namespace Company.Web
{
    public partial class Site : MasterPageBase
    {

        #region Properties

        [Inject]
        public IInventoryRepository InventoryRepo { get; set; }     

Bước 6 - Phương thức dịch vụ web tĩnh

Vấn đề tiếp theo là không thể đưa vào các phương thức tĩnh. Chúng tôi đã có một vài Ajax PageMethods, rõ ràng là tĩnh, vì vậy tôi phải chuyển các phương thức này vào một dịch vụ web tiêu chuẩn. Một lần nữa, dịch vụ web cần bắt nguồn từ lớp Ninject - Ninject.Web.WebServiceBase:

using Ninject;
using Ninject.Web;    
namespace Company.Web.Services
{

    [WebService(Namespace = "//tempuri.org/">http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]    
    [System.Web.Script.Services.ScriptService]
    public class YourWebService : WebServiceBase
    {

        #region Properties

        [Inject]
        public ICountbackRepository CountbackRepo { get; set; }

        #endregion

        [WebMethod]
        public Productivity GetProductivity(int userID)
        {
            CountbackService _countbackService =
                new CountbackService(CountbackRepo, ListRepo, LoggerRepo);

Trong JavaScript của mình, bạn sẽ cần tham chiếu đến dịch vụ chuẩn - Company.Web.Services.YourWebService.GetProductivity(user, onSuccess)thay vì tham chiếu PageMethods.GetProductivity(user, onSuccess).

Vấn đề duy nhất khác mà tôi tìm thấy là đưa các đối tượng vào User Controls. Mặc dù có thể tạo UserControl cơ sở của riêng bạn với các khả năng Ninject, nhưng tôi thấy việc thêm Thuộc tính vào quyền điều khiển của người dùng cho đối tượng được yêu cầu và đặt Thuộc tính trong trang vùng chứa sẽ nhanh hơn. Tôi nghĩ rằng hỗ trợ UserControls ra khỏi hộp nằm trong danh sách "việc cần làm" của Ninject.

Thêm Ninject khá đơn giản và nó là một giải pháp IoC hùng hồn. Nhiều người thích nó vì không có cấu hình Xml. Nó có những "thủ thuật" hữu ích khác như biến các đối tượng thành các Singleton chỉ với cú pháp Ninject - Bind<ILogger>().To<WebLogger>().InSingletonScope(). Không cần phải thay đổi WebLogger thành một cấy ghép Singleton thực tế, tôi thích điều này.


1
Cách này có hiệu quả nhưng tôi đã thử điều này trên một ứng dụng WebForms mới (từ các mẫu) và nhận thấy rằng khi tệp Global.asax.cs có các phương thức phiên mặc định trong (ví dụ: Application_Start), ứng dụng đã trả về một lỗi khó hiểu. Có thể rõ ràng là bạn cần phải xóa những thứ này (vì chúng được triển khai trong NinjectHttpApplication) nhưng tôi không hiểu.
Matt

Rất vui vì nó hữu ích. Lỗi nghe có vẻ lạ, ngoại lệ là gì? Tôi có mã trong Application_Start và nó hoạt động tốt.
Joe Ratzer

3
Tôi vừa quên gọi phương thức của supertype NinjectHttpApplication.Application_Start từ phương thức Application_Start của tệp Global.asax.cs. Hoạt động khi tôi làm điều đó, nếu không nó đã bị hỏng.
Matt

1
Tất nhiên, ứng dụng tôi đang làm việc hiện có một trang cơ sở (luôn luôn là một ý tưởng hay), chỉ cần lấy trang cơ sở để triển khai PageBase.
Joe Ratzer

2
Điều này có vẻ lỗi thời bây giờ. Gói NuGet, ninject.web, chứa một số mã để khởi động ứng dụng, khiến nhu cầu kế thừa trực tiếp từ NinjectHttpApplication đã lỗi thời?
RyanW

68

Nó trở nên dễ dàng hơn với việc phát hành Ninject v3.0 (kể từ ngày 4/12/2012). Injection được triển khai thông qua HttpModule nên không cần các trang của bạn kế thừa từ một Trang / MasterPage tùy chỉnh. Dưới đây là các bước (và mã) để tăng đột biến nhanh chóng.

  1. Tạo một dự án ASP.NET WebForms mới
  2. Sử dụng NuGet để thêm lib Ninject.Web (cũng sẽ đưa các lib Ninject.Web.Common và Ninject xuống)
  3. Đăng ký các ràng buộc tùy chỉnh của bạn trong phương thức App_Start / NinjectWebCommon.cs / RegisterServices
  4. Sử dụng chèn thuộc tính trên các trang của bạn

NinjectWebCommon / RegisterServices

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<IAmAModel>().To<Model1>();
    } 

Mặc định

public partial class _Default : System.Web.UI.Page
{

    [Inject]
    public IAmAModel Model { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        System.Diagnostics.Trace.WriteLine(Model.ExecuteOperation());
    }
}

Site.Master

public partial class SiteMaster : System.Web.UI.MasterPage
{

    [Inject]
    public IAmAModel Model { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        System.Diagnostics.Trace.WriteLine("From master: " 
            + Model.ExecuteOperation());
    }
}

Mô hình

public interface IAmAModel
{
    string ExecuteOperation();         
}

public class Model1 : IAmAModel
{
    public string ExecuteOperation()
    {
        return "I am a model 1";
    }
}

public class Model2 : IAmAModel
{
    public string ExecuteOperation()
    {
        return "I am a model 2";
    }
}

Kết quả từ cửa sổ đầu ra

I am a model 1
From master: I am a model 1

Xin chào Jason ... Tôi đang cố gắng triển khai điều đó ... Đã có lib Ninject.Web từ NuGet tốt ... Nó đã tạo Bootstrapper trên App_Start ... Tôi đã cố gắng thêm một điểm ngắt trên RegisterServices để gỡ lỗi, nhưng nó không bao giờ đến đó ... Tôi có muốn thêm thứ gì khác không?
Paul

1
@Paul Bạn có thể đặt Debugger.Break () trong phương thức RegisterServices để bắt đầu gỡ lỗi.
Boggin

5
Chào Jason. Tôi gặp sự cố khi làm việc này, vì vậy tôi tự hỏi liệu đây có phải là bản tóm tắt hoàn chỉnh không? Tôi có thể thấy rằng NinjectHttpModule được tải trong thời gian chạy, nhưng không có quá trình tiêm nào xảy ra. Bạn có thể nghĩ ra lý do nào khiến điều này xảy ra không?
rusmus

3
Ví dụ tuyệt vời Cảm ơn Nó hoạt động trên trang / trang chủ nhưng không hoạt động trên Asmx. Làm cách nào để làm cho nó hoạt động trên Asmx? Cảm ơn.
lawphotog

1
@mreyeros Hãy chắc chắn rằng bạn có một NinjectWeb.cstrong App_Start. Mã của bạn để khởi tạo Ninject phải có trong tệp này. Nếu nó nằm trong một tệp riêng (ví dụ: NinjectWebCommon.csnó sẽ không hoạt động). Điều này có thể xảy ra nếu bạn cài đặt Ninject.Web muộn hơn các gói Ninject khác sử dụng NuGet.
nebffa

12

Câu trả lời ở đây hiện không hoạt động do một lỗi mở . Đây là phiên bản sửa đổi của các bước của @ Jason bằng cách sử dụng httpmodule của khách hàng để đưa vào các trang và điều khiển mà không cần kế thừa từ các lớp ninject.

  1. Tạo một dự án ASP.NET WebForms mới
  2. Sử dụng NuGet để thêm lib Ninject.Web
  3. Đăng ký các ràng buộc tùy chỉnh của bạn trong phương thức App_Start / NinjectWebCommon.cs / RegisterServices
  4. Thêm InjectPageModule và đăng ký NinjectWebCommon
  5. Sử dụng chèn thuộc tính trên các trang của bạn

InjectPageModule.cs

 public class InjectPageModule : DisposableObject, IHttpModule
{
    public InjectPageModule(Func<IKernel> lazyKernel)
    {
        this.lazyKernel = lazyKernel;
    }

    public void Init(HttpApplication context)
    {
        this.lazyKernel().Inject(context);
        context.PreRequestHandlerExecute += OnPreRequestHandlerExecute;
    }

    private void OnPreRequestHandlerExecute(object sender, EventArgs e)
    {
        var currentPage = HttpContext.Current.Handler as Page;
        if (currentPage != null)
        {
            currentPage.InitComplete += OnPageInitComplete;
        }
    }

    private void OnPageInitComplete(object sender, EventArgs e)
    {
        var currentPage = (Page)sender;
        this.lazyKernel().Inject(currentPage);
        this.lazyKernel().Inject(currentPage.Master);
        foreach (Control c in GetControlTree(currentPage))
        {
            this.lazyKernel().Inject(c);
        }

    }

    private IEnumerable<Control> GetControlTree(Control root)
    {
        foreach (Control child in root.Controls)
        {
            yield return child;
            foreach (Control c in GetControlTree(child))
            {
                yield return c;
            }
        }
    }

    private readonly Func<IKernel> lazyKernel;
}

NinjectWebCommon / RegisterServices

    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<IHttpModule>().To<InjectPageModule>();
        kernel.Bind<IAmAModel>().To<Model1>();

    } 

Mặc định

public partial class _Default : System.Web.UI.Page
{

    [Inject]
    public IAmAModel Model { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        System.Diagnostics.Trace.WriteLine(Model.ExecuteOperation());
    }
}

Site.Master

public partial class SiteMaster : System.Web.UI.MasterPage
{

    [Inject]
    public IAmAModel Model { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        System.Diagnostics.Trace.WriteLine("From master: " 
            + Model.ExecuteOperation());
    }
}

Mô hình

public interface IAmAModel
{
    string ExecuteOperation();         
}

public class Model1 : IAmAModel
{
    public string ExecuteOperation()
    {
        return "I am a model 1";
    }
}

public class Model2 : IAmAModel
{
    public string ExecuteOperation()
    {
        return "I am a model 2";
    }
}

Kết quả từ cửa sổ đầu ra

I am a model 1
From master: I am a model 1

4
Xin lưu ý rằng điều này không thành công đối với các trang không có trang Chính. Tôi sửa đổi NinjectWebCommon với điều này: if (currentPage.Master!=null) { this.lazyKernel().Inject(currentPage.Master); }
H.Wolper

1
Cảm ơn đã dành thời gian để ghi lại điều này. Tôi đã gặp vấn đề tương tự khi làm việc với một dự án biểu mẫu web cũ. Nhờ bạn, mỏ đã được sắp xếp - điều chỉnh này hoạt động trước Page_Init vì nó được gọi quá muộn, nhưng nếu không thì hoàn hảo. Cảm ơn @Adam!
PoorbandTony

Giải pháp này gây ra một số vấn đề thực sự ngẫu nhiên cho tôi. Ví dụ: các sự kiện OnCommand ngừng chạy trên LinkButtons trong Bộ lặp. Tuy nhiên, nó không phá vỡ tất cả các sự kiện phía sau mã.
Mike Cole

8

Tôi nghĩ đây là các bước để triển khai Ninject.Web trên ASP.NET Web Forms.

  1. Triển khai NinjectHttpApplication tại Global.asax. Đối với Kernel, hãy chuyển nó vào bằng cách triển khai NinjectModule.
  2. Trên mỗi sự kiện tải trang của biểu mẫu web ở mã phía sau, hãy triển khai Ninject.Web.PageBase. Thêm lớp cá thể với bộ lọc [Inject] ở trên nó.

Để có ví dụ chi tiết hơn, dưới đây là một số liên kết hữu ích mà tôi tìm thấy:

1. http://joeandcode.net/post/Ninject-2-with-WebForms-35

2. http://davidhayden.com/blog/dave/archive/2008/06/20/NinjectDependencyInjectionASPNETWebPagesSample.aspx


1
điều này giả sử bạn đã thêm phần mở rộng Ninject.Web, đây chính xác là những gì bạn cần làm.
Dave Thieben

7
@nellbryant Cả hai liên kết đó hiện đã chết.
Boggin

liên kết joeandcode.net hiện đã chết. Phiên bản lưu trữ ở đây: web.archive.org/web/20160324142135/http://joeandcode.net/post/…
Chris Walsh

4

Hãy xem phần mở rộng Ninject.Web. Nó cung cấp cơ sở hạ tầng cơ sở https://github.com/ninject/ninject.web


5
Tôi biết tôi nên dẫn đầu bằng ví dụ, nhưng README phải> 0 byte!
Ruben Bartelink

@Ruben: Tôi đồng ý cập nhật tài liệu là một trong những nhiệm vụ quan trọng nhất trong danh sách atm.
Remo Gloor

2
Tất cả là về mức độ ưu tiên và mức độ giúp đỡ từ cộng đồng. Rất nhiều tài liệu đã được bổ sung trong năm qua. Đối với Ninject.Web thì không vì tôi coi nó ít quan trọng hơn các tính năng khác vì: a) WebForms đã lỗi thời - hãy sử dụng MVC thay thế b) Tôi chưa viết tiện ích mở rộng này. Giống như những người khác, tôi phải nhận được kiến ​​thức về tiện ích mở rộng này từ mã. c) Bản thân tôi không sử dụng nó - có những người khác có thể viết tài liệu tốt hơn tôi nhiều. Nhưng có vẻ như nó không quan trọng với bất kỳ ai trong số họ. Thời gian rảnh rỗi của tôi cũng có hạn như của bạn và do đó tôi không thể làm mọi thứ.
Remo Gloor

6
@RyanW Phản đối chỉ vì thiếu tài liệu sẽ không thực sự làm tăng động lực của tôi hoặc tăng mức độ ưu tiên viết tài liệu này cho bạn!
Remo Gloor

1
@RyanW Bạn lấy ý tưởng của mình ở đâu? Tôi cảm thấy tồi tệ về nhận xét khó nghe của mình từ một năm trước, nhưng a) nó đi kèm với một sự ủng hộ b) nó mỉa mai nhưng không xuýt xoa. Vui lòng bác bỏ những quan điểm hoàn toàn chính đáng mà Remo đưa ra muốn ném đồ chơi ra ngoài. BTW Tôi chắc rằng Unity có tài liệu tuyệt vời và có thể phù hợp hơn với bạn. Và hãy nhìn vào câu trả lời của nellbryant hoặc Jor R và cố gắng tìm ra lỗi với câu trả lời đó hoặc sử dụng nó để tự viết bài đọc hoặc mẫu.
Ruben Bartelink

0

Kiểm tra cuốn sách "Pro ASP.NET MVC 2 Framework, 2nd Edition" của Steve Sanderson (Apress). Tác giả sử dụng Ninject để kết nối với cơ sở dữ liệu. Tôi nghĩ bạn có thể sử dụng các ví dụ và điều chỉnh chúng theo nhu cầu của bạn.


Vâng, tôi có điều đó khiến tôi đặt câu hỏi đó. Nó được thực hiện như thế nào nếu ứng dụng web là biểu mẫu web?
nellbryant

Đây cũng là cách tôi thường sử dụng trong WebForms. Bí quyết là bạn cần sử dụng phương thức Get của Kernel.
Didaxis

0
public IGoalsService_CRUD _context { get; set; }

Đối tượng _context đang được đặt thành null bằng cách nào đó. Sau đây là phần còn lại của cài đặt

public partial class CreateGoal : Page
{
    [Inject]
    public IGoalsService_CRUD _context { get; set; }
}

Đối với tệp chung

protected override IKernel CreateKernel()
{
    IKernel kernel = new StandardKernel(new Bindings());
    return kernel;
}

public class Bindings : NinjectModule
{
    public override void Load()
    {
        Bind<goalsetterEntities>().To<goalsetterEntities>();
        Bind<IGoalsService_CRUD>().To<GoalsService_CRUD>();
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.