2012-02-21 3 views
1

Проблема:Как перезаписать/обновить файл, который в настоящее время обслуживается 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 - это дата (отформатированная) загрузки.

В любом случае, я уверен, что код выше не создания эксклюзивной блокировки файла, так что файл может быть перезаписана безопасно.

В конце концов, я хотел бы, чтобы убедиться, что происходит следующее:

  1. Если IIS в настоящее время служит файл, подождите, пока IIS не закончит обслуживающим.
  2. Прежде чем IIS сможет снова обслуживать файл, установите исключительную блокировку файла, чтобы ни один другой процесс, поток, пользователь (и т. Д.) Не могли читать или записывать в файл.
  3. Либо полностью удалите файл и напишите новый файл, чтобы заменить его, либо перезапишите существующий файл новым контентом.
  4. Удалите блокировку, чтобы пользователи снова могли получить доступ к файлу.

Предложения?

Кроме того, могу ли я использовать Mutex, чтобы получить взаимоисключающую блокировку файла в файловой системе Windows?

Заранее благодарю вас за помощь и совет.

EDIT:

Путь, что ссылки на рассылку генерируются на основе физического файла. Используемый метод:

  1. Получить все файлы PDF в каталоге «архивы». Для каждого файла:
  2. Разберите дату публикации с именем файла.
  3. магазин дата, путь к файлу, имя файла, и URL для каждого файла в DataRow в DataTable
  4. Сортировка DataTable по дате (по убыванию).
  5. Вывести первую строку в качестве текущей проблемы.
  6. Вывести все последующие строки как «архивы», организованные по годам и месяцам.

UPDATE:

Вместо не в состоянии различить, когда все существующие запросы на этот файл уже завершены, я присмотрелся в первой части @ ответ Джастина ("ваш мьютекс будет только если эффект, который читается из файла, также получает тот же мьютекс. »)

Это привело меня к Configure IIS7 to server static content through ASP.NET Runtime и связанной статье в принятом ответе.

С этой целью я применил обработчик для всех файлов PDF, который реализует New Mutex(True, "MyMutexToPreventReadsOnOverwrite"), чтобы гарантировать, что только один поток что-то делает с PDF в любой момент времени.

Благодарим вас за ответ, @ Justin. В то время как я не закончил использовать предложенную вами реализацию, ваш ответ указал мне на приемлемое решение.

+0

Я добавил тэг C#, поскольку я могу читать C# и переводить его обратно в vb.net. Не стесняйтесь публиковать код в C#. – pete

+0

Со всем уважением - это глупо. Почему бы не просто 1) загрузить в «промежуточную область» (это всегда * записывается), затем 2) копировать - с помощью «повторить попытку» на ошибке «файл в использовании»? – paulsm4

ответ

3

Ваш мьютекс будет иметь эффект только в том случае, если процесс, который читается из файла, также получает тот же мьютекс. Каков метод, используемый для работы с файлом? Используется ли ASP.Net или это просто статический файл?

Мой рабочее будет немного по-другому:

  1. Написать новый бюллетень в файл нового
  2. Наличия IIS начать обслуживать до нового файла вместо старого для данных новостей URL
  3. Удалите старый файл, как только все существующие запросы на этот файл закончившего

Это не требует блокировок, а также означает, что ТНА t нам не нужно ждать, пока запросы для текущего файла будут завершены (что может потенциально занять неопределенное количество времени, если люди продолжают делать новые запросы).Единственный интересный бит шаг 2, который будет зависеть от того, как подается файл - самый простой способ, вероятно, будет либо настроить HTTP перенаправления или использовать URL переписывания

Перенаправление HTTP

HTTP-редирект, где сервер сообщает клиенту искать в другом месте, когда он получает запрос для данного ресурса, чтобы URL-адрес браузера автоматически обновлялся в соответствии с новым местоположением. Например, если пользователь запросил http://server/20120221.pdf, они могли автоматически перенаправляться на другой URL-адрес, например http://server/20120221_v2.pdf (URL-адрес, отображаемый в браузере, изменился, однако URL-адрес, который им нужно ввести, не будет).

Вы можете сделать это в IIS 7 с помощью элемента httpRedirect конфигурации, например:

<configuration> 
    <system.webServer> 
     <httpRedirect enabled="true" exactDestination="true" httpResponseStatus="Found"> 
     <!-- Note that I needed to add a * in for IIS to accept the wildcard even though it isn't used in this case --> 
     <add wildcard="*20120221.pdf" destination="20120221_v2.pdf" /> 
     </httpRedirect> 
    </system.webServer> 
</configuration> 

Связанная страница показывает, как изменить эти настройки из ASP.Net

Url Переписывая

В качестве альтернативы IIS может быть настроен для автоматической подачи содержимого другого файла для заданного URL-адреса без того, чтобы клиент (браузер) знал разницу. Это называется перезаписи URL и может быть выполнено в IIS, используя что-то вроде this, но для этого требуется, чтобы в IIS были установлены дополнительные компоненты.

Использование HTTP-перенаправления, вероятно, самый простой способ.

+0

Мои проблемы с этим в два раза. 1) Я понятия не имею, как это сделать. 2) Имя файла должно быть в формате YYYYMMDD.pdf, так как я могу написать * новый * файл с тем же именем, пока он служит старым? Если у вас есть примеры, я готов учиться. – pete

+0

«Используется ли ASP.Net или это только статический файл?» Это всего лишь статический файл. – pete

+0

@pete Я обновил свой ответ более подробно – Justin

Смежные вопросы