Working with Relative Urls

Aditi is the lead developer on a corporate handbook tool at a multinational manufacturing company. Her users are HR business partners who write policy pages -- onboarding, leave, expense rules -- inside a WPF desktop app she ships. Every page contains screenshots, org charts, and inline logos. Those images are stored as files next to the document on disk while the author is editing, but the same HTML eventually publishes to an internal SharePoint Web view where the images live at relative URLs.

The dual life of those URLs was the entire problem. While authoring, the WPF editor needed file:///D:/handbook/content/images/leave-policy.png to display the image. After publication, the saved HTML had to contain images/leave-policy.png so SharePoint could resolve it against the page's own URL. Aditi had been doing this rewrite by hand with a string replace before saving, and it kept missing edge cases.

The WpfHtmlEditor anchored everything around one property: BaseUrl. She set it to the folder that holds the handbook content the moment the window opens.

private void OnLoaded(object sender, RoutedEventArgs e)
{
    editor.BaseUrl = Path.Combine(AppContext.BaseDirectory, "handbook-content");
}

With that one line, relative URLs in the document resolved against the folder. An <img src="leave-policy.png" /> tag rendered correctly in the editor, and the built-in image picker dialog opened on the same folder by default, so her HR authors did not have to navigate the file system every time they inserted a screenshot.

Handbook page authoring with relative-path images resolved against BaseUrl

The save path was the half Aditi was reinventing. The editor offers two options that, together, do the rewrite for her. ConvertFileUrlsToLocalPaths turns file:///D:/handbook/content/images/x.png into D:\handbook\content\images\x.png. ConvertAbsoluteUrlsToRelativeUrls then trims away the part that matches BaseUrl, leaving the relative remainder her SharePoint instance expects.

editor.Options.ConvertFileUrlsToLocalPaths      = true;
editor.Options.ConvertAbsoluteUrlsToRelativeUrls = true;

She also flipped on a third option after a hyperlink with a space in the URL broke a published page. UrlEncodeHyperlinkHRefs percent-encodes the href attribute on save, so href="Q1 Reports/index.html" becomes href="Q1%20Reports/index.html". The visible link text stays exactly as the author typed it; only the URL is encoded.

editor.Options.UrlEncodeHyperlinkHRefs = true;
All three URL handling options enabled together on the editor

One detail mattered for Aditi's setup. Her handbook also publishes a printable PDF, and the PDF generator uses the WinForms HTML editor on the build server. She did not want to maintain two configuration code paths. The four members she relied on -- BaseUrl, ConvertFileUrlsToLocalPaths, ConvertAbsoluteUrlsToRelativeUrls, UrlEncodeHyperlinkHRefs -- all live on the shared SpiceLogic.HtmlEditor.Abstractions.IEditorOptions contract. She wrote one helper that takes IEditorOptions and reused it from both apps.

Three months later her HR team had published over four hundred handbook pages without a single broken-image ticket. Aditi deleted the hand-rolled string-replace code and never thought about URL rewriting again.

Last updated on May 12, 2026