Добавление отчетов профессионального качества в приложение пользователя на платформе Visual Studio .NET. Часть 1Эндрю Браст (Andrew Brust)
Для понимания статьи требуется знание среды Visual Studio .NET. Аннотация Генератор отчетов Crystal Reports for Visual Studio .NET предлагает комплексное решение по организации отчетности для .NET-разработчиков, которое полностью интегрируется с такими операционными средами, как Visual Studio .NET IDE и .NET Framework. Crystal Reports поддерживает технологии ADO.NET и XML Web Services, серверные ASP.NET элементы управления и кэширования. Он "бесшовно" интегрируется с Visual Studio .NET Server Explorer, набором инструментальных средств и средой разработки. Crystal Reports имеет богатую модель программирования и располагает гибкими возможностями настройки и развертывания отчетов. Перечисленные основные возможности Crystal Reports, как и другие, рассматриваемые здесь, позволяют выполнять сложную рутинную работу над представлением данных в приложениях пользователя. Используя технологии Microsoft, разработчики долго и тесно сотрудничали с Crystal Reports еще во время внедрения Visual Basic 1.0. Теперь, с появлением платформы .NET и Visual Studio .NET, Crystal Reports снова установил стандарт для интеграции сторонних программных продуктов с инструментальными средствами Microsoft. Генератор отчетов Crystal Reports for Visual Studio .NET был разработан совместно с инженерами Microsoft с целью наиболее полной интеграции Crystal Reports с операционными средами .NET Framework и Visual Studio .NET. Он выполняет функции встроенного разработчика, позволяющего создавать новые отчеты, импортировать любые существующие отчеты Crystal Reports (или отчеты данных на языке Visual Basic 6.0) в формате .rpt, а также предоставляет ряд других возможностей, которые будут описаны ниже. В этой статье я сначала рассмотрю процедуру создания приложения Windows Forms, затем технологию ASP.NET Web Service и построение клиентского приложения ASP.NET. Попутно я расскажу о некоторых полезных приемах программирования для решения таких задач, как создание документов Acrobat (PDF) из имеющихся отчетов, формирование отчетов на базе параметризованных хранимых процедур SQL Server передача отчетов с помощью учетных данных текущего пользователя базы данных. Загружаемый пример программы для этой статьи включает приложения Windows Forms, ASP.NET Web Forms и ASP.NET Web Services. Простой отчетНачнем с чего-нибудь простого. Я создам отчет из таблицы Customers (Клиенты) базы данных SQL Server Northwind и открою его в приложении Windows Forms. Для этого нужно создать новое приложение для Windows в Visual Studio .NET. (Я буду работать с языком Visual Basic, хотя эта концепция переносима на любой язык .NET.) После того, как приложение будет создано, щелкните правой кнопкой мыши по имени проекта в окне Solution Explorer и выберите в контекстном меню Add / Add New Item (Добавить / Добавить новый элемент). Затем в списке шаблонов Templates диалогового окна Add New Item выберите Crystal Report, укажите в строке Name отчет CustomersBasic.rpt и щелкните по кнопке Open (см. рис. 1). Рис. 1. Создание простого отчета После того, как откроется диалоговое окно Crystal Report Gallery, вы можете принять настройки по умолчанию (радиокнопка Using the Report Expert и строка Standard) и щелкнуть по кнопке OK. Когда откроется диалоговое окно Report Expert, перейдите к ветке OLE DB (ADO) древовидного списка на вкладке Data. В появившемся диалоговом окне OLE DB (ADO) выберите Microsoft OLE DB Provider for SQL Server, укажите сервер SQL Server и информацию для входа в этот сервер, затем выберите базу данных Northwind и щелкните по кнопке Finish. Вернитесь к диалоговому окну Standard Report Expert, открыв узел Northwind иерархического дерева, перейдите к узлу Tables, затем дважды щелкните по узлу Customers. На вкладке Fields щелкните по кнопке Add All, чтобы добавить в отчет все поля таблицы Customers. Далее, убедитесь в том, что на вкладке Style для создаваемого отчета указан соответствующий заголовок в поле Title и выбран стиль в списке Style, затем щелкните по кнопке Finish. После этого активируется разработчик Crystal Reports for Visual Studio .NET и появится созданный отчет. Также появится окно Field Explorer, состыкованное с окнами Server Explorer и Toolbox. В последнем из них находится палитра Crystal Reports. Кроме того, в левом верхнем углу панели инструментов Visual Studio .NET появится панель инструментов Crystal Reports. Я воспользуюсь этим отчетом для иллюстрации примеров, содержащихся в этой статье. В качестве первого примера рассмотрим отображение отчета в окне. Выполнить это довольно легко. Просто перенесите CrystalReportViewer из палитры Windows Forms окна Toolbox в среду разработчика для формы по умолчанию в проекте и установите для атрибута Name значение cvwMain, для атрибута Dock значение Fill, для атрибута ReportSource - мой отчет (используя опцию Browse) и затем запустите приложение. После того, как я спроектирую отчет, войдя в базу данных с пустым паролем, этот отчет сразу появится на экране. При наличии непустого пароля для отображения отчета потребуется снова войти в базу данных. Далее я покажу, как написать небольшую программу, автоматизирующую вход в базу данных, с помощью которой пользователи, уже прошедшие процедуру аутентификации, не будут повторно входить в базу данных для запуска отчетов. Строго типизированные отчетыТеперь, когда я кратко изложил основные принципы создания простых отчетов, давайте перейдем к более сложным вопросам. Подобно тому, как создаются строго типизированные наборы DataSets со своими атрибутами и методами, можно создать строго типизированные отчеты. По своему существу все отчеты, созданные с помощью Crystal Reports и Visual Studio .NET, составляют класс строго типизированных отчетов в качестве побочного продукта самого процесса разработки. Чтобы в этом убедиться, щелкните по кнопке Show All Files (Показать все файлы) в Solution Explorer, перейдите по иерархическому дереву к CustomersBasic.rpt и убедитесь в существовании файла класса, созданного Visual Studio .NET. Я могу создать экземпляр этого класса в программе и назначить его атрибуту ReportSource объекта CrystalReportViewer, содержащегося в моей форме. Для этого я добавлю следующую строку текста программы к событию формы Load (установив атрибут ReportSource формы cvwMain в None в первом окне Properties). cvwMain.ReportSource = New CustomersBasic() Подобно строго типизированным наборам DataSets, которые используют разработчик компонентов DataSet, строго типизированные отчеты также имеют соответствующий разработчик компонентов. Если щелкнуть по палитре компонентов Components окна Toolbox в Visual Studio .NET, появится объект под названием ReportDocument. Перетащив его на свою форму, вы увидите имя класса вашего отчета в раскрывающемся списке Name диалогового окна Choose a ReportDocument. Выберите его и щелкните по кнопке OK. Вы получите исполняемый доступный экземпляр класса вашего отчета. Переименуйте этот объект в cbsMain (cbs является префиксом CustomersBasic) и замените следующей строкой текста программы в событии формы Load: cvwMain.ReportSource = cbsMain Если вы сейчас снова запустите приложение, то ваш отчет запустится, как и прежде. Этот запуск отличается от предыдущего тем, что, не ссылаясь на конкретный файл, находящийся в конкретном физическом месте, ReportViewer обращается непосредственно к объекту, который может выступать в качестве экземпляра, полученного из соответствующего класса в сборке приложения, внешней сборке или, как вы увидите далее, в XML Web Service. Как я уже упоминал, если вы для создания отчета предоставили информацию о подключении с идентификатором пользователя и пустым паролем, то этот отчет после своего создания будет открыт немедленно. В любых других случаях генератор отчетов Crystal Reports for Visual Studio .NET предложит вам зарегистрироваться, поскольку вся информация о подключении, кроме пароля, сохраняется отчетом. Если вам потребуется предоставить пароль во время выполнения программы или другой набор информации о подключении, кроме той, которая уже была предоставлена во время создания отчета (что случается довольно часто), используйте программу, приведенную на рисунке 2 перед установкой cvwMain.ReportSource.
Рис. 2. Запись Crystal Reports в базу данных В программе на рисунке 2 я произвольно задал сервер, идентификатор пользователя и пароль, т.е. localhost, ReportUser и msdn соответственно. В большинстве приложений вам, вероятно, придется использовать глобальные переменные или атрибуты класса, или даже переменные сеанса в случае приложения ASP.NET, чтобы в любой момент можно было предъявить имя базы данных и учетные данные пользователя вашего приложения, введенные при первоначальной регистрации. Обратите внимание на цикл For Each в программе. Поскольку в моем отчете содержится только одна таблица, этот цикл по большому счету необязателен (я мог бы просто сделать ссылку на cbsMain.Database.Tables(0)), однако, эта программа будет работать с любым отчетом Crystal Reports for Visual Studio .NET, поэтому я предпочел его оставить, сделав программу более функциональной. Server ExplorerТеперь рассмотрим другие способы конфигурации элементов управления объекта CrystalReportViewer. Одним из таких способов на этапе разработки является использование проводника Server Explorer. В связи с последними изменениями в .NET Framework данная функция генератора отчетов Crystal Reports for Visual Studio .NET некорректно устанавливается инсталлятором Visual Studio. Чтобы ее настроить и продолжить выполнение следующих шагов, описанных в статье, убедитесь, что все права доступа для папки Crystal Reports в каталоге Visual Studio .NET установлены и осуществляется полное управление пользовательской средой ASPNET. (Кстати, по умолчанию эта папка находится в C:\Program Files\Microsoft Visual Studio .NET\Crystal Reports). Проверить права доступа можно с помощью вкладки Security в окне свойств папки. Чтобы открыть вкладку Security, пользователи Windows XP должны выбрать пункт меню Tools / Folder Options в окне Explorer, щелкнуть по вкладке View и снять флажок "Use simple file sharing", который является последним пунктом в списке Advanced settings. После выполнения этих шагов все последующие шаги должны выполняться корректно. Щелкните по узлу Servers иерархического дерева, затем по узлу с именем вашего локального компьютера, далее по расположенному под ним Crystal Services и, наконец, по Server Files. Под этим узлом появятся две папки, в каждой из которых будут содержаться несколько файлов отчетов (см. рис.3). Любой из этих .rpt-файлов можно перетащить в среду разработчика формы, который завершит создание объекта разработчика компонентов ServerFileReport, указывающего на правильный .rpt-файл. Теперь нашим следующим шагом будет установление связи между этим объектом и вашим отчетом. Рис. 3. Server Explorer Таким образом, все папки и файлы отчетов, отображаемые в этом разделе Server Explorer, будут расположены в отдельном каталоге на жестком диске сервера. По умолчанию эта папка содержится в подкаталоге Samples\Reports основной папки Crystal Reports, о которой я уже говорил. Две упомянутые прежде папки являются подкаталогами основной папки Crystal Reports и в них физически содержатся все персональные .rpt-файлы. Чтобы ваш отчет появился в Server Explorer, скопируйте его в родительскую папку, либо в одну из его дочерних папок, либо в вашу собственную. Например, в папке Samples\Reports вы можете создать папку MSDN и скопировать в нее CustomersBasic.rpt. Затем, если вы щелкните правой кнопкой мыши по узлу Server Files в Server Explorer и выберите Refresh в контекстном меню, то появится папка MSDN с дочерним узлом для CustomersBasic.rpt. Перетащите его на вашу форму и переименуйте конечный объект sfrCustomersBasic. В окне Properties задайте атрибут ReportSource формы cvwMain, указав на этот объект. Закомментируйте каждую строку программы в событии формы Load и запустите приложение, после чего на экране появится ваш отчет. Создание отчетов из DataSetsПозднее я расскажу о дополнительных возможностях разработчика компонентов ServerFileReport, а сейчас нам нужно рассмотреть следующий шаг, который заключается в модифицировании отчета с целью получения данных посредством поставщика DB OLE из ADO.NET DataSet, а не из физической базы данных. Сначала создадим строго типизированный набор DataSet на основе таблицы Customers базы данных Northwind. Для этого используем наиболее простой способ, добавим в проект пустой набор DataSet и присвоим ему имя DataSet dsNorthwind.xsd, открыв диалоговое окно Add New Item (см. рис.4). Рис.4. Добавление DataSet Откройте дизайнер компонентов DataSet, дважды щелкнув по соответствующему узлу в Solution Explorer. Перетащите таблицу Customers из Server Explorer на плоскость разработки DataSet и сохраните файл. Затем откройте отчет, щелкните правой кнопкой мыши по его плоскости разработки, чтобы открыть контекстное меню, и выберите Database и Set Location. В диалоговом окне Set Location разверните узлы Project Data, ADO.NET DataSets и узел для вашего набора DataSet, затем выберите таблицу Customers. Наконец, в раскрывающемся списке Current Data Source выберите Customers и щелкните по кнопке Replace. После этого отчет будет обращаться к вашему строго типизированному набору DataSet для получения метаданных и будет запускаться при привязке к экземпляру этого набора. Для продолжения щелкните по кнопке Close. Теперь, когда я модифицировал отчет для работы с экземпляром dsNorthwind, нужно создать его в моей форме и задать в атрибуте ReportSource объекта CrystalReportViewer. Для этого перетащите таблицу Customers из Server Explorer на плоскость разработки формы, тем самым добавив в нее объекты SQLConnection и SQLDataAdapter, указывающих на базу данных Northwind и на таблицу Customers этой базы данных соответственно. Переименуйте эти объекты в scnNorthwind и sdaCustomers и измените атрибут ConnectionString объекта scnNorthwind, включив в него идентификатор пользователя и пароль. Затем щелкните правой кнопкой мыши по sdaCustomers и выберите Generate Dataset. В разделе "Choose a dataset" выберите радиокнопку Existing, а в правом от нее раскрывающемся списке имя класса вашего строго типизированного набора DataSet (такой выбор наиболее соответствует настройкам по умолчанию). На рисунке 5 это показано достаточно ясно. Рис. 5. Создание DataSet Щелкните по кнопке OK, переименуйте новый объект DataSet в "ndsMain" и замените код события Load на следующий фрагмент: sdaCustomers.Fill(ndsMain) Обратите внимание, что в данном фрагменте фигурирует созданный мною объект "ndsMain", который является экземпляром класса dsNorthwind строго типизированного набора DataSet. Далее, этот фрагмент программы задает атрибуту DataSource объекта "cbsMain" (экземпляр класса строго типизированных отчетов CustomersBasic) значение "ndsMain". И, наконец, как и в предыдущих примерах, атрибуту ReportSource формы cvwMain (мой объект CrystalReportViewer) я задаю значение "cbsMain". Запустите свое приложение и убедитесь, что отчет выполняется и отображается на экране так же, как и в других случаях. Этот пример отличается тем, что в нем данные поступают не из базы данных, а от изолированного объекта DataSet. В моем случае заполнение объекта DataSet осуществлялось с помощью прямого запроса к таблице Customers. (Чтобы увидеть фактический текст запроса, в объекте sdaCustomer выберите SelectCommand и затем CommandText.) Я мог бы построить этот объект DataSet из любого источника данных или из нескольких выбранных мною источников, поскольку построенный набор данных зависим от структуры ndsNorthwind. Создание отчетов из хранимых процедурЧтобы проиллюстрировать эту тему, сначала создадим параметризованную хранимую процедуру для работы с таблицей базы данных Customers, имеющей имя spCustomers. Эта хранимая процедура забирает параметр строки, который должен использоваться в операторе WHERE для ограничения количества возвращаемых записей. После этого в тексте программы я построю объект набора данных DataSet для этой процедуры и свяжу отчет с этим набором данных. Вот текст хранимой процедуры. CREATE PROCEDURE dbo.spCustomers Вы можете создать хранимую процедуру любым удобным способом; например, с помощью Visual Studio .NET, как это показано на рисунке 6. Рис. 6. Создание хранимой процедуры с помощью Visual Studio .NET Чтобы создать отчет из хранимой процедуры (присвоив параметру @CustPattern произвольное значение "A"), я изменил текст события формы Load (см. пример на рисунке 7).
Рис. 7. Модифицированный OnLoad Event В этой программе не используется ни один из тех объектов, которые были созданы на этапе разработки, за исключением объекта scnNorthwind. Существенно и то, что в этой программе также не используется экземпляр dsNorthwind строго типизированного набора DataSet в качестве источника данных для отчета. Вместо него я применил объект ADO.NET DataSet без контроля типов и с именем dsReport. Это чрезвычайно важно несмотря на то, что этот отчет разработан для строго типизированного набора DataSet. Во время запуска отчета в качестве источника данных будет задан универсальный объект DataSet без контроля типов, структура которого соответствует структуре экземпляра dsNorthwind. Когда потребуется вызвать метод Fill объекта DataAdapter, я буду использовать переопределяемую версию, которая должна принять некое табличное имя. Чтобы гарантировать структурное соответствие dsReport и dsNorthwind, я задам для этого табличного имени имя Customers. Если я этого не сделаю, то на экране появится отчет без каких-либо данных. Отчет можно создать не только на основе таблицы базы данных, как это было продемонстрировано в первом примере, но и на основе хранимой процедуры. Для установки значения параметра в программе требуется определенная команда, затрагивающая объекты, атрибуты и методы в разных пространствах имен генератора отчетов Crystal Reports for Visual Studio .NET. Рассмотрим это более подробно. Чтобы хранимые процедуры можно было выбирать в качестве источников данных, требуется настроить генератор отчетов Crystal Reports for Visual Studio .NET. Для этого щелкните правой кнопкой мыши по пустой области в плоскости разработки отчета и выберите в контекстном меню пункт Designer / Default Settings. В диалоговом окне Default Settings откройте вкладку Database, проверьте, установлен ли флажок Stored Procedures в разделе Show, и щелкните по кнопке OK. Затем щелкните правой кнопкой мыши по плоскости разработки отчета и выберите в контекстном меню пункт Database / Set Location. Спуститесь по иерархическому дереву Replace With к узлу OLE DB (ADO), еще раз щелкните правой кнопкой мыши, чтобы открылось диалоговое окно OLE DB (ADO), и введите всю необходимую информацию для подключения к вашей копии базы данных SQL Server Northwind. Вернувшись к диалоговому окну Set Location, разверните узел Northwind, затем узел Stored Procedures и выберите узел spCustomers;1. В комбинированном списке Current Data Source укажите Customers, щелкните по кнопке Replace и затем по кнопке Close. Теперь, когда вы настроили этот отчет - который был первоначально разработан на основе таблицы Customers базы данных Northwind и преобразован для использования строго типизированного набора данных в качестве источника данных - вы можете использовать для получения данных хранимую процедуру spCustomers. Поскольку spCustomers является параметризированной хранимой процедурой, генератор отчетов Crystal Reports for Visual Studio .NET автоматически добавит в ваш отчет поле для параметров Crystal Reports с именем параметра хранимой процедуры. Чтобы в этом убедиться, разверните в окне Field Explorer узел Parameter Fields. Справа под ним вы увидите поле с параметром @CustPattern (см. рис.8). Рис. 8. Параметры Теперь вы можете установить cvwMain.ReportSource как на этапе разработки, так и в самой программе, указав на rpt-файл или на экземпляр cbsMain разработчика компонентов ReportDocument. При запуске приложения генератор отчетов Crystal Reports for Visual Studio .NET автоматически откроет диалоговое окно, запрашивающее значение параметра @CustPattern. Введите любую понравившуюся вам строку, чтобы генератор отчетов подключал только тех клиентов, у которых значение поля CompanyName будет начинаться с этой строки. Не смотря на то, что генератор отчетов Crystal Reports for Visual Studio .NET может запросить значения параметров и запустить отчет без написания программного кода, в большинстве случаев желательно, чтобы эти значения запрашивались у приложений и передавались в отчет программным путем. На рисунке 9 приведена программа, необходимая для программного присваивания значений параметров с помощью объектной модели Crystal Reports. В этой программе я снова использовал произвольное значение "A", присвоив его параметру pdvCustPattern.
Рис. 9. Назначение параметров Относительно этой программы необходимо сделать ряд замечаний. Мне не совсем понятно, почему параметрам T-SQL можно присвоить только одно значение, в то время как полям параметров генератора отчетов Crystal Reports for Visual Studio .NET присваивается совокупность значений. Учитывая этот факт, я построил такую совокупность значений, которая состоит только из одного элемента, и присвоил ему значение "A". В результате эта программа создает не только pvCustPattern, экземпляр объекта CrystalDecisions.Shared.ParameterValues, который допускает использование нескольких значений, но и pdvCustPattern, экземпляр класса CrystalDecisions.Shared.ParameterDiscreteValue, который допускает использование только одного значения. Программа присваивает строку "A" атрибуту Value для pdvCustPattern и загружает его в pvCustPattern посредством метода суммирования. Затем pvCustPattern присваивается полю параметра @CustPattern посредством метода ApplyCurrentValues, а экземпляр CustomersBasic присваивается атрибуту ReportSource в средстве отображения отчетов. Хотя эта программа может показаться несколько скомканной, она, тем не менее, работает. |