System.ServiceModel.FaultException - 进程无法访问文件'xxx',因为它正由另一个进程使用

时间:2014-02-12 10:02:47

标签: wcf c#-4.0 file-io concurrency

我有一个Web服务WCF,它在流程结束时记录请求:

public void xxxxx(string sXmlIn, out string sXmlOut)
{
    [...]
    // log
    log.PrintDatas = bPrintDatas;
    log.sXmlIn = sXmlIn;
    log.sXmlOut = sXmlOut;
    log.error = error;
    log.toFile();
}

这是我的Log类:

    public class LogFile
    {
        public String sXmlIn;
        public String sXmlOut;
        public Error error;

        private bool bPrintDatas;
        public bool PrintDatas
        {
            set { bPrintDatas = value; }
        }

        private bool bInitWs;
        public bool InitWs
        {
            get { return bInitWs; }
            set { bInitWs = value; }
        }

        private string sMethodName;
        public string MethodName
        {
            get { return sMethodName; }
            set { sMethodName = value; }
        }

        private bool bCallWs;
        public bool CallWs
        {
            get { return bCallWs; }
            set { bCallWs = value; }
        }

        private DateTime dtDebutSession;
        private DateTime dtEndSession;

        private DateTime dtDebutWS;
        private DateTime dtEndWS;

        public void startWScall()
        {
            dtDebutWS = DateTime.Now;
        }

        public void stopWScall()
        {
            dtEndWS = DateTime.Now;
        }

        public LogFile()
        {
            dtDebutSession = DateTime.Now;   
        }

        public void toFile()
        {
            dtEndSession = DateTime.Now;

            Uri pathUri = new Uri(Path.GetDirectoryName(Assembly.GetAssembly(typeof(xxxxx)).CodeBase));
            string path = pathUri.AbsolutePath + "/logs/";
            path = System.Web.HttpUtility.UrlDecode(path);
            System.IO.Directory.CreateDirectory(path);

            string name = DateTime.Now.ToString("yyyyMMdd") + ".txt";

            // create a StreamWriter and open the file
            StreamWriter logFile = new StreamWriter(path + name, true, System.Text.Encoding.GetEncoding("iso-8859-1"));

            logFile.Write(ToString());
            logFile.Close();
        }

        override
        public String ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("Session begin : " + dtDebutSession);
            sb.AppendLine("Method : " + sMethodName);
            sb.AppendLine("Init WS : " + bInitWs);
            sb.AppendLine("Calling WS : " + bCallWs);
            sb.AppendLine("Callins WS Duration : " + (dtEndWS - dtDebutWS).TotalSeconds);
            sb.AppendLine("Duration : " + (dtEndSession - dtDebutSession).TotalSeconds);
            sb.AppendLine("Session end : " + dtEndSession);
            sb.AppendLine("Result : " + Enum.GetName(typeof(ErrorCodes), error.RC));
            if (error.RC != ErrorCodes.OK)
            {
                sb.AppendLine("Exception Name : " + error.ExceptionType);
                sb.AppendLine("Exception Message : " + error.ErrorMsg);
            }

            if (error.RC != ErrorCodes.OK || bPrintDatas == true)
            {
                sb.AppendLine("--------------------");
                sb.AppendLine(sXmlIn);
                sb.AppendLine("--------------------");
                sb.AppendLine(sXmlOut);
            }
            sb.AppendLine("----------------------------------------");

            return sb.ToString();
        }

        public void toXML()
        {
        }
    }

问题是,有时(我不能重做问题),会出现异常:

  

日期:2014年2月11日20:19:49

     

例外:   System.ServiceModel.FaultException`1 [System.ServiceModel.ExceptionDetail]    - 进程无法访问文件'C:\ xxx \ xxxt \ xxx \ bin \ logs \ 20140211.txt',因为它正在   被另一个过程使用。

     

堆栈跟踪:服务器堆栈跟踪:at   System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(消息   回复,MessageFault错误,字符串操作,MessageVersion版本,   FaultConverter faultConverter)at   System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime   操作,ProxyRpc& rpc)at   System.ServiceModel.Channels.ServiceChannel.Call(String action,   Boolean oneway,ProxyOperationRuntime操作,Object [] ins,   对象[]出局,TimeSpan超时)at   System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage   methodCall,ProxyOperationRuntime operation)at   System.ServiceModel.Channels.ServiceChannelProxy.Invoke(即时聊天   消息)在[0]处重新抛出异常:at   System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(即时聊天   reqMsg,IMessage retMsg)at   System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&安培;   msgData,Int32类型)位于xxxxxxxx处xxxxxxxx处   c:\ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319 \ Temporary ASP.NET   Files \ root \ 24b8742a \ 5648f098 \ App_WebReferences.b9kkgfpv.0.cs:第811行   在xxxxxxxx xxxxxxxx \ tools.cs:第547行xxxxxxxx()中   xxxxxxxx.cs:第48行,位于xxxxxxxx.Page_Load(对象发送者,EventArgs e)   在xxxxxxxx.aspx.cs中:第41行   System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp,Object   o,对象t,EventArgs e)在System.Web.UI.Control.LoadRecursive()at   System.Web.UI.Page.ProcessRequestMain(布尔   includeStagesBeforeAsyncPoint,Boolean includeStagesAfterAsyncPoint)

我不明白为什么因为WCF管理每个WCF条目实例之间的并发。

编辑:

这是在LogFile类中添加了Mutex的代码

private readonly Mutex mutex = new Mutex();

[...]

mutex.WaitOne();
StreamWriter logFile = new StreamWriter(path + name, true, System.Text.Encoding.GetEncoding("iso-8859-1"));
logFile.Write(ToString());
logFile.Close();
mutex.ReleaseMutex();

1 个答案:

答案 0 :(得分:2)

首先,您应该在try finally块

中包装互斥锁用法
private readonly Mutex mutex = new Mutex();

[...]
try
{
mutex.WaitOne();
StreamWriter logFile = new StreamWriter(path + name, true, System.Text.Encoding.GetEncoding("iso-8859-1"));
logFile.Write(ToString());
logFile.Close();
}
catch(Exception e)
{
// trace your exception somewhere useful here!
throw;
}
finally
{
mutex.ReleaseMutex();
}

你也在使用Mutex错误,看看这里非常好的例子:

<强> What is a good pattern for using a Global Mutex in C#?