2016-02-05 4 views
4

Я слияние файлов XPS через веб-приложение IIS, но во время процесса слияния он оставляет открытым дескриптор документа документа. В Windows WPF или консольном приложении я не буду беспокоиться о дескрипторах, поскольку они будут выпущены после закрытия приложения. Утилизация пула приложений также будет эффективно закрывать ручки. Однако я не могу повторно использовать пул приложений только для закрытия дескрипторов файлов из-за кеширования и производительности.Слияние файлов XPS оставляет открытые дескрипторы файлов для ссылок на документы

Есть ли способ закрыть эти дескрипторы файлов после завершения слияния? Я попробовал несколько различных подходов сливаясь, но следующий код дал мне лучшие результаты:

private DocumentPaginator CreateMergedDocument(IEnumerable<string> xpsFiles) { 
    using (MemoryStream mergedStream = new MemoryStream()) { 
    using (var pkg = Package.Open(mergedStream, FileMode.Create, FileAccess.ReadWrite)) { 
     var pack = "pack://merged.xps"; 
     var uri = new Uri(pack, UriKind.Absolute); 
     PackageStore.AddPackage(uri, pkg); 
     using (XpsDocument mergedDocument = 
      new XpsDocument(pkg, CompressionOption.Maximum, pack)) { 
     FixedDocumentSequence seqNew = new FixedDocumentSequence(); 

     foreach (string sourceDocument in xpsFiles) { 
      using (XpsDocument xpsOld = 
       new XpsDocument(sourceDocument, FileAccess.Read)) { 
      FixedDocumentSequence seqOld = xpsOld.GetFixedDocumentSequence(); 

      foreach (DocumentReference dr in seqOld.References) { 
       DocumentReference newDocumentReference = new DocumentReference(); 
       newDocumentReference.Source = dr.Source; 
       (newDocumentReference as IUriContext).BaseUri = 
       (dr as IUriContext).BaseUri; 
       seqNew.References.Add(newDocumentReference); 
      } 
      } 
     } 

     XpsDocumentWriter xpsWriter = XpsDocument.CreateXpsDocumentWriter(mergedDocument); 
     xpsWriter.Write(seqNew); 

     PackageStore.RemovePackage(uri); 

     return seqNew.DocumentPaginator; 
     } 
    } 
    } 
} 

Я разыскал файл ручку открытия в xpsWriter.Write(seqNew) строки коды. Ожидается, так как нужно загрузить файлы для копирования в новый FixedDocumentSequence. Однако было бы неплохо, если бы XpsDocumentWriter был доступен и очистил свои неуправляемые ресурсы/файлы.

Во время моего исследования я пробовал несколько других подходов. Один из подходов, который я пробовал, заключается в написании каждой визуальной страницы на SerializerWriterCollator. Другой подход, который я рассмотрел, - это обработка содержимого FixedPage и обновление URI для скопированных потоков изображений и шрифтов и запись исходного XAML в XmlWriter. Ни один из них не работал слишком хорошо. С визуальными страницами страницы и SerializerWriterCollator, я получал неправильные размеры страниц на объединенной XPS, и это прерывало контент. С использованием метода raw XmlWriter он смешивал некоторые изображения в объединенном XPS и неправильно отображал часть содержимого страницы.

ответ

0

После еще нескольких исследований я обнаружил, что исходный код, используемый для запуска моей функции в потоке STA, не выдает должным образом дескрипторы файлов и неуправляемые ресурсы. У нас был собственный класс потоковой обработки с пользовательской реализацией вызова действия и запуска соединения в потоке. После того, как метод действия завершен, поток не выходил корректно. Чтобы исправить это, я завернул свой код в блок, подобный этому:

private static readonly TaskScheduler _staScheduler = new StaTaskScheduler(1); 

[Route("merge")] 
[HttpGet] 
public async Task<HttpResponseMessage> MergeXps() { 
    var paginator = await Task<DocumentPaginator>.Factory.StartNew(
    () => 
     { 
     var xpsFiles = Directory.GetFiles("C:\\Xps", "*.xps"); 
     var documentPaginator = CreateMergedDocument(xpsFiles); 

     return documentPaginator; 
     }, 
    CancellationToken.None, 
    TaskCreationOptions.None, 
    _staScheduler); 

    var response = new HttpResponseMessage(); 
    response.Content = new StringContent($"Merged Document Page Count: {paginator.PageCount}"); 
    response.StatusCode = HttpStatusCode.OK; 
    return response; 
}