SSIS 包中的 C# 脚本在 SQL Server 表的数据执行过程中挂起,没有明确的错误消息
Posted
技术标签:
【中文标题】SSIS 包中的 C# 脚本在 SQL Server 表的数据执行过程中挂起,没有明确的错误消息【英文标题】:C# script in SSIS package hangs in the middle of data implementation to SQL Server table with no clear error message 【发布时间】:2021-02-03 11:40:46 【问题描述】:我不是 C# 专家,但我在 SSIS 脚本任务中有一个 C# 脚本,该脚本使用用户和密码凭据连接到 SQL Server 表。该脚本将地理数据从 WGS 转换为 Lambert。
一开始它运行良好,但脚本在大约 30 分钟后停止执行数据,没有明确的错误消息,我会弹出此消息
调用的目标抛出了异常
à System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) à System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments) à System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfoculture) à System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] 修饰符, CultureInfoculture, String[] namedParams) à Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTATaskScriptingEngine.ExecuteScript()
我尝试将包部署到 SQL Server,但它在中间也停止工作。
提前谢谢你
这是脚本
#region Help: Introduction to the script task
#endregion
#region Namespaces
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Text;
#endregion
namespace ST_1e550fb6488d4c91bf7449b1754af4cc
/// <summary>
/// </summary>
[Microsoft.SqlServer.Dts.Tasks.ScriptTask.SSISScriptTaskEntryPointAttribute]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
#region Help: Using Integration Services variables and parameters in a script
#endregion
#region Help: Firing Integration Services events from a script
#endregion
#region Help: Using Integration Services connection managers in a script
#endregion
public void Main()
string constring = @"Data Source=sqls01-bus.database.windows.net;User ID=*******;password = ******;Initial Catalog=*****;Persist Security Info=True;";
SqlConnection connection = new SqlConnection(constring);
Dts.TaskResult = (int)ScriptResults.Success;
using (connection)
SqlCommand command = new SqlCommand(
"SELECT MINX, MINY, ID_ELEMENT FROM SPATIALPOINT order by ID_ELEMENT;",
connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
while (reader.Read())
Point pt = convertToWGS84Deg(double.Parse(reader.GetValue(0).ToString()), double.Parse(reader.GetValue(1).ToString()), Zone.Lambert93);
double[] tab = WGS84ToLambert2e(pt.x, pt.y);
int idElement = int.Parse(reader.GetValue(2).ToString());
insererElementDansLaTableElementComp(pt, constring, idElement, tab, double.Parse(reader.GetValue(0).ToString()), double.Parse(reader.GetValue(1).ToString()));
else
Console.WriteLine("No rows found.");
reader.Close();
//Point pt = convertToWGS84Deg(668832.5384, 6950138.7285, Zone.Lambert93);
public static double[] WGS84ToLambert2e(double longitude, double latitude)
// Le système de coordonnées géographiques utilisé est postif vers le Nord et vers l'Est
var orientation_lat = 'N';
if (latitude < 0)
orientation_lat = 'S';
latitude = -1 * latitude;
var degree_lat = Math.Truncate(latitude);
var decPart = latitude - degree_lat;
var multipliedBy3600 = decPart * 3600;
var dividedBy60 = multipliedBy3600 / 60.0;
var minute_lat = Math.Truncate(dividedBy60);
decPart = dividedBy60 - minute_lat;
var seconde_lat = decPart * 60;
// Le système de coordonnées géographiques utilisé est postif vers le Nord et vers l'Est
var orientation_long = 'E';
if (longitude < 0)
orientation_long = 'W';
longitude = -1 * longitude;
var degree_long = Math.Truncate(longitude);
decPart = longitude - degree_long;
multipliedBy3600 = decPart * 3600;
dividedBy60 = multipliedBy3600 / 60.0;
var minute_long = Math.Truncate(dividedBy60);
decPart = dividedBy60 - minute_long;
var seconde_long = decPart * 60;
return WGS84toLambert2e(degree_long, minute_long, seconde_long, orientation_long, degree_lat, minute_lat, seconde_lat, orientation_lat);
public static double[] WGS84toLambert2e(double d_long, double m_long, double s_long, char orientation_long, double d_lat, double m_lat, double s_lat, char orientation_lat)
double lambda_w, phi_w;
/**************************************************************************************************************/
/** 0) degres-minutes-secondes + orientation (d,m,s,o) -> radian **/
/**************************************************************************************************************/
// Pour la longitude
lambda_w = d_long + m_long / 60 + s_long / 3600;
if (orientation_long == 'W') lambda_w = -1 * lambda_w; // Le système de coordonnées géographiques utilisé est postif vers le Nord et vers l'Est
lambda_w = lambda_w * Math.PI / 180;
// Pour la latitude
phi_w = d_lat + m_lat / 60 + s_lat / 3600;
if (orientation_lat == 'S') phi_w = -1 * phi_w; // Le système de coordonnées géographiques utilisé est postif vers le Nord et vers l'Est
phi_w = phi_w * Math.PI / 180;
/**************************************************************************************************************/
/** 1) coordonnées géographiques WGS84 (phi_w,lambda_w) -> coordonnées cartésiennes WGS84 (X_w,Y_w,Z_w) **/
/**************************************************************************************************************/
// J'ai utilisé 2 formules données par l'IGN dans un de leur document ainsi que deux constantes de
// l'ellipsoide de référence du système WGS84 (les deux demi-axes) :
double a_w = 6378137.0;
double b_w = 6356752.314;
// d'où
double e2_w = (a_w * a_w - b_w * b_w) / (a_w * a_w);
// et on a la grande normale de l'ellipsoide WGS84
double N = a_w / Math.Sqrt(1 - e2_w * Math.Pow(Math.Sin(phi_w), 2));
// ainsi on obtient
double X_w = N * Math.Cos(phi_w) * Math.Cos(lambda_w);
double Y_w = N * Math.Cos(phi_w) * Math.Sin(lambda_w);
double Z_w = N * (1 - e2_w) * Math.Sin(phi_w);
/**************************************************************************************************************/
/** 2) coordonnées cartésiennes WGS84 (X_w,Y_w,Z_w) -> coordonnées cartésiennes NTF (X_n,Y_n,Z_n) **/
/**************************************************************************************************************/
// Là il n'y a qu'un translation à effectuer :
// on a donc
double dX = 168.0;
double dY = 60.0;
double dZ = -320.0;
// et...
double X_n = X_w + dX;
double Y_n = Y_w + dY;
double Z_n = Z_w + dZ;
/**************************************************************************************************************/
/** 3) coordonnées cartésiennes NTF (X_n,Y_n,Z_n) -> coordonnées géographiques NTF (phi_n,lambda_n) **/
/**************************************************************************************************************/
// J'ai utilisé 1 formule donnée par l'IGN toujours dans le même document ainsi que deux constantes de l'ellipsoide
// de référence du système NTF, Clarke 1880 :
double a_n = 6378249.2;
double b_n = 6356515.0;
// d'où
double e2_n = (a_n * a_n - b_n * b_n) / (a_n * a_n);
// on définit une tolérance de convergence
double epsilon = Math.Pow(10, -10);
// puis on amorce une boucle de calcul
double p0 = Math.Atan(Z_n / Math.Sqrt(X_n * X_n + Y_n * Y_n) * (1 - (a_n * e2_n) / (Math.Sqrt(X_n * X_n + Y_n * Y_n + Z_n * Z_n))));
double p1 = Math.Atan((Z_n / Math.Sqrt(X_n * X_n + Y_n * Y_n)) / (1 - (a_n * e2_n * Math.Cos(p0)) / (Math.Sqrt((X_n * X_n + Y_n * Y_n) * (1 - e2_n * Math.Pow(Math.Sin(p0), 2))))));
while (!(Math.Abs(p1 - p0) < epsilon))
p0 = p1; p1 = Math.Atan((Z_n / Math.Sqrt(X_n * X_n + Y_n * Y_n)) / (1 - (a_n * e2_n * Math.Cos(p0)) / (Math.Sqrt((X_n * X_n + Y_n * Y_n) * (1 - e2_n * Math.Pow(Math.Sin(p0), 2))))));
double phi_n = p1;
double lambda_n = Math.Atan(Y_n / X_n);
/**********************************************************************************************************************/
/** 4) coordonnées géographiques NTF (phi_n,lambda_n) coordonnées projetées en Lambert II étendu (X_l2e, Y_l2e) **/
/**********************************************************************************************************************/
// J'utilise les formules de projection et les constantes fournies par l'IGN dans un autre document :
// avant tout on définit quelques constantes
double n = 0.7289686274;
double c = 11745793.39;
double Xs = 600000.0;
double Ys = 8199695.768;
double e_n = Math.Sqrt(e2_n);
double lambda0 = 0.04079234433198; //correspond à la longitude en radian de Paris (2°20'14.025" E) par rapport à Greenwich
// puis on calcule la latitude isométrique
double L = Math.Log(Math.Tan(Math.PI / 4 + phi_n / 2) * Math.Pow(((1 - e_n * Math.Sin(phi_n)) / (1 + e_n * Math.Sin(phi_n))), (e_n / 2)));
// enfin on projette
double X_l2e = Xs + c * Math.Exp((-n * L)) * Math.Sin(n * (lambda_n - lambda0));
double Y_l2e = Ys - c * Math.Exp((-n * L)) * Math.Cos(n * (lambda_n - lambda0));
double[] tabXY = new double[2];
tabXY[0] = X_l2e;
tabXY[1] = Y_l2e;
return tabXY;
public static void insererElementDansLaTableElementComp(Point pt, string conString, int idElement, double[] tab, double minx93, double miny93)
string sqlQuery = string.Format("INSERT into COMP_ELEMENTS_COORDONNEES (COORDONNEE_X, COORDONNEE_Y,ELEMENT , MINX_LAMBERT2 , MINY_LAMBERT2 , MINX_LAMBERT93 , MINY_LAMBERT93 , ELEMENT_TYPE, TYPE_SPATIAL) values (@CoordonneX, @CoordonnneeY , @ElementID, @MinXLambert , @MinYLambert , @MinXLambert93 , @MinYLambert93 , @ElementType, @TypeSpatial)");
SqlConnection con = new SqlConnection(conString);
SqlCommand s = new SqlCommand(sqlQuery, con);
s.Parameters.Add("@CoordonneX", SqlDbType.Float).Value = pt.x;
s.Parameters.Add("@CoordonnneeY", SqlDbType.Float).Value = pt.y;
s.Parameters.Add("@ElementID", SqlDbType.Int).Value = idElement;
s.Parameters.Add("@MinXLambert", SqlDbType.Float).Value = tab[0];
s.Parameters.Add("@MinYLambert", SqlDbType.Float).Value = tab[1];
s.Parameters.Add("@MinXLambert93", SqlDbType.Float).Value = minx93;
s.Parameters.Add("@MinYLambert93", SqlDbType.Float).Value = miny93;
s.Parameters.Add("@ElementType", SqlDbType.VarChar).Value = "ELE";
s.Parameters.Add("@TypeSpatial", SqlDbType.VarChar).Value = "POINT";
con.Open();
s.ExecuteNonQuery();
con.Close();
public static Point convertToWGS84Deg(double x, double y, Zone zone)
Point pt = new Point(x, y, 0);
pt = convertToWGS84(pt, zone);
pt.toDegree();
return pt;
public static Point convertToWGS84(Point org, Zone zone)
var lzone = new LambertZone(zone);
if (zone == Zone.Lambert93)
return lambertToGeographic(org, lzone, LambertZone.LON_MERID_IERS, LambertZone.E_WGS84, LambertZone.DEFAULT_EPS);
else
Point pt1 = lambertToGeographic(org, lzone, LambertZone.LON_MERID_PARIS, LambertZone.E_CLARK_IGN, LambertZone.DEFAULT_EPS);
Point pt2 = geographicToCartesian(pt1.x, pt1.y, pt1.z, LambertZone.A_CLARK_IGN, LambertZone.E_CLARK_IGN);
pt2.translate(-168, -60, 320);
//WGS84 refers to greenwich
return cartesianToGeographic(pt2, LambertZone.LON_MERID_GREENWICH, LambertZone.A_WGS84, LambertZone.E_WGS84, LambertZone.DEFAULT_EPS);
private static double lambertNormal(double lat, double a, double e)
return a / Math.Sqrt(1 - e * e * Math.Sin(lat) * Math.Sin(lat));
private static Point geographicToCartesian(double lon, double lat, double he, double a, double e)
double N = lambertNormal(lat, a, e);
Point pt = new Point(0, 0, 0);
pt.x = (N + he) * Math.Cos(lat) * Math.Cos(lon);
pt.y = (N + he) * Math.Cos(lat) * Math.Sin(lon);
pt.z = (N * (1 - e * e) + he) * Math.Sin(lat);
return pt;
private static Point cartesianToGeographic(Point org, double meridien, double a, double e, double eps)
double x = org.x, y = org.y, z = org.z;
double lon = meridien + Math.Atan(y / x);
double module = Math.Sqrt(x * x + y * y);
double phi0 = Math.Atan(z / (module * (1 - (a * e * e) / Math.Sqrt(x * x + y * y + z * z))));
double phiI = Math.Atan(z / module / (1 - a * e * e * Math.Cos(phi0) / (module * Math.Sqrt(1 - e * e * Math.Sin(phi0) * Math.Sin(phi0)))));
double delta = Math.Abs(phiI - phi0);
while (delta > eps)
phi0 = phiI;
phiI = Math.Atan(z / module / (1 - a * e * e * Math.Cos(phi0) / (module * Math.Sqrt(1 - e * e * Math.Sin(phi0) * Math.Sin(phi0)))));
delta = Math.Abs(phiI - phi0);
double he = module / Math.Cos(phiI) - a / Math.Sqrt(1 - e * e * Math.Sin(phiI) * Math.Sin(phiI));
Point pt = new Point(lon, phiI, he);
return pt;
private static double latitudeFromLatitudeISO(double latISo, double e, double eps)
double phi0 = 2 * Math.Atan(Math.Exp(latISo)) - LambertZone.M_PI_2;
double phiI = 2 * Math.Atan(Math.Pow((1 + e * Math.Sin(phi0)) / (1 - e * Math.Sin(phi0)), e / 2d) * Math.Exp(latISo)) - LambertZone.M_PI_2;
double delta = Math.Abs(phiI - phi0);
while (delta > eps)
phi0 = phiI;
phiI = 2 * Math.Atan(Math.Pow((1 + e * Math.Sin(phi0)) / (1 - e * Math.Sin(phi0)), e / 2d) * Math.Exp(latISo)) - LambertZone.M_PI_2;
delta = Math.Abs(phiI - phi0);
return phiI;
private static Point lambertToGeographic(Point org, LambertZone zone, double lonMeridian, double e, double eps)
double n = zone.n();
double C = zone.c();
double xs = zone.xs();
double ys = zone.ys();
double x = org.x;
double y = org.y;
double lon, gamma, R, latIso;
R = Math.Sqrt((x - xs) * (x - xs) + (y - ys) * (y - ys));
gamma = Math.Atan((x - xs) / (ys - y));
lon = lonMeridian + gamma / n;
latIso = -1 / n * Math.Log(Math.Abs(R / C));
double lat = latitudeFromLatitudeISO(latIso, e, eps);
Point dest = new Point(lon, lat, 0);
return dest;
public static Point convertToWGS84(double x, double y, Zone zone)
Point pt = new Point(x, y, 0);
return convertToWGS84(pt, zone);
#region ScriptResults declaration
/// <summary>
/// This enum provides a convenient shorthand within the scope of this class for setting the
/// result of the script.
///
/// This code was generated automatically.
/// </summary>
enum ScriptResults
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
;
#endregion
public enum Zone
LambertI = 0, LambertII = 1, LambertIII = 2, LambertIV = 3, LambertIIExtended = 4, Lambert93 = 5
public enum Unit Degree, Grad, Radian, Meter ;
public class Point
private const double radianTodegree = 180.0 / Math.PI;
public Point(double x, double y, double z)
this.x = x;
this.y = y;
this.z = z;
public double x get; set;
public double y get; set;
public double z get; set;
public void translate(double x, double y, double z)
this.x += x;
this.y += y;
this.z += z;
private void Scale(double scale)
this.x *= scale;
this.y *= scale;
this.z *= scale;
public void toDegree()
Scale(radianTodegree);
public class LambertZone
private readonly static double[] LAMBERT_N = 0.7604059656, 0.7289686274, 0.6959127966, 0.6712679322, 0.7289686274, 0.7256077650 ;
private readonly static double[] LAMBERT_C = 11603796.98, 11745793.39, 11947992.52, 12136281.99, 11745793.39, 11754255.426 ;
private readonly static double[] LAMBERT_XS = 600000.0, 600000.0, 600000.0, 234.358, 600000.0, 700000.0 ;
private readonly static double[] LAMBERT_YS = 5657616.674, 6199695.768, 6791905.085, 7239161.542, 8199695.768, 12655612.050 ;
public readonly static double M_PI_2 = Math.PI / 2.0;
public readonly static double DEFAULT_EPS = 1e-10;
public readonly static double E_CLARK_IGN = 0.08248325676;
public readonly static double E_WGS84 = 0.08181919106;
public readonly static double A_CLARK_IGN = 6378249.2;
public readonly static double A_WGS84 = 6378137.0;
public readonly static double LON_MERID_PARIS = 0;
public readonly static double LON_MERID_GREENWICH = 0.04079234433;
public readonly static double LON_MERID_IERS = 3.0 * Math.PI / 180.0;
public LambertZone(Zone zone)
this.lambertZone = zone;
public double n()
return LAMBERT_N[(int)lambertZone];
public double c()
return LAMBERT_C[(int)lambertZone];
public double xs()
return LAMBERT_XS[(int)lambertZone];
public double ys()
return LAMBERT_YS[(int)lambertZone];
public Zone lambertZone get; private set;
【问题讨论】:
这里是代码,但我认为这不是问题,因为它可以正常工作大约 30 分钟 在您的脚本中使用 try catch,例如 - ***.com/a/52653538/10376537,这应该会得到更好的错误消息,并可能会为我们指出问题所在的更好方向。 在代码中添加断点并从 Visual Studio 运行。你会得到一个行号和一个真实的错误描述 如果 SELECT MINX, MINY, ID_ELEMENT FROM SPATIALPOINT 其中 MINX 为 null 或 miny 为 null 或 ID_ELEMENT 为 null 返回任何内容,那么这就是您的问题 除了已经提到的try....catch
,您还应该注意,您可能会遇到 NULL 结果,因此if (!reader==null && reader.HasRows)
之类的内容可能会有所帮助。此外,我猜问题可能在一开始就存在:30 分钟的运行时间可能暗示连接或命令超时。但是,只有在您发现异常时才能确定这一点。
【参考方案1】:
我以另一种方式解决了这个问题,因为 Azure 数据库不断切断连接并且无法修改 azure 安全设置。我修改了脚本,现在我有一个工作每周运行一次,只插入新数据。
【讨论】:
以上是关于SSIS 包中的 C# 脚本在 SQL Server 表的数据执行过程中挂起,没有明确的错误消息的主要内容,如果未能解决你的问题,请参考以下文章