Unity и ASP.NET WebForms - для этого объекта не определен конструктор без параметров
У кого-нибудь есть хорошие примеры того, как заставить Unity 1.2 или 2.0 работать с ASP.NET WebForms?
Я думал, что понял это, но, очевидно, я что-то упустил. Теперь я получаю ошибку; Msgstr "Для этого объекта не определен конструктор без параметров". Я помню, как получил эту ошибку пару лет назад, и я просто не помню, что я сделал.
Очевидно, что Unity не работает должным образом, потому что где-то по пути я кое-что забыл. Любая помощь будет оценена.
Вот часть моего кода:
Global.asax
используя Систему; using System.Collections.Generic; использование System.Linq; использование System.Web; использование System.Web.Security; using System.Web.SessionState; используя Microsoft.Practices.Unity; используя PIA35.Unity; пространство имен PIA35.Web { открытый класс Global: System.Web.HttpApplication { защищенный void Application_Start(отправитель объекта, EventArgs e) { IUnityContainer container = Application.GetContainer(); PIA35.Web.IoC.Bootstrapper.Configure(контейнер); } } }
Вот мой раздел httpModules файла web.config:
httpModules>
Вот код для моего класса загрузчика IoC.
используя Систему; using System.Collections.Generic; использование System.Linq; использование System.Web; используя Microsoft.Practices.Unity; использование PIA35.Services.Interfaces; используя PIA35.Services; использование PIA35.DataObjects.Interfaces; использование PIA35.DataObjects.SqlServer; пространство имен PIA35.Web.IoC { открытый статический класс Bootstrapper { public static void Configure(контейнер IUnityContainer) { контейнер.RegisterType().RegisterType ().RegisterType ().RegisterType ().RegisterType ().RegisterType ().RegisterType ().RegisterType ().RegisterType ().RegisterType (); } } }
Вот файл HttpApplicationStateExtensions.cs.
использование System.Web; используя Microsoft.Practices.Unity; Пространство имен PIA35.Unity { открытый статический класс HttpApplicationStateExtensions { приватная константная строка GlobalContainerKey = "GlobalUnityContainerKey"; public static IUnityContainer GetContainer(это приложение HttpApplicationState) { application.Lock(); пытаться { IUnityContainer container = application[GlobalContainerKey] as IUnityContainer; if (container == null) { container = new UnityContainer(); application[GlobalContainerKey] = контейнер; } возвратный контейнер; } в конце концов { application.UnLock(); } } } }
Вот мой файл UnityHttpModule.cs.
используя Систему; using System.Collections.Generic; использование System.Web; использование System.Web.UI; используя Microsoft.Practices.Unity; namespace PIA35.Unity {открытый класс UnityHttpModule: IHttpModule { #region Члены IHttpModule /// /// Инициализирует модуль и подготавливает его для обработки запросов. /// /// /// ///, который предоставляет доступ к методам, свойствам, /// и событиям, общим для всех объектов приложения в приложении ASP.NET public void Init(HttpApplication context) { context.PreRequestHandlerExecute += OnPreRequestHandlerExecute; } /// /// Удаляет ресурсы (кроме памяти) ///, используемые модулем, который реализует. /// /// public void Dispose() { } #endregion private void OnPreRequestHandlerExecute(отправитель объекта, EventArgs e) { IHttpHandler handler = HttpContext.Current.Handler; HttpContext.Current.Application.GetContainer().BuildUp(handler.GetType(), обработчик); // Пользовательские элементы управления готовы к созданию после завершения инициализации страницы Page page = HttpContext.Current.Handler as Page; if (page!= null) { page.InitComplete += OnPageInitComplete; } } // Получить элементы управления в дереве элементов управления страницы, исключая саму страницу private IEnumerable GetControlTree(Control root) { foreach (дочерний элемент управления в root.Controls) { yield return child; foreach (элемент управления c в GetControlTree(child)) { yield return c; } } } // Создаем каждый элемент управления в дереве элементов управления страницы. Void OnPageInitComplete(object sender, EventArgs e) { Page page = (Page)sender; IUnityContainer container = HttpContext.Current.Application.GetContainer(); foreach (Элемент управления c в GetControlTree(page)) { container.BuildUp(c.GetType(), c); } } } }
Вот пример одного из моих классов обслуживания.
Пространство имен PIA35.Услуги { открытый класс CategoryService: ICategoryService { #region Dependency Injection частный ICategoryDao CategoryDao; public CategoryService(ICategoryDao CategoryDao) { this.categoryDao = CategoryDao; } #endregion #region ICategoryService Участники публичный список GetAll() { возвращать categoryDao.GetAll().ToList(); } общедоступная категория GetById(int CategoryId) { вернуть categoryDao.GetById(CategoryId); } public void Add(модель категории) { categoryDao.Insert(модель); } публичное обновление void (модель категории) { categoryDao.Update(модель); } public void Удалить (модель категории) { categoryDao.Delete(модель); } #endregion } }
3 ответа
Я вижу, что на него уже ответили, но я подумал, что хотел бы отметить, что вы синхронизируете все вызовы GetContainer с вашим шаблоном блокировки. Вызов Application.Lock() фактически снимает блокировку записи для applicationState, который является одноэлементным объектом в вашем веб-приложении, и вы увидите проблемы, если захотите масштабировать это.
Чтобы привести это в порядок, вы можете сделать двойную проверку блокировки. как это:
public static IUnityContainer GetContainer(this HttpApplicationState application)
{
IUnityContainer container = application[GlobalContainerKey] as IUnityContainer;
if (container == null)
{
application.Lock();
try
{
container = application[GlobalContainerKey] as IUnityContainer;
if (container == null)
{
container = new UnityContainer();
application[GlobalContainerKey] = container;
}
}
finally
{
application.UnLock();
}
}
return container;
}
Я также хотел бы указать на аккуратный шаблон, который мы использовали, чтобы убедиться, что элементы управления и страницы имеют свои зависимости. У нас в основном есть Generic PageBase и Generic ControlBase, от которых наследуются все наши страницы и элементы управления. Я просто зайду в базу данных в качестве примера:
public abstract class SitePageBase<T> : SitePageBase where T : SitePageBase<T>
{
protected override void OnInit( EventArgs e )
{
BuildUpDerived();
base.OnInit( e );
}
protected void BuildUpDerived()
{
ContainerProvider.Container.BuildUp( this as T );
}
}
Тогда в наших страницах мы можем просто извлечь из базовой базы, и она будет следить за сборкой.
public partial class Default : SitePageBase<Default>
{
[Dependency]
public IContentService ContentService { get; set; }
protected override void OnPreRender( EventArgs e )
{
this.label.Text = ContentService.GetContent("labelText");
}
}
ObjectDataSource может принимать интерфейс, но не с помощью мастера. Вы можете использовать мастер для создания тега ObjectDataSource, затем отредактировать его и превратить значение атрибута TypeName в имя вашего интерфейса.
Затем вам нужно указать ObjectDataSource, как создать объект. Я использую способ обработки события OnObjectCreating, поэтому в приведенном ниже коде я имею:
[Dependency]
public IMyService Service { get; set; }
protected void OnObjectCreating(...)
{
e.ObjectInstance = Service;
}
У меня был рабочий проект некоторое время назад, и я начал новый проект и получил ту же проблему. Сделайте некоторое сравнение и заняло у меня некоторое время. Но я вспомнил, что вам нужно инициализировать его в global.asax.
Bootstrapper.Initialise(); // Missing in the global.asax