发布时服务炸弹
Service bombs out when released
希望能在这里得到一些帮助。
在 DEV 服务器上,我在 Visual Studio 2013 社区中创建了一个 C# windows 服务。我已经在调试模式下对其进行了测试:
在 Main()
#if DEBUG
...run debug code...
#else
...run service code...
#endif
在调试模式下它运行得很好。然后我添加了一个安装程序 class 并在 same 服务器上成功安装了该服务并在服务 window 中启动了它.但是,它什么都不做。我检查了事件日志并看到了这条错误消息:
Application: SharenetIFF.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.NullReferenceException
at SharenetIFF.RunValues.GetRunValues()
at SharenetIFF.SearchFiles.LookforIFFFiles(Int32)
at SharenetIFF.Program.DoThis()
at System.Threading.ThreadHelper.ThreadStart_Context(System.Object)
at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
at System.Threading.ThreadHelper.ThreadStart()
这是 RunValues 中的代码:
class RunValues
{
public int id { get; set; }
public int runTimeSpan { get; set; }
public int numberOfRunTime { get; set; }
private SqlConnection myCon = new SqlConnection();
public List<int> GetRunValues()
{
List<int> values = null;
string destPath = "";
try
{
string mySQL = "select RunFreq, RunTimes from IFFRunValues";
myCon.ConnectionString = ConfigurationManager.ConnectionStrings["DatabaseConn"].ConnectionString;
myCon.Open();
SqlCommand myCmd = new SqlCommand(mySQL, myCon);
SqlDataReader runValuesReader = myCmd.ExecuteReader();
if (runValuesReader.HasRows)
{
while (runValuesReader.Read())
{
runTimeSpan = Convert.ToInt16(runValuesReader["RunFreq"]);
numberOfRunTime = Convert.ToInt16(runValuesReader["RunTimes"]);
}
values = new List<int>();
values.Add(runTimeSpan);
values.Add(numberOfRunTime);
}
runValuesReader.Close();
myCon.Close();
runValuesReader.Dispose();
myCmd.Dispose();
myCon.Dispose();
}
catch (Exception ex)
{
destPath = Path.Combine("C:\", "error_log.txt");
File.AppendAllText(destPath, ex.Message);
values.Clear();
}
return values;
}
}
我认为它在连接字符串上失败了,主要是因为这里没有其他东西。但不知道为什么。所有代码都在 try/catch 块中,那么未处理的异常怎么可能呢?如果将服务发布到开发它的同一台开发机器上,如果 运行 在 visual studio 之外,服务是否需要不同的权限?
这开始是评论,但太长了,所以...
尚不完全清楚该方法应该做什么。一方面,您填充实例的属性。另一方面,您 return 一个 int
的列表,但是您将值转换为 Int16
(即 short
)而不是 Int32
。您在 之后 循环填充该列表,这意味着您仅从 select 语句中获得最后的值 returned,没有 order by 子句意味着行是return以任意顺序编辑,您根本不使用 Id
属性。
此外,请注意史蒂夫关于将文件直接保存到 C:\
的评论。
那是在我们甚至触及您正在为 SQLConnection
使用字段而不是 using
语句中的局部变量这一事实之前,这将确保它会被关闭并处理一次你已经完成了它,或者你只处理 try
块内的所有东西,这意味着如果你在代码到达那里之前有一个异常,没有任何东西被处理,或者 table 列在数据库中可能可以为空,因此如果 reader 包含 DBNull.Value
而不是实际值,Convert.ToInt
可能会失败。
也就是说,这是您当前代码的改进版本。我只是将它修改到它应该正确处理所有内容,安全地从 dataReader 获取值而不是抛出 NullReferenceException
的程度,但正如我所说,我不太清楚你试图在此实现的目标方法。
class RunValues
{
public int id { get; set; }
public int runTimeSpan { get; set; }
public int numberOfRunTime { get; set; }
public List<int> GetRunValues()
{
var values = new List<int>();
// I'm guessing it needs " where id = @id" here...
var mySQL = "select RunFreq, RunTimes from IFFRunValues";
using(var myCon = new SqlConnection(ConfigurationManager.ConnectionStrings["DatabaseConn"].ConnectionString))
{
using(var myCmd = new SqlCommand(mySQL, myCon))
{
try
{
myCon.Open();
SqlDataReader runValuesReader = myCmd.ExecuteReader();
if (runValuesReader.HasRows)
{
while (runValuesReader.Read())
{
runTimeSpan = runValuesReader.GetValueOrDefault<int>("RunFreq");
numberOfRunTime = runValuesReader.GetValueOrDefault<int>("RunTimes");
values.Add(runTimeSpan);
values.Add(numberOfRunTime);
}
}
}
catch (Exception ex)
{
var destPath = Path.Combine("C:\", "error_log.txt");
File.AppendAllText(destPath, ex.Message);
values.Clear();
}
}
}
return values;
}
}
GetValueOrDefault<T>
是我使用了很长时间的扩展方法,我什至不记得我第一次遇到它的地方 - 这是包含它的 class:
/// <summary>
/// Provides extension methods for IDataReader.
/// </summary>
public static class IDataReaderExtensions
{
/// <summary>
/// Gets the value of type T from the column specified by the index parameter, or default(T) if it's null.
/// </summary>
/// <typeparam name="T">The type of the value to get.</typeparam>
/// <param name="reader">An instance of a class implementing IDataReader.</param>
/// <param name="index">The index of the column from where to get the value.</param>
/// <returns>The value of type T from the specified column, default(T) if null.</returns>
public static T GetValueOrDefault<T>(this IDataReader reader, int index)
{
return (Convert.IsDBNull(reader[index])) ? default(T) : (T)reader.GetValue(index);
}
/// <summary>
/// Gets the value of type T from the column specified by the name parameter, or default(T) if it's null.
/// </summary>
/// <typeparam name="T">The type of the value to get.</typeparam>
/// <param name="reader">An instance of a class implementing IDataReader.</param>
/// <param name="name">The name of the column from where to get the value.</param>
/// <returns>The value of type T from the specified column, default(T) if null.</returns>
public static T GetValueOrDefault<T>(this IDataReader reader, string name)
{
return reader.GetValueOrDefault<T>(reader.GetOrdinal(name));
}
}
希望能在这里得到一些帮助。
在 DEV 服务器上,我在 Visual Studio 2013 社区中创建了一个 C# windows 服务。我已经在调试模式下对其进行了测试: 在 Main()
#if DEBUG
...run debug code...
#else
...run service code...
#endif
在调试模式下它运行得很好。然后我添加了一个安装程序 class 并在 same 服务器上成功安装了该服务并在服务 window 中启动了它.但是,它什么都不做。我检查了事件日志并看到了这条错误消息:
Application: SharenetIFF.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.NullReferenceException
at SharenetIFF.RunValues.GetRunValues()
at SharenetIFF.SearchFiles.LookforIFFFiles(Int32)
at SharenetIFF.Program.DoThis()
at System.Threading.ThreadHelper.ThreadStart_Context(System.Object)
at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
at System.Threading.ThreadHelper.ThreadStart()
这是 RunValues 中的代码:
class RunValues
{
public int id { get; set; }
public int runTimeSpan { get; set; }
public int numberOfRunTime { get; set; }
private SqlConnection myCon = new SqlConnection();
public List<int> GetRunValues()
{
List<int> values = null;
string destPath = "";
try
{
string mySQL = "select RunFreq, RunTimes from IFFRunValues";
myCon.ConnectionString = ConfigurationManager.ConnectionStrings["DatabaseConn"].ConnectionString;
myCon.Open();
SqlCommand myCmd = new SqlCommand(mySQL, myCon);
SqlDataReader runValuesReader = myCmd.ExecuteReader();
if (runValuesReader.HasRows)
{
while (runValuesReader.Read())
{
runTimeSpan = Convert.ToInt16(runValuesReader["RunFreq"]);
numberOfRunTime = Convert.ToInt16(runValuesReader["RunTimes"]);
}
values = new List<int>();
values.Add(runTimeSpan);
values.Add(numberOfRunTime);
}
runValuesReader.Close();
myCon.Close();
runValuesReader.Dispose();
myCmd.Dispose();
myCon.Dispose();
}
catch (Exception ex)
{
destPath = Path.Combine("C:\", "error_log.txt");
File.AppendAllText(destPath, ex.Message);
values.Clear();
}
return values;
}
}
我认为它在连接字符串上失败了,主要是因为这里没有其他东西。但不知道为什么。所有代码都在 try/catch 块中,那么未处理的异常怎么可能呢?如果将服务发布到开发它的同一台开发机器上,如果 运行 在 visual studio 之外,服务是否需要不同的权限?
这开始是评论,但太长了,所以...
尚不完全清楚该方法应该做什么。一方面,您填充实例的属性。另一方面,您 return 一个 int
的列表,但是您将值转换为 Int16
(即 short
)而不是 Int32
。您在 之后 循环填充该列表,这意味着您仅从 select 语句中获得最后的值 returned,没有 order by 子句意味着行是return以任意顺序编辑,您根本不使用 Id
属性。
此外,请注意史蒂夫关于将文件直接保存到 C:\
的评论。
那是在我们甚至触及您正在为 SQLConnection
使用字段而不是 using
语句中的局部变量这一事实之前,这将确保它会被关闭并处理一次你已经完成了它,或者你只处理 try
块内的所有东西,这意味着如果你在代码到达那里之前有一个异常,没有任何东西被处理,或者 table 列在数据库中可能可以为空,因此如果 reader 包含 DBNull.Value
而不是实际值,Convert.ToInt
可能会失败。
也就是说,这是您当前代码的改进版本。我只是将它修改到它应该正确处理所有内容,安全地从 dataReader 获取值而不是抛出 NullReferenceException
的程度,但正如我所说,我不太清楚你试图在此实现的目标方法。
class RunValues
{
public int id { get; set; }
public int runTimeSpan { get; set; }
public int numberOfRunTime { get; set; }
public List<int> GetRunValues()
{
var values = new List<int>();
// I'm guessing it needs " where id = @id" here...
var mySQL = "select RunFreq, RunTimes from IFFRunValues";
using(var myCon = new SqlConnection(ConfigurationManager.ConnectionStrings["DatabaseConn"].ConnectionString))
{
using(var myCmd = new SqlCommand(mySQL, myCon))
{
try
{
myCon.Open();
SqlDataReader runValuesReader = myCmd.ExecuteReader();
if (runValuesReader.HasRows)
{
while (runValuesReader.Read())
{
runTimeSpan = runValuesReader.GetValueOrDefault<int>("RunFreq");
numberOfRunTime = runValuesReader.GetValueOrDefault<int>("RunTimes");
values.Add(runTimeSpan);
values.Add(numberOfRunTime);
}
}
}
catch (Exception ex)
{
var destPath = Path.Combine("C:\", "error_log.txt");
File.AppendAllText(destPath, ex.Message);
values.Clear();
}
}
}
return values;
}
}
GetValueOrDefault<T>
是我使用了很长时间的扩展方法,我什至不记得我第一次遇到它的地方 - 这是包含它的 class:
/// <summary>
/// Provides extension methods for IDataReader.
/// </summary>
public static class IDataReaderExtensions
{
/// <summary>
/// Gets the value of type T from the column specified by the index parameter, or default(T) if it's null.
/// </summary>
/// <typeparam name="T">The type of the value to get.</typeparam>
/// <param name="reader">An instance of a class implementing IDataReader.</param>
/// <param name="index">The index of the column from where to get the value.</param>
/// <returns>The value of type T from the specified column, default(T) if null.</returns>
public static T GetValueOrDefault<T>(this IDataReader reader, int index)
{
return (Convert.IsDBNull(reader[index])) ? default(T) : (T)reader.GetValue(index);
}
/// <summary>
/// Gets the value of type T from the column specified by the name parameter, or default(T) if it's null.
/// </summary>
/// <typeparam name="T">The type of the value to get.</typeparam>
/// <param name="reader">An instance of a class implementing IDataReader.</param>
/// <param name="name">The name of the column from where to get the value.</param>
/// <returns>The value of type T from the specified column, default(T) if null.</returns>
public static T GetValueOrDefault<T>(this IDataReader reader, string name)
{
return reader.GetValueOrDefault<T>(reader.GetOrdinal(name));
}
}