DbToDocx Windows Workflow Activity

Статья описывает Windows Workflow Activity DbToDocx. Activity разработан на языке C#. Activity читает содержимого полей одной или нескольких таблиц базы данных, формирует на основе считанных данных DataSet, затем из DataSet формирует Word docx документ и в нем таблицу с данными , далее записывает документ на диск в виде файла Docx, передает данные клиенту посредством Web Service технологии WCF.
Представлен рабочий проект MS Visual Studio 2010 WCF + WorkFlow, в котором применяется описываемое Activity. В состав проекта входят WorkFlow, библиотека входных и выходных классов, Windows Form клиент запрашивающий, получающий и отображающий данные с сервера при помощи компонента DataGridView и Microsofr Word.
1. Входные данные Activity DbToDocx.
Входные аргументы для Activity собраны в классе InputArguments и состоят из трех полей:
code
public class InputArguments
{
    public string ConnectStrig  { get; set; }
    public string SqlCommand    { get; set; }
    public string nameFile      { get; set; }
}
2. Выходные данные Activity DbToDocx.
Выходные аргументы для Activity находяться в класса OutputResult и состоят из трех свойств: byteDocx - выходной документ формата Docx, dataSet и Error - сообщения о потенциально возможной ошибке. Примечание. Клиенту достаточно передавать два объекта:dataSet и Error, передача byteDocx - избыточна.
code
public class OutputResult
{
    public string Error             { get; set; }
    public DataSet dataSet          { get; set; }
    public byte[] byteDocx          { get; set; }
}
3. Исходный текст Activity DbToDocx.
Класс реализующий Activity DbToDocx создан асинхронным, содержащим два метода:
  • BeginExecute;
  • EndExecute.
Как видно из приведенного ниже текста, SQL запрос запускается в методе BeginExecute, затем работа Activity приостаналивается и завершается процесс в методе EndExecute.
code
/*  27.09.2012. Activity DbToDocx. Рекомендуется для публикации   
    1. Activity читает содержимое таблицы в базе данных Northwind и переводит их в DataSet,
    затем, создает документ Word *.docx, преобразовывает DataSet в таблицу Docx,
    записывает созданный Word документ диск в виде файла Docx.

    2. Входным параметром является класс InputArguments с полями:  
        public string ConnectStrig  { get; set; }
        public string SqlCommand    { get; set; }
        public string nameFile      { get; set; }

    3. Выходным аргументом является класс OutputResult с полями:
        public string Error         { get; set; }
        public DataSet dataSet      { get; set; }
        public byte[] byteDocx      { get; set; }

    4. Клиент передает InputArguments, принимает OutputResult. Отображает DataSet
        в DataGridView, из byte[] byteDocx формирует Word документ, записывает его
        на диск и отображает.
*/

using System;
using System.Collections.Generic;
using System.Text;
using System.Activities;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Windows.Markup;
using System.ComponentModel;
using System.Reflection;
using Word = Microsoft.Office.Interop.Word;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using ClassLibrary;

namespace ActivityLibrary
{
    public sealed class DbToDocx : AsyncCodeActivity<OutputResult>
    {       
        // Input Object
        [RequiredArgument]
        [DefaultValue(null)]
        public InArgument<InputArguments> inputArguments { get; set; }

        // Temporary variable for Input Arguments
        private InputArguments inputObject      = null;
        private string connectStr               = null;
        private string cmdSQL                   = null;
        private string nameFile                 = null;
        private string activityDirectory        = null;

        //Output Object
        private OutputResult OutRes = null;

        // Temporary use variable
        private DataSet dataSet                 = null;
        private SqlConnection connect           = null;
        private SqlCommand command              = null;
        private SqlDataAdapter adapter          = null;
        private SqlDataReader reader            = null;

        private Word._Application word          = null;
        private Word._Document document         = null;
        Object missing = (Object)Type.Missing;

       protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
        {        
            try
            {
                // Input Object
                inputObject = inputArguments.Get(context);
                // Connection string
                connectStr  = inputObject.ConnectStrig;
                // Command string
                cmdSQL      = inputObject.SqlCommand;
                // Name File for write docx
                nameFile    = inputObject.nameFile;

                // If connect string is empty
                if (String.IsNullOrEmpty(connectStr)) throw new ArgumentNullException("Value", "Connection String is Empty");

                // If command string is empty
                if (String.IsNullOrEmpty(cmdSQL)) throw new ArgumentNullException("Value", "Command String is Empty");

                // If nameFile string is empty
                if (String.IsNullOrEmpty(nameFile)) throw new ArgumentNullException("Value", "File Name String is Empty");

                connect = new SqlConnection(connectStr);
                connect.Open();
                command = new SqlCommand(cmdSQL, connect);
                adapter = new SqlDataAdapter(command);
                context.UserState = adapter;
                return adapter.SelectCommand.BeginExecuteReader(callback, state);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return null;
            }
        }

       protected override OutputResult EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
       {
           try
           {
               SqlDataAdapter adapter = (SqlDataAdapter)context.UserState;
               //Create Output Object
               OutRes = new OutputResult();
               // End Execute Reader
               reader = adapter.SelectCommand.EndExecuteReader(result);
               reader.Close();
               // Create DataSet
               dataSet = new DataSet();
               adapter.Fill(dataSet);
               // Count Rows and Columns
               int countRows = dataSet.Tables[0].Rows.Count;
               int countField = dataSet.Tables[0].Columns.Count;

             //  countRows = 105; //debugging

               // Create Word document
               word = new Word.Application();
               word.Visible = false;
               document = word.Documents.Add();
               word.Selection.TypeText("SQL: " + cmdSQL);
               document.Tables.Add(word.Selection.Range, countRows, countField,
                  Word.WdDefaultTableBehavior.wdWord9TableBehavior,
                  Word.WdAutoFitBehavior.wdAutoFitContent);
               for (int itemRow = 1; itemRow <= countRows; itemRow++)
               {
                   for (int itemColumn = 1; itemColumn <= countField; itemColumn++)
                   {
                       word.ActiveDocument.Tables[1].Cell(itemRow, itemColumn).Range.InsertAfter(dataSet.Tables[0].Rows[itemRow - 1].ItemArray[itemColumn - 1].ToString());
                   }
               }

               // Output text in end Page
               word.Selection.GoTo(Word.WdGoToItem.wdGoToLine, Word.WdGoToDirection.wdGoToLast, ref missing, ref missing);
               word.Selection.TypeParagraph();
               word.Selection.TypeText("All in Table: " + countRows.ToString() + " rows");

               // Write File in directory Activity     
               activityDirectory = AppDomain.CurrentDomain.BaseDirectory;                 
               document.SaveAs(activityDirectory + nameFile);

               // Close All
               document.Close(ref missing, ref missing, ref missing);
               word.Quit(ref missing, ref missing, ref missing);
               document = null;
               word = null;

               // Read File in byte[]
               OutRes.byteDocx = File.ReadAllBytes(activityDirectory + nameFile);
               OutRes.dataSet = this.dataSet;
           }
           catch (Exception ex)
           {
               Console.WriteLine(ex.Message);
               this.OutRes.Error = ex.ToString();
           }
           finally
           {
               if (document != null)
               {
                   document.Close(ref missing, ref missing, ref missing);
                   document = null;
               }

               if (word != null)
               {
                   word.Quit(ref missing, ref missing, ref missing);
                   word = null;
               }
               GC.Collect();
               GC.WaitForPendingFinalizers();
               this.connect.Close();
           }
           return OutRes;
       }
    }
}
4. Клиент для Activity DbToDocx
Ниже приведен пример клиента, который организует запрос к серверу, принимает и отображает данные в DataGridView и в Microsofr Word.
code
> /* 27.09.2012
    Клиент для проверки Activity DbToDataSet.
    1. Формирует и передает на сервер объест InputArguments.
    2. Принимает и отображает объест OutputResult содержащий DataSet и Docx документ
        в виде byte[].
    3. Записывает на диск файл tempory.docx
    4. Считывает с диска и отображает tempory.docx
    5. Отображение приянятые данные  в DataGridView.
    Примечание: Преобразование DataSet в docx можно выполнять и на клиенте.
*/
using System;
using System.ComponentModel;
using System.Data;
using System.Text;
using System.Windows.Forms;
using ClassLibrary;
using System.Diagnostics;
using System.Reflection;
using Word = Microsoft.Office.Interop.Word;
using System.IO;

namespace WindowsFormsClient
{
    public partial class Form1 : Form
    {
        private ServiceReference.ServiceClient client;
        private ClassLibrary.InputArguments input;
        private ClassLibrary.OutputResult output;

        private Word._Application word = null;
        private Word._Document document = null;
        Object missing = (Object)Type.Missing;

        public Form1()
        {
            InitializeComponent();
            client = new ServiceReference.ServiceClient();
            input = new InputArguments();
            output = new OutputResult();
            textBox2.Text = @"Data Source=PROGR\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True; Asynchronous Processing=true";
            textBox3.Text = @"SELECT Orders.OrderID, Orders.CustomerID, Orders.ShipAddress FROM Orders";
            textBox1.Text = "DbToDocx.docx";
        }

        
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                // Input string for connect
                input.ConnectStrig = textBox2.Text;
                // Input SQL command
                input.SqlCommand = textBox3.Text;
                // Input name File for write
                input.nameFile = textBox1.Text;
                // Set null view
                this.dataGridView1.DataSource = null;
                this.dataGridView1.Update();

                // Send and receive data
                output = client.GetData(input);

                // Write docx File in Disk
                File.WriteAllBytes(@"g:\tempory.docx", output.byteDocx);
                // Open docx File
                word = new Word.Application();
                document = word.Documents.Open(@"g:\tempory.docx");
                word.Visible = true;

                // View data
                this.dataGridView1.DataSource = output.dataSet.Tables[0];
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }
    }
        
}

Visual Studio 2010 проект содержащий: Activity, Workflow для Activity, Windows Form клиент можно загрузить.
Мы ответим на Ваши вопросы. C уважением, Евгений Вересов.
27.09.2012 года.