question

PinoCarafa-9556 avatar image
0 Votes"
PinoCarafa-9556 asked GiuseppeCarafa-3011 commented

XPS suppress navigateuri error for custom URL

We are trying to view an XPS document using a Document Viewer as follows ( VB.NET code )

oDoc = New Xps.Packaging.XpsDocument(path:=sDocument, packageAccess:=IO.FileAccess.Read)
oSequence = oDoc.GetFixedDocumentSequence
oDocViewer.Document = oSequence

The second line causes it to throw an error
System.Windows.Markup.XamlParseException: ''Failed to create a 'NavigateUri' from the text .....

With an inner exception
Invalid URI: The hostname could not be parsed.

The URI in question, however, is a custom one, something like:
mylittlecustomprotocol://tonsandtonsofencryptedgarbagehere

The protocol handler we wrote for this has no problem with it. So we were hoping that there is a way to suppress this error for the mylittlecustomprotocol protocol

windows-wpf
· 8
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

@PinoCarafa-9556. How did you use URI? And what is the path:=sDocument used in your New Xps.Packaging.XpsDocument(path:=sDocument, packageAccess:=IO.FileAccess.Read) ? Please provide more related code to reproduce your problem and analyze the issue.

0 Votes 0 ·

The sDocument is not really that relevant. You can use any small HTML file with something like

<a href="mylittlecustomprotocol://58098++2089290sd72poiusouiso=="> ..... etcetera

in it

0 Votes 0 ·

except of course that HTML document would need to be converted to an .xps file with your favourite converter. We use Aspose for that.

Let me try and get you and example

0 Votes 0 ·

Drat...

I have an HTML file and the resulting XPS file, but it won't allow me to upload them here :(

0 Votes 0 ·

I used XpsDocument(Package, CompressionOption, String) in the following code, it can display Xps normally.
Xaml code:
<Grid>
<DocumentViewer Name="dv"></DocumentViewer>
</Grid>

Xaml.vb code:
Imports System.IO
Imports System.IO.Packaging
Imports System.Windows.Xps.Packaging
Partial Public Class MainWindow
Inherits Window
Public Sub New()
InitializeComponent()
Dim ogXps = File.ReadAllBytes("C:\...\\test.xps")
readXps(ogXps)
End Sub
Public Sub readXps(ByVal originalXps As Byte())
Dim ms As MemoryStream = New MemoryStream(originalXps)
Dim msUri As String = "mylittlecustomprotocol://" & System.IO.Path.GetFileName(Guid.NewGuid().ToString() & ".xps")
Dim packageUri As Uri = New Uri(msUri)
Dim package As Package = Package.Open(ms)
PackageStore.AddPackage(packageUri, package)
Dim xpsDoc As XpsDocument = New XpsDocument(package, CompressionOption.Normal, msUri)
Dim seqDoc As FixedDocumentSequence = xpsDoc.GetFixedDocumentSequence()
dv.Document = seqDoc
End Sub
End Class

I did not reproduce your problem. What steps did I miss or which steps are different from yours? Please let me know if you have any questions.

0 Votes 0 ·

I implemented your suggestion but I'm still getting exactly the same error. Did you try it with the .xps document I uploaded? See the sharefile link in one of my other comments:

https://keyhouse.sharefile.eu/d-s5fd42643a93042c2944fd5e7196673fd

I think we're talking cross purposes here. The URL that's causing a problem is a URL that's present in the document's content, not a URL pointing to (a copy of) the document itself, which, it seems to me, is what you're trying to construct in the line:
Dim msUri As String = "mylittlecustomprotocol://" & System.IO.Path.GetFileName(Guid.NewGuid().ToString() & ".xps")

I don't understand what you're doing there, and why.

0 Votes 0 ·

1 Answer

HuiLiu-MSFT avatar image
0 Votes"
HuiLiu-MSFT answered GiuseppeCarafa-3011 commented

For self-generated xps files with custom hyperlinks, you need to add RequestNavigate to the hyperlinks. Then you can navigate the hyperlink to your target file.
The code of the project that generates the xps file:

 Imports System.IO
 Imports System.IO.Packaging
 Imports System.Windows.Xps.Packaging
 Imports System.Windows.Xps.Serialization
    
 Partial Public Class MainWindow
     Inherits Window
    
     Public Sub New()
         InitializeComponent()
     End Sub
    
     Private Sub Hyperlink_RequestNavigate(ByVal sender As Object, ByVal e As System.Windows.Navigation.RequestNavigateEventArgs)
         Process.Start(New ProcessStartInfo(e.Uri.AbsoluteUri))
         e.Handled = True
     End Sub
    
     Private Sub Window_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
         Dim myParagraph As Paragraph = New Paragraph()
         Dim run1 As Run = New Run("mylittlecustomprotocol://tonsandtonsofencryptedgarbagehere")
         Dim h1 As Hyperlink = New Hyperlink(run1)
         h1.NavigateUri = New Uri("mylittlecustomprotocol://tonsandtonsofencryptedgarbagehere")
         AddHandler h1.RequestNavigate, AddressOf Hyperlink_RequestNavigate
    
         myParagraph.Inlines.Add(h1)
         Dim myFlowDocument As FlowDocument = New FlowDocument()
         myFlowDocument.Blocks.Add(myParagraph)
         Me.Content = myFlowDocument
         Dim ftx As FlowToXps = New FlowToXps()
         ftx.SaveAsXps("C:\\...\\tt.xps", myFlowDocument)
     End Sub
 End Class
    
 Public Class FlowToXps
     Public Sub SaveAsXps(ByVal path As String, ByVal document As FlowDocument)
         Using package As Package = Package.Open(path, FileMode.Create)
    
             Using xpsDoc = New XpsDocument(package, CompressionOption.Maximum)
                 Dim xpsSm = New XpsSerializationManager(New XpsPackagingPolicy(xpsDoc), False)
                 Dim dp As DocumentPaginator = (CType(document, IDocumentPaginatorSource)).DocumentPaginator
                 xpsSm.SaveAsXaml(dp)
             End Using
         End Using
     End Sub
 End Class

The code of the project that reads the xps file:

 Imports System.IO
 Imports System.Windows.Xps.Packaging
 Partial Public Class MainWindow
     Public Sub New()
         InitializeComponent()
         Dim ogXps = "C:\\...\\tt.xps"
         Dim xpsDoc As XpsDocument = New XpsDocument(ogXps, FileAccess.Read)
         Dim seqDoc As FixedDocumentSequence = xpsDoc.GetFixedDocumentSequence()
         dv.Document = seqDoc
     End Sub
 End Class

The result is shown in the figure:
115228-11.png




11.png (17.5 KiB)
· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

@HuiLiu-MSFT thanks so much for taking all this time to help. Sadly it's not quite as simple as a "self generated" xps.

The xps file originates as an Outlook Message into which somebody put that hyperlink. This message is then saved as an .msg file and stored in our storage solution. We use a product called Aspose to convert documents. We use another product to read the original .msg and to convert it to an .html file, and from that we use Aspose to convert that html into an .xps file. So the way the .xps file is produced is through what to us is a "black box" - msg goes in, xps comes out. We have no control over that ourselves.

Going back to my OP, I have currently modified our protocol so that we add a dummy server to it. That stops the error happening. I had already implemented a RequestNavigate handler and it works ....

0 Votes 0 ·

@HuiLiu-MSFT

Got the same problem with a mailto: link. The original document contained a mailto: shortcut, but the shortcut contained a code. Long story short - the document is used as a Template, and it would contain hyperlinks like mailto:[somecodehere] and the same document would then be processed and rendered where the "generated" document would have the [somecodehere] replaced with an actual email address. The code can contain hashes, ampersands or question marks.

Once again the GetFixedDocumentSequence() call fails because it tries to "create a 'NavigateUri' from the text"

Given that there is no real solution here I have taken an alternative approach. With Aspose it's possible to use their PDF software to extract text from an XPS file. So if the GetFixedDocumentSequence() call fails, I release the Xps.Packaging.XpsDocument object, I extract the text from the XPS document, generate a new XPS document from the text to produce a "text only" version of same, and then I use that in the DocumentViewer. This obviously loses any of the visual formatting that may have been in the document, but it's meant to be a "preview" of a document, not a perfect rendering of same, so being able to see the text in the document unformatted is better than seeing nothing at all.

Still hoping that someone can point me toward how we could "tell" the Xps.Packaging.XpsDocument to not try and create 'NavigateUri's or to ignore errors raised when trying to do so, though

0 Votes 0 ·

And I just realised that Aspose also allows us to save an XPS as a PDF. So when GetFixedDocumentSequence fails I'll abandon the attempt to display the document in a DocumentViewer. Instead, I use Aspose to convert it to a PDF and I'll display it in our PDF Viewer instead. Job's a good'un.

0 Votes 0 ·