0

I have a webservice WCF which log requests at the end of the process :

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

Here is my Log class :

    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()
        {
        }
    }

The problem is, sometimes (I can't redo the problem), an exception appears :

Date : 11/02/2014 20:19:49

Exception : System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail] - The process cannot access the file 'C:\xxx\xxxt\xxx\bin\logs\20140211.txt' because it is being used by another process.

Stack Trace : Server stack trace: at System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter) at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc) at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message) Exception rethrown at [0]: at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) at xxxxxxxx at xxxxxxxx in c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\24b8742a\5648f098\App_WebReferences.b9kkgfpv.0.cs:line 811 at xxxxxxxx in xxxxxxxx\tools.cs:line 547 at xxxxxxxx() in xxxxxxxx.cs:line 48 at xxxxxxxx.Page_Load(Object sender, EventArgs e) in xxxxxxxx.aspx.cs:line 41 at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) at System.Web.UI.Control.LoadRecursive() at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

I don't understand why because WCF manage concurrency between each instance of WCF entry.

EDIT :

This is the code with the Mutex added in LogFile class

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();
tshepang
  • 12,111
  • 21
  • 91
  • 136
BaptX
  • 561
  • 1
  • 7
  • 21

1 Answers1

2

At first you should wrap your mutex usage in a try finally block

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

You are also using the Mutex wrong, have a look at the very good example here:

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

Community
  • 1
  • 1
flayn
  • 5,272
  • 4
  • 48
  • 69
  • Ok I'll try but i'm afraid it will not work because each thread in WCF are separate. My problem is I don't know if the mutex of one thread is visible from another thread. That's THE question – BaptX Feb 20 '14 at 14:18
  • Please read the last sentence of my answer, the link points exactly the answer you are looking for! – flayn Feb 20 '14 at 15:30
  • It seems that it works for now. I accept the answer tonight or Monday if no exception has occurred :) Anyway thank you for your help – BaptX Feb 21 '14 at 14:26