Разработчикам бизнес-приложений часто приходиться создавать решения, автоматизирующие повседневные операции в их организациях. Эти операции обычно включают обработку данных и манипулирование ими в различных документах, например выборку и консолидацию данных из множества документов-источников, слияние данных в сообщения электронной почты, поиск и замена блоков содержимого в документах, пересчет данных в рабочих книгах, извлечение изображений из презентаций и... список можно продолжать еще долго.
Microsoft Office упрощает выполнение таких повторяющихся задач, предоставляя богатый API, который разработчики могут использовать для автоматизации операций. Поскольку такие решения для обычных пользователей настольных приложений работают бесшовно, разработчики потом выводят их на следующий уровень: развертывают решения на серверах, создающих централизованную точку выполнения всех этих повторяющихся задач для множества пользователей без всякого вмешательства со стороны человека.
Хотя перемещение решений, выполняющих повторяющиеся задачи Office, с настольного компьютера на сервер кажется делом прямолинейным, оно вовсе не так просто.
Изначально Microsoft проектировала пакет приложений Office для настольных компьютеров, где пользователь входит в систему и садится перед экраном своего компьютера. По соображениям безопасности, производительности и надежности приложения Office — неподходящие средства для применения на серверной стороне. Приложения Office в серверной среде могут потребовать вмешательства человека, а это не оптимально для серверного решения. Microsoft рекомендует избегать такого рода решений; соответствующие соображения изложены в статье «Considerations for server-side Automation of Office» от Microsoft Support.
Однако с выпуском Office 2007 автоматизация Office сильно изменилась. В Office 2007 компания Microsoft ввела Office OpenXML и Excel Services для разработчиков, желающих создавать решения на основе Office для серверной стороны.
Выпустив Office 2010 и SharePoint 2010, Microsoft предоставила новый набор компонентов под названием Application Services. Они добавляют богатый инструментарий в арсенал разработчика решений по автоматизации Office. Application Services включает Excel Services, Word Automation Services, InfoPath Forms Services, PerformancePoint Services и Visio Services. Подробнее об этих сервисах см. по ссылке msdn.microsoft.com/library/ee559367(v=office.14).
В этой статье мы покажем, как использовать Office OpenXML, Word Automation Services и SharePoint для создания простого приложения, которое выполняет слияние отдельных отчетов о состоянии в единый документ.
Рабочий процесс
Допустим, вы разработчик в компании, занимающейся созданием сервисов, в которой многие проекты управляются разными группами. Еженедельно каждый руководитель проекта использует общий шаблон для создания отчета о состоянии дел и загружает его во внутреннее хранилище SharePoint. Теперь ваш руководитель группы хочет получить консолидированный отчет, в котором содержатся все эти еженедельные отчеты, и, догадайтесь с трех раз, именно вам поручили реализовать это требование.
Однако вам повезло. Как мы уже упоминали, сегодня ваша задача упростилась, потому что вы можете реализовать это требование с куда меньшими усилиями, используя OpenXML и Word Automation Services. Вы сможете создать более надежное и стабильное решение, построить которое раньше — в отсутствие этих технологий —было бы весьма проблематично.
Начнем со схемы решения. Предлагаемый рабочий процесс показан на рис. 1. Он запускается индивидуальными руководителями проектов, заполняющими отчеты о состоянии дел и загружающими их в SharePoint на сервере. Руководитель группы может после этого инициировать процесс слияния любых отчетов, хранящихся на сервере, и сгенерировать объединенный отчет.
Увеличить
Рис. 1. Рабочий процесс генерации отчета о состоянии
Создание шаблона
Чтобы реализовать это решение, первым делом следует позаботиться об общем шаблоне еженедельных отчетов для всех руководителей проектов. Закончив заполнять отчеты, они будут загружать их в хранилище SharePoint. Утром в понедельник руководитель группы может войти на сайт SharePoint и запустить логику, которая выполняет следующие задачи.
- Считывает все индивидуальные документы с отчетами о состоянии дел.
- Объединяет их в единый отчет.
- Сохраняет отчет в хранилище, доступном для пользователей.
Как выглядит шаблон отчета о состоянии дел (назовем его WeeklyStatusReport.dotx), показано на рис. 2. Как видите, шаблон включает поля для вставки заголовка, дат, имени руководителя проекта, основных этапов (milestones) и связанных данных, текстовых полей для ввода подробностей о выполненной работе, планах и проблемах. В этом случае для упрощения примера мы использовали текстовые поля и элемент управления «выбор даты» (date picker), но вы можете легко заменить их на раскрывающиеся списки, флажки и множество других элементов управления для большего удобства ввода данных.
Рис. 2. Шаблон еженедельного отчета о состоянии дел
Библиотека документов
Следующий шаг — создание собственной библиотеки документов, в которой будут размещаться еженедельные отчеты на основе показанного ранее шаблона.
В панели навигации SharePoint щелкните Libraries, а затем Create, чтобы создать новую библиотеку. В диалоге Create установите фильтрацию по Library, выберите Document Library и введите имя библиотеки (мы ввели WSR Library). Теперь щелкните Create.
Теперь вам надо создать тип контента для новой библиотеки. Выберите Site Actions | Site Settings и в разделе Galleries щелкните Site content types. Нажмите Create и введите имя типа контента (мы ввели Weekly Status Report).
В списке Select Parent Content Type From выберите Document Content Types, а в списке Parent Content Type — Document и щелкните OK.
В разделе Settings выберите Advanced Settings, щелкните кнопку-переключатель Upload a new document template и нажмите Browse. Найдите шаблон отчета (WeeklyStatusReport.dotx) и загрузите его в библиотеку.
Далее перейдите в WSR Library и выберите Library Settings. В General Settings укажите Advanced Settings. Выберите Yes для Allow management of content types и щелкните OK.
Вы увидите список типов контента, показываемый на странице параметров библиотеки. Выберите ссылку Add from Existing Site Content Types. Укажите тип контента, созданный вами ранее, в списке доступных типов контента сайта. В данном примере это Weekly Status Report. Щелкните Add и OK.
И вновь в списке типов контента укажите Document и выберите Delete this content type. Щелкните OK в окне с предупреждением.
Теперь вы должны увидеть свой тип контента, когда выберете New Document в WSR Library (рис. 3).
Рис. 3. Выбор собственного типа контента
Теперь вы можете двигаться дальше и добавить в библиотеку документов парочку отчетов.
Создание веб-фрагмента
Далее нужно разрешить руководителю группы запускать логику консолидации. Для этого можно воспользоваться кнопкой внизу представления библиотеки документов по умолчанию.
Здесь потребуются два этапа. Во-первых, вы создадите визуальный веб-фрагмент (Visual Web Part) с помощью Visual Studio 2010, а во-вторых, добавите веб-фрагмент в библиотеку документов, используя SharePoint Designer 2010.
Чтобы создать собственный веб-фрагмент, откройте новый проект Visual Studio 2010, используя шаблон Visual Web Part. Присвойте проекту имя, например DocumentMerge, и щелкните OK.
На странице мастера SharePoint Customization выберите свое веб-приложение (URL на сайт SharePoint, где размещена ваша библиотека документов) и щелкните Finish.
Создав проект, откройте файл VisualWebPart1.cs и модифицируйте метод CreateChildControls следующим кодом:
protected override void CreateChildControls() {
Control control = Page.LoadControl(_ascxPath);
Controls.Add(control);
base.CreateChildControls();
Button btnSubmit = new Button();
btnSubmit.Text = "Merge Reports";
btnSubmit.Click += new EventHandler(OnSubmitClick);
Controls.Add(btnSubmit);
}
Также добавьте обработчик события щелчка кнопки:
void OnSubmitClick(object sender, EventArgs e) {
// TODO : Put code to merge documents here
}
На этом этапе вы можете скомпилировать и развернуть свой проект. Мы добавим реализацию обработчика OnSubmitClick немного позже.
Следующий шаг — добавление веб-фрагмента в библиотеку документов. В SharePoint Designer 2010 откройте сайт (узел) SharePoint. Выберите All Files | WSR Library | Forms, а затем щелкните AllItems.aspx для редактирования.
Нажмите кнопку на странице. Щелкните Insert | Web Part, потом выберите More Web Parts. В поле поиска введите VisualWebPart (имя веб-фрагмента, который вы только что создали и развернули) и щелкните OK (рис. 4). На рис. 5 показана страница с установленным веб-фрагментом. Сохраните страницу и закройте SharePoint Designer.
Рис. 4. Вставка веб-фрагмента
Рис. 5. Веб-фрагмент, установленный в нужное место страницы
Слияние отчетов
Теперь добавим логику слияния документов, загруженных в библиотеку. Для большей простоты этот код будет объединять все документы, загруженные в данную папку, в единственный файл. Более реалистичный подход — слияние лишь выбранных элементов или элементов, загруженных в заданный период. Вы могли бы также сохранять объединенный документ в другом месте или другой библиотеке. Вот сейчас мы и добавим реализацию обработчика OnSubmitClick к нашему проекту VisualWebPart в Visual Studio 2010.
В обработчике OnSubmitClick веб-фрагмента нужно предоставить логику для чтения отчетов, загруженных в библиотеку документов, генерации пустого документа OpenXML и последующего слияния отчетов в этот новый документ.
Сначала мы считываем все документы из текущей библиотеки. Для этого можно перебирать SPListItemCollection текущего SPContext, считывая каждый файл в байтовый массив с использованием SPFile.OpenBinary API:
SPListItemCollection files = SPContext.Current.List.Items;
foreach (SPListItem item in files) {
SPFile inputFile = item.File;
byte[] byteArray =
inputFile.OpenBinary();
// process each byte array
}
Затем генерируем пустой документ OpenXML. Генерировать его нужно в памяти с использованием MemoryStream, так как OpenXML SDK не позволяет сохранять документы по URI. Вместо этого объект MemoryStream может скопировать документ в библиотеку в виде нового файла. Код для создания этого файла показан на рис. 6.
Рис. 6. Создание нового файла для объединенного отчета
// String containing the blank document part for our new DOCX
string strEmptyMainPart =
"<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" +
"<w:document xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>" +
"<w:body><w:p><w:r><w:t></w:t></w:r></w:p></w:body></w:document>";
// In-memory stream for our consolidated DOCX.
MemoryStream memOut = new MemoryStream();
// Output document's OpenXML object
WordprocessingDocument outputDoc =
WordprocessingDocument.Create(memOut,
DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
MainDocumentPart mainPart = outputDoc.AddMainDocumentPart();
Stream partStream = mainPart.GetStream();
UTF8Encoding encoder = new UTF8Encoding();
// Add blank main part string to the newly created document
Byte[] buffer = encoder.GetBytes(strEmptyMainPart);
partStream.Write(buffer, 0, buffer.Length);
// Save the document in memory
mainPart.Document.Save();
Заметьте, что вы должны добавить DocumentFormat.OpenXml.dll и WindowsBase.dll в ссылки и включить в код соответствующие выражения using:
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
Следующий шаг — реализация логики для сохранения объединенного документа в библиотеке как нового документа. Это потребует некоторых усилий, но эту задачу можно упростить с помощью SharePoint Managed Client Object Model. Вам понадобится добавить две ссылки в проект: на Microsoft.SharePoint.Client.dll и Microsoft.SharePoint.Client.Runtime.dll, которые находятся в следующей папке:
%ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\ISAPI
Новый документ в библиотеке SharePoint создается так:
ClientContext clientContext =
new ClientContext(SPContext.Current.Site.Url);
ClientOM.File.SaveBinaryDirect(clientContext,
outputPath, memOut, true);
Чтобы эти инструкции работали, нужно добавить в файл исходного кода следующие выражения using:
using Microsoft.SharePoint.Client;
using ClientOM = Microsoft.SharePoint.Client;
Как сделать, чтобы документ поддерживал поиск
На этом этапе у вас есть логика для генерации полнофункциональных консолидированных документов на сервере (слияние осуществляется щелчком кнопки Merge Reports).
Однако здесь есть один маленький подвох: сгенерированный документ несовместим с поисковым механизмом SharePoint, так как он содержит OpenXML-разметку altChunk. Это побочный эффект слияния отчетов в пустой документ с использованием показанного ранее кода. Разметка altChunk заменяется исходным контентом, когда документ открывается в Word.
Благодаря новым сервисам Word Automation Services в SharePoint 2010 эту задачу можно выполнить программно с применением класса ConversionJob. Этот класс является частью сборки Microsoft.Office.Word.Server.dll, поэтому вручную добавьте ссылку на эту сборку в проект. После этого вы можете использовать код на рис. 7 для преобразования altChunk.
Рис. 7. Преобразование altChunk в объединенном документе
string docPath = string.Format(@"{0}{1}",
SPContext.Current.Site.Url.Replace(@"\\", ""),
outputPath);
ConversionJobSettings JobSettings =
new ConversionJobSettings();
JobSettings.OutputFormat = SaveFormat.Document;
JobSettings.OutputSaveBehavior =
SaveBehavior.AlwaysOverwrite;
ConversionJob ConvJob = new ConversionJob(
"Word Automation Services", JobSettings);
ConvJob.UserToken = SPContext.Current.Site.UserToken;
ConvJob.AddFile(docPath, docPath);
ConvJob.Start();
Дополнительные подробности о решении см. в исходном коде, который можно скачать для этой статьи; данный код вы сможете использовать в качестве основы для своей системы отчетности.
Заключительные этапы
Чтобы протестировать этот код, мы изменили в своем сервере SharePoint параметры запуска Automation Service, установив старт через одну минуту после приема запроса. По умолчанию этот интервал равен пяти минутам, и мы не хотели ждать так долго выполнения преобразования.
Если вы захотите изменить этот параметр, то можете задать его в SharePoint Central Administration; для этого откройте Application Management | Manage Service Applications | Word Automation Services и установите параметр Frequency в разделе Conversion Throughput таким, чтобы преобразования начинались через одну минуту.
Окончательный сгенерированный отчет содержит все еженедельные отчеты о состоянии дел, созданные вами, и они объединены в один новый документ, где каждый из индивидуальных отчетов размещается один за другим.
Вот и все. В одной из будущих статей мы выведем концепцию слияния содержимого документов на серверной стороне на следующий уровень. Мы покажем, как реализовать вариант со слиянием почты на серверной стороне, и для этого вновь задействуем Office 2010, SharePoint 2010 и Visual Studio 2010. Ну а пока удачи в программировании.
Подробнее об Office 2010 и SharePoint 2010 см. центры разработчиков Office и SharePoint. Информацию об Office OpenXML см. по ссылке msdn.microsoft.com/library/bb448854, а сведения о Word Automation Services можно найти по ссылке msdn.microsoft.com/library/ee558278(v=office.14).