2008-09-23 121 views
6

我在.net 2.0中创建了一个webservice,C#。当Web服务客户端调用不同的方法时,我需要将一些信息记录到文件中。使用.NET编写Web服务中单个文件的问题

问题出现在一个用户进程正在写入文件并且另一个进程尝试写入文件时。我收到以下错误:

The process cannot access the file because it is being used by another process.

我试图在C#中实现的解决方案失败如下。

  1. 实现的单例类包含写入文件的代码。
  2. 使用lock语句来包装写入文件的代码。
  3. 我也尝试使用开源记录器log4net,但它也不是一个完美的解决方案。
  4. 我知道登录到系统事件记录器,但我没有这个选择。

我想知道是否存在这样一个问题的完美和完整的解决方案?

回答

10

锁定可能失败,因为您的webservice正在由多个工作进程运行。 你可以保护与命名的互斥体,这是跨越进程共享的访问,不像锁你使用lock(someobject) {...}

Mutex lock = new Mutex("mymutex", false); 

lock.WaitOne(); 

// access file 

lock.ReleaseMutex(); 
+0

Mutex lockobj = new Mutex(false,“mymutex”); 将编译 – 2009-07-07 15:32:57

+0

在创建它之前,您应该尝试先使用该名称打开现有的Mutex。否则,该“新的互斥体(...)”行可能会抛出异常。 我也建议使用一个try/catch/finally块,释放呼叫移动进入finally块,只释放它,如果你确实拿到了锁。 – 2012-02-29 20:34:27

0

也许写入一个“队列行”来写入文件,所以当你试图写入文件时,它会一直检查文件是否被锁定,如果是 - 它会一直等待,如果它不是锁定 - 然后写入它。

0

您可以将结果推送到MSMQ队列并让Windows服务从队列中选取项目并记录它们。这有点沉重,但它应该工作。

0

乔尔和查尔斯。那很快! :)

Joel:当你说“队列线”时,你的意思是创建一个单独的线程运行在一个循环中,以保持检查队列以及写入文件时,它没有被锁定?

查尔斯:我知道MSMQ和窗口服务组合,但就像我说我比从Web服务:)

感谢 pradeep_tp

0

麻烦与所有内以书面文件别无选择到目前为止所尝试的是多线程可以输入代码。 这是多个线程试图获取和使用文件处理程序 - 因此错误 - 您需要一个单独的线程以外的工作线程来完成工作 - 单个文件句柄保持打开状态。

可能最简单的做法是在Global.asax的应用程序启动过程中创建一个线程,并监听同步的内存队列(System.Collections.Generics.Queue)。让线程打开并拥有文件句柄的生命周期,只有该线程可以写入文件。

ASP中的客户端请求会暂时锁定队列,将新的日志消息推送到队列中,然后解锁。

记录器线程将定期轮询队列中的新消息 - 当消息到达队列时,线程将读取并分配数据到文件中。

1

你没有说你的web服务是如何托管的,所以我假设它在IIS中。我不认为这个文件应该被多个进程访问,除非你的服务在多个应用程序池中运行。不过,我想你可能会遇到这个错误,当一个进程中的多个线程正在尝试写入。

我想我会为你自己建议的解决方案,Pradeep,建立一个单一的对象,做所有的写入日志文件。在那个对象里面,我有一个Queue,所有要记录的数据都被写入到Queue中。我有一个单独的线程读取这个队列并写入日志文件。在像IIS这样的线程池环境中,创建另一个线程似乎不太好,但它只是一个......请记住,内存中的队列不会在IIS重置后不起作用;当IIS进程关闭时,您可能会丢失一些“正在进行中”的条目。

其他替代方案当然包括使用单独的进程(如服务)写入文件,但这会带来额外的部署开销和IPC成本。如果这不适合你,请与单身人士一起去。

0

要知道我想在我的代码做的,下面是singletone类我在C#中实现

公共密封类FileWriteTest {

private static volatile FileWriteTest instance; 

private static object syncRoot = new Object(); 

private static Queue logMessages = new Queue(); 

private static ErrorLogger oNetLogger = new ErrorLogger(); 

private FileWriteTest() { } 

public static FileWriteTest Instance 
{ 
    get 
    { 
     if (instance == null) 
     { 
      lock (syncRoot) 
      { 
       if (instance == null) 
       { 
        instance = new FileWriteTest(); 
        Thread MyThread = new Thread(new ThreadStart(StartCollectingLogs)); 
        MyThread.Start(); 

       } 
      } 
     } 

     return instance; 
    } 
} 

private static void StartCollectingLogs() 
{ 

    //Infinite loop 
    while (true) 
    { 
     cdoLogMessage objMessage = new cdoLogMessage(); 
     if (logMessages.Count != 0) 
     { 
      objMessage = (cdoLogMessage)logMessages.Dequeue(); 
      oNetLogger.WriteLog(objMessage.LogText, objMessage.SeverityLevel); 

     } 
    } 
} 

public void WriteLog(string logText, SeverityLevel errorSeverity) 
{ 
    cdoLogMessage objMessage = new cdoLogMessage(); 
    objMessage.LogText = logText; 
    objMessage.SeverityLevel = errorSeverity; 
    logMessages.Enqueue(objMessage); 

} 

}

当我在调试模式下运行此代码(仅模拟一个用户访问),则会在队列出队的行处出现错误“堆栈溢出”。

注意:在上面的代码中ErrorLogger是一个有代码写入文件的类。 objMessage是一个携带日志消息的实体类。

+0

为什么要使用volatile,如果你不知道如何使用它? ; P – leppie 2008-09-23 13:59:21

0

或者,你可能想要做的错误记录到数据库中(如果你使用一个)

0

KOTH,

我已经实现互斥锁,已经去掉了“堆栈溢出”错误。在我可以断定它是否在所有情况下都工作正常之前,我还必须进行负载测试。

我在一个网站上阅读关于Mutex objets的内容,它说Mutex会影响性能。我想通过互斥锁了解一件事。

假设用户进程1正在写入文件,同时用户进程2尝试写入同一文件。由于Process1已经对代码块进行了锁定,因此Process2会在第一次尝试之后继续尝试或者死掉。

感谢 pradeep_tp

0

它会等到互斥锁的释放....

0

Joel: When you say "queue line" do you mean creating a separate thread that runs in a loop to keep checking the queue as well as write to a file when it is not locked?

是啊,基本上我在想什么。让另一个线程有一个while循环,直到它可以访问文件并保存,然后结束。

但是,您必须以第一个线程开始查找的方式首先获取访问权限。这就是为什么我说队列。