Існує безліч прикладів того, як це працювало над додатком MVC. Як це робиться у веб-формах?
Відповіді:
Ось кроки для використання 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, мені це подобається.
З випуском Ninject v3.0 (станом на 12.12.2012) стало простіше. Ін'єкція реалізована за допомогою HttpModule, тому немає необхідності вимагати, щоб ваші сторінки успадковувалися від користувацької Page / MasterPage. Ось кроки (і код) для швидкого спайку.
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
NinjectWeb.cs
in App_Start
. Ваш код для ініціалізації Ninject повинен знаходитись у цьому файлі. Якщо це в окремому файлі (наприклад, NinjectWebCommon.cs
це не буде працювати). Це може статися, якщо ви інсталюєте Ninject.Web пізніше інших пакетів Ninject за допомогою NuGet.
Наразі відповідь тут не працює через відкриту помилку . Ось модифікована версія кроків @ Jason за допомогою клієнтського httpmodule для введення в сторінки та елементи керування без необхідності успадкування від класів ninject.
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
if (currentPage.Master!=null) { this.lazyKernel().Inject(currentPage.Master); }
Думаю, ось кроки для реалізації Ninject.Web у веб-формах ASP.NET.
Для більш детального прикладу нижче є кілька корисних посилань, які я знайшов:
Погляньте на розширення Ninject.Web. Він забезпечує базову інфраструктуру https://github.com/ninject/ninject.web
Перегляньте книгу "Pro ASP.NET MVC 2 Framework, 2nd Edition" Стіва Сандерсона (Apress). Автор використовує Ninject для зв’язку з базою даних. Я думаю, ви можете скористатися прикладами та адаптувати їх до своїх потреб.
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>();
}
}