When multiple users authenticate simultaneously (e.g. after an app domain restart), Utilities.WritePhoto throws an unhandled System.IO.IOException ("The process cannot access the file because it is being used by another process") that crashes the entire DNN request pipeline, taking the site down for all users.
The exception propagates all the way up through WindowsSignin.aspx, making the signin page inaccessible site-wide until the locked file is manually deleted and IIS is restarted. I experienced this today in production -- it was not fun!
To reproduce
- Have 20+ active users on the site
- Trigger an app domain restart (e.g. install any DNN module, which modifies web.config)
- All users re-authenticate simultaneously, hitting
WritePhoto concurrently for the same user
- File lock race condition throws
IOException inside WritePhoto
- Unhandled exception crashes
WindowsSignin.aspx with HTTP 500 for all subsequent requests
Expected behavior
WritePhoto should handle IOException gracefully -- either with a try/catch that logs the error and skips the photo write, or with a file lock mechanism that prevents concurrent writes. A photo sync failure should never be fatal to the authentication pipeline.
Actual behavior
Site goes down completely. All users get HTTP 500. Recovery requires manually deleting the locked photo file from Portals\0\Users\{id}\ and restarting IIS.
Stack trace
System.IO.IOException: The process cannot access the file
'C:\inetpub\wwwroot\DNN\Portals\0\Users\255\01\-1\employeephotofilename.jpg'
because it is being used by another process.
at DotNetNuke.Services.FileSystem.FileManager.AddFile(...)
at DotNetNuke.Authentication.ActiveDirectory.ADSI.Utilities.WritePhoto(ADUserInfo, Byte[])
at DotNetNuke.Authentication.ActiveDirectory.ADSI.ADSIProvider.FillUserInfo(...)
at DotNetNuke.Authentication.ActiveDirectory.ADSI.ADSIProvider.GetUser(String)
at DotNetNuke.Authentication.ActiveDirectory.AuthenticationController.AuthenticationLogon()
Environment
- DNN version: 10.2.2
- DNN.ActiveDirectory version: latest
- Windows Server 2022 / IIS 10
- .NET Framework 4.8
Workaround
Set SynchProfilePicture = False in the HostSettings table to disable photo sync entirely. This prevents the crash but loses photo sync functionality.
INSERT INTO dbo.HostSettings (SettingName, SettingValue, SettingIsSecure)
VALUES ('SynchProfilePicture', 'False', 0)
Suggested fix
The current code (inferred from stack trace) calls FileManager.AddFile with no exception handling. The fix is a two-part change.
Part 1: Wrap the entire WritePhoto body in a try/catch
Public Shared Sub WritePhoto(objUserInfo As ADUserInfo, photo() As Byte)
Try
' ... existing photo write logic ...
Dim folder = FolderManager.Instance.GetFolder(portalId, folderPath)
Dim fileName = objUserInfo.Username & "_profile_photo.jpg"
Using stream As New System.IO.MemoryStream(photo)
FileManager.Instance.AddFile(folder, fileName, stream, True)
End Using
Catch ex As System.IO.IOException
' Another thread is writing this user's photo -- skip silently.
' This is benign: the photo will sync on the user's next login.
DotNetNuke.Services.Exceptions.Exceptions.LogException(ex)
Catch ex As Exception
' Any other photo sync failure must never crash the auth pipeline.
DotNetNuke.Services.Exceptions.Exceptions.LogException(ex)
End Try
End Sub
Part 2: Also wrap the WritePhoto call site in ADSIProvider.FillUserInfo
Try
Utilities.WritePhoto(objUserInfo, photo)
Catch ex As Exception
' Photo sync failure is non-fatal -- log and continue authentication.
DotNetNuke.Services.Exceptions.Exceptions.LogException(ex)
End Try
Why both: Part 1 fixes the root cause. Part 2 is defense-in-depth -- if any future code change to WritePhoto accidentally re-introduces an unhandled exception, the auth pipeline still won't crash.
The core principle: photo synchronization is a convenience feature. It must never be able to prevent users from logging in or bring down the site. Any exception from WritePhoto should be logged and swallowed, never propagated.
When multiple users authenticate simultaneously (e.g. after an app domain restart),
Utilities.WritePhotothrows an unhandledSystem.IO.IOException("The process cannot access the file because it is being used by another process") that crashes the entire DNN request pipeline, taking the site down for all users.The exception propagates all the way up through
WindowsSignin.aspx, making the signin page inaccessible site-wide until the locked file is manually deleted and IIS is restarted. I experienced this today in production -- it was not fun!To reproduce
WritePhotoconcurrently for the same userIOExceptioninsideWritePhotoWindowsSignin.aspxwith HTTP 500 for all subsequent requestsExpected behavior
WritePhotoshould handleIOExceptiongracefully -- either with a try/catch that logs the error and skips the photo write, or with a file lock mechanism that prevents concurrent writes. A photo sync failure should never be fatal to the authentication pipeline.Actual behavior
Site goes down completely. All users get HTTP 500. Recovery requires manually deleting the locked photo file from
Portals\0\Users\{id}\and restarting IIS.Stack trace
Environment
Workaround
Set
SynchProfilePicture = Falsein theHostSettingstable to disable photo sync entirely. This prevents the crash but loses photo sync functionality.Suggested fix
The current code (inferred from stack trace) calls
FileManager.AddFilewith no exception handling. The fix is a two-part change.Part 1: Wrap the entire
WritePhotobody in a try/catchPart 2: Also wrap the
WritePhotocall site inADSIProvider.FillUserInfoWhy both: Part 1 fixes the root cause. Part 2 is defense-in-depth -- if any future code change to
WritePhotoaccidentally re-introduces an unhandled exception, the auth pipeline still won't crash.The core principle: photo synchronization is a convenience feature. It must never be able to prevent users from logging in or bring down the site. Any exception from
WritePhotoshould be logged and swallowed, never propagated.