在执行异步触发时忘记await语句并忘记使用ado.net写入数据库,在C#中是否安全?

Sti*_*son 3 c# asp.net ado.net asynchronous

在asp.net应用程序中,我希望尽可能高效地登录数据库.我使用基本的ADO.NET写入日志数据库,我想做这个异步,所以这是我做的:

        using (var conn = new SqlConnection(_connectionString)) {
            using (var cmd = new SqlCommand("INSERT INTO dbo.Logs (TimeStamp,ThreadId,Level,Message,Exception) VALUES (@TimeStamp,@ThreadId,@Level,@Message,@Exception)", conn)) {
                cmd.Parameters.AddWithValue("@TimeStamp", DateTime.UtcNow);
                cmd.Parameters.AddWithValue("@ThreadId", Thread.CurrentThread.ManagedThreadId);
                cmd.Parameters.AddWithValue("@Level", level);
                cmd.Parameters.AddWithValue("@Message", msg);
                cmd.Parameters.AddWithValue("@Exception", ex == null ? "" : ex.ToString());
                conn.Open();
                cmd.ExecuteNonQueryAsync();
            }
        }
Run Code Online (Sandbox Code Playgroud)

现在我的问题是我是否应该对cmd.ExecuteNonQueryAsync()语句进行等待,或者如果可以省略等待,因为我基本上只需要做一次即发即弃.

Jea*_*nal 8

只是触发并忘记异步操作是不行的 - 它可能会因异常而失败,并且在这种情况下你几乎肯定想做某事(通知用户/重试/爆炸).(此外,如果有人使用特定选项,则任务中的异常最终会导致该过程失效).

另外:谁负责关闭连接?

编辑:为了使连接关闭的问题更加清晰,我将使用try/ 重写using语句finally(我知道它不是完全相同的IL,但它足够接近,看看问题出在哪里) - 在这种情况下,代码大致变为:

SqlConnection conn;
try {
    conn = new SqlConnection("connString");
    SqlCommand cmd;
    try {
        cmd = new SqlCommand("INSERT INTO dbo.Logs (TimeStamp,ThreadId,Level,Message,Exception) VALUES (@TimeStamp,@ThreadId,@Level,@Message,@Exception)", conn);
        cmd.AddParameters();
        conn.Open();
        cmd.ExecuteNonQueryAsync();
    } finally {
        if (cmd != null) cmd.Dispose();
 } finally {
    if (conn != null) conn.Close();
 }
Run Code Online (Sandbox Code Playgroud)

你可以看到cmd.Dispose()之后被称为cmd.ExecuteNonQueryAsync().这怎么可行?我看到两种可能性:

  1. 要么cmd.Dispose()(通过设计或事故)不能返回,直到cmd.ExecuteNonQueryAsync能够完成它的工作 - 这意味着你实际上只能从cmd.Dispose之后返回cmd.ExecuteNonQueryAsync; 在这种情况下,代码可以工作,但是你不会受益于await/async;
  2. 或者cmd.Dispose()以防止cmd.ExecuteNonQueryAsync()完成的方式执行; 在这种情况下,代码不起作用;

在这两种情况下,程序都是错误的 - 您需要或者await调用Wait()任务以确保它的行为正确.