发布时服务炸弹爆炸

时间:2018-03-28 20:56:37

标签: c# ado.net

希望我能在这里得到一些帮助。

在DEV服务器上,我在Visual Studio 2013社区中创建了一个C#windows服务。我在调试模式下测试了它: 在Main()

#if DEBUG
   ...run debug code...
#else
   ...run service code...
#endif

在调试模式下,它运行得很好。然后,我添加了一个安装程序类,并在 相同的 服务器上成功安装了该服务,并在“服务”窗口中启动了该服务。但是,它没有做任何事情。我检查了事件日志并看到了以下错误消息:

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外部运行,服务是否需要不同的权限?

1 个答案:

答案 0 :(得分:0)

这最初是作为评论,但是太长了,所以......

该方法应该做什么并不完全清楚。一方面,您填充实例的属性。另一方面,您返回int的列表,但是您将值转换为Int16short}而不是Int32。在循环之后填充该列表,这意味着您只获得select语句返回的最后一个值,没有order by子句意味着行以任意顺序返回,并且您不使用Id属性。

另外,请注意Steve关于将文件直接保存到C:\的评论。

在我们甚至触及您使用SQLConnection的字段而不是using语句中的局部变量这一事实之前,这将确保它将被关闭并且一旦你完成它就被处置掉了,或者你只将一切都放在try块内,这意味着如果你的代码到达那里之前有一个例外,那么什么都不会被处理掉,或者表中的列是数据库可能是可空的,因此如果读者包含Convert.ToInt而不是实际值,则DBNull.Value可能会失败。

话虽如此,这是您当前代码的改进版本。我只修改了它应该正确处理所有内容,安全地从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>是我一直在使用的扩展方法,我甚至不记得我第一次遇到它的地方 - 这是包含它的类:

/// <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));
    }
}