<?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/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Sergey Homyuk * Dev</title>
	<atom:link href="http://sergeyhomyuk.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://sergeyhomyuk.wordpress.com</link>
	<description>Sergey Homyuk as Software Developer Blog</description>
	<lastBuildDate>Sun, 18 Sep 2011 03:24:05 +0000</lastBuildDate>
	<language>ru</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='sergeyhomyuk.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Sergey Homyuk * Dev</title>
		<link>http://sergeyhomyuk.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://sergeyhomyuk.wordpress.com/osd.xml" title="Sergey Homyuk * Dev" />
	<atom:link rel='hub' href='http://sergeyhomyuk.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Структура моих SharePoint проектов</title>
		<link>http://sergeyhomyuk.wordpress.com/2011/06/28/sharepoint-projects-structure/</link>
		<comments>http://sergeyhomyuk.wordpress.com/2011/06/28/sharepoint-projects-structure/#comments</comments>
		<pubDate>Tue, 28 Jun 2011 07:01:39 +0000</pubDate>
		<dc:creator>Sergey Homyuk</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[sharepont]]></category>
		<category><![CDATA[solution]]></category>
		<category><![CDATA[structure]]></category>

		<guid isPermaLink="false">http://sergeyhomyuk.wordpress.com/?p=71</guid>
		<description><![CDATA[Структура моих SharePoint проектов Структуру своего первого SharePoint проекта я строил, руководствуясь принципами и практиками, которые я выработал, будучи ASP.NET разработчиком. Модульность, слабая связанность между частями проекта, точки агрегации зависимостей &#8211; все эти принципы так же удачно ложатся в основу структуры SharePoint проекта, как и в структуру большинства проектов созданных на основании других технологий. Если [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sergeyhomyuk.wordpress.com&amp;blog=5423806&amp;post=71&amp;subd=sergeyhomyuk&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<h1>Структура моих SharePoint проектов</h1>
<p>Структуру своего первого SharePoint проекта я строил, руководствуясь принципами и практиками, которые я выработал, будучи ASP.NET разработчиком. Модульность, слабая связанность между частями проекта, точки агрегации зависимостей &#8211; все эти принципы так же удачно ложатся в основу структуры SharePoint проекта, как и в структуру большинства проектов созданных на основании других технологий. Если для вас эта тема нова или же хотите ее освежить, то я настоятельно рекомендую вам ознакомиться с серией <a href="http://blogs.msdn.com/b/simonince/archive/2008/06/05/wcsf-application-architecture-1-introduction.aspx">статей Simon Ince</a> посвященных созданию архитектуры на базе принципов заложенных в <a href="http://msdn.microsoft.com/en-us/library/ff648752.aspx">Microsoft Web Client Software Factory</a>. В свое время они перевернули мое представление о том, как надо структурировать проекты.</p>
<p><span id="more-71"></span></p>
<p>Моя типичная структура одного модуля в ASP.NET проекте с backend-ом, скажем, в виде MS SQL базы данных выглядела следующим образом:</p>
<p><a href="http://sergeyhomyuk.files.wordpress.com/2011/06/1.png"><img class="aligncenter size-full wp-image-72" title="Архитектура типичного проекта" src="http://sergeyhomyuk.files.wordpress.com/2011/06/1.png?w=630" alt="Архитектура типичного проекта"   /></a></p>
<p>Думаю, что никого не удивил этой картинкой. Все как обычно: Repository формируется с учетом особенности базы данных, View завязывается на модель представления предлагаемую ASP.NET-ом, ну а Services (они же BLL) опираются лишь на интерфейсы торчащие из DAL и PL и ни на что конкретное не завязываются. В случае с  ASP.NET такая архитектура, в принципе, разворачивается без особых проблем – пара-тройка сервисов-фасадов для работы с HttpContext.Current и у нас полностью развязаны руки в BLL.</p>
<p>Но при попытке построить архитектуру SharePoint проекта по этим же принципам возникают некоторые трудности <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>В итоге, вместо, примерно, такой структуры:</p>
<p><a href="http://sergeyhomyuk.files.wordpress.com/2011/06/2.png"><img class="aligncenter size-full wp-image-73" title="Архитектура идеального SharePoint проекта" src="http://sergeyhomyuk.files.wordpress.com/2011/06/2.png?w=630" alt="Архитектура идеального SharePoint проекта"   /></a></p>
<p>У меня получилось вот это:</p>
<p><a href="http://sergeyhomyuk.files.wordpress.com/2011/06/3.png"><img class="aligncenter size-full wp-image-74" title="Получившаяся структура SharePoint проекта" src="http://sergeyhomyuk.files.wordpress.com/2011/06/3.png?w=630" alt="Получившаяся структура SharePoint проекта"   /></a></p>
<p>Иными словами: все слои приложения завязываются на модель SharePoint. При этом мы, разумеется, теряем всякую гибкость и жестко привязываемся всеми слоями к сущностям SharePoint. Жуть, не правда ли? Я долго и тщетно пытался все-таки скрыть от Services тот факт, что он работает с SharePoint. Но многочисленные фасады, адаптеры, прокси и прочие паттерны, которые я пытался применять, сильно замедляли процесс разработки и, в конечном счете, настолько усложняли код, что это делало его практически нечитаемым. Сейчас я остановился на мысли, что отвязаться от сущностей SharePoint на BLL не удастся, т.к. большая часть логики определяется структурой SharePoint и выполнения большей части операций приходится оперировать именно ими, а не Domain Model объектами, как это было в решениях, построенных на более легковесных платформах.</p>
<p>Ну, с архитектурными принципами, вроде бы более или менее определились, теперь, давайте более подробно остановимся на внутренней структуре моего текущего SharePoint проекта. Сразу оговорюсь &#8211; проект не очень большой &#8211; всего 3-4 модуля и 2 уровня их иерархии. Поэтому некоторыми из принципов я пренебрег в угоду простоты разработки и компактности решения. Вот, что у меня получилось:</p>
<p style="text-align:center;"><a href="http://sergeyhomyuk.files.wordpress.com/2011/06/4.png"><img class="size-full wp-image-75" title="Структура Solution" src="http://sergeyhomyuk.files.wordpress.com/2011/06/4.png?w=630" alt="Структура Solution"   /></a></p>
<p>Весь проект разбит на модули в соответствии с их назначением. Так, к примеру, у меня были модули для работы с поручениями, жалобами, предложениями, организациями и модуль для шаблона сайта. Такое модульное разделение позволяет жестче контролировать зависимости между сервисами, т.к. каждая зависимость выливается в reference между проектами. К тому же мы получаем возможность развертывать и отлаживать каждый модуль по отдельности.</p>
<p>Далее, каждый из модулей в свою очередь состоит из нескольких проектов. Рассмотрим назначение каждого из проектов на примере модуля жалоб.</p>
<p><a href="http://sergeyhomyuk.files.wordpress.com/2011/06/5.png"><img class="aligncenter size-full wp-image-77" title="Структура модуля" src="http://sergeyhomyuk.files.wordpress.com/2011/06/5.png?w=630" alt="Структура модуля"   /></a></p>
<ul>
<li><strong>Complaints</strong> – SharePoint проект с представлениями. Здесь у нас находятся Controls, Application Pages, WebParts, EventReceivers(сами определения, но не их логика), Ribbons. Плюс здесь находятся Presenter-ы (я использую именно этот паттерн для разделения логики и представления). В процессе разработки этот модуль deploy-ится чаще всего.</li>
<li><strong>Complaints.Lists</strong> – SharePoint проект содержащий все, что связанно с уровнем хранения: Fields, Content Types, List Definitions и Instances. Обычно, заполняем его в самом начале и далее уже не трогаем.<strong></strong></li>
<li><strong>Complaints</strong><strong>.</strong><strong>Manager</strong><strong> </strong>– самая обычная .NET сборка, deploy которой выполняется через обычное копирование в GAC (включена в пакет всех проектов, которые ее используют). По сути, это наша рабочая лошадка. Здесь находятся репозитории для работы со списками, сервисы с бизнес логикой, утилиты и всякие вспомогательные сущности.<strong></strong></li>
<li><strong>Complaints</strong><strong>.</strong><strong>Workflow</strong> – Ещё один SharePoint проект с рабочими процессами.<strong></strong></li>
</ul>
<p>С назначением проектов в модуле вроде бы разобрались. Теперь перейдем к внутреннему строению каждого из модулей.</p>
<p><strong>Common</strong></p>
<p><a href="http://sergeyhomyuk.files.wordpress.com/2011/06/6.png"><img class="size-full wp-image-78 aligncenter" title="Common" src="http://sergeyhomyuk.files.wordpress.com/2011/06/6.png?w=630" alt="Common"   /></a></p>
<p>В основе решения лежат 4 сборки с общими компонентами:</p>
<ul>
<li><strong>Common</strong><strong>.</strong><strong>References</strong> – пустой проект, который разворачивает все сторонние сборки в GAC.</li>
<li><strong>Common</strong>.<strong>UI</strong> &#8211; проект с общими страницами и эл-тами управления (№ custom страница с сообщением об ошибке).</li>
<li><strong>Framework</strong> – проект с различными вспомогательными утилитами и базовыми классами, которые не относятся к предметной области.</li>
<li><strong>GlobalResources</strong> – ну, думаю, это из названия понятно.</li>
</ul>
<p><strong>Complaints</strong></p>
<p><a href="http://sergeyhomyuk.files.wordpress.com/2011/06/7.png"><img class="size-full wp-image-79 aligncenter" title="Complaints" src="http://sergeyhomyuk.files.wordpress.com/2011/06/7.png?w=630" alt="Complaints"   /></a><a href="http://sergeyhomyuk.files.wordpress.com/2011/06/7.png"><br />
</a></p>
<p>В принципе, тут все должно быть понятно из скриншота. Все четко и по полочкам. В Pages лежат строковые константы с путями и аргументами страниц использующихся внутри модуля. В Views – реализации паттерна MVP.</p>
<p><strong> </strong></p>
<p><strong>Complaints</strong><strong>.</strong><strong>Lists</strong></p>
<p><a href="http://sergeyhomyuk.files.wordpress.com/2011/06/8.png"><img class="size-full wp-image-80 aligncenter" title="Complaints.Lists" src="http://sergeyhomyuk.files.wordpress.com/2011/06/8.png?w=630" alt="Complaints.Lists"   /></a></p>
<p>Все сгруппировано по спискам. Там где есть необходимость – определены Custom формы. Они также построены с использованием паттерна MVP. Field-ы лежат в корне проекта.</p>
<p><strong>Complaints.Manager</strong></p>
<p><a href="http://sergeyhomyuk.files.wordpress.com/2011/06/9.png"><img class="aligncenter size-full wp-image-81" title="Complaints.Manager" src="http://sergeyhomyuk.files.wordpress.com/2011/06/9.png?w=630" alt="Complaints.Manager"   /></a></p>
<p>Пожалуй, самый интересный и сложный по своей структуре модуль.</p>
<ul>
<li>В Entities лежат различные вспомогательные DTO, которые, как правило, формируются в сервисах и передаются во View.</li>
<li>Handlers – это своеобразные Presenter-ы для EventReceiver-ов. Они определяют какие сервисы и в каком порядке вызывать для обработки того или иного события.</li>
<li>С Helpers, Resources и Services, думаю все понятно.</li>
<li>Для каждого из списков имеется свой Repository, в который включены следующие файлы:
<ul>
<li>Entity – небольшой и абсолютно «плоский» DTO, который формируется вручную из SPListItem. Используется там, где-то нужно просто получить и отобразить.</li>
<li>Fields – набор строковых констант-имен полей.</li>
<li>ListDefinition – сущность, отображающая сам список. Содержит ряд вспомогательных методов для работы с  ним (но не с его элементами).</li>
<li>Repository – а это, непосредственно, сам репозиторий с CRUD методами для работы с элементами списка. Он абсолютно stateless, все, что нужно – приходит к нему в аргументах методов.</li>
</ul>
</li>
</ul>
<p>Модуль может зависеть только от других Manager-ов. Но это крайне нежелательно. В идеале – он автономен и зависит лишь от утилитарных сборок, вроде GlobalResources и Framework.</p>
<p><strong>Complaint.Workflow</strong></p>
<p><a href="http://sergeyhomyuk.files.wordpress.com/2011/06/10.png"><img class="aligncenter size-full wp-image-82" title="Complaints.Workflow" src="http://sergeyhomyuk.files.wordpress.com/2011/06/10.png?w=630" alt="Complaints.Workflow"   /></a></p>
<p>Тут ничего особенного. Просто определения рабочих процессов, из которых дергаются необходимые сервисы, определенные в ComplaintsManager.</p>
<p>Вот, что у нас в итоге получается в плане зависимостей между проектами модулями:</p>
<p><a href="http://sergeyhomyuk.files.wordpress.com/2011/06/11.png"><img class="aligncenter size-full wp-image-83" title="Зависимости между проектами модуля" src="http://sergeyhomyuk.files.wordpress.com/2011/06/11.png?w=630" alt="Зависимости между проектами модуля"   /></a></p>
<p>А вот схема зависимостей между модулями:</p>
<p><a href="http://sergeyhomyuk.files.wordpress.com/2011/06/12.png"><img class="aligncenter size-full wp-image-84" title="Зависимости между модулями" src="http://sergeyhomyuk.files.wordpress.com/2011/06/12.png?w=630&#038;h=329" alt="Зависимости между модулями" width="630" height="329" /></a></p>
<p>Архитектура не идеальная, но вполне жизнеспособная и расширяемая. При дальнейшем росте проекта и увеличении степени зацепления между модулями имеет смысл выделить интерфейсы сервисов и сущностей в отдельную сборку. Но тут надо быть аккуратным и не плодить сильно много SharePoint проектов – иначе замучаетесь ждать пока выполнится их deploy. Тему архитектуры проектов в SharePoint можно развивать и дальше, но, пожалуй, оставлю это на следующую статью. А сейчас жду ваших комментариев и предложений!</p>
<br /> Tagged: <a href='http://sergeyhomyuk.wordpress.com/tag/project/'>project</a>, <a href='http://sergeyhomyuk.wordpress.com/tag/sharepont/'>sharepont</a>, <a href='http://sergeyhomyuk.wordpress.com/tag/solution/'>solution</a>, <a href='http://sergeyhomyuk.wordpress.com/tag/structure/'>structure</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/sergeyhomyuk.wordpress.com/71/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/sergeyhomyuk.wordpress.com/71/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/sergeyhomyuk.wordpress.com/71/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/sergeyhomyuk.wordpress.com/71/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/sergeyhomyuk.wordpress.com/71/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/sergeyhomyuk.wordpress.com/71/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/sergeyhomyuk.wordpress.com/71/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/sergeyhomyuk.wordpress.com/71/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/sergeyhomyuk.wordpress.com/71/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/sergeyhomyuk.wordpress.com/71/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/sergeyhomyuk.wordpress.com/71/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/sergeyhomyuk.wordpress.com/71/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/sergeyhomyuk.wordpress.com/71/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/sergeyhomyuk.wordpress.com/71/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sergeyhomyuk.wordpress.com&amp;blog=5423806&amp;post=71&amp;subd=sergeyhomyuk&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://sergeyhomyuk.wordpress.com/2011/06/28/sharepoint-projects-structure/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">sergeyhomyuk</media:title>
		</media:content>

		<media:content url="http://sergeyhomyuk.files.wordpress.com/2011/06/1.png" medium="image">
			<media:title type="html">Архитектура типичного проекта</media:title>
		</media:content>

		<media:content url="http://sergeyhomyuk.files.wordpress.com/2011/06/2.png" medium="image">
			<media:title type="html">Архитектура идеального SharePoint проекта</media:title>
		</media:content>

		<media:content url="http://sergeyhomyuk.files.wordpress.com/2011/06/3.png" medium="image">
			<media:title type="html">Получившаяся структура SharePoint проекта</media:title>
		</media:content>

		<media:content url="http://sergeyhomyuk.files.wordpress.com/2011/06/4.png" medium="image">
			<media:title type="html">Структура Solution</media:title>
		</media:content>

		<media:content url="http://sergeyhomyuk.files.wordpress.com/2011/06/5.png" medium="image">
			<media:title type="html">Структура модуля</media:title>
		</media:content>

		<media:content url="http://sergeyhomyuk.files.wordpress.com/2011/06/6.png" medium="image">
			<media:title type="html">Common</media:title>
		</media:content>

		<media:content url="http://sergeyhomyuk.files.wordpress.com/2011/06/7.png" medium="image">
			<media:title type="html">Complaints</media:title>
		</media:content>

		<media:content url="http://sergeyhomyuk.files.wordpress.com/2011/06/8.png" medium="image">
			<media:title type="html">Complaints.Lists</media:title>
		</media:content>

		<media:content url="http://sergeyhomyuk.files.wordpress.com/2011/06/9.png" medium="image">
			<media:title type="html">Complaints.Manager</media:title>
		</media:content>

		<media:content url="http://sergeyhomyuk.files.wordpress.com/2011/06/10.png" medium="image">
			<media:title type="html">Complaints.Workflow</media:title>
		</media:content>

		<media:content url="http://sergeyhomyuk.files.wordpress.com/2011/06/11.png" medium="image">
			<media:title type="html">Зависимости между проектами модуля</media:title>
		</media:content>

		<media:content url="http://sergeyhomyuk.files.wordpress.com/2011/06/12.png" medium="image">
			<media:title type="html">Зависимости между модулями</media:title>
		</media:content>
	</item>
		<item>
		<title>10 фактов о SharePoint, которые не помешали бы мне год назад</title>
		<link>http://sergeyhomyuk.wordpress.com/2011/06/22/10-facts-about-sharepoint/</link>
		<comments>http://sergeyhomyuk.wordpress.com/2011/06/22/10-facts-about-sharepoint/#comments</comments>
		<pubDate>Wed, 22 Jun 2011 03:09:39 +0000</pubDate>
		<dc:creator>Sergey Homyuk</dc:creator>
				<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[facts]]></category>
		<category><![CDATA[sharepoint]]></category>

		<guid isPermaLink="false">http://sergeyhomyuk.wordpress.com/?p=58</guid>
		<description><![CDATA[10 фактов* о SharePoint, которые не помешали бы мне год назад. 1. Используй виртуальную машину. Сразу бери/проси машину помощнее, тебе понадобится, как минимум процессор i3/i5 и 8 gb памяти, чтобы поднять виртуальную машину в которой и будет вестись вся разработка. Работая в виртуальной среде, ты сэкономишь себе кучу времени и нервов, т.к. в случае чего [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sergeyhomyuk.wordpress.com&amp;blog=5423806&amp;post=58&amp;subd=sergeyhomyuk&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<h1><strong>10 фактов* о SharePoint, которые не помешали бы мне год назад.</strong><strong></strong></h1>
<p><strong>1. Используй виртуальную машину.</strong><br />
Сразу бери/проси машину помощнее, тебе понадобится, как минимум процессор i3/i5 и 8 gb памяти, чтобы поднять виртуальную машину в которой и будет вестись вся разработка. Работая в виртуальной среде, ты сэкономишь себе кучу времени и нервов, т.к. в случае чего &#8211; всегда можно откатиться к предыдущему snapshot-у, а при старте нового проекта восстановить исходное состояние системы с чистым SharePoint всего за пару кликов. Ну а если разработка ведется сразу в двух ветках одного проекта (скажем, branch с фиксами для прошлого релиза и trunk с новой функциональностью), то без возможности переключаться между snapshot-ами просто никак. Выбор платформы остается за тобой, но я, лично, предпочитаю связку VMWare + Windows 2008 R2.</p>
<p><strong>2. Выработай четкую политику накатывания обновлений.</strong><br />
С webpart-ами, формами и т.п. у тебя не должно возникнуть никаких проблем при накатывании новых изменений, т.к. при их re-deploy ты ничего не потеряешь, но вот с полями, типами, списками и рабочими процессами тебе придется помучиться. Постарайся четко определиться (а ещё лучше как-то автоматизировать) каким образом ты будешь накатывать изменения на production сервер. Я для себя выбрал следующую тактику: при внесении какого-либо изменения в схему списка или контентного типа тут же создается PowerShell скрипт, позволяющий накатить те же самые изменения на предыдущий релиз, развернутый у заказчика и на тестовом сервере. Скрипты упорядочиваются по задачам, к которым они привязаны и номерам версий. <a href="http://www.sharepointnutsandbolts.com/2010/06/feature-upgrade-part-1-fundamentals.html">Feature Upgrade</a>, конечно более естественный для SharePoint механизм накатывания изменений на схему, но у меня с ним возникала куча самых разных проблем.</p>
<p><strong>3. Нет, от конетекста SharePoint тебе не отвязаться.</strong><br />
Поначалу я очень-очень старался скрыть от слоя бизнес-логики тот факт, что (о ужас!) она взаимодействует с SharePoint. Подсовывал всякие DTO и DataModel объекты, генерировал фасады и медиаторы, сервисы-провайдеры и репозитории. Но все это бесполезно, не тратьте впустую время &#8211; ты работаешь с SharePoint, так что изволь играть по его правилам. Передавай SPListItem-ы в сервисы уровня BLL, которые отвечают за назначения прав доступа, прокидывай SPWeb сквозь View в Presenter и далее в Model. Да &#8211; некрасиво, да &#8211; очень сложно тестировать. Но иначе ты просто рискуешь запутаться из какого контекста пришел тот или иной объект (страница/ресивер/таймер) и увязнуть в тонне фасадов, созданных на каждый случай. Улучшай читаемость, степень повторного использования кода внедряй модные паттерны и разделяй на слои, но делай это все в духе SharePoint.</p>
<p><strong>4. Разделяй и властвуй.</strong><br />
Советую сразу выделять все, что связано с уровнем хранения данных (поля, типы, списки) в отдельные проекты. Это существенно упростит процесс deploy и отладки. Рабочие процессы, кстати, тоже по-хорошему надо выносить в отдельный пакет.</p>
<p><strong>5. EventReciver-ы не так просты, как кажутся.</strong><br />
Если у тебя есть задача, которая решается при помощи EventReceiver-ов и это твоя первая встреча с ними &#8211; не торопись. Они только с виду кажутся простыми, а на практике с ними столько заморочек. Лучше сядь, прочитай главу про EventReceiver-ы в какой-нибудь умной книжке (мне, кстати, нравится Jorg Krause &#8211; SharePoint 2010 as a Development Platform (<a href="http://www.amazon.com/SharePoint-Development-Platform-Experts-Sharepoint/dp/1430227060">amazon</a>)) и серию из двух статей в блоге gandjustas-а (<a href="http://gandjustas.blogspot.com/2011/05/blog-post.html">часть 1</a>, <a href="http://gandjustas.blogspot.com/2011/06/2.html">часть 2</a>). А затем определить какой именно из Receiver -ов тебе нужен, и не спеша, вдумчиво приступай к реализации. Я в свое время потратил кучу времени и нервов, пытаясь с ходу реализовать сложный Receiver.</p>
<p><strong>6. Использовать Linq To SharePoint не самая лучшая идея.</strong><br />
Я вот тоже очень обрадовался, когда узнал, что в SharePoint 2010 теперь есть настоящий Linq для работы со списками. Сразу же кинулся все на нем реализовывать и только потом понял, что зря я это сделал. Linq2SP предоставляет очень скудную функциональность по работе со списками. Если ты реализуешь что-то, действительно, серьезное, то почти наверняка придется плодить параллельную иерархию на основе объектной модели SharePoint (SPListItem, CAML и т.п.). А дублирование кода никогда ни к чему хорошему не приводило. Плюс, к тому же, ты его никак не контролируешь и из-за этого можно очень легко накосячить с производительностью. Но если все-таки хочется чего-то Linq-ушного, то бери на вооружение <a href="http://camlex.codeplex.com/">Camlex</a>. Вещь неплохая, хорошо встраивается в существующие SharePoint проекты, да и к тому же он OpenSource.</p>
<p><strong>7. Есть много плагинов и приложений, которые упрощают работу с SharePoint.</strong><br />
<a href="http://visualstudiogallery.msdn.microsoft.com/4c5664f6-fefc-446b-b91c-36bec0c87e35">SharePoint Software Factory</a> &#8211; сборник “рецептов” и полезных утилит для работы с SharePoint. Особенно советую обратить внимание на возможность копирования файлов напрямую в GAC/Hive, минуя deploy (неплохо экономит время) и на attach к процессам SharePoint(IIS, Timer) для отладки.<br />
<a href="http://visualstudiogallery.msdn.microsoft.com/ee876627-962c-4c35-a4a6-a4d89bfb61dc">CKS &#8211; Development Tools Edition </a>- почти тоже, что и Software Factory, но без рецептов.<br />
<a href="http://archive.msdn.microsoft.com/ULSViewer">ULS Viewer</a> &#8211; утилита для работы с логами SharePoint. Он там пишет очень много всего интересного. В случае возникновения непонятной ошибки в первую очередь советую заглянуть именно туда.<br />
<a href="http://spm.codeplex.com/">SharePoint Manager 2010</a> &#8211; Невероятно полезная утилита. Позволяет посмотреть структуру сайтов SharePoint и получить схемы всего и вся. Много раз выручал меня.<br />
<a href="http://www.u2u.net/Tools/wincamlquerybuilder/CamlQueryBuilder.aspx">U2U Caml Query Builder</a> &#8211; Утилита для построения CAML запросов. Удобно, просто, наглядно.<br />
<a href="http://archive.msdn.microsoft.com/SPDisposeCheck">SPDisposeCheck</a> &#8211; Проверяет проекты на предмет утечки памяти. Запускай время от времени, а ещё лучше, интегрируй в свой Continuous Integration сервер.</p>
<p><strong>8. PowerShell твой лучший друг.</strong><br />
Серьезно, не пренебрегай им. На PowerShell очень просто писать патчи для обновления схем и небольшие утилиты для автоматизации каких-либо действий. В качестве IDE я советую использовать <a href="http://www.powergui.org/index.jspa">PowerGUI</a>.</p>
<p><strong>9. Не забывай освобождать ресурсы.</strong><br />
Надеюсь, ты уже в курсе, что часть SharePoint реализовано с использованием COM, и что такие объекты как SPSite и SPWeb тянут за собой неуправляемые ресурсы, которые надо явно высвобождать через Dispose? Вот я когда-то не знал и очень удивлялся, когда через день активной работы SharePoint забирал себе всю память, и ни в какую не хотел ее отдавать назад. Так что следи за каждым созданием SPSite и SPWeb, прочитай <a href="http://msdn.microsoft.com/en-us/library/aa973248(v=office.12).aspx">эту статью на MSDN</a> и время от времени запускай SPDisposeCheck (см. п.7).</p>
<p><strong>10. SharePoint с налету не взять.</strong><br />
Когда мне предложили попробовать себя в роли SharePoint разработчика я подумал: “Хм, а почему бы и нет? Я вроде бы поднаторел в изучении новых платформ. IPhone и Flex пошли на “ура”. А SharePoint, это всего-навсего надстройка над ASP.NET. Легко!”. Как окажется позднее &#8211; я сильно ошибался, SharePoint с налету не взять. Будь сразу готов к тому, что у разработчиков SharePoint было свое мнение по поводу того, что логично, а что нет. Тебе придется потратить кучу времени, раскапывая тонны javascript-ов и xml-ек, чтобы разобраться, как добавить одну единственную кнопку, без которой заказчик не хочет принимать форму. Для меня SharePoint это один большой Challenge. Читай книжки, блоги, выискивай статьи на msdn, общайся на форумах и будь готов к сложностям. Впрочем, как раз из-за обилия этих сложностей нам хорошо платят и мы нужны всем.</p>
<p>Буду очень рад, если кто-то захочет дополнить этот список и поделиться своим опытом работы с SharePoint. Пишите, комментируйте!</p>
<p><em>* &#8211; хотя, корректнее, было бы сказать мыслей или знаний полученных в результате практической работы с SharePoint.</em></p>
<br /> Tagged: <a href='http://sergeyhomyuk.wordpress.com/tag/facts/'>facts</a>, <a href='http://sergeyhomyuk.wordpress.com/tag/sharepoint-2/'>sharepoint</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/sergeyhomyuk.wordpress.com/58/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/sergeyhomyuk.wordpress.com/58/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/sergeyhomyuk.wordpress.com/58/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/sergeyhomyuk.wordpress.com/58/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/sergeyhomyuk.wordpress.com/58/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/sergeyhomyuk.wordpress.com/58/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/sergeyhomyuk.wordpress.com/58/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/sergeyhomyuk.wordpress.com/58/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/sergeyhomyuk.wordpress.com/58/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/sergeyhomyuk.wordpress.com/58/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/sergeyhomyuk.wordpress.com/58/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/sergeyhomyuk.wordpress.com/58/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/sergeyhomyuk.wordpress.com/58/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/sergeyhomyuk.wordpress.com/58/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sergeyhomyuk.wordpress.com&amp;blog=5423806&amp;post=58&amp;subd=sergeyhomyuk&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://sergeyhomyuk.wordpress.com/2011/06/22/10-facts-about-sharepoint/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">sergeyhomyuk</media:title>
		</media:content>
	</item>
		<item>
		<title>Разработчик о SharePoint</title>
		<link>http://sergeyhomyuk.wordpress.com/2010/12/25/dveloper-about-sharepoint/</link>
		<comments>http://sergeyhomyuk.wordpress.com/2010/12/25/dveloper-about-sharepoint/#comments</comments>
		<pubDate>Sat, 25 Dec 2010 15:52:11 +0000</pubDate>
		<dc:creator>Sergey Homyuk</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[sharepoint]]></category>

		<guid isPermaLink="false">http://sergeyhomyuk.wordpress.com/?p=42</guid>
		<description><![CDATA[Как я провел лето (или мысли разработчика о SharePoint) Microsoft SharePoint 2010 Server представленный корпорацией Microsoft является ничем иным, как очень мощным инструментов для построения документо-оринетированных систем. Но эта “мощность” SharePoint, как платформы носит двуликий характер: с одной стороны, он предоставляет широкий спектр инструментов и функций для работы с документами (и другими абстракциями описанными в [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sergeyhomyuk.wordpress.com&amp;blog=5423806&amp;post=42&amp;subd=sergeyhomyuk&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div>
<h1>Как я провел лето (или мысли разработчика о SharePoint)</h1>
<p>Microsoft SharePoint 2010 Server представленный корпорацией Microsoft является ничем иным, как очень мощным инструментов для построения документо-оринетированных систем. Но эта “мощность” SharePoint, как платформы носит двуликий характер: с одной стороны, он предоставляет широкий спектр инструментов и функций для работы с документами (и другими абстракциями описанными в рамках системы), но с другой стороны &#8211; разработчику крайне тяжело(а, порою, и вовсе невозможно) менять абстракции и процессы лежащие в основе платформы.</p>
<h2><span id="more-42"></span>С точки зрения разработчика</h2>
<h3>Модель предметной области</h3>
<p>Microsoft SharePoint полностью инкапсулирует слой работы с SQL базой данных от разработчика, предоставляя свой набор базовых абстракций (поле, контентный тип, определение и экземпляр списка/документа) и инструментов (LinqToSharePoint, CAML, объектная модель) для взаимодействия с уровнем доступа к данным (DAL). Данный подход существенно упрощает создание новых сущностей предметной области, т.к. основные типы и абстракции уже описаны в системе. Так для создания нового типа документа обладающего стандартным набором атрибутов (Имя, Автор, Дата создания, и т.п.) достаточно воспользоваться предопределенным контентным типом “Документ”, который уже содержит необходимый набор атрибутов. SharePoint так же предоставляет удобные графические инструменты для формирования и редактирования сущностей уровня хранения данных.</p>
<p>Но, помимо вышеперечисленных преимуществ, данный подход обладает множеством недостатков.  Прежде всего, стоит отметить, что большинство разработчиков привыкли использовать в качестве хранилища данных реляционную СУБД. В этой области наработано огромное количество теоретического материала, практик и инструментов, которые существенно упрощают разработку системы, делая её прогнозируемым, сходящимся процессом. Подход к хранению данных, используемый в SharePoint почти полностью исключает возможность использования существующих практик. Остановимся более подробно на особенностях DAL в SharePoint:</p>
<h3>Поля</h3>
<p>SharePoint обладает весьма скудным набором типов полей, и при этом они определены на довольно-таки высоком уровне (по сравнению с базовыми типами, предоставляемыми реляционными базами данных). Такой подход существенно усложняет проверку корректности данных на уровне хранения. При работе с SQL сервером, к примеру, можно легко указать диапазон допустимых значений для того или иного поля. В Microsoft SharePoint предусмотрен механизм расширения набора типов полей, но он является весьма нетривиальным и плохо документированным. Помимо этого, все проверки осуществляются в управляемом коде, а не в базе данных, что при работе с большими объемами данных может крайне негативно сказаться на производительности системы.</p>
<h3>Типы и списки</h3>
<p>В роли аналогов таблиц реляционных СУБД в SharePoint выступают контентные типы и списки. Этот подход позволяет использовать некоторые концепции объектно-ориентированного программирования при проектировании уровня хранения данных. Но при этом утрачивается вся та гибкость в проектировании и оптимизации структур данных, которая возможна была с реляционной СУБД. Так же, в SharePoint имеются существенные проблемы с объемами хранимых данных (Microsoft не советует хранить более 5000 элементов в списке, что абсолютно неприемлемо для большинства задач. Решения этой проблемы существуют, но они требуют дополнительных трудозатрат и ведут к запутыванию логики приложения). И, на конец, SharePoint не поддерживает транзакционных операций при работе со списками и документами.</p>
<h3>Выборка данных</h3>
<p>SharePoint предоставляет несколько инструментов для получения данных с уровня хранилища. Но ни одно из них не обладает той производительностью и гибкостью, которую способна обеспечить реляционная база данных через SQL запрос или хранимую процедуру. LinqToSharePoint является очень сырым и ограниченным инструментом (низкая скорость, узкий спектр поддерживаемых операций для выборки данных, сложность в генерации модели, отсутствие точек расширения и т.д.). CAML, в отличие от LinqToSharePoint, более приспособлен к работе с абстракциями SharePoint, но при этом он абсолютно нетипизирован и довольно-таки сложен в плане динамического построения запросов.</p>
<h3>Точки доступа</h3>
<p>При классическом подходе к проектированию систем, уровень хранения данных является абсолютно изолированным от бизнес логики, такой подход позволяет жестко контролировать зависимости в приложении и помогает четко определять места расширения и изменения, минимизируя при этом влияние на другие части системы. В SharePoint этой концепции придерживаться крайне тяжело, т.к. в зависимости от контекста текущей операции может варьироваться способ доступа к данным.</p>
<h3>Изменение схемы хранения данных</h3>
<p>Одним из серьезных недостатков платформы является сложность внесения изменений в уже развернутую систему. Вынесение обновлений в отдельный пакет является весьма трудоемкой операцией, которая, к тому же влияет на целостность структуры приложения.</p>
<h2>Процесс разработки</h2>
<h3>Тестирование</h3>
<p>Процесс тестирования системы написанной на базе платформы SharePoint существенно затруднен по сравнению с тестированием системы созданной на базе ASP.NET. Крайне сложно (а, порою, и вовсе невозможно) обеспечить идентичное состояние системы на тестовом сервере, сервере заказчика и машине разработчика. Автоматическое Unit-тестирование так же затруднено из-за того, что каждый запуск и выполнение теста может занимать до нескольких минут. Это делает почти невозможным использование таких практик, как Test Driven Development, которые могли бы существенно повысить качество разрабатываемого кода и снизить издержки на ручное тестирование.</p>
<h3>Отладка</h3>
<p>Одним из преимуществ современных сред разработки является возможность удобной отладки кода. При разработке на SharePoint почти все преимущества в отладке приложения сходят на нет. Каждое подключение к серверу в режиме отладки, как и в случае с тестами, может занимать до нескольких минут. Такое состояние дел превращает процесс отлаживания кода приложения в затянутый и скучный процесс, который разработчики стараются избегать, что, в свою очередь, ведет к снижению качества кода. Так же, стоит отметить систему логирования SharePoint. Это весьма мощный инструмент для диагностирования ошибок, но для его эффективного использования необходимо применять сторонние утилиты (ULSViewer).</p>
<h3>Рабочее место</h3>
<p>Не смотря на существенный прогресс в интеграции средств разработки SharePoint в Microsoft Visual Studio 2010 и в возможности разворачивания сервера на клиентской операционной системе (Microsoft Windows 7 x64), организация “комфортного” рабочего места разработчика по прежнему остается нетривиальной задачей. Прежде всего, для одновременной работ в Visual Studio и SharePoint Server рабочая машина должна быть оснащена мощным процессором и большим (6-8 gb) объемом оперативной памяти. Разработка на общим, выделенном сервере невозможна из-за необходимости в постоянных перезагрузках IIS сервера. Наиболее рациональным видится решение с организацией рабочего места в рамках виртуальной машины. Это позволит существенно сократить время на переустановку системы в случае, если SharePoint перестанет работать (такая ситуация довольно-таки часто возникает на машине разработчика и в ряде случаев исправляется лишь полной переустановкой операционной системы).</p>
<h3>Концепции и структура</h3>
<p>Отличительной чертой хорошо спроектированного приложения является четкая структура и соблюдение архитектурных концепций на всех его уровнях и во всех модулях. В классическом подходе привычном большинству разработчиков в архитектуре приложения явно выделяется три слоя: слой хранения данных, бизнес логики и представления. Как уже упоминалось ранее, в SharePoint сложно явно выделить слой работы с данными, т.к. в зависимости от текущего контекста (страница, обработчик события, рабочий процесс, и т.д.) варьируется способ доступа и изменения данных. Можно построить свой ORM(платформа и рынок не предоставляет готовых библиотек), но для решения ряда задач в рамках системы придется отходить от него, что только запутает архитектуру. То есть, классический подход к проектированию информационных систем не применим по отношению к SharePoint. Есть предположение, что каждая часть, каждый модуль должен выступать в качестве самостоятельной под-системы. Чем меньше будет общих абстракций и слоев &#8211; тем проще будет обеспечить работоспособность и производительность каждого модуля и всей системы в целом. При этом, разумеется, увеличивается время и сложность поддержки системы.</p>
<p>&nbsp;</p>
<p><span style="font-size:20px;font-weight:bold;">Итого</span></p>
<p>Вне всякого сомнения, Microsoft SharePoint 2010 является крайне мощной платформой для построения бизнес-ориентированных систем, включающей в себя огромное число самых разнообразных компонент. Но при этом порог вхождения в разработку на этой платформе очень велик (по сравнению с классическим ASP.NET). Это обусловлено плохой документированностью функциональности, не очень удачной архитектурой существенно затрудняющей внесение изменений и чрезмерной внутренней сложностью. Любая команда, сколь опытной она бы ни была &#8211; почти наверняка столкнется с серьезными трудностями при разработке их первого приложения на базе  Microsoft SharePoint. Большинство практик, библиотек и методик, гарантировавших успех и качество проекта при разработке на ASP.NET (или любом другом низкоуровневом framework-е)  в случае с SharePoint не только могут оказаться бесполезными, но так же могут нанести “вред” разработке из-за того, что они изначально спроектированы для работы с совсем иным уровнем абстракций, нежели тот, что предоставляет SharePoint.</p>
<p>&nbsp;</p>
<p>P.S. Все выше сказанное &#8211; это мое мнение, как разработчика, которое сложилось за 9 месяцев участия в проекте разрабатываемом на Microsoft SharePoint 2010.  Не смотря на то, что за это время мне пришлось очень плотно работать с платформой, я по прежнему не могу сказать, что понимаю, как именно нужно правильно разрабатывать приложения на SharePoint. Буду крайне признателен за конструктивную критику.</p>
</div>
<br /> Tagged: <a href='http://sergeyhomyuk.wordpress.com/tag/sharepoint-2/'>sharepoint</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/sergeyhomyuk.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/sergeyhomyuk.wordpress.com/42/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/sergeyhomyuk.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/sergeyhomyuk.wordpress.com/42/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/sergeyhomyuk.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/sergeyhomyuk.wordpress.com/42/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/sergeyhomyuk.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/sergeyhomyuk.wordpress.com/42/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/sergeyhomyuk.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/sergeyhomyuk.wordpress.com/42/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/sergeyhomyuk.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/sergeyhomyuk.wordpress.com/42/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/sergeyhomyuk.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/sergeyhomyuk.wordpress.com/42/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sergeyhomyuk.wordpress.com&amp;blog=5423806&amp;post=42&amp;subd=sergeyhomyuk&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://sergeyhomyuk.wordpress.com/2010/12/25/dveloper-about-sharepoint/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">sergeyhomyuk</media:title>
		</media:content>
	</item>
		<item>
		<title>C# &#124; Manage local &amp; domain groups &#8211; II</title>
		<link>http://sergeyhomyuk.wordpress.com/2010/01/10/csharp-manage-local-domain-groups/</link>
		<comments>http://sergeyhomyuk.wordpress.com/2010/01/10/csharp-manage-local-domain-groups/#comments</comments>
		<pubDate>Sun, 10 Jan 2010 17:54:01 +0000</pubDate>
		<dc:creator>Sergey Homyuk</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[active directory]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[domain]]></category>
		<category><![CDATA[group]]></category>
		<category><![CDATA[local]]></category>

		<guid isPermaLink="false">http://sergeyhomyuk.wordpress.com/?p=33</guid>
		<description><![CDATA[Некоторое время назад я писал про работу с доменными и локальными группами. Представленное мною решение является вполне рабочим, но тем не менее, у него есть один недостаток &#8211; оно позволяет работать лишь с одним из доменов в котором находится машина исполняющая программу. Если быть точнее &#8211; с тем доменом который вернется в результате выполнения метода [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sergeyhomyuk.wordpress.com&amp;blog=5423806&amp;post=33&amp;subd=sergeyhomyuk&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Некоторое время назад я писал про работу с доменными и локальными группами. Представленное мною решение является вполне рабочим, но тем не менее, у него есть один недостаток &#8211; оно позволяет работать лишь с одним из доменов в котором находится машина исполняющая программу. Если быть точнее &#8211; с тем доменом который вернется в результате выполнения метода Domain.GetComputerDomain().</p>
<p>Сегодня я хотел бы написать об улучшенной версии. Методы были подвергнуты тотальному рефакторингу + добавилась возможность явно указывать домен в котором будут производиться манипуляции над группами.</p>
<p><span id="more-33"></span></p>
<p>1. Создание доменной группы:</p>
<p><pre class="brush: csharp;">
const string GroupSchemaClassName = &quot;group&quot;;

/// &lt;summary&gt;
/// Типы доменных групп.
/// &lt;/summary&gt;
[Flags]
enum DomainGroupTypes : uint
{
    UniversalGroup = 0x08,
    DomainLocalGroup = 0x04,
    GlobalGroup = 0x02,
    SecurityGroup = 0x80000000
}

/// &lt;summary&gt;
/// Создать новую группу в домене.
/// &lt;/summary&gt;
/// &lt;param name=&quot;domain&quot;&gt;Имя домена в котором будет создана группа.&lt;/param&gt;
/// &lt;param name=&quot;name&quot;&gt;Имя создаваемой группы.&lt;/param&gt;
/// &lt;param name=&quot;description&quot;&gt;Описание группы, которое будет отображаться в поле &quot;Description&quot;.&lt;/param&gt;
void CreateDomainGroup(string domain, string name, string description)
{
	//Получение DirectoryEntry для указанного домена.
	var root = DomainUtil.GetDomainDirectoryEntry(domain);

	root = root.Children.Find(&quot;CN=Users&quot;);

	using (var group = root.Children.Add(string.Format(&quot;CN={0}&quot;, name), GroupSchemaClassName))
	{
		group.Properties[&quot;sAMAccountName&quot;].Add(name);
		group.Properties[&quot;description&quot;].Add(description);

		//Можете варьировать тип группы как вам нужно через операцию &quot;|&quot; (побитовое или)
		DomainGroupTypes groupType = DomainGroupTypes.DomainLocalGroup | DomainGroupTypes.SecurityGroup;

		group.Properties[&quot;groupType&quot;].Add((int) groupType);

		group.CommitChanges();
	}
}
</pre></p>
<p>2. Создание локальной группы</p>
<p><pre class="brush: csharp;">
/// &lt;summary&gt;
/// Создать новую группу на текущей машине.
/// &lt;/summary&gt;
/// &lt;param name=&quot;name&quot;&gt;Имя создаваемой группы.&lt;/param&gt;
/// &lt;param name=&quot;description&quot;&gt;Описание группы, которое будет отображаться в поле &quot;Description&quot;.&lt;/param&gt;
void CreateLocalGroup(string name, string description)
{
	var root = new DirectoryEntry(string.Format(&quot;WinNT://{0},computer&quot;, Environment.MachineName));

	using (var group = root.Children.Add(name, GroupSchemaClassName))
	{
		group.Invoke(&quot;Put&quot;, new object[] {&quot;description&quot;, description});

		group.CommitChanges();
	}
}
</pre></p>
<p>3. Проверка, существует ли группа с указанным именем в некотором домене.</p>
<p><pre class="brush: csharp;">
[/// &lt;summary&gt;
/// Проверить, существует ли группа с указанным именем в домене или нет.
/// &lt;/summary&gt;
/// &lt;param name=&quot;domain&quot;&gt;Домен в котором осуществляется поиск группы.&lt;/param&gt;
/// &lt;param name=&quot;name&quot;&gt;Имя искомой группы.&lt;/param&gt;
/// &lt;returns&gt;&quot;true&quot; если группа существует, иначе - &quot;false&quot;.&lt;/returns&gt;
bool IsDomainGroupExists(string domain, string name)
{
	try
	{
		var result = GetDomainGroupSid(domain, name);
		return result != null;
	}
	catch (DirectoryServicesCOMException e)
	{
		//There is no such object in the server.
		if (e.ErrorCode == -2147016656)
			return false;

		throw;
	}
}
</pre></p>
<p>4. Проверка, существует ли группа с указанным именем на локальной машине.</p>
<p><pre class="brush: csharp;">
/// &lt;summary&gt;
/// Проверить, существует ли группа с указанным именем на локальной машине или нет.
/// &lt;/summary&gt;
/// &lt;param name=&quot;name&quot;&gt;Имя искомой группы.&lt;/param&gt;
/// &lt;returns&gt;&quot;true&quot; если группа существует, иначе - &quot;false&quot;.&lt;/returns&gt;
bool IsLocalGroupExists(string name)
{
	try
	{
		var result = GetLocalGroupSid(name);
		return result != null;
	}
	catch (COMException e)
	{
		//There is no such object in the server.
		if (e.ErrorCode == -2147022676)
			return false;

		throw;
	}
}
</pre></p>
<p>5. Получение SID (Security IDentifier) доменной группы:</p>
<p><pre class="brush: csharp;">
/// &lt;summary&gt;
/// Получение SID-а доменной группы.
/// &lt;/summary&gt;
/// &lt;param name=&quot;domain&quot;&gt;Домен в котором осуществляется поиск группы.&lt;/param&gt;
/// &lt;param name=&quot;name&quot;&gt;Имя искомой группы.&lt;/param&gt;
/// &lt;returns&gt;SID доменной группы.&lt;/returns&gt;
SecurityIdentifier GetDomainGroupSid(string domain, string name)
{
	try
	{
		var result = DomainUtil.GetDomainIdentitySid(domain, name, GroupSchemaClassName);
		return result;
	}
	catch (DirectoryServicesCOMException e)
	{
		//There is no such object in the server.
		if (e.ErrorCode == -2147016656)
			return null;

		throw;
	}
}
</pre></p>
<p>6. Получение SID-а локальной группы:</p>
<p><pre class="brush: csharp;">
/// &lt;summary&gt;
/// Получение SID-а локальной группы.
/// &lt;/summary&gt;
/// &lt;param name=&quot;name&quot;&gt;Имя искомой группы.&lt;/param&gt;
/// &lt;returns&gt;SID доменной группы.&lt;/returns&gt;
SecurityIdentifier GetLocalGroupSid(string name)
{
	try
	{
		return LocalUtil.GetLocalIdentitySid(name, GroupSchemaClassName);
	}
	catch (COMException e)
	{
		//There is no such object in the server.
		if (e.ErrorCode == -2147022676)
			return null;

		throw;
	}
}
</pre></p>
<p>+В выше описанном коде так же встречается два вспомогательных класса DomainUtil и LocalUtil с функциями для получения SID-а сущности:</p>
<p><pre class="brush: csharp;">
static class DomainUtil
{
	/// &lt;summary&gt;
	/// Получение SID-а доменной сущности.
	/// &lt;/summary&gt;
	/// &lt;param name=&quot;domain&quot;&gt;Имя домена.&lt;/param&gt;
	/// &lt;param name=&quot;name&quot;&gt;Имя сущности.&lt;/param&gt;
	/// &lt;param name=&quot;schemaClassName&quot;&gt;Тип сущности.&lt;/param&gt;
	/// &lt;returns&gt;SID доменной сущности, если она существует. В противном случае null.&lt;/returns&gt;
	public static SecurityIdentifier GetDomainIdentitySid(string domain, string name, string schemaClassName)
	{
		var root = GetDomainDirectoryEntry(domain);
		root = root.Children.Find(&quot;CN=Users&quot;);

		foreach (DirectoryEntry entry in root.Children)
		{

			if (!string.Equals(entry.SchemaClassName, schemaClassName, StringComparison.OrdinalIgnoreCase))
				continue;

			var entiryName = entry.Properties[&quot;sAMAccountName&quot;][0].ToString();
			if (string.Equals(entiryName, name, StringComparison.OrdinalIgnoreCase))
			{
				var sid = new SecurityIdentifier((byte[])entry.Properties[&quot;objectSid&quot;].Value, 0);
				return sid;
			}
		}

		return null;
	}

	/// &lt;summary&gt;
	/// Вспомогательная функция для получения корня домена.
	/// &lt;/summary&gt;
	private static DirectoryEntry GetDomainDirectoryEntry(string domain)
	{
		var path = string.Format(&quot;LDAP://{0}&quot;, domain);
		return new DirectoryEntry(path);
	}
}

static class LocalUtil
{
	/// &lt;summary&gt;
	/// Получение SID-а локальной сущности.
	/// &lt;/summary&gt;
	/// &lt;param name=&quot;name&quot;&gt;Имя сущности.&lt;/param&gt;
	/// &lt;param name=&quot;schemaClassName&quot;&gt;Тип сущности.&lt;/param&gt;
	/// &lt;returns&gt;SID локальной сущности&lt;/returns&gt;
	public static SecurityIdentifier GetLocalIdentitySid(string name, string schemaClassName)
	{
		var root = new DirectoryEntry(string.Format(&quot;WinNT://{0},computer&quot;, Environment.MachineName));

		var entry = root.Children.Find(name, schemaClassName);

		var sid = new SecurityIdentifier((byte[]) entry.Properties[&quot;objectSid&quot;].Value, 0);
		return sid;
	}
}
</pre></p>
<br /> Tagged: active directory, c#, Dev, domain, group, local <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/sergeyhomyuk.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/sergeyhomyuk.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/sergeyhomyuk.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/sergeyhomyuk.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/sergeyhomyuk.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/sergeyhomyuk.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/sergeyhomyuk.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/sergeyhomyuk.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/sergeyhomyuk.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/sergeyhomyuk.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/sergeyhomyuk.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/sergeyhomyuk.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/sergeyhomyuk.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/sergeyhomyuk.wordpress.com/33/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sergeyhomyuk.wordpress.com&amp;blog=5423806&amp;post=33&amp;subd=sergeyhomyuk&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://sergeyhomyuk.wordpress.com/2010/01/10/csharp-manage-local-domain-groups/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">sergeyhomyuk</media:title>
		</media:content>
	</item>
		<item>
		<title>C# &#124; Get current platform (x86/x64)</title>
		<link>http://sergeyhomyuk.wordpress.com/2009/12/28/csharp-get-current-platform/</link>
		<comments>http://sergeyhomyuk.wordpress.com/2009/12/28/csharp-get-current-platform/#comments</comments>
		<pubDate>Mon, 28 Dec 2009 13:25:23 +0000</pubDate>
		<dc:creator>Sergey Homyuk</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[platform]]></category>

		<guid isPermaLink="false">http://sergeyhomyuk.wordpress.com/?p=26</guid>
		<description><![CDATA[В этом посте я приведу фрагменты кода для определения типа системы (32-х или 64-х разрядная) на которой исполняется приложение. (Скачать) Самое простое решение на которое можно натолкнуться в сети выглядит следующим образом: Оно основывается на том факте, что на 32-х битных платформах размер указателя(IntPtr) равен 4-м байтам (или 32 битам), в то время как на [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sergeyhomyuk.wordpress.com&amp;blog=5423806&amp;post=26&amp;subd=sergeyhomyuk&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>В этом посте я приведу фрагменты кода для определения типа системы (32-х или 64-х разрядная) на которой исполняется приложение.</p>
<p><a href="http://dl.dropbox.com/u/2168045/Blog/PlatformUtility.cs">(Скачать)</a></p>
<p><span id="more-26"></span></p>
<p>Самое простое решение на которое можно натолкнуться в сети выглядит следующим образом:</p>
<p><pre class="brush: csharp;">
Platform GetApplicationPlatform()
{
	switch (IntPtr.Size)
	{
		case 4:
			return Platform.X86;
		case 8:
			return Platform.X64;
		default:
			return Platform.Unknown;
	}
}
</pre></p>
<p>Оно основывается на том факте, что на 32-х битных платформах размер указателя(IntPtr) равен 4-м байтам (или 32 битам), в то время как на 64-х битной платформе он равен 8-ми. Тем не менее, у данного решения есть один <strong>существенный</strong> недостаток &#8211; оно работает лишь в том случае, если вы при компиляции приложения указали значение параметра &laquo;Solution Platform&raquo; как &laquo;Any CPU&raquo; (это позволяет JIT-компилятору самостоятельно выбирать размерность адресного пространства в зависимости от текущей платформы).</p>
<p>Существует и более универсальное решение, которое будет работать вне зависимости от значения параметра &laquo;Solution Platform&raquo;. Оно заключается в вызове WinAPI функций GetNativeSystemInfo и GetSystemInfo. Первая используется для OS семейства Windows основанных на ядре NT 5.1 или старше (начиная от Windows XP), вторая &#8211; для более ранних версий.</p>
<p><pre class="brush: csharp;">
const ushort PROCESSOR_ARCHITECTURE_INTEL = 0;
const ushort PROCESSOR_ARCHITECTURE_IA64 = 6;
const ushort PROCESSOR_ARCHITECTURE_AMD64 = 9;
const ushort PROCESSOR_ARCHITECTURE_UNKNOWN = 0xFFFF;

[StructLayout(LayoutKind.Sequential)]
struct SYSTEM_INFO
{
	public ushort wProcessorArchitecture;
	public ushort wReserved;
	public uint dwPageSize;
	public IntPtr lpMinimumApplicationAddress;
	public IntPtr lpMaximumApplicationAddress;
	public UIntPtr dwActiveProcessorMask;
	public uint dwNumberOfProcessors;
	public uint dwProcessorType;
	public uint dwAllocationGranularity;
	public ushort wProcessorLevel;
	public ushort wProcessorRevision;
};

[DllImport(&quot;kernel32.dll&quot;)]
static extern void GetNativeSystemInfo(ref SYSTEM_INFO lpSystemInfo);

[DllImport(&quot;kernel32.dll&quot;)]
static extern void GetSystemInfo(ref SYSTEM_INFO lpSystemInfo);

Platform GetOperationSystemPlatform()
{
	var sysInfo = new SYSTEM_INFO();

	// Если WinXP или старше - используем GetNativeSystemInfo
	if (Environment.OSVersion.Version.Major &gt; 5 ||
		(Environment.OSVersion.Version.Major == 5 &amp;&amp; Environment.OSVersion.Version.Minor &gt;= 1))
	{
		GetNativeSystemInfo(ref sysInfo);
	}
	// Иначе используем GetSystemInfo
	else
	{
		GetSystemInfo(ref sysInfo);
	}

	switch (sysInfo.wProcessorArchitecture)
	{
		case PROCESSOR_ARCHITECTURE_IA64:
		case PROCESSOR_ARCHITECTURE_AMD64:
			return Platform.X64;

		case PROCESSOR_ARCHITECTURE_INTEL:
			return Platform.X86;

		default:
			return Platform.Unknown;
	}
}
</pre></p>
<p>P.S. Platform &#8211; простой enum, со следующими значениями:</p>
<p><pre class="brush: csharp;">
enum Platform
    {
        X86,
        X64,
        Unknown
    }
</pre></p>
<br /> Tagged: c#, Dev, platform <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/sergeyhomyuk.wordpress.com/26/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/sergeyhomyuk.wordpress.com/26/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/sergeyhomyuk.wordpress.com/26/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/sergeyhomyuk.wordpress.com/26/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/sergeyhomyuk.wordpress.com/26/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/sergeyhomyuk.wordpress.com/26/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/sergeyhomyuk.wordpress.com/26/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/sergeyhomyuk.wordpress.com/26/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/sergeyhomyuk.wordpress.com/26/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/sergeyhomyuk.wordpress.com/26/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/sergeyhomyuk.wordpress.com/26/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/sergeyhomyuk.wordpress.com/26/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/sergeyhomyuk.wordpress.com/26/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/sergeyhomyuk.wordpress.com/26/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sergeyhomyuk.wordpress.com&amp;blog=5423806&amp;post=26&amp;subd=sergeyhomyuk&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://sergeyhomyuk.wordpress.com/2009/12/28/csharp-get-current-platform/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">sergeyhomyuk</media:title>
		</media:content>
	</item>
		<item>
		<title>C# &#124; Manage Local Users &amp; Groups</title>
		<link>http://sergeyhomyuk.wordpress.com/2009/06/13/c-manage-local-users-groups/</link>
		<comments>http://sergeyhomyuk.wordpress.com/2009/06/13/c-manage-local-users-groups/#comments</comments>
		<pubDate>Sat, 13 Jun 2009 09:01:15 +0000</pubDate>
		<dc:creator>Sergey Homyuk</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[group]]></category>
		<category><![CDATA[local]]></category>
		<category><![CDATA[user]]></category>

		<guid isPermaLink="false">http://sergeyhomyuk.wordpress.com/?p=24</guid>
		<description><![CDATA[На этот раз рассмотрим работу с локальными пользователями и группами в C#. 1. Создание пользователя. 2. Создание группы. 3. Добавление пользователя в группу. 4. Проверка, существует ли группа с заданным именем. 5. Проверка, является ли пользователь членом группы. (Скачать) 1. Создание пользователя: 2. Создание группы: 3. Добавление пользователя в группу: 4. Проверка, существует ли группа [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sergeyhomyuk.wordpress.com&amp;blog=5423806&amp;post=24&amp;subd=sergeyhomyuk&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>На этот раз рассмотрим работу с локальными пользователями и группами в C#.</p>
<p>1. Создание пользователя.<br />
2. Создание группы.<br />
3. Добавление пользователя в группу.<br />
4. Проверка, существует ли группа с заданным именем.<br />
5. Проверка, является ли пользователь членом группы.</p>
<p><a href="http://dl.dropbox.com/u/2168045/Blog/LocalUtility.cs">(Скачать)</a></p>
<p><span id="more-24"></span></p>
<p>1. <strong>Создание пользователя:</strong></p>
<p><pre class="brush: csharp;">
public static void CreateLocalUser(string login, string fullName, string password)
{
    var root = new DirectoryEntry(string.Format(&quot;WinNT://{0},computer&quot;, Environment.MachineName));
    using (var user = root.Children.Add(login, &quot;user&quot;))
    {
        user.Properties[&quot;FullName&quot;].Value = fullName;
        user.Invoke(&quot;SetPassword&quot;, new object[] { password });
        user.CommitChanges();
    }
}
</pre></p>
<p>2. <strong>Создание группы:</strong></p>
<p><pre class="brush: csharp;">
public static void CreateLocalGroup(string name, string description)
{
    var root = new DirectoryEntry(string.Format(&quot;WinNT://{0},computer&quot;, Environment.MachineName));
    using (var group = root.Children.Add(name, &quot;group&quot;))
    {
        group.Invoke(&quot;Put&quot;, new object[] {&quot;description&quot;, description});
        group.CommitChanges();
    }
}
</pre></p>
<p>3. <strong>Добавление пользователя в группу:</strong></p>
<p><pre class="brush: csharp;">
public static void AddLocalUserToLocalGroup(string userName, string groupName)
{
    string groupPath = string.Format(&quot;WinNT://{0}/{1},group&quot;, Environment.MachineName, groupName);
    string userPath = string.Format(&quot;WinNT://{0}/{1},user&quot;, Environment.MachineName, userName);
    var root = new DirectoryEntry(groupPath);
    root.Invoke(&quot;Add&quot;, new object[] { userPath });
    root.CommitChanges();
}
</pre></p>
<p>4. <strong>Проверка, существует ли группа с заданным именем:</strong></p>
<p><pre class="brush: csharp;">
public static bool IsLocalGroupExists(string name)
{
    var root = new DirectoryEntry(string.Format(&quot;WinNT://{0},computer&quot;, Environment.MachineName));
    try
    {
        root.Children.Find(name, &quot;group&quot;);
        return true;
    }
    catch (COMException e)
    {
        if (e.ErrorCode == -2147022676)
            return false;
        throw;
    }
}
</pre></p>
<p>5. <strong>Проверка, является ли пользователь членом группы:</strong></p>
<p><pre class="brush: csharp;">
public static bool IsUserInLocalGroup(string userName, string groupName)
{
    var root = new DirectoryEntry(string.Format(&quot;WinNT://{0},computer&quot;, Environment.MachineName));
    root = root.Children.Find(userName, &quot;user&quot;);
    var groups = root.Invoke(&quot;groups&quot;);
    foreach (var group in (IEnumerable) groups)
    {
        var groupEntry = new DirectoryEntry(group);
        if (string.Equals(groupEntry.Name, groupName, StringComparison.CurrentCultureIgnoreCase))
            return true;
    }
    return false;
}
</pre></p>
<br /> Tagged: c#, Dev, group, local, user <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/sergeyhomyuk.wordpress.com/24/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/sergeyhomyuk.wordpress.com/24/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/sergeyhomyuk.wordpress.com/24/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/sergeyhomyuk.wordpress.com/24/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/sergeyhomyuk.wordpress.com/24/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/sergeyhomyuk.wordpress.com/24/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/sergeyhomyuk.wordpress.com/24/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/sergeyhomyuk.wordpress.com/24/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/sergeyhomyuk.wordpress.com/24/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/sergeyhomyuk.wordpress.com/24/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/sergeyhomyuk.wordpress.com/24/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/sergeyhomyuk.wordpress.com/24/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/sergeyhomyuk.wordpress.com/24/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/sergeyhomyuk.wordpress.com/24/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sergeyhomyuk.wordpress.com&amp;blog=5423806&amp;post=24&amp;subd=sergeyhomyuk&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://sergeyhomyuk.wordpress.com/2009/06/13/c-manage-local-users-groups/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">sergeyhomyuk</media:title>
		</media:content>
	</item>
		<item>
		<title>C# &#124; Manage Domain Users &amp; Groups</title>
		<link>http://sergeyhomyuk.wordpress.com/2009/06/12/c-manage-domain-users-groups/</link>
		<comments>http://sergeyhomyuk.wordpress.com/2009/06/12/c-manage-domain-users-groups/#comments</comments>
		<pubDate>Fri, 12 Jun 2009 17:53:00 +0000</pubDate>
		<dc:creator>Sergey Homyuk</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[active directory]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[domain]]></category>
		<category><![CDATA[group]]></category>
		<category><![CDATA[user]]></category>

		<guid isPermaLink="false">http://sergeyhomyuk.wordpress.com/2009/06/12/c-manage-domain-users-groups/</guid>
		<description><![CDATA[В данной статье приведены примеры работы с доменными пользователями и группами в C#. 1. Создание пользователя. 2. Создание группы. 3. Добавление пользователя в группу. 4. Проверка, существует ли группа с заданным именем. 5. Проверка, является ли пользователь членом группы. + Флаги, описывающие тип доменной группы. + Флаги, описывающие параметры пользователя. (Скачать) 1. Создание пользователя: 2. [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sergeyhomyuk.wordpress.com&amp;blog=5423806&amp;post=6&amp;subd=sergeyhomyuk&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>В данной статье приведены примеры работы с доменными пользователями и группами в C#.</p>
<p>1. Создание пользователя.<br />
2. Создание группы.<br />
3. Добавление пользователя в группу.<br />
4. Проверка, существует ли группа с заданным именем.<br />
5. Проверка, является ли пользователь членом группы.<br />
+ Флаги, описывающие тип доменной группы.<br />
+ Флаги, описывающие параметры пользователя.</p>
<p><a href="http://dl.dropbox.com/u/2168045/Blog/DomainUtility.cs">(Скачать)</a></p>
<p><span id="more-6"></span></p>
<p>1. <strong>Создание пользователя:</strong></p>
<p><pre class="brush: csharp;">
public static void CreateDomainUser(string login, string fullName, string password)
{
    string domainDNS = Domain.GetComputerDomain().ToString();
    var root = Domain.GetComputerDomain().GetDirectoryEntry();
    root = root.Children.Find(&quot;CN=Users&quot;);
    string cn = string.IsNullOrEmpty(fullName) ? login : fullName;
    using (var user = root.Children.Add(string.Format(&quot;CN={0}&quot;, cn), &quot;user&quot;))
    {
        user.Properties[&quot;sAMAccountName&quot;].Value = login;
        string upn = string.Format(&quot;{0}@{1}&quot;, login, domainDNS);
        user.Properties[&quot;userPrincipalName&quot;].Value = upn;
        user.CommitChanges();
        user.Invoke(&quot;SetPassword&quot;, new object[] { password });
        user.Properties[&quot;userAccountControl&quot;].Value = AdsUserFlags.NormalAccount | AdsUserFlags.PasswordDoesNotExpire;
        user.CommitChanges();
    }
 }
</pre></p>
<p>2. <strong>Создание группы:</strong></p>
<p><pre class="brush: csharp;">
public static void CreateDomainGroup(string name, string description, DomainGroupTypes groupTypes)
{
    var root = Domain.GetComputerDomain().GetDirectoryEntry();
    root = root.Children.Find(&quot;CN=Users&quot;);
    using (var group = root.Children.Add(string.Format(&quot;CN={0}&quot;, name), &quot;group&quot;))
    {
        group.Properties[&quot;sAMAccountName&quot;].Add(name);
        group.Properties[&quot;description&quot;].Add(description);
        group.Properties[&quot;groupType&quot;].Add((int) groupTypes);
        group.CommitChanges();
    }
}
</pre></p>
<p>3. <strong>Добавление пользователя в группу:</strong></p>
<p><pre class="brush: csharp;">
public static void AddDomainUserToDomainGroup(string userName, string groupName)
{
    string domainDNS = Domain.GetComputerDomain().ToString();
    var root = Domain.GetComputerDomain().GetDirectoryEntry();
    root = root.Children.Find(&quot;CN=Users&quot;);
    var group = root.Children.Find(string.Format(&quot;CN={0}&quot;, groupName), &quot;group&quot;);
    var user = root.Children.Find(string.Format(&quot;CN={0}&quot;, userName), &quot;user&quot;);
    group.Properties[&quot;member&quot;].Add(user.Path.Substring(7 + domainDNS.Length + 1));
    group.CommitChanges();
}
</pre></p>
<p> <br />
4. <strong>Проверка, существует ли группа с заданным именем:</strong></p>
<p><pre class="brush: csharp;">
public static bool IsDomainGroupExists(string name)
{
    var root = Domain.GetComputerDomain().GetDirectoryEntry();
    root = root.Children.Find(&quot;CN=Users&quot;);
    try
    {
        root.Children.Find(string.Format(&quot;CN={0}&quot;, name), &quot;group&quot;);
        return true;
    }
    catch (DirectoryServicesCOMException e)
    {
        if (e.ErrorCode == -2147016656)
            return false;
        throw;
    }
}
</pre></p>
<p>5. <strong>Проверка, является ли пользователь членом группы:</strong></p>
<p><pre class="brush: csharp;">
public static bool IsUserInDomainGroup(string userName, string groupName)
{
    var root = Domain.GetComputerDomain().GetDirectoryEntry();
    var searcher = new DirectorySearcher(root)
                       {
                           Filter = string.Format(&quot;sAMAccountName={0}&quot;, userName)
                       };
    searcher.PropertiesToLoad.Add(&quot;memberOf&quot;);
    SearchResult result = searcher.FindOne();
    if (result != null)
    {
        var groups = result.Properties[&quot;memberOf&quot;];
        foreach (var group in groups)
        {
            string entry = group.ToString();
            entry = entry.Substring(0, entry.IndexOf(&quot;,&quot;, 0));
            entry = entry.Replace(&quot;CN=&quot;, string.Empty);
            entry = entry.Trim();
            if (string.Equals(entry, groupName, StringComparison.CurrentCultureIgnoreCase))
                return true;
        }
    }
    return false;
}
</pre></p>
<p>+ <strong>Флаги, описывающие тип доменной группы:</strong></p>
<p><pre class="brush: csharp;">
[Flags]
public enum DomainGroupTypes : uint
{
    UniversalGroup = 0x08,
    DomainLocalGroup = 0x04,
    GlobalGroup = 0x02,
    SecurityGroup = 0x80000000
}
</pre></p>
<p>+ <strong>Флаги, описывающие параметры пользователя:</strong></p>
<p><pre class="brush: csharp;">
[Flags]
public enum AdsUserFlags
{
    Script = 1,                          // 0x1
    AccountDisabled = 2,                 // 0x2
    HomeDirectoryRequired = 8,           // 0x8
    AccountLockedOut = 16,               // 0x10
    PasswordNotRequired = 32,            // 0x20
    PasswordCannotChange = 64,           // 0x40
    EncryptedTextPasswordAllowed = 128,  // 0x80
    TempDuplicateAccount = 256,          // 0x100
    NormalAccount = 512,                 // 0x200
    InterDomainTrustAccount = 2048,      // 0x800
    WorkstationTrustAccount = 4096,      // 0x1000
    ServerTrustAccount = 8192,           // 0x2000
    PasswordDoesNotExpire = 65536,       // 0x10000
    MnsLogonAccount = 131072,            // 0x20000
    SmartCardRequired = 262144,          // 0x40000
    TrustedForDelegation = 524288,       // 0x80000
    AccountNotDelegated = 1048576,       // 0x100000
    UseDesKeyOnly = 2097152,              // 0x200000
    DontRequirePreauth = 4194304,         // 0x400000
    PasswordExpired = 8388608,           // 0x800000
    TrustedToAuthenticateForDelegation = 16777216, // 0x1000000
    NoAuthDataRequired = 33554432        // 0x2000000
}
</pre></p>
<br /> Tagged: active directory, c#, Dev, domain, group, user <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/sergeyhomyuk.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/sergeyhomyuk.wordpress.com/6/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/sergeyhomyuk.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/sergeyhomyuk.wordpress.com/6/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/sergeyhomyuk.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/sergeyhomyuk.wordpress.com/6/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/sergeyhomyuk.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/sergeyhomyuk.wordpress.com/6/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/sergeyhomyuk.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/sergeyhomyuk.wordpress.com/6/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/sergeyhomyuk.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/sergeyhomyuk.wordpress.com/6/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/sergeyhomyuk.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/sergeyhomyuk.wordpress.com/6/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sergeyhomyuk.wordpress.com&amp;blog=5423806&amp;post=6&amp;subd=sergeyhomyuk&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://sergeyhomyuk.wordpress.com/2009/06/12/c-manage-domain-users-groups/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">sergeyhomyuk</media:title>
		</media:content>
	</item>
		<item>
		<title>Hello world!</title>
		<link>http://sergeyhomyuk.wordpress.com/2008/11/06/hello-world/</link>
		<comments>http://sergeyhomyuk.wordpress.com/2008/11/06/hello-world/#comments</comments>
		<pubDate>Thu, 06 Nov 2008 05:58:06 +0000</pubDate>
		<dc:creator>Sergey Homyuk</dc:creator>
				<category><![CDATA[Без категории]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Welcome to WordPress.com. This is your first post. Edit or delete it and start blogging!<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sergeyhomyuk.wordpress.com&amp;blog=5423806&amp;post=1&amp;subd=sergeyhomyuk&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Welcome to <a href="http://wordpress.com/">WordPress.com</a>. This is your first post. Edit or delete it and start blogging!</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/sergeyhomyuk.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/sergeyhomyuk.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/sergeyhomyuk.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/sergeyhomyuk.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/sergeyhomyuk.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/sergeyhomyuk.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/sergeyhomyuk.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/sergeyhomyuk.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/sergeyhomyuk.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/sergeyhomyuk.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/sergeyhomyuk.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/sergeyhomyuk.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/sergeyhomyuk.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/sergeyhomyuk.wordpress.com/1/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sergeyhomyuk.wordpress.com&amp;blog=5423806&amp;post=1&amp;subd=sergeyhomyuk&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://sergeyhomyuk.wordpress.com/2008/11/06/hello-world/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">sergeyhomyuk</media:title>
		</media:content>
	</item>
	</channel>
</rss>
