I don't have an answer (yet), probably more like additional information, although this can be used to form a final answer, so I'm posting it anyways. Hoping on some reactions from the community and possibly somebody who can answer it.
Looking at the DD4T code there are two classes dealing with binaries, BinaryDistributionModule.cs
and BinaryFileManager.cs
, and only in the BinaryFileManager
class a lock is used in the WriteBinaryToFile()
method. The lock used is a string, and while generally locking on strings is discouraged, because of deadlock situations, since only this single method is using that lock there seems to be a deeper issue.
Inspecting the rest of the code, there are more places that are dealing with (potentially) the same binary file, and it is done in both classes mentioned. Methods like BinaryFileManager.DeleteFile()
, Binary.DistributionModule.DistributionModule_OnPreRequestHandlerExecute()
, and BinaryDistributionModule.DistributionModule_OnBeginRequest()
all should implement the same lock I suspect, or even better a different between read and write (multiple threads are allowed to read, as long as no other thread is trying to write at the same time, and only one thread is allowed to write the binary at all times).
I tried implementing a named locker using a ConcurrentDictionary
on all mentioned methods, but that didn't seem to fix the problem. I still get exceptions while accessing the file, most are occurring on BinaryFileManager.WriteBinaryToFile()
. So it appears that I'm still missing a method somewhere that accesses the binary in some way.
Here is the code of my named locker class:
internal static class NamedLocker
{
private static readonly ConcurrentDictionary<string, object> Locks = new ConcurrentDictionary<string, object>();
public static object GetLock(string name)
{
return Locks.GetOrAdd(name, s => new object());
}
public static void RemoveLock(string name)
{
object o;
Locks.TryRemove(name, out o);
}
}
And it is being used like this in BinaryFileManager.WriteBinaryToFile()
:
lock (NamedLocker.GetLock(physicalPath))
{
if (File.Exists(physicalPath))
{
fileStream = new FileStream(physicalPath, FileMode.Create);
}
...
fileStream.Write(buffer, 0, buffer.Length);
}
And also in all other mentioned methods, like BinaryDistributionModule.DistributionModule_OnPreRequestHandlerExecute()
:
lock (NamedLocker.GetLock(request.PhysicalPath))
{
response.TransmitFile(request.PhysicalPath);
}
As mentioned, I'm stuck here, there are still file access exceptions being thrown. Who can make us see the light?