Аннотация: эта статья содержит информация, необходимую для настройки шаблона инверсии управления (IoC) в приложениях ASP.NET MVC, используя Castle Windsor.
В этой статья я расскажу вам обо всех шагах необходимых для того, чтобы вы могли создать собственную фабрику контроллеров для реализации IoC в вашем приложении. Более подробную информацию об IoC и том, зачем использовать его, вы можете найти здесь http://www.mikesdotnetting.com/Article/117/Dependency-Injection-and-Inversion-of-Control-with-ASP.NET -MVC
Я узнал о том, как использовать Windsor для реализации IoC в выдающейся книге Стивена Сандерсона "Pro ASP.NET MVC framework" (ASP.NET MVC Framework для профессионалов).
...
Последнюю версию Castle Windsor можно взять с его официального сайта.
И так, сначала добавим ссылки в наш проект на след. сборки: "Castle.Core.dll", "Castle.MicroKernel.dll", "Castle.Windsor.dll"
Далее создадим класс фабрики контроллеров. В корневой папке проекта создадим файл WindsorControllerFactory.cs. В него запишем след. код:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Castle.Windsor;
using Castle.Windsor.Configuration.Interpreters;
using Castle.Core.Resource;
using System.Reflection;
using Castle.Core;
using System.Web.Routing;
namespace Mvc2Application6
{
public class WindsorControllerFactory : DefaultControllerFactory
{
WindsorContainer container;
// The constructor:
// 1. Sets up a new IoC container
// 2. Registers all components specified in web.config
// 3. Registers all controller types as components
public WindsorControllerFactory()
{
// Instantiate a container, taking configuration from web.config
container = new WindsorContainer(
new XmlInterpreter(new ConfigResource("castle"))
);
// Also register all the controller types as transient
var controllerTypes =
from t in Assembly.GetExecutingAssembly().GetTypes()
where typeof(IController).IsAssignableFrom(t)
select t;
foreach (Type t in controllerTypes)
container.AddComponentWithLifestyle /* Либо используйте AddComponentLifeStyle для второй версии */
(t.FullName, t,LifestyleType.Transient);
}
// Constructs the controller instance needed to service each request this part is Updated to be compatible with MVC 2
protected override IController
GetControllerInstance
(RequestContext requestContext, Type controllerType)
{
return (IController)container.Resolve(controllerType);
}
/*
* For MVC 1 use this
protected override IController GetControllerInstance(Type controllerType)
{
return (IController)container.Resolve(controllerType);
}*/
}
}
Этот код реализует интерфейс IControllerFactory (это след. хотя бы из того, что он наследует класс DefaultControllerFactory). Далее нам осталось внести след. изменения в Web.config:
//содержимое
Лучше сделать это сразу перед system.web (здесь это показано)
Далее в configSections добавить след. строку (если узел configSections еще не создан, то его след. создать внутри configuration)
Теперь необходимо указать ASP.NET использовать новую фабрику контроллеров, делается это добавлением строки
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory());
В метод Application_Start(), находящегося в файле Global.asax.
Допустим, вы используете интерфейс IUserRepository
namespace Models.Abstract
{
public interface IUserRepository
{
IQueryableUsers { get; }
}
}
И существует реализация этого интерфейса:
namespace Model.Concrete
{
public class SqlUserRepository : IUserRepository
{
private Tablecurrent;
public SqlUserRepository(String connectionString)
{
current = (new DataContext(connectionString)).GetTable();
}
public IQueryableUsers
{
get { return current; }
}
}
}
Теперь, можно использовать данный интерфейс так:
public class UsersController : Controller
{
public IUserRepository myUser;
public UsersController(IUserRepository userRepository)
{
this.myUser = userRepository;
}
public ViewResult List()
{
return View(userRepository.Users.ToList());
}
}
Необходимо зарегистрировать интерфейс и его реализацию в CastleWindsor
service="Model.Abstract.IUserRepository, Model"
type="Model.Concrete.SqlUserRepository, Model"
lifestyle="PerWebRequest">
Server=.\SQLEXPRESS;DataBase=SportStore;Trusted_Connection=yes;
Теперь осталось зарегистрировать стиль поведения объекта PerRequestLifestyle в httpModules (если в web.config еще нет узла httpModules, то его следует объявить внутри system.web)
Ну, вот и все. Теперь CastleWindsor установлен и готов к использованию.
спасибо, чуть-чуть запутался в книге
ОтветитьУдалитьнашел нужный совет
Сейчас читаю даную книгу и у меня такая проблемка:
ОтветитьУдалитьCastle.MicroKernel.dll в версии 2.5.2 нету. Всё сделал так как в книге и у меня ругается: 1 Web.config (чтото вроде не может найти библиотеку в Castle.windsor. ...... in Castle.windsor)
2 AddComponentLifeStyle для второй версии */
(t.FullName, t,LifestyleType.Transient);
К сожалению, у меня сейчас нет возможности скачать последнюю версии CastleWindsor, но, насколько я вас понял, проблема заключается в том, что в последней версии нет библиотеки Castle.MicroKernel.dll. Как только появится возможность, изучу изменения, пришедшие с этим обновлением. А пока могу лишь посоветовать использовать более раннюю версию. В конце концов, библиотека, скачанная мной незадолго до написания этой статьи, до сих пор прекрасно работает в одном из проектов.
ОтветитьУдалитьЕвгений, пожалуйста отредактируйте настройки web.config. Они не отображаются!
ОтветитьУдалитьЗдравствуйте, Евгений!
ОтветитьУдалитьПо поводу Castle.MicroKernel.dll - в версии 2.5.3 эта библиотека встроена в CastleCore (попробуйте добавить сборку в проект и просмотреть содержимое - там она есть)
У меня другая проблема - всё сделал так как Вы и написали, но каждый раз одна и та же ошибка
Could not convert from 'DomainModel.Concrete.SqlProductsRepository, DomainModel' to System.Type - Maybe type could not be found
Как вы думаете, в чём может быть проблема - вроде все нужные изменения в web.config сделаны
Здравствуйте Евгений!
ОтветитьУдалитьРазобрал ваш пример однако при компиляции в методе GetControllerInstance выдает ошибку ArgumentNullException не подскажете как решить эту проблему?
Здравствуйте, по вашему описанию трудно сделать вывод в чем именно дело, однако, на сколько я помню, данная функция - одна из немногих, что изменилась при переходе от MVC 1 к MVC 2. Возможно дело в этом. А вообще, причина может быть в чем угодно, например, некорректно заполненный Web.config.
ОтветитьУдалитьЗдравствуйте Евгений еще раз.
ОтветитьУдалитьв конфиге ошибки нет. Я так же как и в книге Сандерсона отображаю список из экземпляра класса, и он отображаеться, однако, после отображения
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
Вызывается еще раз только Type controllerType=null и происходит ошибка.
По поводу отсутствия Castle.MicroKernel.dll смотрите след. ссылку:
ОтветитьУдалитьhttp://www.ssidelnikov.ru/2011/01/castle-microkernel/