Проблема:Как перезаписать/обновить файл, который в настоящее время обслуживается IIS?
Моя компания выпускает ежемесячный информационный бюллетень, который я размещаю на нашем внутреннем веб-сайте. У меня есть страница для автора бюллетеня для загрузки последней версии. После того как автор загрузил последний информационный бюллетень, он отправляет широковещательное электронное письмо, чтобы объявить новый информационный бюллетень. Сотрудники неизменно проверяют новый информационный бюллетень и отправляют отзыв автору с исправлениями, которые необходимо внести.
После того, как автор внес необходимые исправления (обычно в течение часа после отправки широковещательного сообщения электронной почты), он пересматривает мою страницу и заменяет последнюю версию обновленным информационным бюллетенем.
Сразу же после замены (или обновления, если хотите) бюллетеня, любой, кто пытается получить к нему доступ, получает 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», где YYYYMMDD - это дата (отформатированная) загрузки.
В любом случае, я уверен, что код выше не создания эксклюзивной блокировки файла, так что файл может быть перезаписана безопасно.
В конце концов, я хотел бы, чтобы убедиться, что происходит следующее:
- Если IIS в настоящее время служит файл, подождите, пока IIS не закончит обслуживающим.
- Прежде чем IIS сможет снова обслуживать файл, установите исключительную блокировку файла, чтобы ни один другой процесс, поток, пользователь (и т. Д.) Не могли читать или записывать в файл.
- Либо полностью удалите файл и напишите новый файл, чтобы заменить его, либо перезапишите существующий файл новым контентом.
- Удалите блокировку, чтобы пользователи снова могли получить доступ к файлу.
Предложения?
Кроме того, могу ли я использовать Mutex
, чтобы получить взаимоисключающую блокировку файла в файловой системе Windows?
Заранее благодарю вас за помощь и совет.
EDIT:
Путь, что ссылки на рассылку генерируются на основе физического файла. Используемый метод:
- Получить все файлы PDF в каталоге «архивы». Для каждого файла:
- Разберите дату публикации с именем файла.
- магазин дата, путь к файлу, имя файла, и URL для каждого файла в
DataRow
вDataTable
- Сортировка
DataTable
по дате (по убыванию). - Вывести первую строку в качестве текущей проблемы.
- Вывести все последующие строки как «архивы», организованные по годам и месяцам.
UPDATE:
Вместо не в состоянии различить, когда все существующие запросы на этот файл уже завершены, я присмотрелся в первой части @ ответ Джастина ("ваш мьютекс будет только если эффект, который читается из файла, также получает тот же мьютекс. »)
Это привело меня к Configure IIS7 to server static content through ASP.NET Runtime и связанной статье в принятом ответе.
С этой целью я применил обработчик для всех файлов PDF, который реализует New Mutex(True, "MyMutexToPreventReadsOnOverwrite")
, чтобы гарантировать, что только один поток что-то делает с PDF в любой момент времени.
Благодарим вас за ответ, @ Justin. В то время как я не закончил использовать предложенную вами реализацию, ваш ответ указал мне на приемлемое решение.
Я добавил тэг C#, поскольку я могу читать C# и переводить его обратно в vb.net. Не стесняйтесь публиковать код в C#. – pete
Со всем уважением - это глупо. Почему бы не просто 1) загрузить в «промежуточную область» (это всегда * записывается), затем 2) копировать - с помощью «повторить попытку» на ошибке «файл в использовании»? – paulsm4