我希望 async 在asp.net mvc中写入日志,代码如下:
public ActionResult Index()
{
byte[] buffer = Encoding.UTF8.GetBytes(string.Format("log:{0}{1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ffff"), Environment.NewLine));
FileStream fs = new FileStream(@"c:\log.txt", FileMode.Append, FileAccess.Write, FileShare.Write, 1024, true);
fs.BeginWrite(buffer, 0, buffer.Length, ar =>
{
fs.EndWrite(ar);
fs.Close();
}, null);
}
但结果不是我预期的,有些日志没有记录,有人能告诉我代码有什么问题
答案 0 :(得分:6)
您需要确保只有一个线程正在写入该文件。如果有2个并发用户同时调用Index操作,他们可能会同时尝试写入日志文件,而第二个用户将失败。在ASP.NET等多线程应用程序中,始终确保正确同步对共享资源的访问。
同样在您的代码中,您无法防范错误。如果抛出异常怎么办?您永远不会关闭此流,第二次尝试访问它将引发异常。
因此,简化此代码的一种可能性是使用TPL:
private static object _synRoot = new object();
public ActionResult Index()
{
Task.Factory.StartNew(() =>
{
lock (_synRoot)
{
var data = string.Format("log:{0}{1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ffff"), Environment.NewLine)
System.IO.File.AppendAllText("log.txt", data);
}
});
return View();
}
为了避免控制器中出现这种噪音和污染,您可以使用动作过滤器:
public class LogAttribute : ActionFilterAttribute
{
private static object _synRoot = new object();
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Task.Factory.StartNew(() =>
{
lock (_synRoot)
{
var data = string.Format("log:{0}{1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ffff"), Environment.NewLine)
System.IO.File.AppendAllText(@"log.txt", data);
}
});
}
}
然后:
[Log]
public ActionResult Index()
{
return View();
}
但是我建议您使用.NET框架中内置的tracing capabilities而不是重新发明轮子。