Як я можу застосувати Ninject або DI у веб-формах asp.net?


83

Існує безліч прикладів того, як це працювало над додатком MVC. Як це робиться у веб-формах?

Відповіді:


79

Ось кроки для використання Ninject з WebForms.

Крок 1 - Завантаження

Потрібні два завантаження - Ninject-2.0.0.0-release-net-3.5 та розширення WebForm Ninject.Web_1.0.0.0_With.log4net (існує альтернатива NLog ).

У веб-програмі потрібно посилатися на такі файли: Ninject.dll, Ninject.Web.dll, Ninject.Extensions.Logging.dll та Ninject.Extensions.Logging.Log4net.dll.

Крок 2 - Global.asax

Клас Global повинен походити від Ninject.Web.NinjectHttpApplicationі реалізовувати CreateKernel(), що створює контейнер:

using Ninject; using Ninject.Web;

namespace Company.Web {
    public class Global : NinjectHttpApplication


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

StandardKernelКонструктор приймає Module.

Крок 3 - Модуль

У цьому випадку Модуль YourWebModuleвизначає всі прив’язки, необхідні веб-програмі:

using Ninject;
using Ninject.Web;

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

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

У цьому прикладі, скрізь, де на ICustomerRepositoryінтерфейс посилається конкретнийCustomerRepository .

Крок 4 - Сторінки

Після цього кожну сторінку потрібно успадкувати від 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);
            }

The InjectAttribute -[Inject]- повідомляє Ninject вводити ICustomerRepositoryвласність CustomerRepo.

Якщо у вас вже є базова сторінка, вам просто потрібно отримати базову сторінку, яка походить від Ninject.Web.PageBase.

Крок 5 - Основні сторінки

Неминуче у вас будуть основні сторінки, і щоб дозволити MasterPage отримати доступ до інжектованих об'єктів, вам потрібно буде отримати свою головну сторінку з Ninject.Web.MasterPageBase:

using Ninject;
using Ninject.Web;

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

        #region Properties

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

Крок 6 - Статичні методи веб-сервісу

Наступною проблемою була неможливість введення статичних методів. У нас було декілька методів Ajax PageMethod, які, очевидно, є статичними, тому мені довелося перенести методи в стандартну веб-службу. Знову ж таки, веб-служба повинна походити з класу 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);

У вашому JavaScript вам потрібно буде посилатися на стандартну послугу - Company.Web.Services.YourWebService.GetProductivity(user, onSuccess), а не на PageMethods.GetProductivity(user, onSuccess).

Єдиною іншою проблемою, яку я виявив, було введення об’єктів у елементи керування користувача. Незважаючи на те, що можливо створити власний базовий UserControl з можливостями Ninject, я виявив, що швидше додати властивість до елемента керування для потрібного об'єкта та встановити властивість на сторінці контейнера. Я думаю, що підтримка UserControls з коробки знаходиться в списку завдань Ninject.

Додавання Ninject досить просте, і це промовисте рішення IoC. Це подобається багатьом, оскільки немає конфігурації Xml. У нього є й інші корисні "фокуси", такі як перетворення об'єктів на одиночні з використанням лише синтаксису Ninject - Bind<ILogger>().To<WebLogger>().InSingletonScope(). Немає необхідності перетворювати WebLogger на справжню імплементацію Singleton, мені це подобається.


1
Це працює, але я спробував це на новій програмі WebForms (із шаблонів) і виявив, що коли файл Global.asax.cs використовував методи сеансу за замовчуванням у (наприклад, Application_Start), програма повертала загадкову помилку. Можливо, очевидно, що вам потрібно їх видалити (оскільки вони реалізовані в NinjectHttpApplication), але це мене зачепило.
Matt

Радий, що це було корисно. Помилка звучить дивно, що було винятком? У мене є код у Application_Start, і він працює нормально.
Джо Ратцер,

3
Я просто забув викликати метод супертипу NinjectHttpApplication.Application_Start з методу Application_Start файлу Global.asax.cs. Працює, коли я це роблю, інакше воно зламалося.
Matt

1
Абсолютно, додаток, над яким я працюю, тепер має базову сторінку (завжди гарна ідея), просто отримайте базову сторінку для реалізації PageBase.
Joe Ratzer,

2
Зараз це здається застарілим. Пакет NuGet, ninject.web, містить деякий код для завантаження програми, що робить необхідність успадкування безпосередньо від NinjectHttpApplication застарілою?
RyanW,

68

З випуском Ninject v3.0 (станом на 12.12.2012) стало простіше. Ін'єкція реалізована за допомогою HttpModule, тому немає необхідності вимагати, щоб ваші сторінки успадковувалися від користувацької Page / MasterPage. Ось кроки (і код) для швидкого спайку.

  1. Створіть новий проект ASP.NET WebForms
  2. Використовуйте NuGet, щоб додати бібліотеку Ninject.Web (яка також призведе до знищення Ninject.Web.Common та Ninject)
  3. Зареєструйте власні прив'язки в методі App_Start / NinjectWebCommon.cs / RegisterServices
  4. Використовуйте введення атрибутів на своїх сторінках

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>();
    } 

За замовчуванням

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());
    }
}

Моделі

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";
    }
}

Результати з вікна виводу

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

Привіт Джейсоне ... Я намагаюся це реалізувати ... Отримав бібліотеку Ninject.Web від NuGet fine ... Він створив Bootstrapper на App_Start ... Я намагався додати точку зупинки на RegisterServices для налагодження, але вона ніколи не потрапляла туди ... Чи повинен я додати щось інше?
Пол,

1
@Paul Ви можете поставити Debugger.Break () в метод RegisterServices, щоб розпочати налагодження.
Боггін

5
Привіт Джейсоне. Я маю проблеми з тим, щоб це працювало, тому мені було цікаво, чи це повний звіт? Я бачу, що NinjectHttpModule завантажується під час виконання, але ніякої ін'єкції не відбувається. Чи можете ви придумати будь-яку причину, якою це має бути?
rusmus

3
Чудовий приклад Спасибі Це працює на сторінці / головній сторінці, але не на Asmx. Як я можу змусити це працювати на Asmx? Дякую.
lawphotog

1
@mreyeros Переконайтеся, що у вас є NinjectWeb.csin App_Start. Ваш код для ініціалізації Ninject повинен знаходитись у цьому файлі. Якщо це в окремому файлі (наприклад, NinjectWebCommon.csце не буде працювати). Це може статися, якщо ви інсталюєте Ninject.Web пізніше інших пакетів Ninject за допомогою NuGet.
nebffa

12

Наразі відповідь тут не працює через відкриту помилку . Ось модифікована версія кроків @ Jason за допомогою клієнтського httpmodule для введення в сторінки та елементи керування без необхідності успадкування від класів ninject.

  1. Створіть новий проект ASP.NET WebForms
  2. Використовуйте NuGet, щоб додати бібліотеку Ninject.Web
  3. Зареєструйте власні прив'язки в методі App_Start / NinjectWebCommon.cs / RegisterServices
  4. Додайте InjectPageModule та зареєструйтесь у NinjectWebCommon
  5. Використовуйте введення атрибутів на своїх сторінках

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>();

    } 

За замовчуванням

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());
    }
}

Моделі

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";
    }
}

Результати з вікна виводу

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

4
Зверніть увагу, що це не вдається для сторінок, які не мають основної сторінки. Я модифікував NinjectWebCommon таким чином: if (currentPage.Master!=null) { this.lazyKernel().Inject(currentPage.Master); }
H.Wolper

1
Дякуємо, що знайшли час, щоб задокументувати це. У мене була та ж проблема при роботі зі застарілим проектом веб-форм. Завдяки вам ви отримали цю відсортовану коригувальну шахту, щоб вона працювала і до Page_Init, оскільки вона зателефонувала занадто пізно, але в іншому випадку ідеальна. Дякую @Adam!
PoorbandTony

Це рішення викликало у мене справді випадкові проблеми. Наприклад, події OnCommand перестали запускатись на LinkButtons в Repeaters. Однак це не зламало всіх подій із затримкою коду.
Майк Коул

8

Думаю, ось кроки для реалізації Ninject.Web у веб-формах ASP.NET.

  1. Впровадити NinjectHttpApplication на Global.asax. Для ядра передайте його, реалізувавши NinjectModule.
  2. На кожній події завантаження сторінки веб-форм із кодом позаду реалізуйте Ninject.Web.PageBase. Додайте клас екземпляра з фільтром [Inject] поверх нього.

Для більш детального прикладу нижче є кілька корисних посилань, які я знайшов:

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

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


1
це передбачає, що ви додали розширення Ninject.Web, саме те, що вам потрібно зробити.
Dave Thieben

7
@nellbryant Обидва ці посилання вже мертві.
Боггін

joeandcode.net посилання вже мертве. Заархівована версія тут: web.archive.org/web/20160324142135/http://joeandcode.net/post/…
Кріс Уолш,

4

Погляньте на розширення Ninject.Web. Він забезпечує базову інфраструктуру https://github.com/ninject/ninject.web


5
Я знаю, що маю наводити приклад, але README має бути> 0 байт!
Ruben Bartelink

@Ruben: Я згоден, що оновлення документа є одним із головних завдань пріо в банкоматі списку.
Remo Gloor

2
Вся справа в пріоритеті та обсязі допомоги від громади. За минулий рік було додано багато документації. Не для Ninject.Web, оскільки я вважаю це менш важливим, ніж інші функції, оскільки: а) WebForms застарілий - використовуйте замість MVC б) Я не писав цього розширення. Як і всі інші, я повинен отримати знання про це розширення з коду. в) Я не використовую його сам - є й інші, хто може написати документ набагато краще за мене. Але, здається, це не важливо для жодного з них. Мій вільний час обмежений, як і ваш, і тому я не можу робити все.
Remo Gloor,

6
@RyanW Проголосування проти лише через відсутність документації насправді не збільшить мою мотивацію та не зробить пріоритетом написання цього документа для вас!
Remo Gloor,

1
@RyanW Де ти береш свої ідеї? Мені погано здається моїм химерним коментарем із минулого року, але а) він супроводжувався підтримкою "б". Будь ласка, спростуйте цілком законні зауваження, які Ремо робить на користь викидання іграшок. До речі, я впевнений, що Unity має дивовижну документацію, і, можливо, це вам більше подобається. І подивіться на відповідь nellbryant або Jor R і спробуйте або придумати це, або скористайтеся ним, щоб написати readme або зразок самостійно.
Рубен Бартелінк,

0

Перегляньте книгу "Pro ASP.NET MVC 2 Framework, 2nd Edition" Стіва Сандерсона (Apress). Автор використовує Ninject для зв’язку з базою даних. Я думаю, ви можете скористатися прикладами та адаптувати їх до своїх потреб.


Так, у мене є те, що спонукало мене поставити це питання. Як це робиться, якщо веб-програма є веб-формами?
nellbryant

Це також те, як я зазвичай це роблю у WebForms. Фокус у тому, що вам потрібно використовувати метод Get ядра.
Didaxis

0
public IGoalsService_CRUD _context { get; set; }

Об'єкт _context якось встановлюється як нульовий. Нижче наведено решту налаштувань

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

Для глобального файлу

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>();
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.