Ни класс Page, ни презентеры не должны иметь дело непосредственно с управлением построением или жизненным циклом любой из его зависимостей — все это должен обрабатывать ваш контейнер. Поскольку внедрение конструктора не работает с WebForms, вам нужно будет предоставить все необходимые зависимости как свойства класса. Например, вы можете изменить свой класс на:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
public _DefaultPresenter Presenter { get; set; }
}
Страница не должна нуждаться в каких-либо ссылках на репозиторий, так как она будет внедрена в презентатор.
Остальная часть этого ответа относится к StructureMap — детали могут отличаться для других контейнеров.
Чтобы включить внедрение сеттера, вам нужно сообщить StructureMap, какие свойства следует заполнить. Один из способов — применить атрибут [SetterProperty] к самому свойству. Тем не менее, это может показаться немного навязчивым, чтобы иметь детали StructureMap в ваших классах. Другой способ — настроить StructureMap так, чтобы он знал, какие типы свойств следует вводить. Например:
protected void Application_Start(object sender, EventArgs e)
{
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
});
x.ForRequestedType<IRepository>().TheDefaultIsConcreteType<Repository>().CacheBy(InstanceScope.Hybrid);
x.SetAllProperties(set => set.WithAnyTypeFromNamespaceContainingType<IRepository>());
});
}
Метод SetAllProperties позволяет указать StructureMap, как распознавать свойства, которые он должен заполнять. В этом случае я говорю StructureMap внедрить всех докладчиков (при условии, что все они находятся в одном и том же пространстве имен).
Вам по-прежнему необходимо выполнять инъекцию сеттера для каждого запроса. В StructureMap вы используете метод BuildUp() для внедрения зависимостей в существующий экземпляр. Вы можете сделать это в событиях Init или Load каждой страницы или базового класса страницы, но опять же, это кажется навязчивым. Чтобы полностью исключить контейнер из классов страниц, вы можете использовать событие PreRequestHandlerExecute приложения (в global.asax или IHttpModule):
protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
var application = (HttpApplication)sender;
var page = application.Context.CurrentHandler as Page;
if (page == null) return;
ObjectFactory.BuildUp(page);
}
Наконец, если вы хотите явно удалить свой IRepository, вы можете обработать это в событии EndRequest:
protected void Application_EndRequest(object sender, EventArgs e)
{
var disposable = ObjectFactory.GetInstance<IRepository>() as IDisposable;
if (disposable != null) disposable.Dispose();
}
Обратите внимание, что это работает правильно, потому что при инициализации мы указали StructureMap кэшировать IRepository с помощью Hybrid, что означает «дайте мне один и тот же экземпляр для каждого HTTP-запроса (или потока, если он не выполняется на веб-сайте)». Когда вы извлекаете IRepository в EndRequest, вы получите тот же самый, который использовался во всем запросе, и вы можете его удалить.
person
Joshua Flanagan
schedule
07.11.2009