







<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>с .NET по жизни</title>
	<atom:link href="http://blog.zzlab.ru/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.zzlab.ru</link>
	<description>Записки C# программиста</description>
	<lastBuildDate>Tue, 31 Aug 2010 17:20:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=abc</generator>
		<item>
		<title>Биндинг сложных объектов в ASP.NET MVC</title>
		<link>http://blog.zzlab.ru/coding/binding-slozhnyx-obektov-v-asp.net-mvc.html</link>
		<comments>http://blog.zzlab.ru/coding/binding-slozhnyx-obektov-v-asp.net-mvc.html#comments</comments>
		<pubDate>Mon, 16 Aug 2010 11:22:03 +0000</pubDate>
		<dc:creator>AlexandrYZ</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[ASP.NET MVC]]></category>

		<guid isPermaLink="false">http://blog.zzlab.ru/?p=326</guid>
		<description><![CDATA[Механизм биндинга данных в ASP.NET MVC мощный, и позволяет биндить не только простые типы, но и достаточно сложные классы. В данной статье будут рассмотрены 4 сценария. Опыт разработки ASP.NET MVC приложений у меня небольшой, но с данными задачками я уже столкнулся. Подготовка Запускаем студию и создаем приложение на основе шаблона ASP.NET MVC Application. Далее создаем [...]]]></description>
			<content:encoded><![CDATA[<p>Механизм биндинга данных в ASP.NET MVC мощный, и позволяет биндить не только простые типы, но и достаточно сложные классы. В данной статье будут рассмотрены 4 сценария. Опыт разработки ASP.NET MVC приложений у меня небольшой, но с данными задачками я уже столкнулся.</p>
<p><span id="more-326"></span></p>
<h3>Подготовка</h3>
<p>Запускаем студию и создаем приложение на основе шаблона ASP.NET MVC Application. Далее создаем новый контроллер, пусть это будет StarsController.<br />
<img src="http://a.imageshack.us/img411/751/0createcontroller.png"/><br />
Далее откройте Views\Home\Index и замените код следующим:<br />
[xhtml]<br />
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"<br />
         Inherits="System.Web.Mvc.ViewPage" %></p>
<p><asp:Content ID="indexTitle"<br />
             ContentPlaceHolderID="TitleContent" runat="server"><br />
    Home Page<br />
</asp:Content><br />
<asp:Content ID="indexContent"<br />
             ContentPlaceHolderID="MainContent" runat="server"><br />
    <%= Html.ActionLink("Передача списка строк","Index","Stars") %><br />
    <%= Html.ActionLink("Передача простого объекта","SimpleObject","Stars") %><br />
    <%= Html.ActionLink("Передача списка простых объектов","SimpleObjectList","Stars") %><br />
    <%= Html.ActionLink("Передача сложного объекта","ComplexObject","Stars") %></p>
<p></asp:Content><br />
[/xhtml]</p>
<h3>Передача массива/списка простых значений</h3>
<p>Это может пригодиться если нужно предоставить пользователю сформировать список чего либо. Для простоты список я сформирую сразу же, можно прикрутить jQuery и сделать красиво, а можно сделать проще <img src='http://blog.zzlab.ru/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>В нашем случае пусть это будет список звезд, благо на выходных я наконец узнал где находиться Полярная!<br />
Вот список подопытных: Солнце, Бетельгейзе, Арктур и Полярная звезда.</p>
<p><strong>Контроллер</strong><br />
Добавим в контроллер метод ShowList, который и будет принимать отправленные данные. Можно использовать как List<> т<br />
[csharp]<br />
public ActionResult ShowList(List<string> stars)<br />
	{<br />
		return View();<br />
	}<br />
[/csharp]<br />
Обратите внимание, что имя передаваемого в метод параметра совпадает с атрибутом name у полей ввода. Поставим точку останова в методе ShowList и посмотрим на то что получиться.</p>
<p><strong>Представление</strong><br />
Открываем созданный ранее контроллер StarsController и для его метода Index создадим View.<br />
<img alt="" src="http://a.imageshack.us/img291/1707/1addview.png" class="aligncenter" /></p>
<p>Добавим в тело представления следующий код:<br />
[xhtml]<br />
<% using (Html.BeginForm("ShowList", "Stars"))<br />
       { %></p>
<input name="stars" value="Солнце" /></p>
<input name="stars" value="Бетельгейзе" /></p>
<input name="stars" value="Арктур" /></p>
<input name="stars" value="Полярная звезда" /></p>
<input type="submit" value="Отправить список" />
    <%} %><br />
[/xhtml]</p>
<p><strong>Результат</strong><br />
<img alt="" src="http://a.imageshack.us/img810/979/showlistbreakpoint.png" class="aligncenter" width="633" height="124" /><br />
Мы получили то что нужно, то же самое можно проделать с числами и другими простыми типами. Кроме типизированного списка можно использовать: T[], IEnumerable<T>, IList<T>, List<T>, ICollection<T> и Collection<T>. Те метод ShowList можно изменить следующим образом:<br />
[csharp]<br />
public ActionResult ShowList(IEnumerable<string> stars)<br />
	{<br />
		return View();<br />
	}<br />
[/csharp]</p>
<h3>Передача простого объекта</h3>
<p>А теперь передадим в метод контроллера простой класс:<br />
[csharp]<br />
using System;</p>
<p>namespace MvcAppBindingEx.Models<br />
{<br />
	public class SimpleObject<br />
	{<br />
		public string Name { get; set; }<br />
		public double Value { get; set; }<br />
	}<br />
}<br />
[/csharp]</p>
<p><strong>Контроллер</strong><br />
Создаем метод контроллера.<br />
[csharp]<br />
	public ActionResult SimpleObject(Models.SimpleObject data)<br />
	{<br />
		return View();<br />
	}<br />
[/csharp]</p>
<p><strong>Представление</strong><br />
[xhtml]<br />
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"<br />
Inherits="System.Web.Mvc.ViewPage" %></p>
<p><asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"><br />
	SimpleObject<br />
</asp:Content></p>
<p><asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"></p>
<h2>SimpleObject</h2>
<p>     <% using (Html.BeginForm())<br />
       { %></p>
<input name="data.Name" value="η Киля" /></p>
<input name="data.Value" value="6,21" /></p>
<input type="submit" value="Отправить" />
    <%} %></p>
<p></asp:Content><br />
[/xhtml]</p>
<p>Запускаем и смотрим что возвращается из представления.<br />
<img alt="" src="http://a.imageshack.us/img40/1440/4simpleobjectbreakpoint.png" class="aligncenter" width="727" height="78" /><br />
Как видно из кода формы, поля имеют названия вида [имя параметра].[Название свойства класса]. Это и используется механизмом биндинга для корректной привязки данных и класса.</p>
<h3>Передача списка простых объектов</h3>
<p>Теперь чуть сложнее задача &#8211; нужно передать список простых объектов.</p>
<p><strong>Контроллер</strong><br />
[csharp]<br />
public ActionResult SimpleObjectList(List<Models.SimpleObject> list)<br />
	{<br />
		return View();<br />
	}<br />
[/csharp]</p>
<p><strong>Представление</strong><br />
В этом случае нужно использоват индексное поле для формирования имени полей в виде [parameterName][Index].[PropertyName]<br />
[xhtml]<br />
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"<br />
Inherits="System.Web.Mvc.ViewPage" %></p>
<p><asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"><br />
	SimpleObjectList<br />
</asp:Content></p>
<p><asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"></p>
<h2>SimpleObjectList</h2>
<p>    <% using (Html.BeginForm())<br />
       { %><br />
            Название:<br />
<input name="list[0].Name" value="η Киля" />
            Расстояние:<br />
<input name="list[0].Value" value="6,21" /> св. лет</p>
<p>            Название:<br />
<input name="list[1].Name" value="αС Центавра" />
            Расстояние:<br />
<input name="list[1].Value" value="4,225" /> св. лет</p>
<input type="submit" value="Отправить" />
    <%} %><br />
</asp:Content><br />
[/xhtml]<br />
<img alt="" src="http://a.imageshack.us/img843/7396/5simpleobjectlistview.png" class="aligncenter" /></p>
<p><strong>Результат</strong><br />
<img alt="" src="http://a.imageshack.us/img571/8743/5simpleobjectlistresult.png" class="aligncenter" /></p>
<h3>Передача сложного объекта</h3>
<p>В данном случае в качестве сложного объекта выбран класс ComplexObject. Который имеет несколько полей, одно из которых содержит список</p>
<p><strong>Контроллер</strong></p>
<p>[csharp]<br />
public ActionResult ComplexObject(Models.ComplexObject data)<br />
	{<br />
		return View();<br />
	}<br />
[/csharp]</p>
<p><strong>Представление</strong><br />
В передставлении заранее заданы поля объекта и массив простых объектов. По сути это комбинация вышеприведенных способов передачи простого объекта и списка объектов.<br />
[xhtml]<br />
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"<br />
Inherits="System.Web.Mvc.ViewPage" %></p>
<p><asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"><br />
    ComplexObject<br />
</asp:Content><br />
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"></p>
<h2>
        ComplexObject</h2>
<p>    <% using (Html.BeginForm())<br />
       { %><br />
       <strong>Созвездие</strong> <br/><br />
    Название:<br />
<input name="data.Name" value="Волопас" />
    Аббревиатура:<br />
<input name="data.Abbreviation" value="Boo" /><br/><br />
    <br/></p>
<p>    <strong>Ярчайшие звёзды</strong><br/></p>
<p>
        Название:<br />
<input name="data.Stars[0].Name" value="Арктур" />
        Расстояние:<br />
<input name="data.Stars[0].Value" value="36,7" /> св. лет<br />
        Название:<br />
<input name="data.Stars[1].Name" value="Муфрид" />
        Расстояние:<br />
<input name="data.Stars[1].Value" value="37" /> св. лет<br />
        Название:<br />
<input name="data.Stars[2].Name" value="Ицар" />
        Расстояние:<br />
<input name="data.Stars[2].Value" value="270" /> св. лет
    </p>
<input type="submit" value="Отправить" />
    <%} %><br />
</asp:Content><br />
[/xhtml]</p>
<p><strong>Результат</strong><br />
<img alt="" src="http://a.imageshack.us/img806/261/6complexobjectresult.png" class="aligncenter" /></p>
<p><a href="https://sites.google.com/site/de7c9621c3fd45309efc/Home/MvcAppBindingEx.7z?attredirects=0&#038;d=1">Исходники</a> проекта с примерами.</p>
<p><strong>Ссылки:</strong><br />
0. <a href="http://msdn.microsoft.com/en-us/library/dd410405.aspx">Models and Validation in ASP.NET MVC</a><br />
1. <a href="http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx">Phil Haack &#8211; Model Binding To A List</a><br />
2. <a href="http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx">Scot Hanselman &#8211; ASP.NET Wire Format for Model Binding to Arrays, Lists, Collections, Dictionaries</a> </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zzlab.ru/coding/binding-slozhnyx-obektov-v-asp.net-mvc.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Загрузка файла или нескольких файлов в ASP.NET MVC 2</title>
		<link>http://blog.zzlab.ru/perevod/zagruzka-fajla-ili-neskolkix-fajlov-v-asp.net-mvc.html</link>
		<comments>http://blog.zzlab.ru/perevod/zagruzka-fajla-ili-neskolkix-fajlov-v-asp.net-mvc.html#comments</comments>
		<pubDate>Tue, 20 Jul 2010 08:23:59 +0000</pubDate>
		<dc:creator>AlexandrYZ</dc:creator>
				<category><![CDATA[Перевод]]></category>
		<category><![CDATA[ASP.NET MVC]]></category>

		<guid isPermaLink="false">http://blog.zzlab.ru/?p=335</guid>
		<description><![CDATA[Перевод: Phil Haack &#8211; Uploading a File (Or Files) With ASP.NET MVC Я хотел убедиться в том как осуществляется загрузка файла или набора файлов с помощью ASP.NET MVC и первым результатом поиска по фразе “uploading a file with asp.net mvc” была статья в блоге Скотта Хансельмана. Его статья очень подробна и помогает понять что происходит [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Перевод:</strong> <a href="http://haacked.com/archive/2010/07/16/uploading-files-with-aspnetmvc.aspx">Phil Haack &#8211; Uploading a File (Or Files) With ASP.NET MVC</a><br />
Я хотел убедиться в том как осуществляется загрузка файла или набора файлов с помощью ASP.NET MVC и первым результатом поиска по фразе “uploading a file with asp.net mvc” была <a href="http://www.hanselman.com/blog/ABackToBasicsCaseStudyImplementingHTTPFileUploadWithASPNETMVCIncludingTestsAndMocks.aspx">статья</a> в блоге Скотта Хансельмана.<br />
Его статья очень подробна и помогает понять что происходит под капотом. У меня есть только одна претензия к коду, он может стать проще, потому что с тех пор мы доработали ASP.NET MVC 2. Я пишу эту статью в блог в надежде скинуть его статью с первого места.</p>
<p><span id="more-335"></span></p>
<h3>Загрузка одиночного файла</h3>
<p>Давайте начнем с создания представления. Вот форма, которая будет возвращать результат в текущий метод контроллера.<br />
[html]</p>
<form action="" method="post" enctype="multipart/form-data">
<p>  <label for="file">Filename:</label></p>
<input type="file" name="file" id="file" />
<input type="submit" />
</form>
<p>[/html]<br />
Вот метод контроллера, в который будет возвращаться результат из представления и сохраняться в директорию “uploads” на сервере.</p>
<p>[csharp]<br />
[HttpPost]<br />
public ActionResult Index(HttpPostedFileBase file) {</p>
<p>  if (file.ContentLength > 0) {<br />
    var fileName = Path.GetFileName(file.FileName);<br />
    var path = Path.Combine(Server.MapPath(&laquo;~/uploads&raquo;), fileName);<br />
    file.SaveAs(path);<br />
  }</p>
<p>  return RedirectToAction(&laquo;Index&raquo;);<br />
}<br />
[/csharp]<br />
Обратите внимание, аргумент метода является экземпляром типа HttpPostedFileBase. ASP.NET MVC 2 представляет новую возможность &#8211; провайдеры значений (value providers), о которых я уже <a href="http://haacked.com/archive/2010/04/15/sending-json-to-an-asp-net-mvc-action-method-argument.aspx">писал ранее</a>.</p>
<p>“В то время как model binders используются для связывания входных данных с объектной моделью, провайдеры значений представляют абстракцию для самих входных данных.”</p>
<p>В данном случае провайдер значений по умолчанию называется HttpFileCollectionValueProvider, который предоставляет загруженные файлы в model binder. Также обратите внимание на имя аргумента &#8211; file, оно совпадает с именем переданного файла. Это очень важно что бы model binder загруженного файла совпадал с аргументом метода контроллера.</p>
<h3>Загрузка нескольких файлов</h3>
<p>В данном сценарии мы хотим загрузить набор файлов. Мы просто можем иметь несколько полей с одинаковыми именами для выбора файла.<br />
[html]</p>
<form action="" method="post" enctype="multipart/form-data">
<p>  <label for="file1">Filename:</label></p>
<input type="file" name="files" id="file1" />
<p>  <label for="file2">Filename:</label></p>
<input type="file" name="files" id="file2" />
<input type="submit"  />
</form>
<p>[/html]<br />
Теперь мы можем просто подкрутить наш метод контроллера, что бы принимать аргументы типа IEnumerable. Снова обратите внмание, что имя аргумента должно совпадать с именем передаваемого из формы поля.</p>
<p>[csharp]<br />
[HttpPost]<br />
public ActionResult Index(IEnumerable<HttpPostedFileBase> files) {<br />
  foreach (var file in files) {<br />
    if (file.ContentLength > 0) {<br />
      var fileName = Path.GetFileName(file.FileName);<br />
      var path = Path.Combine(Server.MapPath(&laquo;~/uploads&raquo;), fileName);<br />
      file.SaveAs(path);<br />
    }<br />
  }<br />
  return RedirectToAction(&laquo;Index&raquo;);<br />
}<br />
[/csharp]<br />
Да, это очень просто. <img src='http://blog.zzlab.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zzlab.ru/perevod/zagruzka-fajla-ili-neskolkix-fajlov-v-asp.net-mvc.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ASP.NET MVC 2 и jqGrid</title>
		<link>http://blog.zzlab.ru/coding/asp.net-mvc-2-i-jqgrid.html</link>
		<comments>http://blog.zzlab.ru/coding/asp.net-mvc-2-i-jqgrid.html#comments</comments>
		<pubDate>Sat, 29 May 2010 06:29:19 +0000</pubDate>
		<dc:creator>AlexandrYZ</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[ASP.NET MVC]]></category>
		<category><![CDATA[jqGrid]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://blog.zzlab.ru/?p=286</guid>
		<description><![CDATA[Введение При работе с данными часто возникает необходимость отображения их в виде таблицы, и кроме этого еще иметь возможности удобной манипуляции с данными: сортировка, фильтрация, редактирование и тд. После непродолжительных поисков наткнулся на плагин jqGrid к jQuery. Возможности плагина: Постраничная загрузка данных (Paging) Inline редактирование данных Сортировка и фильтрация Режим отображения &#8211; SubGrid. По сути [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Введение</strong><br />
При работе с данными часто возникает необходимость отображения их в виде таблицы, и кроме этого еще иметь возможности удобной  манипуляции с данными: сортировка, фильтрация, редактирование и тд.</p>
<p>После непродолжительных поисков наткнулся на плагин <a href="http://www.trirand.com/blog/">jqGrid</a> к jQuery.<br />
<a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:features">Возможности</a> плагина:</p>
<ul>
<li>Постраничная загрузка данных (Paging)</li>
<li>Inline редактирование данных</li>
<li>Сортировка и фильтрация</li>
<li>Режим отображения &#8211; SubGrid. По сути это разновидность Master &#8211; Detail</li>
<li>Режим отображения древовидных списков &#8211; TreeGrid</li>
</ul>
<p><span id="more-286"></span><br />
<strong>Подготовка</strong></p>
<p>Чтобы начать использовать jqGrid необходимо скачать:<br />
1. <a href="http://www.trirand.com/blog/?page_id=6">Плагин jqGrid</a><br />
2. <a href="http://jqueryui.com/">jQuery UI</a></p>
<p>Запускаем Microsoft Visual Studio 2010 и создаем проект ASP NET MVC 2 Application. После создания проекта необходимо добавить в<br />
Далее добавляем в проект плагин jqGrid и jQuery UI, для этого из архива jqGrid копируем каталоги css и js в каталог Script\jquery.jqGrid проект. Из архива jQuery UI нужны каталоги css, js копируем их в Scripts\jquery.ui.<br />
Получаем следующую структуру проекта<br />
<img alt="" src="http://img697.imageshack.us/img697/9289/solutionexplorer.png" class="aligncenter" width="275" height="361" /></p>
<p>Итак, кроме добавления файлов в проект необходимо добавить следующие строки в \Views\Shared\Site.Master<br />
[html]</p>
<link href="../../Scripts/jquery.UI/css/redmond/jquery-ui-1.8.1.custom.css" rel="Stylesheet" type="text/css" />
<link href="../../Scripts/jquery.jqGrid/css/ui.jqgrid.css" rel="Stylesheet" type="text/css" />
<p>    <script type="text/javascript" src="../../Scripts/jquery.jqGrid/js/jquery-1.4.2.min.js"></script></p>
<p>    <script type="text/javascript" src="../../Scripts/jquery.jqGrid/js/i18n/grid.locale-ru.js"></script><br />
    <script type="text/javascript" src="../../Scripts/jquery.jqGrid/js/jquery.jqGrid.min.js"></script><br />
[/html]</p>
<p>Вот теперь у нас все готово для использования jqGrid.</p>
<p><strong><br />
Задача:<br />
Отобразить список сотрудников в таблице.</strong></p>
<p>В итоге должно получится следующее:<br />
<img alt="" src="http://img197.imageshack.us/img197/8791/workscreen.png" class="alignnone" width="628" height="373" /></p>
<h3>Controller</h3>
<p>Начнем с создания контроллера. Для этого правой кнопкой мыши щелкаем на Controllers в проекте и выбираем Add -> Controller<br />
В появившемся диалоге вводим имя контроллера EmployeeController и убираем галочку &laquo;Add action methods for Create, Update, Delete and Details scenarios&raquo;<br />
<img alt="" src="http://img44.imageshack.us/img44/4559/newcontrollerdialog.png" class="aligncenter" width="493" height="200" /></p>
<p>В результате получаем класс EmployeeController наследник Controller с одним единственным методом Index.<br />
Добавим в каталог Models проекта класс Employee<br />
[csharp]<br />
public class Employee<br />
    {<br />
        public int Id { get; set; }<br />
        public string FirstName { get; set; }<br />
        public string LastName { get; set; }<br />
        public string Email { get; set; }<br />
    }<br />
[/csharp]</p>
<p>Возвращаемся в контроллер и добавляем следующий код:<br />
[csharp]<br />
public JsonResult EmployeeData()<br />
        {<br />
            var list = new List<Employee><br />
                           {<br />
                               new Employee {Id = 1, FirstName = &laquo;Александр&raquo;, LastName = &laquo;Македонский&raquo;, Email = &laquo;alex.mak@test.com&raquo;},<br />
                               new Employee {Id = 2, FirstName = &laquo;Иван&raquo;, LastName = &laquo;Петров&raquo;, Email = &laquo;ivan@test.com&raquo;},<br />
                               new Employee {Id = 3, FirstName = &laquo;Сергей&raquo;, LastName = &laquo;Сидоров&raquo;, Email = &laquo;sarg@test.com&raquo;},<br />
                           };</p>
<p>            var result = new  JsonResult()<br />
                             {<br />
                                 Data = new { page = 0, total = 1, records = list.Count, rows = list }<br />
                             };</p>
<p>            return result;<br />
        }<br />
[/csharp]<br />
Он будет возвращать данные для таблицы в виде Json структуры.<br />
Далее нужно открыть Site.Master и добавить в меню пункт Сотрудники, для нужно после строк<br />
[html light="true"]
<div id="menucontainer">
<ul id="menu">[/html]<br />
добавить: [html light="true"]
<li><%: Html.ActionLink("Сотрудники", "Index", "Employee")%></li>
<p>[/html]</p>
<h3>View</h3>
<p>Теперь для метода Index контроллера EmployeeConroller создадим View в которой и будет отображаться таблица с данными. Правой клавишей мыши на название метода Index и выбираем пункт &laquo;Add View&raquo;.<br />
<img alt="" src="http://img62.imageshack.us/img62/5283/addview.png" class="aligncenter" width="501" height="90" /><br />
В появившемся диалоге ничего не меняем, нажимаем кнопку Add, после чего получаем файл Index.aspx. Далее в блок [html light="true"]<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">[/html] добавляем следующий код<br />
[html]</p>
<table id="EmployeeTable">
    </table>
<div id="EmployeeTablePager">
    </div>
<p>[/html]<br />
Эти элементы будут использоваться плагином для создания jqGrid таблицы и навигатора по страницам. Если указать div вместо table то получим ошибку &laquo;a.rows is undefined&raquo; при получении данных.<br />
Далее вставляем скрипт, содержащий настройки таблицы и колонок.<br />
[html]<br />
    <script type="text/javascript">
        jQuery(document).ready(function () {
            jQuery('#EmployeeTable').jqGrid({
                url: '/Employee/EmployeeData',
                datatype: "json",
                mtype: 'POST',
                jsonReader: {
                    page: "page",
                    total: "total",
                    records: "records",
                    root: "rows",
                    repeatitems: false,
                    id: ""
                },
                colNames: ['Id', 'Имя', 'Фамилия', 'Email'],
                colModel: [
                { name: 'Id',  width: 55 },
                { name: 'FirstName',  width: 155 },
                { name: 'LastName', width: 150 },
                { name: 'Email',  width: 150 }
                ],
                pager: '#EmployeeTablePager',
                width: 600,
                viewrecords: true
            });
        });</p>
<p>    </script><br />
[/html]<br />
Небольшой комментарий к этому скрипту не помешает, но чтение <a href="http://www.trirand.com/jqgridwiki">документации</a> это не отменяет.<br />
[javascript light="true"]jQuery(&#8216;#EmployeeTable&#8217;)[/javascript] &#8211; используя jQuery выбираем по ID контейнер в котором будет создана jqGrid таблица. Таблица должна иметь уникальный ID в пределах документа.<br />
[javascript light="true"]url: &#8216;/Employee/EmployeeData&#8217;[/javascript] &#8211; указываем источник получения данных, в нашем случае это метод EmployeeData контроллера EmployeeController.<br />
[javascript light="true"]datatype: &laquo;json&raquo;[/javascript] &#8211; тип данных получаемых с сервера, так же доступны форматы: xml, local, javascript, function подробнее об этом можно прочитать в разделе <a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data">Retrieving Data</a>.<br />
[javascript light="true"]mtype: &#8216;POST&#8217;[/javascript], &#8211; тип запроса отправляемого серверу, если явно не указывать то по умолчанию будет отправлен GET запрос, что приведет к ошибке:<br />
&laquo;This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.&raquo;<br />
Это можно обойти если в методе EmployeeData добавить [csharp light="true"]result.JsonRequestBehavior = JsonRequestBehavior.AllowGet;[/csharp], но это небезопасно. Phil Haack написал хорошую статью об этом <a href="http://haacked.com/archive/2009/06/25/json-hijacking.aspx">JSON Hijacking</a>.<br />
colNames &#8211; массив с заголовками колонок таблицы<br />
colModel &#8211; модель колонок, детально параметры описаны в разделе <a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:colmodel_options">ColModel API</a></p>
<p>В общем то для простой демонстрации этого достаточно. Запускаем проект.<br />
<img alt="" src="http://img197.imageshack.us/img197/8791/workscreen.png" class="alignnone" width="628" height="373" /></p>
<p>В следующей статье опишу как создавать, удалять и редактировать записи в таблице.<br />
Исходники проекта можно скачать <a href="http://sites.google.com/site/de7c9621c3fd45309efc/Home/jqGridMvcApp_vs2010.zip?attredirects=0&#038;d=1">тут</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zzlab.ru/coding/asp.net-mvc-2-i-jqgrid.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Рейтинг команды Что? Где? Когда?</title>
		<link>http://blog.zzlab.ru/proekty/rejting-komandy-chto-gde-kogda.html</link>
		<comments>http://blog.zzlab.ru/proekty/rejting-komandy-chto-gde-kogda.html#comments</comments>
		<pubDate>Wed, 28 Apr 2010 18:54:04 +0000</pubDate>
		<dc:creator>AlexandrYZ</dc:creator>
				<category><![CDATA[Проекты]]></category>
		<category><![CDATA[WPF]]></category>

		<guid isPermaLink="false">http://blog.zzlab.ru/?p=269</guid>
		<description><![CDATA[Программа позволяет строить график рейтинга команды Что? Где? Когда? (ЧГК). Информация о рейтинге берется с сайта Официальный рейтинг МАК. Ссылка для загрузки программы. Программа позволяет смотреть график рейтинга как одной команды, так и нескольких одновременно. Для работы программы требуется установленный Microsoft .NET Framework 4. Microsoft .NET Framework 4 (Standalone Installer) Microsoft .NET Framework 4 (Web [...]]]></description>
			<content:encoded><![CDATA[<p>Программа позволяет строить график рейтинга команды Что? Где? Когда? (ЧГК). Информация о рейтинге берется с сайта <a href="http://ratingnew.chgk.info">Официальный рейтинг МАК</a>.<br />
<a href="http://sites.google.com/site/de7c9621c3fd45309efc/Home/CHGKRatingv1.0.7.5.zip?attredirects=0&#038;d=1">Ссылка</a> для загрузки программы.<br />
<span id="more-269"></span><br />
Программа позволяет смотреть график рейтинга как одной команды, так и нескольких одновременно.<br />
Для работы программы требуется установленный Microsoft .NET Framework 4.<br />
<a href="http://www.microsoft.com/downloads/details.aspx?displaylang=en&#038;FamilyID=0a391abd-25c1-4fc0-919f-b21f31ab88b7">Microsoft .NET Framework 4 (Standalone Installer)</a><br />
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=9cfb2d51-5ff4-4491-b0e5-b386f32c0992&#038;displaylang=en">Microsoft .NET Framework 4 (Web Installer)</a><br />
<img alt="" src="http://img576.imageshack.us/img576/709/79342645.jpg" class="aligncenter" width="722" height="653" /></p>
<p><strong>История изменений.</strong><br />
Версия 1.0.7.5 (текущая)<br />
01.05.2010<br />
1. Добавил окно &laquo;О программе&raquo;<br />
2. Добавил иконки на кнопки.<br />
3. Добавил возможность начала поиска по нажатию Enter в любом поле поиска<br />
4. Исправил баг в поиске команд, при результате <2 команд ничего не отображалось<br />
5. Добавил информативные сообщения об отсутствии результата или наличии более 100 команд</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zzlab.ru/proekty/rejting-komandy-chto-gde-kogda.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Разработка приложения Hello MEF &#8211; Часть II – Метаданные</title>
		<link>http://blog.zzlab.ru/perevod/razrabotka-prilozheniya-hello-mef-chast-ii-%e2%80%93-metadannye-i-pochemu-lazy-xoroshaya-shtuka.html</link>
		<comments>http://blog.zzlab.ru/perevod/razrabotka-prilozheniya-hello-mef-chast-ii-%e2%80%93-metadannye-i-pochemu-lazy-xoroshaya-shtuka.html#comments</comments>
		<pubDate>Mon, 26 Apr 2010 19:10:55 +0000</pubDate>
		<dc:creator>AlexandrYZ</dc:creator>
				<category><![CDATA[Перевод]]></category>
		<category><![CDATA[Managed Extensibility Framework]]></category>
		<category><![CDATA[Silverlight]]></category>

		<guid isPermaLink="false">http://blog.zzlab.ru/?p=193</guid>
		<description><![CDATA[Еще один перевод статьи Глена Блока на тему Managed Extensibility Framework Building Hello MEF – Part II – Metadata and why being Lazy is a good thing. В первой части этой серии статей мы создали основу нашего приложения, в конце прошлой статьи оно показало один виджет. В этой статье мы покажем два виджета, sensing a [...]]]></description>
			<content:encoded><![CDATA[<p>Еще один перевод статьи Глена Блока на тему Managed Extensibility Framework <a href="http://codebetter.com/blogs/glenn.block/archive/2009/12/04/building-hello-mef-part-ii-metadata-and-why-being-lazy-is-a-good-thing.aspx">Building Hello MEF – Part II – Metadata and why being Lazy is a good thing.</a></p>
<p>В первой части этой серии статей мы создали основу нашего приложения, в конце прошлой статьи оно показало один виджет. В этой статье мы покажем два виджета, sensing a pattern here?<sup><a href="http://blog.zzlab.ru/perevod/razrabotka-prilozheniya-hello-mef-chast-ii-%e2%80%93-metadannye-i-pochemu-lazy-xoroshaya-shtuka.html#footnote_0_193" id="identifier_0_193" class="footnote-link footnote-identifier-link" title="sensing a pattern here?">1</a></sup>  <img src='http://blog.zzlab.ru/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  Мы покажем два, но поместим их в разные места приложения. Мы изучим два способа сделать это, включая очень мощный механизм MEF называемый метаданные. </p>
<p>Если вы только перешли к этой статье вы можете взять исходные коды проекта <a href="http://cid-f8b2fd72406fb218.skydrive.live.com/self.aspx/blog/Hello%20MEF/HelloMEF%5E_Part%5E_I.zip">здесь</a><br />
<span id="more-193"></span></p>
<h3>Добавление второго виджета</h3>
<p>Теперь когда мы получили инфраструктуру нашего приложения, добавление второго виджета должно  быть легко, верно? Давайте сделаем это, на этот раз мы добавим текстовое поле.<br />
Первым делом мы создадим новый пользовательский контрол с именем Widget2.<br />
<img alt="" src="http://img535.imageshack.us/img535/2800/image13cf2a04.png" class="aligncenter" width="640" height="442" /></p>
<p>Далее мы перейдем в Widget2.xaml и добавим кнопку с содержимым &laquo;Hello MEF&raquo;.</p>
<p>[cc lang="xml"]<br />
<UserControl x:Class="HelloMEF.Widget2"<br />
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"<br />
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"<br />
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"<br />
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"<br />
    mc:Ignorable="d"<br />
    d:DesignHeight="300" d:DesignWidth="400"><br />
    <Grid x:Name="LayoutRoot" Height="Auto"><br />
        <TextBox Text="Hello MEF!" TextAlignment="Center" Height="100" Width="300"<br />
    </Grid><br />
</UserControl><br />
[/cc]</p>
<p>Затем перейдем в  Widget2.xaml.cs и добавим наш экспорт.<br />
[cc lang="csharp"]<br />
using System;<br />
using System.ComponentModel.Composition;<br />
using System.Windows.Controls;<br />
using System.Windows;</p>
<p>namespace HelloMEF<br />
{<br />
    [Export(typeof(UserControl))]<br />
    public partial class Widget1 : UserControl<br />
    {<br />
        public Widget1()<br />
        {<br />
            InitializeComponent();<br />
        }<br />
    }<br />
}<br />
[/cc]</p>
<p>Все что мы сделали это создали новый контрол и добавили атрибут экспорта для MEF. Давайте запустим приложение.<br />
<img alt="" src="http://img535.imageshack.us/img535/7383/image45e65481.png" class="aligncenter" width="640" height="347" /></p>
<p>Presto! Показался и второй виджет. Никакого редактирования app.config, никакого явного кода по регистрации. Просто добавили его в проект и все. Неплохо!</p>
<h3>Добавление второго виджета куда нам захочется, и почему Lazy это хорошо</h3>
<p>Выглядит очень хорошо. Но если вы читали мою первую статью, то вы помните что мы хотим показывать виджеты в разных местах потому что у нас есть две панели на экране для виджетов. Одна из них голубая, и одна  желтая, но сейчас она невидимая. Так, что мы должны сделать? Один из вариантов это создать разные интерфейсы, ITopWidget, IBottomWidget. Тогда мы можем проверять класс если он реализует один из этих интерфейсов, мы поместим его в соответствующее место.</p>
<p>Если мы сделаем это, то наш код в MainPage будет выглядеть так:<br />
[cc lang="csharp"]<br />
public MainPage()<br />
{<br />
    InitializeComponent();<br />
    PartInitializer.SatisfyImports(this);<br />
    foreach (var widget in Widgets)<br />
    {<br />
        if (widget is ITopWidget)<br />
            TopWidgets.Items.Add(widget);<br />
        else if (widget is IBottomWidget)<br />
            BottomWidgets.Items.Add(widget);<br />
    }<br />
}<br />
[/cc]</p>
<p>Это работает, однако этот способ принуждает нас создавать новые интерфейсы каждый раз когда мы захотим модернизировать пользовательский интерфейс (UI). Например, если мы захотим добавить панель с левой стороны, то мы должны создать для этого интерфейс ILeftWidget. Другой проблемой является, то что мы создаем виджеты не реализующие ни один из наших интерфейсов. И что нам с этим делать?</p>
<h3>&laquo;Ленивая&raquo; инициализация (Lazy)</h3>
<p>Ответ на этот вопрос &#8211; Lazy. Да друзья, это первый раз когда Lazy оказалось полезным. Если вы еще не знакомы, Lazy<T> это новый тип в SL4 и FX4 BCL который позволяет вам отложить создание экземпляра класса. MEF полностью поддерживает Lazy, таким образом вы можете &laquo;лениво&raquo; (отложено) импортировать отдельные значения или коллекции. Для примера мы можем изменить наш атрибут ImportMany для использования Lazy, вставив следующий код в MainPage.cs:<br />
[cc lang="csharp"]<br />
using System;<br />
using System.Windows.Controls;<br />
using System.ComponentModel.Composition;</p>
<p>namespace HelloMEF<br />
{<br />
    public partial class MainPage : UserControl<br />
    {<br />
        public MainPage()<br />
        {<br />
            InitializeComponent();<br />
            PartInitializer.SatisfyImports(this);<br />
            foreach (var widget in Widgets)<br />
            {<br />
                TopWidgets.Items.Add(widget.Value);<br />
            }<br />
        }<br />
        [ImportMany]<br />
        public Lazy<UserControl>[] Widgets { get; set; }<br />
    }<br />
}<br />
[/cc]</p>
<p>Выше вы должны были заметить две вещи, во-первых наши виджеты теперь импортируются в массив типов Lazy<UserControl>, во-вторых цикл в котором мы добавляем виджеты. <strong>Value rather than the widget value directly</strong>.<sup><a href="http://blog.zzlab.ru/perevod/razrabotka-prilozheniya-hello-mef-chast-ii-%e2%80%93-metadannye-i-pochemu-lazy-xoroshaya-shtuka.html#footnote_1_193" id="identifier_1_193" class="footnote-link footnote-identifier-link" title="Value rather than the widget value directly">2</a></sup> Здесь вместо импорта экземпляров UserControl мы импортируем &laquo;ленивые&raquo; ссылки на наши виджеты. При первом обращении к значению, создается экземпляр UserControl к которому мы и получаем доступ к значению для добавления виджета в ItemControl TopWidget`а.</p>
<h3>Metadata</h3>
<p>Ну вот все хорошо, потому что сейчас мы отложили создание контролов до тех пор пока они нам не понадобятся. Недостатком этого является то что мы не знаем как определить какой из виджетов и куда мы должны его разместить. И это то место где метаданные смогут нам помочь. MEF поддерживает не только &laquo;ленивое&raquo; создание экземпляров, но он так же поддерживает концепцию экспорта метаданных. Это означает что экспорт MEF может дать дополнительную информацию о себе, которую импортер может использовать различными способами, будь то определение должен ли быть создан объект, или в нашем случае определить где он должен показываться на экране.<br />
Импортер может получить доступ к этой информации до того как экземпляр фактически будет активирован. Это означает что если специфический экспорт не соответствует требованиям, то он не должен быть создан.</p>
<p>Метаданные в MEF условны, это означает что вы можете использовать их как вы считаете необходимым в соответствии с потребностями вашего приложения. Использование метаданных состоит из двух частей, первая это та в которой экспортер определяет какие метаданные будут доступны для просмотра импортеру. Затем, импортер в момент импорта может получить доступ к метаданным.</p>
<h3>Определение метаданных для виджетов</h3>
<p>В нашем случае мы хотим чтобы наши виджеты предоставляли нам свое положение. Для того, чтобы сделать это, мы создадим новое перечисление (enum) с именем WidgetLocation.<br />
[cc lang="csharp"]<br />
namespace HelloMEF<br />
{<br />
    public enum WidgetLocation {Top, Bottom}<br />
}<br />
[/cc]</p>
<p>Затем, мы добавим метаданные Location в наши виджеты. Тут есть несколько способов сделать это с помощью MEF, самый простой из которых это начать с простого добавления атрибута ExportMetadata. Сначала перейдем в Widget1.xaml.cs и установим положение виджета сверху формы, как вы можете увидеть ниже. Предупреждение, ключ и значение могут быть произвольными, в моем случае это &laquo;Location&raquo; и &laquo;WidgetLocation.Top&raquo;<br />
[cc lang="csharp"]<br />
    [ExportMetadata("Location", WidgetLocation.Top)]<br />
    [Export(typeof(UserControl))]<br />
    public partial class Widget1 : UserControl<br />
    {<br />
        public Widget1()<br />
        {<br />
            InitializeComponent();<br />
        }<br />
    }<br />
[/cc]<br />
Далее мы перейдем к Widget2 и установим его положение снизу формы.<br />
[cc lang="csharp"]<br />
    [ExportMetadata("Location", WidgetLocation.Bottom)]<br />
    [Export(typeof(UserControl))]<br />
    public partial class Widget2 : UserControl<br />
    {<br />
        public Widget2()<br />
        {<br />
            InitializeComponent();<br />
        }<br />
}<br />
[/cc]<br />
Теперь мы можем перейти к импортеру.</p>
<h3>Предоставление доступа виджета к панели и почему у Lazy есть брат</h3>
<p>Теперь, когда мы определили метаданные которые хотим использовать. Мы поговорили о Lazy<T>, теперь разговор будет о его брате Lazy<T, M>. В порядке предоставления нам доступа к метаданным, MEF представляет специальный класс Lazy, который может содержать метаданные. М в данном случае это интерфейс (мы назовем его представление метаданных) который содержит только методы получения свойств, где имя свойство соответствует значению ключа в метаданных. MEF автоматически создает прокси класс который реализует этот интерфейс и может содержать все метаданные. Это очень хорошо! Вы должны посмотреть на это чтобы поверить (и понять).</p>
<p>Так что давайте просто сделаем это, чем говорить об этом.</p>
<p>Первое, мы должны создать новый интерфейс с именем IWidgetMetadata который будет содержать метаданные положения (Location).</p>
<p>[cc lang="csharp"]<br />
namespace HelloMEF<br />
{<br />
    public interface IWidgetMetadata<br />
    {<br />
        public WidgetLocation Location {get;}<br />
    }<br />
}<br />
[/cc]</p>
<p>Далее мы перейдем в MainPage.xaml.cs, и изменим наш импорт виджетов что бы использовать новые метаданные. Так же, мы должны изменить логику расположения виджетов в подходящих местах.</p>
<p>[cc lang="csharp"]<br />
using System;<br />
using System.Windows.Controls;<br />
using System.ComponentModel.Composition;</p>
<p>namespace HelloMEF<br />
{<br />
    public partial class MainPage : UserControl<br />
    {<br />
        public MainPage()<br />
        {<br />
            InitializeComponent();<br />
            PartInitializer.SatisfyImports(this);<br />
            foreach (var widget in Widgets)<br />
            {<br />
                if (widget.Metadata.Location == WidgetLocation.Top)<br />
                    TopWidgets.Items.Add(widget.Value);<br />
                else if (widget.Metadata.Location == WidgetLocation.Bottom)<br />
                    BottomWidgets.Items.Add(widget.Value);<br />
            }<br />
        }</p>
<p>        [ImportMany]<br />
        public Lazy<UserControl,IWidgetMetadata>[] Widgets { get; set; }<br />
    }<br />
}<br />
[/cc]</p>
<p>Выше вы можете увидеть что теперь тип виджетов стал Lazy<UserControl,IWidgetMetadata>. К тому же, в пределах цикла у нас есть безопасный для компиляции доступ к widget.Metadata.Location, но теперь мы никогда не сможем создать конкретный класс который реализует IWidgetMetadata, не так ли? Мы не сможем, но MEF сможет <img src='http://blog.zzlab.ru/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  Результат не содержит магических строк на стороне импортера, мы получили intellisense, рефакторинг и проверку на этапе компиляции! Так же, обратите внимание мы по прежнему должны получить доступ к значению (widget.Value), что бы получить созданный виджет. На самом деле это преимущество, хотя если мы получим виджет в другом месте, это не будет расточительно. Здесь это не имеет большой разницы, но если мы имели бы 50 виджетов это была бы уже другая история.</p>
<p>Теперь давайте запустим приложение.<br />
<img alt="" src="http://img535.imageshack.us/img535/8134/image5f00thumb5f0033da1.png" class="aligncenter" width="653" height="375" /><br />
Вуаля, мы видим наши виджеты отобразились в нужном месте, и нам не нужно делать сальто назад 1000 раз.</p>
<h4>Магические строки зло! И MEF этому ответ.</h4>
<p>Обратите внимание, выше я упоминал что мы получаем все это безопасно для компиляции и поддержку intellisense для импортера. Но что насчет экспортера? Наши видежты все еще должны указывать магические строки для ключей. Не только это, но представьте если я имею метаданные от многих элементов, которые представлены отнюдь не одной строкой для каждого элемента. Плюс ко всему я теряю понятность кода, потому что я не знаю как интуитивно  создать виджет, и какой смысл имеют метаданные. Даже если мы создадим константы для ключей мы не будем знать тип виджетов.</p>
<p>Было бы очень красиво если бы мы могли сделать это следующим образом: [ExportWidget(Location=WidgetLocation.Top)], не так ли? Нам больше не нужен будет Export, а так же все атрибуты ExportMetadata. Это сделает наш код более чистыми и менее шумным.<br />
Хорошая новость, вы можете так сделать.</p>
<h3>Пользовательские экспорты</h3>
<p>MEF позволяет вам сделать собственный экспорт, который содержит метаданные. Собственный экспорт это ваш собственный атрибут с метаданными, и он строго типизированный.</p>
<p>Давайте создадим наш новый атрибут ExportWidgetAttribute.</p>
<p>[cc lang="csharp"]<br />
using System;<br />
using System.Windows.Controls;<br />
using System.ComponentModel.Composition;</p>
<p>namespace HelloMEF<br />
{<br />
    [MetadataAttribute]<br />
    [AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]<br />
    public class ExportWidgetAttribute : ExportAttribute<br />
    {<br />
        public ExportWidgetAttribute()<br />
            :base(typeof(UserControl))<br />
        {<br />
        }</p>
<p>        public WidgetLocation Location { get; set; }<br />
    }<br />
}<br />
[/cc]</p>
<p>Если посмотрим выше, стоит отметить некоторые вещи:<br />
1. ExportWidgetAttribute наследует ExportAttribute. Это то что говорит MEF &laquo;Эй, я атрибут экспорта&raquo;.<br />
2. Базовый конструктор атрибута передается тип UserControl. Этот шаг является критическим, иначе MEF будет использовать конкретный тип на который установлен атрибут.<br />
3. Атрибут имеет установленный атрибут MetadataAttribute,  это говорит MEF, что это не только экспорт, но так же предоставляет метаданные. Теперь когда он применился, MEF будет искать каждое публичное свойство атрибута которое я добавил, и будет получать из них метаданные, ключем для которых будет имя свойства. В сущности это добавит [ExportMetadata("Location",…)] с значением присвоенным свойству.<br />
4. Атрибут имеет установленный атрибут [AttributeUsage], указывающий допустимые цели для него, в данном случае классы и так что AllowMultiple = false. Если мы не сделаем это, тогда MEF будет принимать множество наборов метаданных которые существуют и будет возвращать метаданные как массив.</p>
<p>Теперь мы можем изменить каждый из наших виджетов для использования нового атрибута.</p>
<p>Первый Widget1.xaml.cs<br />
[cc lang="csharp"]<br />
using System.Windows.Controls;</p>
<p>namespace HelloMEF<br />
{<br />
    [ExportWidget(Location=WidgetLocation.Top)]<br />
    public partial class Widget1 : UserControl<br />
    {<br />
        public Widget1()<br />
        {<br />
            InitializeComponent();<br />
        }<br />
    }<br />
}<br />
[/cc]</p>
<p>И затем Widget2.xaml.cs</p>
<p>[cc lang="csharp"]<br />
using System.Windows.Controls;</p>
<p>namespace HelloMEF<br />
{<br />
    [ExportWidget(Location=WidgetLocation.Bottom)]<br />
    public partial class Widget2 : UserControl<br />
    {<br />
        public Widget2()<br />
        {<br />
            InitializeComponent();<br />
        }<br />
    }<br />
}<br />
[/cc]</p>
<p>Наш собственный атрибут выглядит очень хорошо. Не надо больше указывать контракт, нет больше лишних метаданных, и выглядит очень красиво и компактно. Так же стоит заметить, что наш раздел using включает System.ComponentModel.Composition. Это означает что наши потребители могут использовать MEF даже незнаю что они используют его. Мы только посылаем им наши атрибуты и интерфейсы, и они могут начинать.</p>
<p>Нажмите магическую кнопку Run и вот что вы получите.<br />
<img alt="" src="http://img535.imageshack.us/img535/8134/image5f00thumb5f0033da1.png" class="aligncenter" width="653" height="375" /></p>
<p>Вопросы? <img src='http://blog.zzlab.ru/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Краткое изложение</p>
<p>В этой статье мы изучили как можем использовать метаданные и Lazy что бы делать красивые вещи с помощью MEF. Мы можем снабжать экспорт информацией, которую импортеры могут использовать чтобы определить могут ли они использовать фрагменты, и как они могут сделать это (например поместить фрагмент в верхнее положение). Мы так же узнали, как можно создать собственный атрибут экспорта.</p>
<p>Что дальше?</p>
<p>В следующей статье мы рассмотрим как разделить наши приложения на несколько XAP файлов и использовать MEF для загрузки их по требованию. Мы так же узнаем еще несколько аспектов MEF, которые не столь очевидны. </p>
<p>There’s much more to come after that, the series is shaping up!</p>
<ol class="footnotes"><li id="footnote_0_193" class="footnote">sensing a pattern here?</li><li id="footnote_1_193" class="footnote">Value rather than the widget value directly</li></ol>]]></content:encoded>
			<wfw:commentRss>http://blog.zzlab.ru/perevod/razrabotka-prilozheniya-hello-mef-chast-ii-%e2%80%93-metadannye-i-pochemu-lazy-xoroshaya-shtuka.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Материалы по Command Query Responsibility Segregation (CQRS)</title>
		<link>http://blog.zzlab.ru/links/materialy-po-command-query-responsibility-segregation.html</link>
		<comments>http://blog.zzlab.ru/links/materialy-po-command-query-responsibility-segregation.html#comments</comments>
		<pubDate>Thu, 08 Apr 2010 22:50:30 +0000</pubDate>
		<dc:creator>AlexandrYZ</dc:creator>
				<category><![CDATA[links]]></category>
		<category><![CDATA[CQRS]]></category>

		<guid isPermaLink="false">http://blog.zzlab.ru/?p=197</guid>
		<description><![CDATA[Статьи CQRS, Task Based UIs, Event Sourcing agh! Хорошая статья с обзором элементов архитектуры Greg Young on DDD and CQRS Конспект лекций по DDD и CQRS Clarified CQRS PDF &#8211; Детальный обзор элементов и процессов архитектуры решения CQRS à la Greg Young и CQRS – The Domain Events &#8211; Разбор с примерами кода от Mark [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Статьи</strong><br />
<a href="http://codebetter.com/blogs/gregyoung/archive/2010/02/16/cqrs-task-based-uis-event-sourcing-agh.aspx">CQRS, Task Based UIs, Event Sourcing agh!</a> Хорошая статья с обзором элементов архитектуры<br />
<a href="http://www.agilification.com/post/Greg-Young-on-DDD-and-CQRS.aspx">Greg Young on DDD and CQRS</a> Конспект лекций по DDD и CQRS<br />
<a href="http://www.udidahan.com/2009/12/09/clarified-cqrs/">Clarified CQRS</a> <a href="http://www.udidahan.com/wp-content/uploads/Clarified_CQRS.pdf">PDF</a> &#8211; Детальный обзор элементов и процессов архитектуры решения<br />
<a href="http://elegantcode.com/2009/11/11/cqrs-la-greg-young/">CQRS à la Greg Young</a> и <a href="http://elegantcode.com/2009/11/20/cqrs-the-domain-events/">CQRS – The Domain Events</a> &#8211; Разбор с примерами кода от Mark Nijhof автора фреймворка Fohjin<br />
<a href="http://abdullin.com/journal/2010/3/23/dddd-cqrs-and-other-enterprise-development-buzz-words.html">DDDD, CQRS and Other Enterprise Development Buzz-words</a> &#8211; Статья Рината Абдуллина о применении DDDD и CQRS в разработке приложений.<br />
<span id="more-197"></span></p>
<p><a href="http://www.infoq.com/articles/cqrs_with_axon_framework">Обсуждение </a> Axonframework CQRS Framework с его разработчиком в InfoQ<br />
<a href="http://twitter.com/#search?q=CQRS">лента твиттов</a> о CQRS<br />
<a href="http://groups.google.com/group/dddcqrs/">Google группа</a> Discussions about DDD, CQRS, and Event Sourcing </p>
<p><strong>Видео и слайды</strong><br />
<a href="http://www.infoq.com/presentations/greg-young-unshackle-qcon08">Выступление</a> Greg Young на QCon<br />
<a href="http://skillsmatter.com/podcast/open-source-dot-net/udi-dahan-command-query-responsibility-segregation/rl-311">Видео и слайды</a> выступления Udi Dahan на встрече .NET User Group в Лондоне<br />
<a href="http://jonathan-oliver.blogspot.com/2010/03/cqrs-session-video-utah-code-camp-2010.html">Видео</a> выступления Джонатана Оливера на Utah Code Camp<br />
<a href="http://vimeo.com/9573973">Введение для новичков</a> от Джонатана Оливера</p>
<p><strong>Примеры приложений</strong><br />
<a href="http://myshop.codeplex.com/">Тестовое приложение</a> использующее DDDD и Ncqrs Framework<br />
<a href="http://github.com/MarkNijhof/Fohjin/tree/master/Fohjin.DDD.Example/">Пример</a> использования фреймворка Fohjin</p>
<p><strong>Фреймворки CQRS</strong><br />
<strong>.NET</strong><br />
<a href="http://ncqrs.codeplex.com/">NCQRS Framework</a><br />
<a href="http://agrcqrs.codeplex.com">Agr.CQRS</a><br />
<a href="http://github.com/MarkNijhof/Fohjin">Fohjin</a></p>
<p><strong>Java</strong><br />
<a href="http://code.google.com/p/axonframework/">Axon Framework</a></p>
<p>В довесок ко всему этому создал с помощью Yahoo pipes <a href="http://pipes.yahoo.com/pipes/pipe.run?_id=2529e24136532b266b4ba9010a6e3685&amp;_render=rss" target="_self">агрегированный RSS по CQRS</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zzlab.ru/links/materialy-po-command-query-responsibility-segregation.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Создание OData API для StackOverflow включая XML и JSON за 30 минут</title>
		<link>http://blog.zzlab.ru/perevod/sozdanie-odata-api-dlya-stackoverflow-vklyuchaya-xml-i-json-za-30-minut.html</link>
		<comments>http://blog.zzlab.ru/perevod/sozdanie-odata-api-dlya-stackoverflow-vklyuchaya-xml-i-json-za-30-minut.html#comments</comments>
		<pubDate>Mon, 05 Apr 2010 18:02:58 +0000</pubDate>
		<dc:creator>AlexandrYZ</dc:creator>
				<category><![CDATA[Перевод]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[OData]]></category>

		<guid isPermaLink="false">http://blog.zzlab.ru/?p=145</guid>
		<description><![CDATA[Автор: Скотт Хансельман Статья: Creating an OData API for StackOverflow including XML and JSON in 30 minutes Прошлой ночью я отправил письмо Jeff Atwood в котором была одна строка. &#171;Ты должен сделать Stackoverflow API используя OData&#187;. Then I realized that, as Linus says, Talk is Cheap, Show me the Code. Я отвел под это весь [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Автор:</strong> Скотт Хансельман<br />
<strong>Статья:</strong> <a href="http://www.hanselman.com/blog/CreatingAnODataAPIForStackOverflowIncludingXMLAndJSONIn30Minutes.aspx">Creating an OData API for StackOverflow including XML and JSON in 30 minutes</a></p>
<p>Прошлой ночью я отправил письмо Jeff Atwood в котором была одна строка. &laquo;Ты должен сделать Stackoverflow API используя OData&raquo;. <em>Then I realized that, as Linus says, Talk is Cheap, Show me the Code.</em> Я отвел под это весь 12 часовой полет. Но к сожалению это заняло 30 минут, так что остальное время я смотрел фильмы.</p>
<p>Вы можете следить за процессом и делать это самостоятельно, если хотите.<br />
<span id="more-145"></span></p>
<h3>Подготовка</h3>
<p>Перед моим полетом я сделал две вещи.<br />
Во-первых, я скачал утилиту импорта <a href="http://samsaffron.com/">Сэма Саффрона</a> <a href="http://github.com/SamSaffron/So-Slow">&laquo;So Slow&raquo;</a> Stackoverflow SQL Server. Это маленькая утилита Сэма, которая берет 3х Гб файл XML ежемесячного дампа Stackoverflow и импортирует его в SQL Server.</p>
<p>Во-вторых, я скачал <a href="http://blog.stackoverflow.com/category/cc-wiki-dump/">ежемесячный дамп Stackoverflow</a>. Я скачал его с помощью <a href="http://www.utorrent.com/">uTorrent </a> и распаковал его во время подготовки к полету.</p>
<p><strong>Импорт в SQL Server</strong></p>
<p>Я переключился в Visual Studio 2010 (хотя мог бы использовать 2008, но мне понравились улучшения в Entity Framework в 2010, которые позволяют делать работу проще). Правым кликом мыши на узле Data Connections в Server Explorer я создаю базу данных в SQL Express с именем, гмм, &laquo;Stackoverflow&raquo;.</p>
<p><img alt="" src="http://img511.imageshack.us/img511/8777/createnewsqlserverdatab.png" class="aligncenter" width="426" height="443" /></p>
<p>Далее, я открыл в Visual Studio файл Сэма <a href="http://github.com/SamSaffron/So-Slow/blob/master/RecreateDB.sql">RecreateDB.sql</a> из его проекта (не пользуюсь SQL Server Management Studio, если это возможно) подключился к экземпляру &laquo;.\SQLEXPRESS&raquo;, выбрал новую базу StackOverflow и нажал &laquo;Execute&raquo;.<br />
<img alt="" src="http://img144.imageshack.us/img144/1707/image3eq.png" class="aligncenter" width="550" height="237" /></p>
<p>One nit<sup><a href="http://blog.zzlab.ru/perevod/sozdanie-odata-api-dlya-stackoverflow-vklyuchaya-xml-i-json-za-30-minut.html#footnote_0_145" id="identifier_0_145" class="footnote-link footnote-identifier-link" title=" One nit ">1</a></sup> по поводу SQL файла Сэма, он красиво создает таблицы из дампа, но он не содержит информации о ссылочной целострости. Таблицы никак не связаны с другими и они не имеют  <em>cardinality setup</em><sup><a href="http://blog.zzlab.ru/perevod/sozdanie-odata-api-dlya-stackoverflow-vklyuchaya-xml-i-json-za-30-minut.html#footnote_1_145" id="identifier_1_145" class="footnote-link footnote-identifier-link" title=" cardinality setup">2</a></sup>. Я перезаписал клетки головного мозга которые знали что с этим делать без <s>Google</s> и Bing, поэтому я решил вернуться к этому позже. И вы тоже.</p>
<p>Далее, я открыл приложение Сэма SoSlow и запустил его. Это мелкое красивое приложение с интуитивным интерфейсом,  которое работает так как и обещалось. Как по мне, я бы, наверное назвал кнопку &laquo;Import&raquo; чем то вроде &laquo;Release the Hounds!&raquo;.<br />
<img alt="" src="http://img22.imageshack.us/img22/9083/soslowstackoverflowdata.png" class="aligncenter" width="501" height="324" /><br />
На данный момент я имею базу данных с несколькими сотнями мегабайт публичных данных Stackoverflow.<br />
<img alt="" src="http://img408.imageshack.us/img408/4080/image5iu.png" class="aligncenter" width="194" height="217" /></p>
<h3>Создание Веб проекта и Модели сущностей</h3>
<p>Итак, я выбрал в Visual Studio <strong> File | New Project | ASP.NET Web Application</strong>. Затем, я правым кликом на исходном проекте выбрал <strong>Add | New Item, then clicked Data, then ADO.NET Entity Data Model</strong>.<br />
<img alt="" src="http://img704.imageshack.us/img704/166/addnewitemstackoveflow3.png" class="aligncenter" width="553" height="460" /><br />
<em>Что делать с этим, Хансельман? Вы знаете что Stackoverflow использует LINQ to SQL? Вы наконец продались и скрытно пытаетесь заставить нас использовать Entity Framework с помощью этого замаскированного сообщения?</em></p>
<p>Нет. Я использую EF по нескольким причинам. Во-первых, в Visual Studio 2010 он настолько быстрый (и во время выполнения (runtime) и во время проектирования (design time) ), что я больше не замечаю разницы. Во-вторых, я знал что отсутствие ссылочной целостности приведет к проблеме (помните, я говорил об этом ранее?) и так как маппинг в LINQ to SQL 1:1<sup><a href="http://blog.zzlab.ru/perevod/sozdanie-odata-api-dlya-stackoverflow-vklyuchaya-xml-i-json-za-30-minut.html#footnote_2_145" id="identifier_2_145" class="footnote-link footnote-identifier-link" title=" LINQ to SQL is 1:1 physical/logical ">3</a></sup>, а EF предлагает гибкий маппинг, я понял что будет легче сделать это с EF. В-третьих, &laquo;WCF Data Services&raquo; (сервисы данных ранее известные как ADO.NET Data Services или &laquo;Astoria&raquo;) отлично маппяться на EF.</p>
<p>Я назвал файл StackOverflowEntities.edmx и нажал &laquo;Update Model from Database&raquo; и для начала выбрал все таблицы. Когда открыл дизайнер, я заметил что нет линий связи, только таблицы.<br />
<img alt="" src="http://img130.imageshack.us/img130/1192/image7j.png" class="aligncenter" width="767" height="801" /><br />
Итак, я оказался прав насчет того что между таблицами в SQL Server небыло связей. Я бы подключился к SQL Server`у для добавления этих связей, но подумал что могу добавить их здесь так же хорошо как и другие вещи которые сделают нашу работу с OData Service более приятной.</p>
<p>Я начал просматривать таблицу сообщений (Posts) и представлять что если я смотрю на сообщения, то захочу видеть комментарии (Comments). Поэтому я щелкнул правой кнопкой мыши на таблице Posts и выбрал <strong>Add | Association</strong>. Потратив секунду на понимание появившегося диалога (я никогда не видел его ранее), я понял, что он делает, то о чем написано в предложении снизу, поэтому я сосредоточился чтобы это предложение было верным. В данном случае, &laquo;<em>Post can have * (Many) instances of Comment. Use Post.Comments to access the Comment instances. Comment can have 1 (One) instance of Post. Use Comment.Post to access the Post instance.</em><sup><a href="http://blog.zzlab.ru/perevod/sozdanie-odata-api-dlya-stackoverflow-vklyuchaya-xml-i-json-za-30-minut.html#footnote_3_145" id="identifier_3_145" class="footnote-link footnote-identifier-link" title=" Сообщение может иметь много  комментариев. Используйте Post.Comments для доступа к коментариям. Коментарий может иметь один экземпляр Сообщения. Используйте Comment.Post для доступа к экземпляру Сообщения ">4</a></sup> то что я хотел. Также, у меня были свойства с внешними ключами, поэтому я отключил их и нажал кнопку OK.<br />
<img alt="" src="http://img20.imageshack.us/img20/5900/addassociation23.png" class="aligncenter" width="520" height="577" /><br />
Это привело меня в дизайнер. Обратите внимание на линию с текстом <strong>1..*</strong> и на свойства навигации: Comments в классе Post и Post в классе Comment. Все это появилось из прошлого диалога.<br />
<img alt="" src="http://img144.imageshack.us/img144/346/image9z.png" class="aligncenter" width="375" height="526" /><br />
Потом, после того как я понял что у меня нет внешнего ключа в виде автоматического свойства, и я должен замаппить его сам. Дважды щелкнул на линию ассоциации. Выбрал класс Post как главный элемент (Principal) и связал его свойство Id с свойством PostId класса Comments.<br />
<img alt="" src="http://img708.imageshack.us/img708/4091/referentialconstraint33.png" class="aligncenter" width="566" height="338" /><br />
Поняв это, я просто создал все очевидные связи для таблиц, которые видны на диаграмме, где Users (Пользователи) имеют Badges (идентификационные данные), Posts (сообщения) имеют Votes (голоса), и так далее.<br />
<img alt="" src="http://img194.imageshack.us/img194/6246/imagethumb4f.png" class="aligncenter" width="550" height="640" /><br />
Теперь, давайте создадим сервис.</p>
<h3>Создание OData сервиса</h3>
<p>Нажав правой кнопкой мыши на проект в Solution Explorer выбрал <strong>Add | New Item | Web | WCF Data Service</strong>. Я назвал его Service.svc. Все что вам необходимо для создания полноценного работающего OData сервиса это добавить класс между угловыми скобками (DataService) и добавить код одну строку config.EntitySetAccessRule. Вот мой исходный класс. Я добавил SetEntitySetPageSize, после того как я попытался получить все сообщения. <img src='http://blog.zzlab.ru/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /><br />
[CSharp]<br />
public class Service : DataService<br />
{<br />
    // Этот метод вызывается только один раз для инициализации всех политик сервиса.<br />
    public static void InitializeService(DataServiceConfiguration config)<br />
    {<br />
        config.SetEntitySetAccessRule(&laquo;*&raquo;, EntitySetRights.AllRead);</p>
<p>        //Устанавливаем приемлемый размер страницы<br />
        config.SetEntitySetPageSize(&laquo;*&raquo;, 25);</p>
<p>        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;<br />
    }<br />
}<br />
[/CSharp]<br />
Расширяя этот класс, я добавил кеширование, и пример операции сервиса, так же как <a href="http://code.msdn.microsoft.com/DataServicesJSONP">WCF Data Services support for JSONP</a>. Обратите внимание что операция сервиса это лишь пример чтобы показать что StackOverflow может иметь полный контроль<sup><a href="http://blog.zzlab.ru/perevod/sozdanie-odata-api-dlya-stackoverflow-vklyuchaya-xml-i-json-za-30-minut.html#footnote_4_145" id="identifier_4_145" class="footnote-link footnote-identifier-link" title=" to show StackOverflow that they CAN have total control ">5</a></sup>. Использование OData не означает установить флажок и вывести свою базу данных  в сеть. Это подразумевает выделение ограниченного количества сущностей с большой или малой детализацией, так как нравится вам. Вы можете перехватывать запросы, создавать настраиваемые поведение (например такое как JSONP), создавая настраиваемые операции сервиса (они могут содержать строки запросов, конечно же), и многое другое. OData нативно поддерживает формат JSON, и будет возвращать JSON если заголовок установлен, но я добавил поддержку JSONP что бы позволить междоменное использование сервиса, а так же форматировать параметры в URL, потому что так понятнее и легче для человека.<br />
[CSharp]<br />
namespace StackOveflow<br />
{<br />
    [JSONPSupportBehavior]<br />
    public class Service : DataService<br />
    {<br />
        // Этот метод будет вызван один раз для инициализации всех политик сервиса.<br />
        public static void InitializeService(DataServiceConfiguration config)<br />
        {<br />
            config.SetEntitySetAccessRule(&laquo;*&raquo;, EntitySetRights.AllRead);</p>
<p>            // Здесь могло бы быть &laquo;*&raquo; и так же ReadSingle, и тд.<br />
            config.SetServiceOperationAccessRule(&laquo;GetPopularPosts&raquo;, ServiceOperationRights.AllRead);</p>
<p>            // Установим разумный размер страницы<br />
            config.SetEntitySetPageSize(&laquo;*&raquo;, 25);</p>
<p>            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;<br />
        }</p>
<p>        protected override void OnStartProcessingRequest(ProcessRequestArgs args)<br />
        {<br />
            base.OnStartProcessingRequest(args);<br />
            // Минутный кеш, на основе строки запроса<br />
            HttpContext context = HttpContext.Current;<br />
            HttpCachePolicy c = HttpContext.Current.Response.Cache;<br />
            c.SetCacheability(HttpCacheability.ServerAndPrivate);<br />
            c.SetExpires(HttpContext.Current.Timestamp.AddSeconds(60));<br />
            c.VaryByHeaders["Accept"] = true;<br />
            c.VaryByHeaders["Accept-Charset"] = true;<br />
            c.VaryByHeaders["Accept-Encoding"] = true;<br />
            c.VaryByParams["*"] = true;<br />
        }</p>
<p>        [WebGet]<br />
        public IQueryable GetPopularPosts()<br />
        {<br />
            var popularPosts = (from p in this.CurrentDataSource.Posts<br />
                               orderby p.ViewCount<br />
                               select p).Take(20);</p>
<p>            return popularPosts;<br />
        }<br />
    }<br />
}<br />
[/CSharp]<br />
Но что это нам дало?</p>
<h3>Доступ к данным StackOverflow через OData</h3>
<p>Хорошо, если я открою <a href="http://mysite/service.svc">http://mysite/service.svc</a> Я увижу этот сервис. Обратите внимание на относительные ссылки (HREFs).<br />
<img alt="" src="http://img402.imageshack.us/img402/526/image13mg.png" class="aligncenter" width="432" height="529" /><br />
Если я открою <a href="http://173.46.159.103/service.svc/Posts">http://173.46.159.103/service.svc/Posts</a> Я получу сообщения (постраничные, как я упоминал). Посмотрите на это более детально. Обратили внимание на содержимое тегов  до содержимого? Обратили внимание на атрибут href с относительной ссылкой href=&raquo;Posts(23)&raquo;?<br />
<img alt="" src="http://img10.imageshack.us/img10/6909/httplocalhost42071servi.png" class="aligncenter" width="869" height="814" /><br />
Помните все те связи которые Я настроил ранее? Теперь Я могу посмотреть:</p>
<ul>
<li>Получить сообщение: <a href="http://173.46.159.103/service.svc/Posts(23)/">http://173.46.159.103/service.svc/Posts(23)/</a>
 </li>
<li>
Получить голосование за данное сообщение: <a href="http://173.46.159.103/service.svc/Posts(23)/Votes">http://173.46.159.103/service.svc/Posts(23)/Votes</a><br />
/li&gt;</p>
<li>
Получить сообщение и все комментарии одновременно: <a href="http://173.46.159.103/service.svc/Posts(23)?$expand=Comments">http://173.46.159.103/service.svc/Posts(23)?$expand=Comments</a>
        </li>
<li>
Я даже могу перейти к просмотру информации о пользователе прокомментировавшего сообщение: <a href="http://173.46.159.103/service.svc/Posts(23)/Comments(55049)/User">http://173.46.159.103/service.svc/Posts(23)/Comments(55049)/User</a>
</li>
</ul>
<p>Но это все только навигация. Я также могу делать запросы. Скачайте <a href="http://www.linqpad.net/Beta.aspx">LINQPad Beta for .NET 4</a>. <strong><em>Peep this.</em></strong> Нажмите на <strong>Add Connection</strong>, и укажите мой маленький тестовый сервер Orcsweb.</p>
<p><em>Оговорка: Это тестовый сервер Orcsweb который может остановиться в любой момент. Так же отметим, что вы можете зарегистрироваться на <a href="http://www.vs2010host.com/">http://www.vs2010host.com/</a> и получить свой сервер или найти ASP.NET хостинг или разместить ваш OData сервис в облаке.<br />
</em><br />
Я ввел это и нажал OK.<br />
<img alt="" src="http://img444.imageshack.us/img444/203/linqpadconnection23.png" class="aligncenter" width="475" height="393" /><br />
Теперь я пишу LINQ запросы для StackOverflow через сеть. Нет Twitter подобного API, JSON так или иначе может сделать это. Данные StackOverflow предназначены для OData. Чем больше я вожусь с ними тем больше понимаю что это верно.<br />
<img alt="" src="http://img26.imageshack.us/img26/7470/linqpad4thumb.png" class="aligncenter" width="550" height="421" /><br />
На самом деле этот LINQ запрос можно преобразовать в URL. Кроме того для этого вам не нужен .NET, только HTTP:<br />
<a href="http://173.46.159.103/service.svc/Posts%28%29?$filter=substringof%28%27SQL%27,Title%29%20or%20substringof%28%27%3Csql-server%3E%27,Tags%29">http://173.46.159.103/service.svc/Posts()?$filter=substringof(&#8216;SQL&#8217;,Title) or substringof(&#8216;&lt;sql-server&gt;&#8217;,Tags)</a><br />
Попробуйте то же самое с заголовком:  application/json или просто добавьте к запросу параметр <strong>$format=json</strong><br />
<a href="http://173.46.159.103/service.svc/Posts%28%29?$filter=substringof%28%27SQL%27,Title%29%20or%20substringof%28%27%3Csql-server%3E%27,Tags%29">http://173.46.159.103/service.svc/Posts()?$filter=substringof(&#8216;SQL&#8217;,Title) or substringof(&#8216;&lt;sql-server&gt;&#8217;,Tags)$format=json</a><br />
Это автоматически возвратит данные в формате JSON или Atom, если вы этого захотите.<br />
Если у вас есть Visual Studio, быстро создайте консольное приложение. <strong>File | New Console App</strong>, потом правым щелчком мыши добавьте Add Service Reference. Добавьте туда <a href="http://173.46.159.103/service.svc">http://173.46.159.103/service.svc</a> и нажмите кнопку OK.<br />
<img alt="" src="http://img243.imageshack.us/img243/3899/addservicereferencethum.png" class="aligncenter" width="550" height="450" /><br />
Попробуйте что нибудь подобное. Я добавил в комментарии URI, что бы показать вам что тут нет обмана.<br />
[CSharp]<br />
class Program<br />
{<br />
    static void Main(string[] args)<br />
    {<br />
        StackOverflowEntities so = new StackOverflowEntities(new Uri(&laquo;http://173.46.159.103/service.svc&raquo;));</p>
<p>        //{http://173.46.159.103/service.svc/Users()?$filter=substringof(&#8216;Hanselman&#8217;,DisplayName)}<br />
        var user = from u in so.Users<br />
            where u.DisplayName.Contains(&laquo;Hanselman&raquo;)<br />
            select u;</p>
<p>        //{http://173.46.159.103/service.svc/Posts()?$filter=OwnerUserId eq 209}<br />
        var posts =<br />
            from p in so.Posts<br />
            where p.OwnerUserId == user.Single().Id<br />
            select p;</p>
<p>        foreach (Post p in posts)<br />
        {<br />
            Console.WriteLine(p.Body);<br />
        }</p>
<p>        Console.ReadLine();<br />
    }<br />
}<br />
[/CSharp]<br />
Я мог бы продолжить с примерами на PHP, JavaScript, и так далее, но поставлю на этом<br />
точку.</p>
<h3>Заключение</h3>
<p>StackOverflow всегда  был невероятно открыт и щедрый на свои данные. Предположу что OData предложит нам гораздо более гибкий доступ к своим данным чем настраиваемый XML и/или JSON API которые должны быть постоянно корректироваться.<br />
С проприетарным API, люди кинуться создавать клиентов для StackOverflow на разные языках, но эта работа уже сделана с помощью <strong>OData</strong> включая библиотеки для iPhone и Java. Вот <a href="http://www.odata.org/developers/odata-sdk">растущий список OData SDK</a> которые могут быть использованы для взаимодействия с подобными сервисами. Я могу загрузить данные в Excel с помощью <a href="http://173.46.159.103/service.svc">PowerPivot</a>, если мне это понравится.</p>
<p>Так же, сервис может быть полностью расширен за пределы этого простого GET запроса. Вы можете полностью реализовать CRUD операции с помощью OData и оно ни коим образом не будет связана с .NET. Может быть TweetDeck для StackOverflow?</p>
<p>Я надеюсь мы воодушевим StackOverflow потратить больше чем 30 минут, которые я потратил на это, и сделать достойный OData сервис для своих данных, чем тратить время на создание специализированного API. Я добровольно помогу в этом. Если нет, то мы можем сделать это сами с дампом их данных (еженедельным, надеюсь они могут это ускорить?) и облачным экземпляром.</p>
<p>Вопросы?</p>
<ol class="footnotes"><li id="footnote_0_145" class="footnote"> One nit </li><li id="footnote_1_145" class="footnote"> cardinality setup</li><li id="footnote_2_145" class="footnote"> LINQ to SQL is 1:1 physical/logical </li><li id="footnote_3_145" class="footnote"> Сообщение может иметь много  комментариев. Используйте Post.Comments для доступа к коментариям. Коментарий может иметь один экземпляр Сообщения. Используйте Comment.Post для доступа к экземпляру Сообщения </li><li id="footnote_4_145" class="footnote"> to show StackOverflow that they CAN have total control </li></ol>]]></content:encoded>
			<wfw:commentRss>http://blog.zzlab.ru/perevod/sozdanie-odata-api-dlya-stackoverflow-vklyuchaya-xml-i-json-za-30-minut.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>JSON serializer Generic extension</title>
		<link>http://blog.zzlab.ru/coding/json-generic-extension.html</link>
		<comments>http://blog.zzlab.ru/coding/json-generic-extension.html#comments</comments>
		<pubDate>Thu, 25 Mar 2010 21:00:19 +0000</pubDate>
		<dc:creator>AlexandrYZ</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Generics]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[Silverlight]]></category>

		<guid isPermaLink="false">http://blog.zzlab.ru/?p=115</guid>
		<description><![CDATA[Работая над своим мелким проектом на Silverlight 4, пришла в голову мысль скрестить Extension Methods и Generics. Получилось замечательно. Ведь на самом деле, зачем писать метод расширения для конкретного объекта если можно это сделать для Generic классов. В этом случае мы получаем расширенные методы для всего множества имеющихся классов. JsonExtension.cs [CSharp] using System.IO; using System.Runtime.Serialization.Json; [...]]]></description>
			<content:encoded><![CDATA[<p>Работая над своим мелким проектом на Silverlight 4, пришла в голову мысль скрестить <a href="http://msdn.microsoft.com/ru-ru/library/bb383977.aspx">Extension Methods</a> и <a href="http://msdn.microsoft.com/en-us/library/512aeb7t%28VS.80%29.aspx">Generics</a>.<br />
Получилось замечательно.</p>
<p><span id="more-115"></span></p>
<p>Ведь на самом деле, зачем писать метод расширения для конкретного объекта если можно это сделать для Generic классов. В этом случае мы получаем расширенные методы для всего множества имеющихся классов.</p>
<p><strong>JsonExtension.cs</strong><br />
[CSharp]<br />
using System.IO;<br />
using System.Runtime.Serialization.Json;<br />
using System.Text;</p>
<p>namespace JsonGenericExtExample<br />
{<br />
    public static class JsonExtension<br />
    {<br />
        ///<br />
<summary>
        /// Сериализовать объект в Json строку<br />
        /// </summary>
<p>        ///
<param name="data">Объект</param>
        /// <returns>строка содержащая сериализованный обеъкт в формате Json</returns><br />
public static string GetJson<T>(this T data) where T : class<br />
        {<br />
            string result;<br />
            using (var stream = new MemoryStream())<br />
            {<br />
                var serializer = new DataContractJsonSerializer(typeof(T));<br />
                serializer.WriteObject(stream, data);<br />
                var reader = new StreamReader(stream);<br />
                stream.Position = 0;<br />
                result = reader.ReadToEnd();<br />
            }<br />
            return result;<br />
        }</p>
<p>        ///<br />
<summary>
        /// Десериализация объекта из Json строки<br />
        /// </summary>
<p>        /// <typeparam name="T">Тип результирующего объекта</typeparam><br />
        ///
<param name="data">Json строка</param>
        /// <returns>Десериализованный объект</returns><br />
        public static T Get<T>(this string data) where T : class<br />
        {<br />
            var deserializer = new DataContractJsonSerializer(typeof(T));</p>
<p>            using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(data)))<br />
            {<br />
                stream.Position = 0;<br />
                return deserializer.ReadObject(stream) as T;<br />
            }<br />
        }<br />
    }<br />
}</p>
<p>[/CSharp]</p>
<p>Для использования достаточно вызвать созданный ранее метод.<br />
[CSharp]<br />
// создаем тестовый экземпляр типом User<br />
var CurrentUser = new User<br />
                       {<br />
                           FirstName = &laquo;Карим&raquo;,<br />
                           LastName = &laquo;Офигенов&raquo;,<br />
                           Age = 124<br />
                       };<br />
// вызываем extension метод у экземпляра для сериализации в JSON<br />
string jsonString = CurrentUser.GetJson();</p>
<p>// Десериализуем<br />
var DeserializedUser = jsonString.Replace(&laquo;Карим&raquo;,&raquo;Макар&raquo;).Get<User>();<br />
[/CSharp]<br />
Использование этих методов очень простое, мало того они теперь будут у всех типов объектов в проекте.</p>
<p><strong>Скриншот тестового приложения</strong><br />
<img alt="" src="http://img406.imageshack.us/img406/8800/jsongenericextensionscr.jpg" class="aligncenter" width="578" height="190" /></p>
<p><a href="https://sites.google.com/site/de7c9621c3fd45309efc/Home/JsonGenericExtExample.zip?attredirects=0&amp;d=1">Исходники</a> проекта</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zzlab.ru/coding/json-generic-extension.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Взаимодействие Silverlight приложения с PHP</title>
		<link>http://blog.zzlab.ru/coding/vzaimodejstvie-silverlight-prilozheniya-s-php.html</link>
		<comments>http://blog.zzlab.ru/coding/vzaimodejstvie-silverlight-prilozheniya-s-php.html#comments</comments>
		<pubDate>Sun, 21 Mar 2010 06:02:45 +0000</pubDate>
		<dc:creator>AlexandrYZ</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Silverlight]]></category>

		<guid isPermaLink="false">http://blog.zzlab.ru/?p=75</guid>
		<description><![CDATA[Достать нынче дешевый Windows хостинг легко и дорого, а создавать Silverlight клиент-серверные приложения хочется. Собственно,  тем и занимаюсь последнее время. Так как Linux хостинг у меня уже есть, решил его использовать для этих целей. Итак, опишем задачу. Silverlight приложение позволяет вводить текст и отсылать его на сервер, где эти данные обрабатываются PHP скриптом &#8211; вычисляется [...]]]></description>
			<content:encoded><![CDATA[<p>Достать нынче дешевый Windows хостинг легко и дорого, а создавать Silverlight клиент-серверные приложения хочется. Собственно,  тем и занимаюсь последнее время. Так как Linux хостинг у меня уже есть, решил его использовать для этих целей.</p>
<p>Итак, опишем задачу. Silverlight приложение позволяет вводить текст и отсылать его на сервер, где эти данные обрабатываются PHP скриптом &#8211; вычисляется MD5 хеш, который отсылается клиенту, полученные данные отображаются в ТеxtBox.</p>
<p><em>Примечание: В  Silverlight 4 RC функций по вычислению MD5 хеша все еще нет, хотя при непродолжительном поиске можно найти готовые классы. </em><br />
<span id="more-75"></span></p>
<h3>Создание клиента</h3>
<p>Для начала создадим стандартный проект  Silverlight Application. Добавим  в главную и единственную форму: TextBox для ввода отсылаемых данных, кнопку, которая инициирует отсылку и TextBlock который и будет отображать ответ, открываем MainPage.xaml и добавляем следующий текст:</p>
<p>[XML]<br />
<UserControl x:Class="SilverlightClient.MainPage"<br />
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"<br />
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"<br />
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"<br />
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"<br />
    mc:Ignorable="d"<br />
    d:DesignHeight="300" d:DesignWidth="400"></p>
<p>    <Grid x:Name="LayoutRoot" Background="White"<br />
          Width="400" Height="300"><br />
        <Grid.ColumnDefinitions><br />
            <ColumnDefinition Width="90" /><br />
            <ColumnDefinition Width="285*" /><br />
        </Grid.ColumnDefinitions><br />
        <Grid.RowDefinitions><br />
            <RowDefinition Height="72*" /><br />
            <RowDefinition Height="50" /><br />
            <RowDefinition Height="25" /><br />
            <RowDefinition Height="153*" /><br />
        </Grid.RowDefinitions><br />
        <TextBlock Text="Данные:" Grid.Row="1" Grid.Column="0"<br />
                   VerticalAlignment="Center" HorizontalAlignment="Right"/><br />
        <TextBlock Text="MD5:" Grid.Row="2" Grid.Column="0"<br />
                   VerticalAlignment="Center" HorizontalAlignment="Right"/><br />
        <TextBox x:Name="inputText" Grid.Column="1" Grid.Row="1"<br />
                 BorderBrush="Black" BorderThickness="1"<br />
                 TextWrapping="Wrap"/><br />
        <TextBox x:Name="ReceivedText" Text="Empty" Grid.Column="1" Grid.Row="2"<br />
                 BorderBrush="Black" BorderThickness="1"/><br />
        <Button x:Name="SendButton" Content="Отправить" Width="100" Height="25"<br />
                HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="3" Grid.Column="1"<br />
                Click="SendButton_Click"/><br />
    </Grid><br />
</UserControl><br />
[/XML]</p>
<p>С разметкой формы закончили, перейдем к разработке клиентской логики.</p>
<ol>
<li>По нажатию кнопки &laquo;SendButton&raquo; отправляем текст из текстового поля &laquo;inputText&raquo;.</li>
<li>При получении данных отображаем их в поле &laquo;ReceivedText&raquo;.</li>
</ol>
<p>Двойной клик мыши по кнопке &laquo;<strong>SendButton</strong>&raquo; автоматически создаст обработчик события <strong>Click</strong>,  остается только его наполнить смыслом:</p>
<p>[CSharp]<br />
// Если поле ввода пустое, то ничего не делаем<br />
if (String.IsNullOrEmpty(inputText.Text)) return;<br />
// Создаем экземпляр класса WebClient<br />
var client = new WebClient();<br />
// Адрес серверной части<br />
var uri = new Uri(&laquo;http://localhost/index.php&raquo;);<br />
// задаем обработчик события UploadStringCompleted<br />
client.UploadStringCompleted += new UploadStringCompletedEventHandler(UploadStringCompleted);</p>
<p>// передаем данные на сервер<br />
client.UploadStringAsync(uri, inputText.Text);<br />
[/CSharp]</p>
<p>Чуть выше мы реализовали метод для отправки данных, и там же подписались на событие <strong>UploadStringCompleted</strong>. Это событие возникает когда данные отправлены и получен ответ от сервера, для проверки этого достаточно добавить в index.php команду sleep(10), это добавить паузу 10 секунд в обработку запроса. В методе [CSharp light=true]void UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)[/CSharp] мы и реализуем логику:<br />
[CSharp]<br />
void UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)<br />
        {<br />
            if (e.Error == null)<br />
            {<br />
                ReceivedText.Text = e.Result;<br />
            }<br />
        }<br />
[/CSharp]<br />
А логика простая, если не возникло ошибок, то отображаем содержимое в ReceivedText.</p>
<h3>Создание сервера</h3>
<p>Получили код который отсылает данные на сервер. Серверную часть напишем на PHP, потому как WCF сервис в Apache ну никак не захостится. Создаем файл index.php со следующим содержимым:<br />
[PHP]<br />
<?php<br />
$data = file_get_contents('php://input');<br />
if ($data) {<br />
	echo md5($data);<br />
}<br />
else {<br />
	echo "";<br />
}<br />
?><br />
[/PHP]<br />
Тут все просто для PHP программиста, а вот для меня этот код стоил 2 часов времени, если не больше. Дело в том, что отсылая данные на сервер и не указывая дополнительных заголовков, они не попадают в массив $_POST. Добраться до них можно только таким способом &#8211; file_get_contents(&#8216;php://input&#8217;). По полученным данным вычисляется хеш md5 и возвращается обратно.</p>
<h3>Примечание</h3>
<p>Для того чтобы клиентское приложение могло обращаться к серверу рядом с index.php нужно создать файл <strong>crossdomain.xml</strong> со следующим содержимым:<br />
[XML]<br />
<?xml version="1.0"?><br />
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"><br />
<cross-domain-policy><br />
  <allow-http-request-headers-from domain="*" headers="*"/><br />
</cross-domain-policy><br />
[/XML]</p>
<p>Скрин запущенного приложения<br />
<img alt="" src="http://img689.imageshack.us/img689/6764/slapp.jpg" class="aligncenter" width="436" height="162" /></p>
<p><a href="http://bit.ly/bUmDin">Исходники</a> проекта</p>
<p>В следующей статье усложним задачу и будем передавать JSON данные из Silverlight в PHP.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zzlab.ru/coding/vzaimodejstvie-silverlight-prilozheniya-s-php.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Разработка приложения Hello MEF на Silverlight 4 &#8211; Часть I</title>
		<link>http://blog.zzlab.ru/perevod/razrabotka-prilozheniya-hello-mef-na-silverlight-4-chast-i.html</link>
		<comments>http://blog.zzlab.ru/perevod/razrabotka-prilozheniya-hello-mef-na-silverlight-4-chast-i.html#comments</comments>
		<pubDate>Mon, 15 Mar 2010 22:09:16 +0000</pubDate>
		<dc:creator>AlexandrYZ</dc:creator>
				<category><![CDATA[Перевод]]></category>
		<category><![CDATA[Managed Extensibility Framework]]></category>
		<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[translate]]></category>

		<guid isPermaLink="false">http://blog.zzlab.ru/?p=58</guid>
		<description><![CDATA[Автор: Glenn Block Оригинал: Building the Hello MEF dashboard in Silverlight 4 &#8211; Part I В моем прошлом посте я продемонстрировал основы Managed Extension Framework с помощью приложения Hello MEF, которое я использовал на PDC. В этой серии постов, мы создадим приложение с нуля о чем и будем говорить в будущем. Это займет несколько статей, [...]]]></description>
			<content:encoded><![CDATA[<p>Автор: <strong>Glenn Block</strong><br />
Оригинал: <a id="cg:2" title="Building the Hello MEF dashboard in Silverlight 4 -  Part I" href="http://codebetter.com/blogs/glenn.block/archive/2009/11/30/building-the-hello-mef-dashboard-in-silverlight-4-part-i.aspx">Building the Hello MEF dashboard in Silverlight 4 &#8211; Part I</a></p>
<p>В  моем прошлом посте я продемонстрировал основы Managed Extension  Framework с помощью приложения Hello MEF, которое я использовал на PDC. В  этой серии постов, мы создадим приложение с нуля о чем и будем говорить  в будущем. Это займет несколько статей, я пока не уверен в этом,  давайте посмотрим <img src='http://blog.zzlab.ru/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  Мы создадим приложение в итеративном стиле, по  пути пересматривая отдельные компоненты чтобы вносить новую  функциональность.</p>
<p>До того как вы продолжите, сделаю анонс тем,  которые мы по пути рассмотрим:</p>
<ul>
<li>Экспорт / Импорт и  инициализатор компонентов.</li>
<li>Экспорт метаданных.</li>
<li>Настраиваемый  экспорт.</li>
<li>Переопределение инициализатора компонентов.</li>
<li>Динамическая  загрузка XAP.</li>
</ul>
<p>В этом посте мы рассмотрим только первый пункт.<br />
Что-бы  продолжить вам необходим Silverlight 4 и Silverlight 4 Toolkit. Вы  можете скачать Silverlight 4 <a id="n2hx" title="здесь" href="http://download.microsoft.com/download/9/9/5/995A6DF3-BBA9-41E4-BD0B-D680498DACBA/Silverlight4_Tools.exe">здесь</a> и toolkit <a id="jhex" title="здесь" href="http://silverlight.codeplex.com/">здесь</a>.</p>
<p><span id="more-58"></span></p>
<h3>Приложение</h3>
<p>Ниже  снимок экрана приложения.</p>
<p style="text-align: left"><img class="aligncenter" src="http://docs.google.com/File?id=dhtr3xvn_35m9qsntp8_b" alt="" width="536" height="356" /></p>
<p>Может оно и выглядит не очень сложно, но на самом деле это довольно  обманчиво. Приложение представляет собой простую оболочку. Два виджета  &laquo;Hello MEF&raquo; которые вы видите на самом деле обнаружены и экспортированы с  помощью MEF. Само по себе приложение не знает о том что нужно искать,  но оно умеет размещать предоставленные эй элементы, для этого оно  содержит разные области на экране. Если вам знакома технология Prism,  принципиально они очень похожи, но вместо модулей контент помещается в  области, MEF достает контент отовсюду где это возможно. Подробнее об  этом далее.</p>
<p><em>Сноска: Признаюсь, я плох как дизайнер,  но смогу стать лучше если буду действительно стараться <img src='http://blog.zzlab.ru/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  Приятной  особенностью Silverlight является то, что вам не обязательно, как ваш знакомый  дизайнер, превращать что нибудь ужасное в произведение искусства. Не ожидайте от  этой заметки произведения искусства.</em></p>
<h3>Шаг 1 &#8211;  Создание приложения</h3>
<p>Тут ничего сложного, просто создайте новое  Silverlight приложение. Введите &laquo;HelloMEF&raquo; в качестве имени.</p>
<p style="text-align: left"><img class="aligncenter" src="http://docs.google.com/File?id=dhtr3xvn_38f2cgqm8r_b" alt="" width="640" height="407" />Оставьте отмеченным пукт &laquo;Host the Silverlight application in a new Web  Site&raquo;. Мы используем это позже для разделения XAP.</p>
<p style="text-align: center"><img class="aligncenter" src="http://docs.google.com/File?id=dhtr3xvn_37d2f57fhj_b" alt="" width="520" height="416" /></p>
<h3>Шаг 2 &#8211; Создание интерфейса панели</h3>
<p>Для нашей панели мы создадим  что нибудь очень и очень простое. Но так чтобы оно работало. Мы создадим  StackPanel с двумя элементами управления, которые будут содержать наши  виджеты. Перейдите к вашему MainPage.xaml и вставьте следующее.<br />
<span style="font-family: Courier New"><span style="color: #0000ff">&lt;</span><span style="color: #800000">UserControl</span> <span style="color: #ff0000">x</span>:<span style="color: #ff0000">Class</span>=<span style="color: #0000ff">&laquo;HelloMEF.MainPage&raquo;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #ff0000">xmlns</span>=<span style="color: #0000ff">&laquo;http://schemas.microsoft.com/winfx/2006/xaml/presentation&raquo;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #ff0000">xmlns</span>:<span style="color: #ff0000">x</span>=<span style="color: #0000ff">&laquo;http://schemas.microsoft.com/winfx/2006/xaml&raquo;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #ff0000">xmlns</span>:<span style="color: #ff0000">d</span>=<span style="color: #0000ff">&laquo;http://schemas.microsoft.com/expression/blend/2008&#8243;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #ff0000">xmlns</span>:<span style="color: #ff0000">mc</span>=<span style="color: #0000ff">&laquo;http://schemas.openxmlformats.org/markup-compatibility/2006&#8243;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #ff0000">mc</span>:<span style="color: #ff0000">Ignorable</span>=<span style="color: #0000ff">&laquo;d&raquo;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #ff0000">d</span>:<span style="color: #ff0000">DesignHeight</span>=<span style="color: #0000ff">&laquo;300&#8243;</span> <span style="color: #ff0000">d</span>:<span style="color: #ff0000">DesignWidth</span>=<span style="color: #0000ff">&laquo;400&#8243;</span><span style="color: #0000ff">&gt;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #0000ff">&lt;</span><span style="color: #800000">StackPanel</span> <span style="color: #ff0000">x</span>:<span style="color: #ff0000">Name</span>=<span style="color: #0000ff">&laquo;LayoutRoot&raquo;</span> <span style="color: #ff0000">Background</span>=<span style="color: #0000ff">&laquo;Black&raquo;</span><span style="color: #0000ff">&gt;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #0000ff"> &lt;</span><span style="color: #800000">Border</span> <span style="color: #ff0000">Background</span>=<span style="color: #0000ff">&laquo;Cyan&raquo;</span><span style="color: #0000ff">&gt;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #0000ff"> &lt;</span><span style="color: #800000">ItemsControl</span> <span style="color: #ff0000">x</span>:<span style="color: #ff0000">Name</span>=<span style="color: #0000ff">&laquo;TopWidgets&raquo;</span> <span style="color: #ff0000">Height</span>=<span style="color: #0000ff">&laquo;Auto&raquo;</span> <span style="color: #ff0000">FontSize</span>=<span style="color: #0000ff">&laquo;30&#8243;</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">ItemsControl</span><span style="color: #0000ff">&gt;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #0000ff"> &lt;/</span><span style="color: #800000">Border</span><span style="color: #0000ff">&gt;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #0000ff"> &lt;</span><span style="color: #800000">Border</span> <span style="color: #ff0000">Background</span>=<span style="color: #0000ff">&laquo;Yellow&raquo;</span><span style="color: #0000ff">&gt;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #0000ff"> &lt;</span><span style="color: #800000">ItemsControl</span> <span style="color: #ff0000">x</span>:<span style="color: #ff0000">Name</span>=<span style="color: #0000ff">&laquo;BottomWidgets&raquo;</span> <span style="color: #ff0000">Height</span>=<span style="color: #0000ff">&laquo;Auto&raquo;</span> <span style="color: #ff0000">FontSize</span>=<span style="color: #0000ff">&laquo;30&#8243;</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">ItemsControl</span><span style="color: #0000ff">&gt;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #0000ff"> &lt;/</span><span style="color: #800000">Border</span><span style="color: #0000ff">&gt;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">StackPanel</span><span style="color: #0000ff">&gt;</span></span><br />
<span style="font-family: Courier New"><span style="color: #0000ff">&lt;/</span><span style="color: #800000">UserControl</span><span style="color: #0000ff">&gt;</span></span></p>
<h3>Шаг 3 Поиск и отображение виджетов &#8211; множественный Импорт</h3>
<p>Наша  панель должна сама заполнять себя виджетами. Первое о чем мы должны  подумать это что же такое виджет <img src='http://blog.zzlab.ru/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  В MEF когда у нас есть концепт  контракта. Контракт представляет собой нечто что может обеспечивать  (exported) или потреблять (imported). Самый легкий путь подумать об этом  сейчас это задуматься о типе расширения. В случае нашей панели давайте  допустим что каждый виджет это UserControl. Мы могли бы создать новый  базовый тип или интерфейс, но нам это не нужно.<br />
Это хорошо сделает  сам UserControl.<br />
Итак мы должны указать для MEF что нам нужна  коллекция UserControl, те мы хотим импортировать много UserControl. И  для этого у нас есть атрибут ImportMany. Для начала добавим ссылки на  сборки System.ComponentModel.Composition.dll и   System.ComponentModel.Composition.Initialization.dll. Для поиска их вам  необходимо отрыть директорию Silverlight SDK (C:\Program Files\Microsoft  SDKs\Silverlight\v4.0\Libraries\Client<sup>1</sup>).  Далее перейдите в code-behind класса MainPage и перепишите класс  следующим кодом:</p>
<div style="margin-left: 40px"><span style="font-family: Courier New"><span style="color: #0000ff">using</span> System;</span><br />
<span style="font-family: Courier New"><span style="color: #0000ff">using</span> System.Windows.Controls;</span><br />
<span style="font-family: Courier New"><span style="color: #0000ff">using</span> System.ComponentModel.Composition;</span></p>
<p><span style="font-family: Courier New"><span style="color: #0000ff">namespace</span> HelloMEF</span><br />
<span style="font-family: Courier New">{</span><br />
<span style="font-family: Courier New"> <span style="color: #0000ff"> public</span> partial <span style="color: #0000ff">class</span> MainPage : UserControl</span><br />
<span style="font-family: Courier New"> {</span><br />
<span style="font-family: Courier New"><span style="color: #0000ff"> public</span> MainPage()</span><br />
<span style="font-family: Courier New"> {</span><br />
<span style="font-family: Courier New"> InitializeComponent();</span><br />
<span style="font-family: Courier New"> }</span></p>
<p><span style="font-family: Courier New"> [ImportMany]</span><br />
<span style="font-family: Courier New"><span style="color: #0000ff"> public</span> UserControl[] Widgets { <span style="color: #0000ff">get</span>; <span style="color: #0000ff">set</span>; }</span><br />
<span style="font-family: Courier New"> }</span><br />
<span style="font-family: Courier New">}</span></div>
<p>По  сути мы говорим &laquo;MEF, дай мне виджеты&raquo;<br />
Как только мы получим  виджеты, мы должны показать их на экране. Сейчас давайте предположим что  все виджеты будут запущены в одном ItemsControl. Давайте добавим логику  в конструктор.</p>
<div style="margin-left: 40px"><span style="font-family: Courier New"><span style="color: #0000ff">using</span> System;</span><br />
<span style="font-family: Courier New"><span style="color: #0000ff">using</span> System.Windows.Controls;</span><br />
<span style="font-family: Courier New"><span style="color: #0000ff">using</span> System.ComponentModel.Composition;</span></p>
<p><span style="font-family: Courier New"><span style="color: #0000ff">namespace</span> HelloMEF</span><br />
<span style="font-family: Courier New">{</span><br />
<span style="font-family: Courier New"> <span style="color: #0000ff"> public</span> partial <span style="color: #0000ff">class</span> MainPage : UserControl</span><br />
<span style="font-family: Courier New"> {</span><br />
<span style="font-family: Courier New"> <span style="color: #0000ff"> public</span> MainPage()</span><br />
<span style="font-family: Courier New"> {</span><br />
<span style="font-family: Courier New"> InitializeComponent();</span><br />
<span style="font-family: Courier New"> <span style="color: #0000ff"> foreach</span> (var widget <span style="color: #0000ff">in</span> Widgets)</span><br />
<span style="font-family: Courier New"> TopWidgets.Items.Add(widget);</span><br />
<span style="font-family: Courier New"> }</span></p>
<p><span style="font-family: Courier New"> [ImportMany]</span><br />
<span style="font-family: Courier New"> <span style="color: #0000ff"> public</span> UserControl[] Widgets { <span style="color: #0000ff">get</span>; <span style="color: #0000ff">set</span>; }</span><br />
<span style="font-family: Courier New"> }</span><br />
<span style="font-family: Courier New">}</span></div>
<h3>Шаг  4 &#8211; Создание виджета &#8211; Экспорт.</h3>
<p>Теперь, когда мы получили базовую  конфигурацию панели, давайте создадим виджет. Правым кликом мыши на  проекте &laquo;HelloMEF&raquo; добавьте новый Silverlight UserControl с именем  Widget1.</p>
<p><img class="alignnone" src="http://docs.google.com/File?id=dhtr3xvn_39gq835svr_b" alt="" width="640" height="407" /></p>
<p>Наш виджет будет очень простой кнопкой.  Откройте Widget1.xaml  и вставьте следующий код.</p>
<div style="margin-left: 40px"><span style="font-family: Courier New"><span style="color: #0000ff">&lt;</span><span style="color: #800000">UserControl</span> <span style="color: #ff0000">x</span>:<span style="color: #ff0000">Class</span>=<span style="color: #0000ff">&laquo;HelloMEF.Widget1&#8243;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #ff0000"> xmlns</span>=<span style="color: #0000ff">&laquo;http://schemas.microsoft.com/winfx/2006/xaml/presentation&raquo;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #ff0000"> xmlns</span>:<span style="color: #ff0000">x</span>=<span style="color: #0000ff">&laquo;http://schemas.microsoft.com/winfx/2006/xaml&raquo;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #ff0000"> xmlns</span>:<span style="color: #ff0000">d</span>=<span style="color: #0000ff">&laquo;http://schemas.microsoft.com/expression/blend/2008&#8243;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #ff0000"> xmlns</span>:<span style="color: #ff0000">mc</span>=<span style="color: #0000ff">&laquo;http://schemas.openxmlformats.org/markup-compatibility/2006&#8243;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #ff0000"> mc</span>:<span style="color: #ff0000">Ignorable</span>=<span style="color: #0000ff">&laquo;d&raquo;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #ff0000"> d</span>:<span style="color: #ff0000">DesignHeight</span>=<span style="color: #0000ff">&laquo;300&#8243;</span> <span style="color: #ff0000">d</span>:<span style="color: #ff0000">DesignWidth</span>=<span style="color: #0000ff">&laquo;400&#8243;</span><span style="color: #0000ff">&gt;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #0000ff"> &lt;</span><span style="color: #800000">Grid</span> <span style="color: #ff0000">x</span>:<span style="color: #ff0000">Name</span>=<span style="color: #0000ff">&laquo;LayoutRoot&raquo;</span> <span style="color: #ff0000">Height</span>=<span style="color: #0000ff">&laquo;Auto&raquo;</span><span style="color: #0000ff">&gt;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #0000ff"> &lt;</span><span style="color: #800000">Button</span> <span style="color: #ff0000">x</span>:<span style="color: #ff0000">Name</span>=<span style="color: #0000ff">&laquo;Button&raquo;</span> <span style="color: #ff0000">Content</span>=<span style="color: #0000ff">&laquo;Hello MEF!&raquo;</span> <span style="color: #ff0000">Width</span>=<span style="color: #0000ff">&laquo;300&#8243;</span> <span style="color: #ff0000">Height</span>=<span style="color: #0000ff">&laquo;100&#8243;</span><span style="color: #0000ff">&gt;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">Button</span><span style="color: #0000ff">&gt;</span></span><br />
<span style="font-family: Courier New"> <span style="color: #0000ff"> &lt;/</span><span style="color: #800000">Grid</span><span style="color: #0000ff">&gt;</span></span><br />
<span style="font-family: Courier New"><span style="color: #0000ff">&lt;/</span><span style="color: #800000">UserControl</span><span style="color: #0000ff">&gt;</span></span></div>
<p>Теперь необходимо  указать MEF что мы хотим обеспечить импорт наших виджетов в элементы  типа UserControl. Для того мы экспортируем их. Откройте Widget.xaml.cs и замените его содержимое этим:</p>
<div style="margin-left: 40px"><span style="font-family: Courier New"><span style="color: #0000ff">using</span> System;</span><br />
<span style="font-family: Courier New"><span style="color: #0000ff">using</span> System.ComponentModel.Composition;</span><br />
<span style="font-family: Courier New"><span style="color: #0000ff">using</span> System.Windows.Controls;</span><br />
<span style="font-family: Courier New"><span style="color: #0000ff">using</span> System.Windows;</span></p>
<p><span style="font-family: Courier New"><span style="color: #0000ff">namespace</span> HelloMEF</span><br />
<span style="font-family: Courier New">{</span><br />
<span style="font-family: Courier New"> [Export(<span style="color: #0000ff">typeof</span>(UserControl))]</span><br />
<span style="font-family: Courier New"> <span style="color: #0000ff"> public</span> partial <span style="color: #0000ff">class</span> Widget1 : UserControl</span><br />
<span style="font-family: Courier New"> {</span><br />
<span style="font-family: Courier New"> <span style="color: #0000ff"> public</span> Widget1()</span><br />
<span style="font-family: Courier New"> {</span><br />
<span style="font-family: Courier New"> InitializeComponent();</span><br />
<span style="font-family: Courier New"> }</span><br />
<span style="font-family: Courier New"> }</span><br />
<span style="font-family: Courier New">}</span></div>
<p>Как  говорилось выше мы добавили атрибут экспорта и указали тип UserControl.  Если мы не  будем передавать тип, тогда MEF сделает экспорт Widget1 как он  есть, что не имеет особого смысла потому как панель никогда не найдет  его! Бывают моменты когда имеет смысл не использовать конкретный тип, но  это не тот случай <img src='http://blog.zzlab.ru/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<h3>Шаг 5 &#8211; Сборка панели</h3>
<p>Хорошо, мы  реализовали нашу Панель, указав импорт и создав виджеты. Это означает  что если мы запустим приложение, мы увидим виджеты, так? Неверно <img src='http://blog.zzlab.ru/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />   Попробуйте запустить и вы увидите неприятную ошибку.</p>
<p><img class="alignnone" src="http://docs.google.com/File?id=dhtr3xvn_40g2cx2tht_b" alt="" width="640" height="410" /></p>
<p>Что произошло? Наше свойство с коллекцией виджетов пустое, но почему?  Причина ли тому то что мы указали MEF сделать с ними что  нибудь? Да мы добавили атрибут ImportMany, но для MEF необходимо что-бы  наш класс MainPage знал что свойство нужно для предоставления чего  нибудь. Что возвращает нас к прошлой концепции.</p>
<p>В MEF  необходимо сделать 3 базовых вещи. Во-первых и во-вторых, объявить экспорт и импорт, что мы уже сделали. В-третьих, указать для MEF  начать делать компоновку что-бы выполнить все импорты. Места для этого  (вы можете сделать это более чем один раз) находятся там где есть один и  более импортов и нет экспорта. В данном случае экспорт виджетов мы  делаем в классе MainPage, поэтому оно и будет таким местом.</p>
<p>Примечание:  Мы не поместим это в виджеты, что-бы они самостоятельно  экспортировались. Почему нет? Потому что когда MEF начнет экспорт, он  автоматически удовлетворит любые импорты теми компонентами которые он  соберет. Существует исключение из этого, но мы рассмотрим это позже.</p>
<p>В  общем когда у вас будут пользовательские контролы созданные в XAML, вы  будете использовать этот способ. Указание MEF скомпоновать Silverlight  занимает всего 12 строк кода. Это действительно очень простой код и 12  строк строк стоят этого.<br />
Шутка <img src='http://blog.zzlab.ru/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>Что-бы указать MEF о  компоновке вы должны сделать единственный вызов класса  <span style="font-family: Courier New">CompositionInitializer.SatisfyImports(<span style="color: #0000ff">this</span>)</span>. В терминах MEF все что  импортируется или экспортируется мы будем считать Компонентом, <em>which  is why the name<sup>2</sup>.</em> Ниже код который добавлен в MainPage.cs.</p>
<p><span style="font-family: Courier New"><span style="color: #0000ff">using</span> System;<br />
</span><span style="font-family: Courier New"><span style="color: #0000ff">using</span> System.Windows.Controls;<br />
</span><span style="font-family: Courier New"><span style="color: #0000ff">using</span> System.ComponentModel.Composition;<br />
</span><br />
<span style="font-family: Courier New"><span style="color: #0000ff">namespace</span> HelloMEF<br />
</span><span style="font-family: Courier New">{<br />
</span><span style="font-family: Courier New"> <span style="color: #0000ff"> public</span> partial <span style="color: #0000ff">class</span> MainPage : UserControl<br />
</span><span style="font-family: Courier New"> {<br />
</span><span style="font-family: Courier New"> <span style="color: #0000ff"> public</span> MainPage()<br />
</span><span style="font-family: Courier New"> {<br />
</span><span style="font-family: Courier New"> InitializeComponent();<br />
</span><span style="font-family: Courier New"> CompositionInitializer.SatisfyImports(<span style="color: #0000ff">this</span>);<br />
</span><span style="font-family: Courier New"> <span style="color: #0000ff"> foreach</span> (var widget <span style="color: #0000ff">in</span> Widgets)<br />
</span><span style="font-family: Courier New"> TopWidgets.Items.Add(widget);<br />
</span><span style="font-family: Courier New"> }<br />
</span><br />
<span style="font-family: Courier New"> [ImportMany]<br />
</span><span style="font-family: Courier New"> <span style="color: #0000ff"> public</span> UserControl[] Widgets { <span style="color: #0000ff">get</span>;  <span style="color: #0000ff">set</span>; }<br />
</span><span style="font-family: Courier New"> }<br />
</span><span style="font-family: Courier New">}<sup>3</sup><br />
</span><br />
Теперь  когда мы запустим приложение, мы увидим наш первый виджет.</p>
<p><img class="alignnone" src="http://docs.google.com/File?id=dhtr3xvn_41g6s5z3dg_b" alt="" width="640" height="352" /></p>
<h3>Выводы</h3>
<p>Хорошо, уже 2:17 АМ<sup>4</sup>,  время ложиться спать. <em> </em>Предполагаю что разработка приложения растянется на несколько постов.  <img src='http://blog.zzlab.ru/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /><br />
В этой статье мы увидели основы экспорта, импорта и  компоновки в MEF. Мы также коснулись концепции контрактов и компонентов,  в которую мы углубимся в будущем.<br />
В следующей статье мы затронем  следующие темы:</p>
<ul>
<li>Обеспечение / Доступ к экспорту метаданных.</li>
<li>Другие  пути импорта и более подробное рассмотрение контрактов.</li>
<li>Обеспечение  настраиваемого экспорта.</li>
</ul>
<p>ПС: Это не мой обычный стиль  повествования. Я следую примеру моего наставника, гуру и вообще  классному парню <a href="http://blogs.msdn.com/brada">Брэд Адамс. </a>Пожалуйста  не стесняйтесь писать фидбак о том как Я могу стать лучше. Жду с  нетерпением продолжения этого путешествия с вами.</p>
<p><strong>Исходники </strong><a id="b60_" title="прилагаются" href="http://sites.google.com/site/de7c9621c3fd45309efc/Home/HelloMEF_Part_I.zip?attredirects=0&amp;d=1">прилагаются</a></p>
<p style="text-align: left">Сноски:</p>
<p><sup>1 </sup>В 64 битных операционных системах &#8211;  C:\Program Files (x86)\Microsoft SDKs\Silverlight</p>
<p><sup>2 </sup>Непонятно как перевести.</p>
<p><sup>3 </sup>В MEF_Preview 9 PartInitializer переименован в  CompositionInitializer</p>
<p><sup>4 </sup>02:17  ночи</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zzlab.ru/perevod/razrabotka-prilozheniya-hello-mef-na-silverlight-4-chast-i.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
