Unity и ASP.NET WebForms - для этого объекта не определен конструктор без параметров - PullRequest
5 голосов
/ 08 сентября 2010

У кого-нибудь есть хорошие примеры того, как заставить Unity 1.2 или 2.0 работать с ASP.NET WebForms?

Я думал, что понял это, но, очевидно, я что-то упустил.Теперь я получаю ошибку;Msgstr "Для этого объекта не определен конструктор без параметров".Я помню, как получил эту ошибку пару лет назад, и я просто не помню, что я сделал.

Очевидно, что Unity не работает должным образом, потому что где-то по пути я что-то забыл.Любая помощь приветствуется.

Вот мой код:

Global.asax

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;

using Microsoft.Practices.Unity;

using PIA35.Unity;

namespace PIA35.Web
{
    public class Global : System.Web.HttpApplication
    {

        protected void Application_Start(object sender, EventArgs e)
        {
            IUnityContainer container = Application.GetContainer();
            PIA35.Web.IoC.Bootstrapper.Configure(container);
        }
    }
}

Вот мой раздел httpModules файла web.config:

<httpModules>
    <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    <add name="UnityHttpModule" type="PIA35.Unity.UnityHttpModule, PIA35.Unity"/>
</httpModules>

Вот код для моего класса загрузчика IoC.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.Practices.Unity;

using PIA35.Services.Interfaces;
using PIA35.Services;
using PIA35.DataObjects.Interfaces;
using PIA35.DataObjects.SqlServer;

namespace PIA35.Web.IoC
{
    public static class Bootstrapper
    {
        public static void Configure(IUnityContainer container)
        {
            container
                .RegisterType<ICategoryService, CategoryService>()
                .RegisterType<ICustomerService, CustomerService>()
                .RegisterType<IOrderService, OrderService>()
                .RegisterType<IOrderDetailService, OrderDetailService>()
                .RegisterType<IProductService, ProductService>()
                .RegisterType<ICategoryDao, SqlServerCategoryDao>()
                .RegisterType<ICustomerDao, SqlServerCustomerDao>()
                .RegisterType<IOrderDao, SqlServerOrderDao>()
                .RegisterType<IOrderDetailDao, SqlServerOrderDetailDao>()
                .RegisterType<IProductDao, SqlServerProductDao>();
        }
    }
}

Вот файл HttpApplicationStateExtensions.cs.

using System.Web;

using Microsoft.Practices.Unity;

namespace PIA35.Unity
{
    public static class HttpApplicationStateExtensions
    {
        private const string GlobalContainerKey = "GlobalUnityContainerKey";

        public static IUnityContainer GetContainer(this HttpApplicationState application)
        {
            application.Lock();
            try
            {
                IUnityContainer container = application[GlobalContainerKey] as IUnityContainer;
                if (container == null)
                {
                    container = new UnityContainer();
                    application[GlobalContainerKey] = container;
                }
                return container;
            }
            finally
            {
                application.UnLock();
            }
        }
    }
}

Вот мой файл UnityHttpModule.cs.

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using Microsoft.Practices.Unity;

namespace PIA35.Unity
{
    public class UnityHttpModule : IHttpModule
    {
        #region IHttpModule Members

        ///
        ///Initializes a module and prepares it to handle requests.
        ///
        ///
        ///An  
        ///that provides access to the methods, properties, 
        ///and events common to all application objects within an ASP.NET application 
        public void Init(HttpApplication context)
        {
            context.PreRequestHandlerExecute += OnPreRequestHandlerExecute;
        }

        ///
        ///Disposes of the resources (other than memory) 
        ///used by the module that implements .
        ///
        ///
        public void Dispose()
        {
        }

        #endregion

        private void OnPreRequestHandlerExecute(object sender, EventArgs e)
        {
            IHttpHandler handler = HttpContext.Current.Handler;
            HttpContext.Current.Application.GetContainer().BuildUp(handler.GetType(), handler);

            // User Controls are ready to be built up after the page initialization is complete
            Page page = HttpContext.Current.Handler as Page;
            if (page != null)
            {
                page.InitComplete += OnPageInitComplete;
            }
        }

        // Get the controls in the page's control tree excluding the page itself
        private IEnumerable GetControlTree(Control root)
        {
            foreach (Control child in root.Controls)
            {
                yield return child;
                foreach (Control c in GetControlTree(child))
                {
                    yield return c;
                }
            }
        }

        // Build up each control in the page's control tree
        private void OnPageInitComplete(object sender, EventArgs e)
        {
            Page page = (Page)sender;
            IUnityContainer container = HttpContext.Current.Application.GetContainer();
            foreach (Control c in GetControlTree(page))
            {
                container.BuildUp(c.GetType(), c);
            }
        }
    }
}

Вот пример одного из моих классов обслуживания.

namespace PIA35.Services
{
    public class CategoryService : ICategoryService
    {

        #region Dependency Injection

        private ICategoryDao categoryDao;

        public CategoryService(ICategoryDao CategoryDao)
        {
            this.categoryDao = CategoryDao;
        }

        #endregion


        #region ICategoryService Members

        public List GetAll()
        {
            return categoryDao.GetAll().ToList();
        }

        public Category GetById(int CategoryId)
        {
            return categoryDao.GetById(CategoryId);
        }

        public void Add(Category model)
        {
            categoryDao.Insert(model);
        }

        public void Update(Category model)
        {
            categoryDao.Update(model);
        }

        public void Delete(Category model)
        {
            categoryDao.Delete(model);
        }

        #endregion
    }
}

Ответы [ 3 ]

6 голосов
/ 27 октября 2010

Я вижу, что на него уже ответили, но я подумал, что хотел бы указать, что вы синхронизируете все вызовы 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");
        }
     }
2 голосов
/ 08 сентября 2010

ObjectDataSource может принимать интерфейс, но не с помощью мастера. Вы можете использовать мастер для создания тега ObjectDataSource, затем отредактировать его и превратить значение атрибута TypeName в имя вашего интерфейса.

Затем вам нужно указать ObjectDataSource, как создать объект. Я использую способ обработки события OnObjectCreating, поэтому в приведенном ниже коде я имею:

[Dependency]
public IMyService Service { get; set; }

protected void OnObjectCreating(...)
{
   e.ObjectInstance = Service;
}
1 голос
/ 04 апреля 2012

Некоторое время назад у меня был рабочий проект, и я начал новый проект и получил ту же проблему.Сделайте некоторое сравнение и заняло у меня некоторое время.Но я вспомнил, что вам нужно инициализировать его в global.asax.

Bootstrapper.Initialise(); // Missing in the global.asax
...