Merging XPS files leaves open file handles to document references

I am merging XPS files via an IIS web application but during the merging process, it leaves the document reference file handles open. In a Windows WPF or console application, I wouldn't worry about the handles as they would get released after the application closed. Recycling the app pool would effectively close the handles too. However, I can't recycle the app pool just for closing the file handles due to caching and performance.

Is there a way to close these file handles after the merge is complete? I've tried a few different merging approaches, but the following code has given me the best results:

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;
      }
    }
  }
}

I tracked down the file handles opening to the xpsWriter.Write(seqNew) line of code. This is expected as it needs to load the files to copy into the new FixedDocumentSequence . However, it would be nice if an XpsDocumentWriter was disposable and cleaned up its unmanaged resources/file handles.

During my research, I have tried a few other approaches. One approach I've tried is writing each page visual to a SerializerWriterCollator . Another approach I've looked into is processing the FixedPage contents and updating the URIs to copied image and font streams and writing back the raw XAML to the XmlWriter . Neither have worked too well. With the page visuals and SerializerWriterCollator , I was getting incorrect page sizes on the merged XPS and it was cutting off content. With the raw XmlWriter approach, it was jumbling some of the images in the merged XPS and incorrectly displaying some of the page content.


After some more research, I found that the original code used for running my function in an STA thread was not properly releasing file handles and unmanaged resources. We had a custom threading class with a custom implementation of invoking an action and running join on the thread. The thread was not exiting correctly after the action method completed. To fix this, I wrapped my code in a block similar to this:

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;
}
链接地址: http://www.djcxy.com/p/40554.html

上一篇: Xamarin.Forms UWP图像从不关闭打开的文件

下一篇: 合并XPS文件留下打开的文件句柄来记录参考