Программный рендеринг отчетов CRM
Как Вы знаете в Reporting Services присутствует функционал по автоматической рассылке отчетов по расписанию. Одним из его недостатков является невозможность динамически передавать в формируемые отчеты какие-либо параметры. Но к счастью эти же самые отчеты можно формировать программно, используя веб-службу SSRS. Рассмотрим несколько вариантов (более-менее) жизненных вариантов ее использования…
Но прежде чем приступим создадим простой тестовы отчет и выполним кое-какие предпосылки для его программного рендеринга:
- Я не буду в этой статье вдаваться в детали разработки отчетов (для этого можете посмотреть эти посты: http://mmcrm.ru/?cat=25), скажу лишь что я создал небольшой отчет, который выводит в текстовых полях информацию об одном (каком-либо) Контакте. Этот отчет принимает два параметра: GUID Контакта, информацию о котором необходимо отобразить и Цвет (в виде любого HTML-цвета), в который необходимо покрасить заголовок отчета.
- Далее я этот отчет опубликовал в CRM. И тут нас поджидает первая «проблема», котороая состоит в том, что Вы видите только GUID’ы отчетов CRM в менеджере отчетов SSRS. Чтобы иметь возможность программно выполнить отчет по его CRM’ному имени, Вы должны опубликовать его для наружного применения. Для этого, выделите Ваш отчет в CRM и нажмите Изменить – откроется окно редактирования отчета – далее меню Действия – Опубликовать отчет для внешнего использования.
Если Вы теперь откроете Менеджер отчетов SSRS (находится по такому пути http://<сервер_отчетов>/reports) и перейдете в папку Вашей организации, то Вы увидите только что опубликованный для наружного применения отчет (и любой другой который в нем используется). Теперь Вы можете использовать веб-службу SSRS для рендеринга этого отчета обратившись к нему по его имени.
Сохранение отчетов на жестком диске и отправка электронных писем с вложенными отчетами из CRM
В этом примере создадим плагин который будет делать две вещи:
- Сохранять нужный нам отчет (в сгенерированном виде) на жестком диске в формате PDF
- Создавать и отправлять из CRM электронной письмо с вложенным динамически сгенерированным отчетом
Приступим…
- Создайте новый CRM-плагин;
- Добавьте в проект web reference на веб-службу SSRS. Ссылка имеет такой вид:
http://<сервер_отчетов>/ReportServer/ReportExecution2005.asmx
Задайте для нее имя ReportService;
- Добавьте в проект ссылки на SDK-сборки;
- Подпишите плагин;
- Поместите в плагин такой код:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Crm.Sdk; using Microsoft.Crm.SdkTypeProxy; using ClassLibrary2.ReportService; using System.Web.Services.Protocols; using System.IO; namespace ClassLibrary2 { public class Class1: IPlugin { public void Execute(IPluginExecutionContext context) { // Настраиваем Crm Service ICrmService service = context.CreateCrmService(true); // Получаем GUID обновяемой записи Контакта (информацию о которой будем выводить в отчете) DynamicEntity entity = (DynamicEntity)context.InputParameters.Properties["Target"]; Key ContactId = (Key)entity.Properties["contactid"]; byte[] result = null; // Настраиваем API Reporting Service ReportService.ReportExecutionService rs = new ReportExecutionService(); //rs.Credentials = System.Net.CredentialCache.DefaultCredentials; rs.Credentials = new System.Net.NetworkCredential("Administrator", "1qaz@WSX", "d2008"); rs.Url = "http://win-n22hj23d1b1/ReportServer/ReportExecution2005.asmx"; // Задаем служебные параметры для выполнения отчета: // 1. Путь к отчету (относительно Reporting Service) // 2. Выходной формат // 3. Информация об устройстве string reportPath = "/superfirma_MSCRM/КонтактИнфо"; string format = "PDF"; string historyID = null; string devInfo = @"<DeviceInfo><Toolbar>False</Toolbar></DeviceInfo>"; // Передаем параметры в отчет ParameterValue[] parameters = new ParameterValue[2]; // Указываем сколько всего параметров parameters[0] = new ParameterValue(); parameters[0].Name = "contactguid"; // Передаем GUID Контакта parameters[0].Value = ContactId.Value.ToString(); parameters[1] = new ParameterValue(); parameters[1].Name = "color"; // Передаем цвет заголовка отчета parameters[1].Value = "red"; // Всякая служебная инфа DataSourceCredentials[] credentials = null; string showHideToggle = null; string encoding; string mimeType; string extension; Warning[] warnings = null; ParameterValue[] reportHistoryParameters = null; string[] streamIDs = null; ExecutionInfo execInfo = new ExecutionInfo(); ExecutionHeader execHeader = new ExecutionHeader(); rs.ExecutionHeaderValue = execHeader; execInfo = rs.LoadReport(reportPath, historyID); rs.SetExecutionParameters(parameters, "en-us"); String SessionId = rs.ExecutionHeaderValue.ExecutionID; try { // Генерируем отчет result = rs.Render(format, devInfo, out extension, out encoding, out mimeType, out warnings, out streamIDs); } catch (SoapException err) { throw new Exception(err.Detail.OuterXml); } // Записываем полученный отчет в файл try { FileStream stream = File.Create(@"c:\test\КонтактИнфо.pdf", result.Length); stream.Write(result, 0, result.Length); stream.Close(); } catch (Exception error) { throw new Exception(error.Message); } // Отправление электронной почты с вложенным файлом отчета try { // Создаем получателя электропочты activityparty partyTo = new activityparty(); partyTo.partyid = new Lookup(); partyTo.partyid.type = EntityName.contact.ToString(); partyTo.partyid.Value = ContactId.Value; // Создаем отправителя электропочты activityparty partyFrom = new activityparty(); partyFrom.partyid = new Lookup(); partyFrom.partyid.type = EntityName.systemuser.ToString(); partyFrom.partyid.Value = context.UserId; // Создаем запись Электронной почты email Email = new email(); Email.subject = "Пример мыла"; Email.torecipients = ContactId.Value.ToString(); Email.description = "Текст сообщение."; Email.to = new activityparty[] { partyTo }; Email.from = new activityparty[] { partyFrom }; Email.regardingobjectid = new Lookup(); Email.regardingobjectid.type = EntityName.contact.ToString(); Email.regardingobjectid.Value = ContactId.Value; Guid EmailId = service.Create(Email); // Добавляем к письму вложение activitymimeattachment setupEmailAttachment = new activitymimeattachment(); setupEmailAttachment.subject = "Заголовок Вложения"; setupEmailAttachment.filename = "КонтактИнфо.pdf"; setupEmailAttachment.body = Convert.ToBase64String(result); setupEmailAttachment.filesize = new CrmNumber(Convert.ToInt32(result.Length.ToString())); setupEmailAttachment.mimetype = "text/plain"; setupEmailAttachment.attachmentnumber = new CrmNumber(); setupEmailAttachment.attachmentnumber.Value = 1; setupEmailAttachment.activityid = new Lookup(); setupEmailAttachment.activityid.type = EntityName.email.ToString(); setupEmailAttachment.activityid.Value = EmailId; service.Create(setupEmailAttachment); // Отправляем письмо SendEmailRequest req = new SendEmailRequest(); req.EmailId = EmailId; req.TrackingToken = ""; req.IssueSend = true; SendEmailResponse res = (SendEmailResponse)service.Execute(req); } catch (Exception error) { throw new Exception(error.Message); } } } }
Разбор полетов:
- Сначала (как всегда 🙂 ) настраиваем Crm Service;
- Из контекста плгина вытаскиваем GUID обновяемой записи Контакта;
- Настраиваем подключение к API Reporting Service;
- Настраиваем служебные параметры для рендеринга отчета:
- Путь к отчету (относительно Reporting Service). Обычно имеет вид:
/<название_организации>_MSCRM/<имя_отчета>
- Выходной формат. В данном случае мы генерируем PDF файл (для этого указываем «PDF»), но Вы также можете получить отчет в других форматах:
- MHT веб-архив – «MHTML»
- XML файл – «XML»
- CSV файл – «CSV»
- Рисунок – «IMAGE»
- EXCEL файл – «EXCEL»
- HTML страница – «HTML4.0», «HTML3.2», «HTMLOWC»
- Путь к отчету (относительно Reporting Service). Обычно имеет вид:
- Информация об устройстве – используется для передачи параметров подготовки к просмотру модуля подготовки отчетов. Более подробно смотрите тут: http://msdn.microsoft.com/ru-ru/library/ms155397.aspx
- Определяем пользовательские параметры, которые будут переданы в отчет (в данном случае это GUID Контакта и цвет заголовка отчета);
- Далее настраиваем всякую служебную инфу…
- Ну и наконец рендерим сам отчет;
- Далее отрендеренный отчет записываем в файл…
- … а также приаттачиваем к (тут же) созданному письму (которое затем и отправляем);
- Соберите плагин и зарегистрируйте в CRM на событие Update объекта Contact;
- Тестируем: откройте какую-нибудь запись Контакта, обновите ее и идите смотреть на созданный на жестком диске файл отчета и тот же файл приаттаченный к созданному письму.
Возвратить отчет в виде файла порльзователю
А сейчас реализуем такую вещь: выдадим пользователю диалоговое окно предлагающее сохранить отчет. Т.е. открывает, например, юзвер запись Контакта, а ему диалог с предложение сохранить ии открыть отчет. Что-то подобное мы уже реализовывали (Выгрузка/загрузка файлов из CRM) – осталось только прикрутить к этому решению рендеринг отчетов…
- Создайте в Visual Studio новый веб-сайт (ASP.Net Web Site) и добавьте в него ссылки на web-сервис Reporting Services и SDK-сборки;
- Добавьте в файл *.aspx.cs такой код:
using System; using System.Configuration; using System.Data; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Net; using System.Collections.Generic; using System.Text; using System.IO; using System.Web.Services.Protocols; using Microsoft.Win32; using Microsoft.Crm.Sdk; using Microsoft.Crm.Sdk.Query; using Microsoft.Crm.SdkTypeProxy; using ReportService; public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { try { // Выполняем код под юзвером открывашем страницу using (new CrmImpersonator()) { // Проверяем что через URL передан параметр guid, иначе прекращаем выполнение if (Request.QueryString["contactguid"] == null || Request.QueryString["color"] == null) return; byte[] result = null; // Настраиваем API Reporting Service ReportService.ReportExecutionService rs = new ReportExecutionService(); //rs.Credentials = System.Net.CredentialCache.DefaultCredentials; rs.Credentials = new System.Net.NetworkCredential("Administrator", "1qaz@WSX", "d2008"); rs.Url = "http://win-n22hj23d1b1/ReportServer/ReportExecution2005.asmx"; // Задаем параметры для выполнения отчета: путь к отчету (относительно Reporting Service), выходной формат и информация об устройстве string reportPath = "/superfirma_MSCRM/КонтактИнфо"; string format = "PDF"; string historyID = null; string devInfo = @"<DeviceInfo><Toolbar>False</Toolbar></DeviceInfo>"; // Передаем параметры в отчет ParameterValue[] parameters = new ParameterValue[2]; // Общее количество параметров parameters[0] = new ParameterValue(); parameters[0].Name = "contactguid"; parameters[0].Value = Request.QueryString["contactguid"]; // Выцепляем GUID Контакта из строки URL parameters[1] = new ParameterValue(); parameters[1].Name = "color"; parameters[1].Value = Request.QueryString["color"]; // Выцепляем цвет заголовка отчета из строки URL // Всякая служебная инфа DataSourceCredentials[] credentials = null; string showHideToggle = null; string encoding; string mimeType; string extension; Warning[] warnings = null; ParameterValue[] reportHistoryParameters = null; string[] streamIDs = null; ExecutionInfo execInfo = new ExecutionInfo(); ExecutionHeader execHeader = new ExecutionHeader(); rs.ExecutionHeaderValue = execHeader; execInfo = rs.LoadReport(reportPath, historyID); rs.SetExecutionParameters(parameters, "en-us"); String SessionId = rs.ExecutionHeaderValue.ExecutionID; try { // Генерируем отчет result = rs.Render(format, devInfo, out extension, out encoding, out mimeType, out warnings, out streamIDs); } catch (SoapException err) { throw new Exception(err.Detail.OuterXml); } // Обнуляем изначальный ответ и возвращяем ответ в виде файла string filename = "КонтактИнфо.pdf"; Response.ClearContent(); Response.AddHeader("content-disposition", "attachment; filename=" + filename); Response.ContentType = "text/plain"; Response.HeaderEncoding = Encoding.Default; Response.BinaryWrite(result); Response.End(); } } catch (SoapException sexc) { throw new Exception(sexc.Detail.InnerText); } catch (Exception ex) { throw new Exception(ex.Message); } } }
Код в в плане работы с RS повторяет предыдущий пример, только инормацию о пользовательских параметрах берет из строки URL. А затем формирует отчет и возвращает его в виде бинарного файла пользователю;
- Код в web.config’е замените на такой:
<?xml version="1.0"?> <configuration> <appSettings> <add key="ReportService.ReportExecution2005" value="http://win-n22hj23d1b1/ReportServer/ReportExecution2005.asmx"/> </appSettings> <connectionStrings/> <system.web> <httpModules> <add name="MapOrg" type="Microsoft.Crm.MapOrgEngine, Microsoft.Crm, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> <add name="CrmAuthentication" type="Microsoft.Crm.Authentication.AuthenticationEngine, Microsoft.Crm, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </httpModules> <identity impersonate="true"/> <compilation debug="true"> <assemblies> <add assembly="Microsoft.Crm.Sdk, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add assembly="Microsoft.Crm.SdkTypeProxy, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> </assemblies> </compilation> </system.web> </configuration>
- Опубликуйте отчет в папке /ISV/dlreport/ сата CRM (для этого в Visual Studio перейдите Build — Publish Web Site — в диалоговом окне укажите путь к созданной папке и жмите ОК);
- Чтобы отчет автоматически скачивался при загрузке формы поместите на onLoad формы Контакта такой JavaScript-код:
if (crmForm.FormType == 2) { var url= window.location.protocol + "//" + window.location.host + "//ISV//dlreport//Default.aspx?" + crmForm.ObjectId + "&color=blue"; window.open(url,'popup','width=100,height=50,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=100,top=200'); }
Этот код проверет является ли данная форма, формой обновления записи (иначе у записи не будет GUID’а), а затем формирует строку URL к созданной ASPX-страничке и открывает ее в новом окне. В результате чего юзвер получает свой отчет 🙂
- Ну и для тестирования просто откройте какую-либо запись контакта…
Лирическое отступление
- В случае плагинов, бизнес-пртнеров и ASPX-страниц операция сохранения файла на диск будет использовать учетные данные пула приложения CRM;
- В примере я использую подключение к веб-сервису под админом, но для того, чтобы юзверы CRM не могли получить данные к которым у них нет доступа, необходимо подключатся под Default credentials;
- Полную документацию по веб-службе SSRS Вы можете посмотреть в MSDN’е: http://msdn.microsoft.com/ru-ru/library/ms152787(v=SQL.90).aspx
не могу найти ссылку на сервис ReportingService. Где мне его можно найти или скачать?
Заранее спасибо за ответ.
Если речь идет об установке самого Reporting Services, то он устанавливается как компонент SQL Server’а 🙂
а если нету?т.е не установился
и еще e меня почему-то не может найти класс ReportingService
Sorry не ReportingService a ReportService
Значит нужно установить! 🙂
А класс появится после того как Вы добавите ссылку на веб-сервис (как показано выше в статье)!
А вы не скинете ссылку,откуда смогу установить его.
и чтот за
007 using ClassLibrary2.ReportService;
что это за сборка и для чего она?
Ну установить Вы сможете с дистрибутива SQL Server. Причем Вам нужен точно такой же какй у Вас установле! Иначе ничего не полуиться 🙂
using ClassLibrary2.ReportService;
Это не сборка а ссылка на веб-сервис Reporting Service’а 🙂
Microsoft.Crm.MapOrgEngine, Microsoft.Crm.Authentication.AuthenticationEngine
а где я могу найти эти библиотеки?
скачивала Microsoft Dynamics Crm 4.0 но там нет их.
Либо в папке bin сайта CRM, либо в GAC’е. И если не ошибаюсь это одна сборка — Microsoft.Crm. А MapOrgEngine и Authentication это пространства имен или калыссы в них.