以编程方式获取 Windows 服务并写入 SQL

本文关键字:SQL 服务 Windows 编程 方式 获取 | 更新日期: 2023-09-27 18:31:23

我正在尝试查询远程服务器上的服务并将它们插入SQL中。 我知道我错过了一些可以真正写回的东西,但我无法弄清楚它是什么。 在我尝试将数据写入 SQL 之前,一切正常。

static void Main(string[] args)
{
    string username = ConfigurationManager.AppSettings["UserName"].ToString();
    string password = ConfigurationManager.AppSettings["Password"].ToString();
    string domain = ConfigurationManager.AppSettings["Domain"].ToString();
    var logonType = SimpleImpersonation.LogonType.NewCredentials;
    using (SimpleImpersonation.Impersonation.LogonUser(domain, username, password, logonType))
    {
        var connection = ConfigurationManager.ConnectionStrings["Connection"].ConnectionString;
        using (SqlConnection conn = new SqlConnection(connection))
        {
            conn.Open();
            using (SqlCommand command = new SqlCommand("SELECT ServerName, ServerIP FROM Server", conn))
            {
                SqlDataReader reader = command.ExecuteReader();
                while (reader.Read())
                {
                    string serverIP = reader["ServerIP"].ToString();
                    string serverName = reader["ServerName"].ToString();
                    ServiceController[] services = ServiceController.GetServices(serverIP);
                    foreach (ServiceController service in services)
                    {
                        using (SqlCommand cmd = new SqlCommand("sp_InsertServices", conn))
                        {
                            cmd.CommandType = System.Data.CommandType.StoredProcedure;
                            SqlParameter ID = new SqlParameter();
                            ID.ParameterName = "@ID";
                            ID.Direction = System.Data.ParameterDirection.Output;
                            cmd.Parameters.AddWithValue("@ID", ID);
                            cmd.Parameters.AddWithValue("@Display", service.DisplayName);
                            cmd.Parameters.AddWithValue("@Service", service.ServiceName);
                            cmd.Parameters.AddWithValue("@Status", service.Status);
                            cmd.Parameters.AddWithValue("@Server", serverName);
                        }
                    }
                }
            }
        }
    }
}

这是存储的过程

PROCEDURE [dbo].[sp_InsertServices]
@ID         int,
@Display    nvarchar(50),
@Service    nvarchar(50),
@Status     nvarchar(50),
@Server     nvarchar(50)
AS
BEGIN
SET NOCOUNT ON
INSERT INTO Services
(ID,
DisplayName,
ServiceName,
Status,
Server)
VALUES
(@ID,
@Display,
@Service,
@Status,
@Server)
SET @ID = SCOPE_IDENTITY()
END

编辑:对不起,更多信息。 在参数添加后,我在最后添加了执行,但出现此错误。

System.Data 中发生类型为"System.InvalidOperationException"的未处理异常.dll

附加信息:已有一个与此命令关联的打开的 DataReader,必须先关闭该读取器。

看起来我需要关闭第一个阅读器,但我仍然在第二个命令中使用它。 现在不要在我可以安全地关闭它的地方。

以编程方式获取 Windows 服务并写入 SQL

你从不执行你的 SqlCommand。 添加参数后,请尝试添加cmd.ExecuteNonQuery();

第二个问题是您正在尝试重用相同的 SqlConnection。 您需要创建新的 SqlConnection,因为您正在使用现有连接来循环访问服务器列表。

您已经构建了 Command 对象 (cmd),现在您只需要保存它,就像cmd.ExecuteNonQuery();

首先,您需要将存储过程声明更改为

ALTER PROCEDURE [dbo].[sp_InsertServices]
    @Display    nvarchar(50),
    @Service    nvarchar(50),
    @Status     nvarchar(50),
    @Server     nvarchar(50)
AS
BEGIN
    SET NOCOUNT ON
    INSERT INTO Services
    (DisplayName, ServiceName, Status, Server)
    VALUES
    (@Display,@Service,@Status,@Server)
    SELECT SCOPE_IDENTITY()
END

现在将调用代码更改为

using (SqlCommand cmd = new SqlCommand("sp_InsertServices", conn))
{
    cmd.CommandType = System.Data.CommandType.StoredProcedure;
    cmd.Parameters.AddWithValue("@Display", service.DisplayName);
    cmd.Parameters.AddWithValue("@Service", service.ServiceName);
    cmd.Parameters.AddWithValue("@Status", service.Status);
    cmd.Parameters.AddWithValue("@Server", serverName);
    int serviceID = (int)cmd.ExecuteScalar();
    // What you want to do with the ID returned?

}

如果您的 ID 字段是 IDENTITY 列,则不需要 ID 参数,它由数据库自动计算,您可以使用简单的选择返回它。如果存储过程以 SELECT SCOPE_IDENTITY() 结尾,则可以使用简单的 ExecuteScalar 在 C# 代码上检索结果,而无需输出参数。

最后,如果您尝试使用 SqlDataReader 使用的相同连接执行 XXX 个 SqlCommand,则会出现异常,因为该连接正忙于 SqlDataReader 提供服务,无法执行该命令。

简单的解决方案是将其添加到连接字符串中

  ....;MultipleActiveResultSets=True;....

请参阅 MSDN 的 MultipleActiveResultsSet