Проблема:
Моя компания выпускает ежемесячный информационный бюллетень, который я размещаю на нашем внутреннем веб-сайте.У меня есть страница для автора рассылки, чтобы загрузить последнюю версию.После того, как автор загрузил последнюю новостную рассылку, он отправляет широковещательное электронное письмо, чтобы объявить о новой рассылке.Сотрудники неизменно проверяют новую рассылку и отправляют автору отзыв с исправлениями, которые необходимо внести.
После того, как автор внес необходимые исправления (обычно в течение часа после отправки широковещательного электронного письма), он повторно посещает мою страницуи заменяет последнюю версию обновленным информационным бюллетенем.
Сразу после замены (или обновления, если хотите) информационного бюллетеня любой, кто пытается получить к нему доступ, получает 500 - Внутренняя ошибка сервера.
Мой ИТ-специалист, который обслуживает сервер, не может удалить / переименовать / переместить файл из-за ошибки прав доступа и должен сделать много запутанных вещей, чтобы удалить файл (и как только файл будет удален, автор новостной рассылки может повторно- загрузите исправленную копию, и она отлично работает.
Мой ИТ-специалист и я почти уверены, что проблема заключается в том, что я пытаюсь заменить файл, пока IIS активно обслуживает его пользователям (что, как мне показалось,и подумал, что я закодировал против происходящего).
Код, выполняющий замену, выглядит следующим образом:
Protected Sub ReplaceLatestNewsletter()
Dim dr As DataRow
Dim sFile As String
Dim mFileLock As Mutex
Try
If Me.Archives.Rows.Count > 0 Then
dr = Me.Archives.Rows(0)
sFile = dr("File").ToString
If dr("Path").ToString.Length > 0 Then
mFileLock = New Mutex(True, "MyMutexToPreventReadsOnOverwrite")
Try
mFileLock.WaitOne()
System.IO.File.Delete(dr("Path").ToString)
Catch ex As Exception
lblErrs.Text = ex.ToString
Finally
mFileLock.ReleaseMutex()
End Try
End If
fuNewsletter.PostedFile.SaveAs(Server.MapPath("~/Newsletter/archives/" & sFile))
End If
Catch ex As Exception
lblErrs.Text = ex.ToString
End Try
dr = Nothing
sFile = Nothing
mFileLock = Nothing
End Sub
Я думал, что Mutex
позаботится об этом (хотя после перечитывания документации я не уверен, что смогу использовать его какЯ пытаюсь).Другие комментарии к коду выше:
Me.Archives
- это DataTable
, сохраненное в ViewState
dr("File").ToString
- это имя файла (без пути) dr("Path").ToString
- это полный путь к локальному компьютеру и имя файла (т. Е. 'C: \ App_Root \ Newsletters \ archives \ 20120214.pdf') - Имена файлов информационных бюллетеней установлены на "YYYYMMDD.pdf", гдеГГГГММДД - это дата (отформатированная) загрузки.
В любом случае, я почти уверен, что приведенный выше код не устанавливает эксклюзивную блокировку файла так, чтобыфайл можно безопасно перезаписать.
В конечном счете, я хотел бы убедиться, что произойдет следующее:
- Если IIS в настоящее время обслуживает файл, подождите, пока IIS не закончит его обслуживание.
- Прежде чем IIS сможет снова обслуживать файл, установите исключительную блокировку для файла, чтобы никакой другой процесс, поток, пользователь (и т. Д.) Не могли читать или записывать в файл.
- Либо удалите файл полностью и напишите новый файл, чтобы заменить его, либо перезапишите существующийфайл с новым содержимым.
- Снимите эксклюзивную блокировку, чтобы пользователи могли снова получить доступ к файлу.
Предложения?
Кроме того, можно ли использовать Mutex
чтобы получить взаимоисключающую блокировку файла в файловой системе Windows?
Заранее благодарим вас за помощь и советы.
РЕДАКТИРОВАТЬ:
Способ создания ссылок на новостную рассылку основан на физическом имени файла.Используемый метод:
- Получить все файлы PDF в каталоге «архивы».Для каждого файла:
- Анализ даты публикации по имени файла.
- Сохранение даты, пути к файлу, имени файла и URL-адреса каждого файла в
DataRow
вa DataTable
- Сортировка
DataTable
по дате (по убыванию). - Вывести первую строку как текущий выпуск.
- Вывести все последующие строки как «архивы»по годам и месяцам.
ОБНОВЛЕНИЕ :
Вместо того, чтобы не различить, когда все существующие запросы для этого файла выполнены, я взялПрисмотритесь к первой части ответа @ Джастина («Ваш мьютекс будет иметь эффект, только если процесс, который читает из файла, также получит тот же мьютекс».)
Это привело меня к Настройка IIS7серверное статическое содержимое через ASP.NET Runtime и связанную статью в принятом ответе.
С этой целью я реализовал обработчик для всех файлов PDF, который реализует New Mutex(True, "MyMutexToPreventReadsOnOverwrite")
, чтобы гарантировать, что только один поток что-то делает с PDF в любой момент времени.
Спасибо за ответ, @ Джастин. Хотя я не использовал предложенную вами реализацию, ваш ответ указал мне на приемлемое решение.