我一直在寻找这个问题的答案,但没有成功,因此请在这里尝试。 我正在尝试在任务中的代码中记录工作。 我试图尽可能简化我的示例。
public void ExecuteRequestOnNewTask(string clientRequestContent)
{
WriteToTextFile("just entered ExecuteRequestOnNewTask");
try
{
string response = string.Empty;
Task.Factory.StartNew(
async () =>
{
WriteToTextFile("About to call ExecuteRequest");
response = await ExecuteRequest(clientRequestContent);
WriteToTextFile("Response received:" + response);
});
}
catch (Exception ex)
{
WriteToTextFile("Exception from task:" + ex);
}
}
public async Task<string> ExecuteRequest(string clientRequestContent)
{
// long running stuff here
}
public void WriteToTextFile(string text)
{
string textWithCurrentDateTime = "\r\n" + DateTime.UtcNow.AddHours(1) + ": " + text;
string path = @"C:\Log.txt";
if (!File.Exists(path))
{
File.Create(path);
TextWriter tw = new StreamWriter(path);
tw.WriteLine(textWithCurrentDateTime);
tw.Close();
}
else if (File.Exists(path))
{
TextWriter tw = new StreamWriter(path, true);
tw.WriteLine(textWithCurrentDateTime);
tw.Close();
}
}
我在日志文件中得到的唯一输出是:
“刚输入的ExecuteRequestOnNewTask” “关于调用ExecuteRequest”
我没有记录响应,也没有长时间运行的方法。
答案 0 :(得分:1)
代码有几个问题:
Task.Factory.StartNew
是非常low-level, dangerous method。它具有一个非显而易见的默认任务计划程序,并且不了解async
委托。如果要在线程池线程上运行代码,请改用Task.Run
。StartNew
返回的任务将被忽略。因此,catch
块将永远不会做任何事情。如果您想在即发即弃的情况下捕获和记录异常,则需要在委托中完成。换句话说,您无法捕获由于正被遗忘而被触发并遗忘的事物的异常! 此外,WriteToTextFile
也不是线程安全的,这在这里绝对是一个问题。但是,导致日志被截断的最可能原因是“一劳永逸”。如果您的应用程序退出,则一劳永逸的任务终止-无例外,无通知。这是设计使然-毕竟是一劳永逸。
答案 1 :(得分:1)
如果您要记录即发即弃任务的异常,可以使用以下扩展方法:
public static Task OnExceptionLogError(this Task task, string message)
{
task.ContinueWith(t =>
{
var exception = t.Exception;
var innerExceptions = exception.Flatten().InnerExceptions;
var lines = innerExceptions.Select(ex => $"{ex.GetType().FullName}: {ex.Message}");
string literal = innerExceptions.Count == 1 ? "an exception" : $"{innerExceptions.Count} exceptions";
WriteToTextFile($"{message}, {literal} occured on task #{task.Id}:\r\n " + String.Join("\r\n ", lines));
}, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
return task;
}
用法示例:
Task.Factory.StartNew(
async () =>
{
WriteToTextFile("About to call ExecuteRequest");
response = await ExecuteRequest(clientRequestContent);
WriteToTextFile("Response received:" + response);
}).OnExceptionLogError("ClientRequestContent"); // <--- give a title for the error
例如通过调用Task.WhenAll
记录所有可能汇总的嵌套错误。
这是从即发即忘任务中记录异常的另一种方法。它的优点是它在一处是全局处理程序,而缺点是除了异常本身之外,它无法记录有关错误的更多信息。
static void Main(string[] args)
{
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
// ...
}
private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
// Log the e.Exception, which is an AggregateException
WriteToTextFile("Exception from task:" + e.Exception);
}
更新:注意事项:
1)TaskScheduler.UnobservedTaskException
事件是在垃圾回收任务时引发的,这可能发生得很晚或根本没有发生!
2)调试版本only on Release builds中不会引发此事件!