65.9K
CodeProject 正在变化。 阅读更多。
Home

自定义 SSIS 控制流组件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.36/5 (6投票s)

2007 年 5 月 29 日

CPOL

5分钟阅读

viewsIcon

79858

downloadIcon

674

为 SQLServer 2005 Integration Service 创建自定义控制流组件

Screenshot - jobTask_Start.gif

引言

本文面向有Web或桌面应用程序开发经验,并且开始开发自定义组件的开发者。最近搜索关于创建SQLServer 2005集成服务(SSIS)自定义控件的教程,发现可用的主题非常少。我能找到的最好的例子是Microsoft的下载中心这里。然而,这些例子除了简短的代码注释外,几乎没有进一步的解释,并且未能涵盖到一个新手控件开发者(我)可能会遇到的陷阱。本文旨在回顾一些陷阱——见下文的关注点——并解释实现的解决方案。

背景

最近的一个Web应用程序项目,每个月都有相对大量的批量处理需求。大约有30多个DTSX包在用户可以访问Web应用程序之前运行,用于加载和处理数据。在运行这些进程时,有必要阻止访问Web UI。这通过数据库中的两个表JobsHeader和JobDetails,以及一个根据需要进行编辑的存储过程来实现。考虑到需要管理包中的重复条目,显然创建一个自定义控件是最佳解决方案。

SQLJobTask

正如大多数优秀的程序员一样,我试图寻找一个现有的例子来使用,而不是重新发明轮子。我在SSIS编程示例中找到了一个很好的例子:SQLConnectionManager,它是前面提到的下载中的一个示例。自定义控件分为两部分。

  • 用户界面
  • 任务

用户界面

通过选择的控制网站访问方法,实际上只需要两个值:programId,以及它是开始还是停止。其他信息在其他区域使用,但在这里也很合适。在构建UI时,有两个类:表单本身和UI逻辑。

表单

创建表单遵循标准流程。这里唯一新增的是TaskHost对象的使用。

#region Private members
    private TaskHost _taskHost;
#endregion

TaskHost是你正在开发的任务的容器。这是用户输入如何从表单传递到任务的方式。表单可以填充TaskHost.Properties...

public SQLJobTaskForm(TaskHost taskHost)
{
    InitializeComponent();

    this._taskHost = taskHost;

    // Initialize TextBox controls with the values from the Task. 
    // These properties are accessed through the task's TaskHost object.
    this.txtProgId.Text = 
        this._taskHost.Properties[Constants.PROG_ID].GetValue(
        taskHost).ToString().Trim();
    .
    .
    .
}

...或者它可以使用TaskHost.Properties来初始化表单中的控件。

private void btnOK_Click(object sender, EventArgs e)
{
    // Set the properties of the task through the TaskHost object.
    this._taskHost.Properties[Constants.ENABLE_SW].SetValue(
        this._taskHost, this.chkEnabled.Checked);
    .
    .
    .
}

UI逻辑

UI逻辑相对简短。它负责将TaskHost对象从任务传递到表单。这在IDtsTaskUI接口的两个方法中完成。

namespace DMOE.DTS
{
    public sealed class SQLJobTaskUI : IDtsTaskUI
    {
        private TaskHost _taskHostValue;
        
        public void Initialize(TaskHost taskHost, 
            IServiceProvider serviceProvider)
        {
            // Store the TaskHost of the task.  
            // This will need to be passed to the form.
            this._taskHostValue = taskHost;
        }

        public System.Windows.Forms.ContainerControl GetView()
        {
            return new SQLJobTaskForm(this._taskHostValue);
        }
    .
    .
    .
    }
}

IDtsTAskUI接口中还有其他方法。但是,在这个控件中不需要它们。正如所见,SQLJobTaskUI用两个参数初始化。它们是TaskHost(我们已经提到的容器)和IServiceProviderGetView()方法将TaskHost对象传递给新表单对象的实例化。

任务

该控件继承自SSIS控件流对象类别中的SQLTask对象,并执行大部分工作。令人惊讶的是,这里的复杂性降低了。

namespace DMOE.DTS
{
    [
    Guid("FF12F4D7-7987-43cf-A5C8-2C31713C2B01"),
    DtsTask(DisplayName="SQLJobTask",
        TaskType="ExecuteSQLTaskDMOEJobs",
        IconResource = "DMOE.DTS.SQLJobTask.SQLJobTask.ico",
        UITypeName = "DMOE.DTS.SQLJobTaskUI,DMOE.DTS.SQLJobTask," +
            "Version=1.0.0.0,Culture=Neutral,PublicKeyToken=06021987c5ebca3a"
        )
    ]
    public sealed class SQLJobTask : Task, IDTSComponentPersist
    {
        #region .Ctor
        public SQLJobTask()
        {
        }
        #endregion

        #region Properties
            #region ProgramId
                private string _progID = string.Empty;
                public string ProgramId
                {
                    set { this._progID = value.Trim(); }
                    get { return this._progID; }
                }
            #endregion
        .
        .
        .
    }
}

如您所见,来自UI表单的值将存储在字段中。这里只需要很少的代码。TaskHost.Properties由表单逻辑设置。您只需要记住属性名称是区分大小写的,并且通过TaskHost.Properties[index]访问。这个索引可以是字符串、索引或标识。我选择使用字符串,并将值保存在Constanst.cs中。存储过程的调用是在运行时发生的重写的Execute()方法中完成的。

关注点

首先,创建您自己的强命名文件。您需要这个文件才能将其添加到GAC,并在源代码中用这个新的公钥令牌替换公共令牌。网上有许多文章回顾了操作方法。有关部署的信息,请参阅下面的参考文献。UI由任务类中的DtsTask元数据引用。

DtsTask(DisplayName="SQLJobTask",
    TaskType="ExecuteSQLTaskDMOEJobs",
    IconResource = "DMOE.DTS.SQLJobTask.SQLJobTask.ico",
    UITypeName = "DMOE.DTS.SQLJobTaskUI,DMOE.DTS.SQLJobTask," +
        "Version=1.0.0.0,Culture=Neutral,PublicKeyToken=06021987c5ebca3a"

UITypeName告诉任务调用哪个UI。请注意,UI程序集和任务程序集都列出了,以及从强命名文件中检索到的公钥令牌。注意IconResource,它提供了图标文件名。我不想使用系统分配的默认图标。

此时,该组件就可以部署并在SSIS IDE中运行了。在SSIS SQL Server Management Studio中部署并运行该组件后,该组件无法工作。programId(唯一必需的信息)未在设计时保存。花了一点时间才意识到我没有持久化属性。一旦我意识到这一点,答案就相当简单了。该包了解XML文档和IDTSInfoEvents

public void LoadFromXML(XmlElement node, IDTSInfoEvents infoEvents)
{
    //    This might occur if the task's XML has been modified outside of 
    //    the Business Intelligence
    //    Or SQL Server Workbenches.
    if (node.Name != Constants.TASK_NAME)
    {
        throw new Exception(string.Format(
            "Unexpected task element when loading task - {0}.", 
            Constants.TASK_NAME));
    }
    else
    {
        // let error bubble up
        // populate the private property variables with values from 
        // the DTS node.
        this._progID = node.Attributes.GetNamedItem(Constants.PROG_ID).Value;
        .
        .
        .
    }
}

public void SaveToXML(XmlDocument doc, IDTSInfoEvents infoEvents)
{
    //create node in the package xml document
    XmlElement taskElement = 
        doc.CreateElement(string.Empty, Constants.TASK_NAME, string.Empty);
    
    // create attributes in the node that represent the 
    // custom properties and add each to the element
    //    ProgramId property
    XmlAttribute xaProgID = doc.CreateAttribute(string.Empty, 
        Constants.PROG_ID, string.Empty);
    xaProgID.Value = this._progID;
    taskElement.Attributes.Append(xaProgID);
    .
    .
    .
    //add the new element to the package document
    doc.AppendChild(taskElement);
}

需要涵盖的信息量——例如部署和调试自定义组件——可能令人望而生畏,并且超出了本文的范围。更多信息,请参阅以下参考文献。

参考文献

历史

  • 2007年5月25日 -- 初始发布
  • 2007年6月22日 -- 文章经过编辑并移至CodeProject.com主文章库
© . All rights reserved.