SharePoint 2010 Beta доступен для закачки TechNet и MSDN подписчикам
Опубликовано: 16 ноября, 2009 Filed under: Uncategorized | Tags: sharepoint, SharePoint 2010, SharePoint Foundation Оставьте комментарийДождались, наконец-то SharePoint Server 2010 Beta доступен для скачивания
подписчикам TechNet и MSDN.
https://msdn.microsoft.com/en-us/subscriptions/securedownloads/default.aspx
Напоминаю вам, что доступен он только в x64 редакциях, а так же есть Русская
редакция.
Так же выложенны все продукты линейки Office 2010.
Можно также посмотреть выступления с конференции «Платфторма 2010», посвященные SharePoint 2010:
- Microsoft SharePoint Server 2010: первое знакомство
http://www.techdays.ru/videos/1522.html - Архитектура идеального предприятия, внедрившего у себя все компоненты Microsoft Office System
http://www.techdays.ru/videos/1524.html
Как подружить ASP.NET Controls и DI-контейнер
Опубликовано: 16 ноября, 2009 Filed under: .net, IoC, Sapphire, sharepoint | Tags: AOP, dependency injection, Microsoft Unity, Sapphire, sharepoint, Unity, Unity Interception 1 комментарийИнтро
В последнее время решил немного освежить свои знания в ASP.NET, в связи с чем углубился в процессы генерации кода контролов по разметке (*.ascx, *.aspx) и обнаружил что можно делать очень интересные решения, о которых о хочу поведать. Итак сегодня мы узнаем, как подружить наш Dependency Injection контейнер с генерируемым контролами кодом.
Поехали
В качестве DI-контейнера будет выступать Microsoft Unity, но это не принципиально, всё что будет касаться DI не зависит от используемого контейнера.
Проблема состоит в следующем – есть некоторый ASP.NET Control, в который мы хотим внедрит зависимости, а так же воспользоваться услугами Service Locator’а для управления интересующими нас зависимостями.
В Microsoft Unity есть некоторые средства для того, чтобы сделать это не прилагая особенных усилий: мы можем произвести инъекцию в свойство элемента управления, нас интересующее примерно следующим образом:
- Отметить атрибутом Dependency необходимое свойство
public class MyControl : UserControl
{
[Dependency]
public MyPresenter Presenter
{
get { return _presenter; }
set
{
_presenter = value;
_presenter.View = this;
}
}
} -
Проинициализировать элемент управления можно следующим образом
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
_сontainer.BuildUp(GetType(), this);
} -
Позаботиться о местоположении контейнера в вашем приложении, я предлагаю использовать для этого HttpApplication, унаследовавшись от которого и произведя небольшие модификации файла global.asax мы получаем необходимое нам хранилище для контейнера, обращаться с ним необходимо примерно следующим образом
((Sapphire.Application)HttpContext.Current.ApplicationInstance).Container
Решение вполне пригодное, однако пуристические воззрения не дают оставить решение на данной стадии, и думаю, что просто необходимо заменить инъекцию свойства на инъекцию в конструктор, тем более подобный подход – это далеко не то, что мы можем выжать из Unity.
Т.е. наш интерес состоит в том, чтобы класс MyUserControl выглядел примерно так (думаю сборщику страницы это не совсем понравится)
{
public MyControl(MyPresenter presenter)
{
_presenter = presenter;
_presenter.View = this;
}
}
Предлагаю этим и заняться. Начнём с того, что у элементов управления, описанных в разметке страницы, при генерации страницы указываются их конструкторы без параметров, интересно, как можно управлять данным процессом, первоначально, покопавшись в web.config я предполагал сделать это через:
<add extension=«.aspx» type=«System.Web.Compilation.PageBuildProvider»/>
<add extension=«.ascx» type=«System.Web.Compilation.UserControlBuildProvider»/>
…
</buildProviders>
Однако реализация своего PageBuildProvider’а – довольно серьезное занятие, думаю отложить это для серьезной на то необходимости. Однако благодаря BuildProvider’ам можно генерить к примеру слой доступа к данным, для этого надо:
Написать и зарегестрировать обработчик для какого-нибудь своего расширения, к примеру *.dal и сделать что-нибудь наподобее http://www.codeproject.com/KB/aspnet/DALComp.aspx
кстати подобная логика реализована в SubSonic http://dotnetslackers.com/articles/aspnet/IntroductionToSubSonic.aspx
так же интересная реализация наследования страницы от generic типов http://stackoverflow.com/questions/1480373/generic-inhertied-viewpage-and-new-property
ещё можно, к примеру генерировать исключения, объекты передачи данных и многое другое, ограничением является лишь ваша фантазия.
Вообщем, данный вариант нам не подходит, необходимо сделать что-нибудь проще, и есть отличное решение, с помощью атрибута ControlBuilder мы можем указать свою логику сборки элемента управления из разметки, это будет выглядеть примерно так
public class UserControl : System.Web.UI.UserControl
{
}
Теперь разберемся с реализацией MyControlBuilder, этот тип должен наследовать от ControlBuilder и с помощью перегрузки ProcessGeneratedCode мы с вами сможем указать сборщику на необходимость использования нашего кода вместо вызова конструктора без атрибутов элемента управления:
CodeTypeDeclaration baseType,
CodeTypeDeclaration derivedType,
CodeMemberMethod buildMethod,
CodeMemberMethod dataBindingMethod)
{
codeCompileUnit.Namespaces[0].Imports.Add(new CodeNamespaceImport(«Sapphire.Web.UI»));
ReplaceConstructorWithContainerResolveMethod(buildMethod);
base.ProcessGeneratedCode(codeCompileUnit, baseType, derivedType, buildMethod, dataBindingMethod);
}
самое интересно скрывает метод ReplaceConstructorWithContainerResolveMethod
{
foreach (CodeStatement statement in buildMethod.Statements)
{
var assign = statement as CodeAssignStatement;
if (null != assign)
{
var constructor = assign.Right as CodeObjectCreateExpression;
if (null != constructor)
{
assign.Right =
new CodeSnippetExpression(
string.Format(«SapphireControlBuilder.Build<{0}>()»,
ControlType.FullName));
break;
}
}
}
}
следуя по коду можно обратить внимание, что он заменяет вызов конструктора на вызов генерик-метода Build, в котором мы и обратимся к нашему контейнеру с просьбой вызвать наш элемент управления и проинициализировать его конструктор необходимыми зависимостями.
Однако это ещё не решении задания, т.к. есть метод динамической загрузки элемента управления Page.LoadControl(), для него придётся написать свой вариант
{
public static UserControl LoadAndBuildUpControl(this Page page, string virtualPath)
{
var control = page.LoadControl(virtualPath);
return SapphireControlBuilder.Build<UserControl>(control.GetType());
}
}
Вот мы и справились с поставленной задачей, однако это ещё не всё. А почему теперь не воспользоваться всеми преимуществами Unity, и не внедрить в наш элемент управления AOP времени исполнения с помощью Unity Interception.
К примеру мы можем сделать следующее
{
[HandleException]
public override void DataBind()
{
base.DataBind();
}
}
Это будет означать, что обработка исключений должна добавляться на лету, к тому ж предоставляя нам возможность её изменения во время исполнения, для начала пусть её реализация будет примерно следующая
public class HandleExceptionAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new ExceptionHandler();
}
}
public class ExceptionHandler : ICallHandler
{
/// <exception cref=»SapphireUserFriendlyException»><c>SapphireUserFriendlyException</c>.</exception>
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
var result = getNext()(input, getNext);
if (result.Exception == null)
return result;
throw new SapphireUserFriendlyException();
}
public int Order { get; set; }
}
Ну и конечно же надо сконфигурировать контейнер для создания наших прокси-обработчиков
{
return (T)((Application)HttpContext.Current.ApplicationInstance)
.Container
. AddNewExtension<Interception>()
.Configure<Interception>()
.SetInterceptorFor<T>(new VirtualMethodInterceptor())
.Container
.Resolve<T>();
}
Ресурсы
Sapphire.Application – для чего всё это реализовывалось http://github.com/butaji/Sapphire/tree/master/trunk/Sapphire.Application/
Дэвид предлагает реализации связывания с данными следующего поколения “Databinding 3.0” на основе аналогичного подхода http://weblogs.asp.net/davidfowler/archive/2009/11/13/databinding-3-0.aspx