1

我想 在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);
         }

但是结果出乎我的意料,一些日志没有被记录,谁能告诉我代码有什么问题

4

1 回答 1

7

You need to ensure that only one thread is writing to the file. If you have 2 concurrent users calling the Index action at the same time chances are they will try to write to the log file at the same time and the second will fail. In a multithreaded applications such as ASP.NET always make sure that you are properly synchronizing access to shared resources.

Also in your code you are not guarding against errors. What if an exception is thrown? You never close this stream and the second attempt to access it will throw an exception.

So one possibility to simplify this code is to use the 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();
}

and to avoid such noise and pollution in your controllers you could use action filters:

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

and then:

[Log]
public ActionResult Index()
{
    return View();
}

But instead of reinventing wheels I would recommend you using the tracing capabilities built into the .NET framework.

于 2012-04-19T06:01:48.463 回答