2016-02-05 133 views
4

我通過IIS Web應用程序合併XPS文件,但在合併過程中,它使文檔引用文件句柄保持打開狀態。在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上獲得了不正確的頁面大小,並且它正在切斷內容。使用原始的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; 
} 
相關問題