C# 如何从编程生成的SSIS包中获取GraphLayout XML
如果在Visual Studio中打开SSIS DTSX包,设计器将创建一些附加的 数据包末尾CDATA块中的DesignTimeProperties 这看起来像C# 如何从编程生成的SSIS包中获取GraphLayout XML,c#,sql-server,ssis,etl,dts,C#,Sql Server,Ssis,Etl,Dts,如果在Visual Studio中打开SSIS DTSX包,设计器将创建一些附加的 数据包末尾CDATA块中的DesignTimeProperties 这看起来像
<![CDATA[
....
问题是,只有在VisualStudio中打开包而在
集成服务项目
如果以编程方式使用ManagedDTS
创建包,则此信息将丢失
我确实在Microsoft.SqlServer.IntegrationServices.Designer.Model.Serialization
程序集Microsoft.SqlServer.IntegrationServices.Graph.dll中的命名空间,您可以在其中调用
var graphLayoutXml = SerializerHelper.Save(graphModelElement);
但不幸的是,坐标丢失(NaN或0,0..)
我现在做的是用字符串加载包
string contents = String.Empty;
Microsoft.SqlServer.Dts.Runtime.Package package =
new Microsoft.SqlServer.Dts.Runtime.Package();
using (StreamReader r = new StreamReader("DemoPackageWithoutDesignTimeProperties.dtsx"))
{
contents = r.ReadToEnd();
}
package.LoadFromXML(contents, null);
然后通过
ControlFlowGraphModelElement controlFlowGraphModelElement =
new ControlFlowGraphModelElement();
controlFlowGraphModelElement.Initialize(package as IDTSSequence);
之后尝试通过
GraphModelElement graphModelElement = new GraphModelElement();
graphModelElement.Container = controlFlowGraphModelElement.Container;
var graphLayoutXml = SerializerHelper.Save(graphModelElement);
显然我错过了一些安排。有人能帮我找到正确的方法吗
我知道Microsoft.SqlServer.IntegrationServices.Graph.dll
中还有其他几个类,例如
Microsoft.SqlServer.Graph.dll
中的LayoutGraph
、GraphLayout
和GraphControl
,但不幸的是
文档没有那么有用。为什么它不起作用?
首先,我想从@Fredipux开始,这里有一些很棒的评论:
此GraphLayout结构描述Visual Studio SSIS Designer中的SSIS任务和组件布局及大小;该布局在包编辑期间定义。以编程方式生成包时,不会定义设计器布局,因为包是在VS Designer外部创建的
没错!!要点是Microsoft.SqlServer.PipelineHost
,Microsoft.SqlServer.DTSPipelineWrap
,Microsoft.SqlServer.DTSRuntimeWrap
和Microsoft.SqlServer.ManagedDTS
是.NET包装器,允许您在设计无意义的地方以编程方式创建和执行包。I如果您参考并浏览所有部分和子部分,您将注意到只提到这三个程序集,而未提及其他程序集,如Microsoft.SqlServer.IntegrationServices.Graph.dll,因为它们与Visual Studio设计器相关
您只需注意,上述四个程序集属于Microsoft.SqlServer.Dts
命名空间,而另一个则属于Microsoft.SqlServer.IntegrationServices
如何在VisualStudio中安排任务?
请注意,在VisualStudio中,可以在菜单条中转到
Format >> Auto Layout >> Diagram
在官方文档中,我搜索了ManagedDT和其他程序集列出的所有属性和方法,但没有发现您可以使用AutoLayout()
方法。此外,即使使用ezApi和BIML,我也没有发现此选项可用
此外,我还尝试使用VisualStudio对象资源管理器搜索此方法,但没有成功
要试试吗
我认为添加布局最简单的方法是手动构建布局XML子句(从现有包中获取XML结构,并更改Id、大小和左上角属性),然后将其添加到包XML中
在运行了许多示例之后,看起来这是可能的,但是当有许多连接的任务时,这非常复杂。在下面的小节中,我演示了有关GraphLayout
XML节点的一些有用信息,以及如何使用C#script添加信息:
图形布局XML节点
我试图创建一个控制台应用程序来构建布局XML部分并将其添加到包中,但是在展示代码和实验之前,我想说明一些关于GraphLayoutXML的信息
Graphlayout节点位于XML中的以下路径中:
DTS:DesignTimeProperties/Objects/Package/LayoutInfo/GraphLayout
它包含有关在控制流中添加的所有对象(甚至优先约束连接器)的设计信息。在此XML节点中,您可以找到三种类型的节点(可能更多):
NodeLayout:用于描述任务,例如:
<NodeLayout
Size="151,42"
Id="Package\Data Flow Task"
TopLeft="369,179" />
<EdgeLayout
Id="Package.PrecedenceConstraints[Constraint]"
TopLeft="308.5,125">
<EdgeLayout.Curve>
<mssgle:Curve
StartConnector="{assembly:Null}"
EndConnector="136,54"
Start="0,0"
End="136,46.5">
<mssgle:Curve.Segments>
<mssgle:SegmentCollection
Capacity="5">
<mssgle:LineSegment
End="0,23" />
<mssgle:CubicBezierSegment
Point1="0,23"
Point2="0,27"
Point3="4,27" />
<mssgle:LineSegment
End="132,27" />
<mssgle:CubicBezierSegment
Point1="132,27"
Point2="136,27"
Point3="136,31" />
<mssgle:LineSegment
End="136,46.5" />
</mssgle:SegmentCollection>
</mssgle:Curve.Segments>
</mssgle:Curve>
</EdgeLayout.Curve>
<EdgeLayout.Labels>
<EdgeLabelCollection />
</EdgeLayout.Labels>
</EdgeLayout>
<AnnotationLayout
Text="This is an annotation"
ParentId="Package"
FontInfo="{assembly:Null}"
Size="121,60"
Id="edef7a97-4253-4bb8-907e-6079f42467c6"
TopLeft="421,152" />
结果和讨论
该节已成功添加,但在Visual studio中打开包时没有意义,因为任务未按所述安排(AutoLayout()由Visual studio执行)
我尝试移除两个任务之间的连接并重新运行实验,任务安排成功:
这意味着,如果未定义任务对象的任何布局,Visual studio将忽略添加的部分,并在打开包时执行AutoLayout()函数。
基于此,如果您决定使用此方法(甚至任何其他方法),您必须知道如何生成EdgeLayout
节点
更新-搜索AutoLayout()方法
根据您的评论,您不希望手动添加每个任务位置,但希望执行AutoLayout()
方法
检查项目中导入的程序集后,我使用对象资源管理器对AutoLayout()
方法进行了一次小搜索。我认为找到了两种相关的方法:
Microsoft.SqlServer.IntegrationServices.Designer.View.BaseGraphControl.AutoLayout()
Microsoft.SqlServer.IntegrationServices.Designer.View.IGraphControlEx.AutoLayout()
我不知道它们是否可以从C#脚本执行,因为它们不带任何参数。我认为它们不是为从C#脚本使用而构建的,但它们是Visual studio的内部方法。但您可以尝试一下
注意:在我看来,以编程方式执行此方法是无用的,因为它会
class Program
{
static void Main(string[] args)
{
string package;
string xmlLayout = " <DTS:DesignTimeProperties><![CDATA[<?xml version=\"1.0\"?>\r\n" +
"<!--This CDATA section contains the layout information of the package. The section includes information such as (x,y) coordinates, width, and height.-->\r\n" +
"<!--If you manually edit this section and make a mistake, you can delete it. -->\r\n" +
"<!--The package will still be able to load normally but the previous layout information will be lost and the designer will automatically re-arrange the elements on the design surface.-->\r\n" +
" <Objects\r\n" +
" Version=\"8\">\r\n" +
" <!--Each node below will contain properties that do not affect runtime behavior.-->\r\n" +
" <Package\r\n" +
" design-time-name=\"Package\">\r\n" +
" <LayoutInfo>\r\n" +
" <GraphLayout\r\n" +
" Capacity=\"4\" xmlns=\"clr-namespace:Microsoft.SqlServer.IntegrationServices.Designer.Model.Serialization;assembly=Microsoft.SqlServer.IntegrationServices.Graph\" xmlns:mssgle=\"clr-namespace:Microsoft.SqlServer.Graph.LayoutEngine;assembly=Microsoft.SqlServer.Graph\" xmlns:assembly=\"http://schemas.microsoft.com/winfx/2006/xaml\">";
xmlLayout += "\r\n" + AddNodeLayout("Execute T-SQL Statement Task", 193, 83);
xmlLayout += "\r\n" + AddNodeLayout("Data Flow Task", 369, 179);
xmlLayout += "\r\n" + " </GraphLayout>\r\n" +
" </LayoutInfo>\r\n" +
" </Package>\r\n" +
"</Objects>]]></DTS:DesignTimeProperties>\r\n";
using (System.IO.StreamReader sr = new System.IO.StreamReader(@"G:\SSIS_Test\Integration Services Project1\Package3.dtsx"))
{
package = sr.ReadToEnd();
sr.Close();
}
package = package.Substring(0, package.LastIndexOf("</DTS:Executable>")) +
xmlLayout + package.Substring(package.LastIndexOf("</DTS:Executable>"));
using (System.IO.StreamWriter sw = new System.IO.StreamWriter(@"G:\SSIS_Test\Integration Services Project1\Package3.dtsx"))
{
sw.Write(package);
sw.Close();
}
}
static string AddNodeLayout(string TaskId, int x, int y)
{
return " <NodeLayout\r\n" +
" Size=\"225,42\"\r\n" +
" Id=\"Package\\" + TaskId + "\"\r\n" +
" TopLeft=\"" + x.ToString() + "," + y.ToString() + "\" />";
}
}