Friendly urls to media archive files

Topics: General
May 9, 2011 at 8:24 PM

Hello there

I am building a new website with Composite C1.

we currently have about 110 PDF documents (technical papers, white papers) on our website.

with Composite C1 and without Issuu player,  I would like serve these PDFs under links such as



instead of

(like creating a folder or a container for the PDFs)


How can I accomplish this?  is this possible?


I hope my question is clear enough.

Thanks in advance for the help



May 10, 2011 at 9:38 AM

Idea is write http module to manage pdf urls.

I suggest quick & dirty solution based on existing package Composite.Tools.LegacyUrlHandler package. 

1. Install package
2. Kill Composite.Tools.LegacyUrlHandler.dll from the bin, remove StoreCurrentPaths.aspx and RemoveRedunantPaths.aspx from the root
3. Copy LegacyUrlHttpModule.cs, LegacyUrlHandlerFacade.cs and Cache.cs to the App_Code (please find them here - - click 2 times Composite.Tools.LegacyUrlHandler - you will find files inside) 
4. Edit LegacyUrlHttpModule.cs and change private const string PathInfoToken = ".pdf";
5. Create /App_Data/LegacyUrlMappings.xml
6. Put inside:

<Mappings>   <Mapping OldPath="/papers/tech-papers/document-1.pdf" NewPath="~/Renderers/ShowMedia.ashx?id=32a3f59c-1d86-4a6f-8acb-d7dcb049fb21" /> </Mappings>

where OldPath is desired url and NewPath - your actual media url.



May 10, 2011 at 9:54 AM
Edited May 10, 2011 at 9:56 AM

@aeont does it mean that in your solution all the document names have to be present in web.config?

I suggest using UrlRewriting 

ShowMedia.ashx can accept path to C1's media archive file as a parameter, urls looks like


So what you need is to add a replacement:


<rewrite url="~/papers/tech-papers/" to="~/Renderers/ShowMedia.ashx?id=MediaArchive:/papers/tech-papers/" />


P.S. I renamed the discussion to "Friendly urls to media archive files"

May 10, 2011 at 10:54 AM
Edited May 10, 2011 at 10:55 AM

yes, in this sample all documents have to be listed in the /App_Data/LegacyUrlMappings.xml
your idea, of course, is more elegant and could be implemented based on Composite.Tools.LegacyUrlHandler package code as well.

May 10, 2011 at 5:59 PM

Hello aeont and napernik

Thank you both. I appreciate

@napernik   the url is looks like


NOT  ~/Renderers/ShowMedia.ashx?id=MediaArchive:/Pdfs/document-1.pdf 

Am I wrong? 

My question is how do i get such a url  so i can add a replacement to it




May 10, 2011 at 8:28 PM
Edited May 10, 2011 at 8:29 PM

>> Am I wrong? 

Both media urls formats are supported. The variant with a GUID is usually more prefereble, since in the case file or it's folder is renamed the url will still be the same.

>> My question is how do i get such a url  so i can add a replacement to it

All the media files are represented as Composite.Data.Types.IMediaFile interface, it has a property called "CompositePath" which is basically "MediaArchive:" + {path to a media file}.

So in C# your code will look like


static string GetUrl(IMediaFile file) {
	return "/Renderers/ShowMedia.ashx?id=" + file.CompositePath;

If you have your pdf link in only one place, you can just create an xslt function that will build those urls.

Or, maybe you would like to have a general solution, that will be fixing all the links by itself. In this case you may use method Composite.Core.WebClient.PageUrlHelper.ChangeRenderingPageUrlsToPublic(...) as an inspiration, 
write a method that searches for all the references like
 /Renderers/ShowMedia.ashx?id={media file id}, 
and replaces it with 

Then call this method in /Renderers/Page.aspx.cs file after line
 xhtml = PageUrlHelper.ChangeRenderingPageUrlsToPublic(markupBuilder.ToString());
Once you are sure it's working, you can replace some of those urls with your own format and use UrlFormatting to redirect it to ShowMedia.ashx
P.S. In upcoming version's we're planning to have seo-friendly media urls. It would be something like{Guid}/{Folder}/document-1.pdf
May 11, 2011 at 12:26 AM

Hi napernik

unfortunately i am just a newbee -I guess you already got that :))  I wish i could implement your suggestions

i placed  the code 

static string GetUrl(IMediaFile file) {
return "/Renderers/ShowMedia.ashx?id=" + file.CompositePath;

onto ShowMedia.ashx page, but i cannot see the "CompositePath". 

i know you did explain it,  but  i am clueless about which code to put where

sorry about the trouble


May 12, 2011 at 12:05 AM

Hi napernik

Did we give up? :)    i need to make this friendly Urls.  I need your help

Please tell me where to place the code.

thank you


May 12, 2011 at 11:22 AM

Hi @Maydin

I'll post the code that replaces media urls in a couple of hours. 

May 12, 2011 at 1:59 PM

Here're the steps.

1. In /App_Code, create MediaUrlReplacer.cs with the following content:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Composite.Data;
using Composite.Data.Types;

namespace Composite.App_Code
    public static class MediaUrlReplacer
        private static readonly string MediaUrlPrefix = "/Renderers/ShowMedia.ashx?id=";

        private class Match
            public int Index;
            public string Value;

        public static string MakeMediaUrlsFriendly(string html)
            StringBuilder result = null;

            var internalUrls = new List<Match>();

            int startIndex = 0;

            // We assume that media url has format "/Renderers/ShowMedia.ashx?id={Guid}"

            while (true)
                int urlOffset = html.IndexOf(MediaUrlPrefix, startIndex, StringComparison.OrdinalIgnoreCase);
                if (urlOffset < 0) break;

                int prefixEndOffset = urlOffset + MediaUrlPrefix.Length;

                int endOffset = prefixEndOffset + 36; /* Guid is 36 characters long*/
                if (endOffset >= html.Length) break;

                internalUrls.Add(new Match
                    Index = urlOffset,
                    Value = html.Substring(urlOffset, endOffset - urlOffset)

                startIndex = endOffset;


            var resolvedUrls = new Dictionary<string, string>();
            using(var conn = new DataConnection())
            foreach (Match mediaUrlMatch in internalUrls)
                string internalMediaUrl = mediaUrlMatch.Value;
                string publicMediaUrl;

                if (!resolvedUrls.TryGetValue(internalMediaUrl, out publicMediaUrl))
                    string guidStr = internalMediaUrl.Substring(MediaUrlPrefix.Length, 36);

                    publicMediaUrl = null;

                    Guid mediaFileId;

                    if(Guid.TryParse(guidStr, out mediaFileId))
                        IMediaFile mediaFile = conn.Get<IMediaFile>().FirstOrDefault(file => file.Id == mediaFileId);
                        if(mediaFile != null)
                            publicMediaUrl = GetFriendlyMediaUrl(mediaFile);

                    resolvedUrls.Add(internalMediaUrl, publicMediaUrl);
                if (publicMediaUrl == null) continue;

                if (result == null)
                    result = new StringBuilder(html);

                result.Remove(mediaUrlMatch.Index, mediaUrlMatch.Value.Length);
                result.Insert(mediaUrlMatch.Index, publicMediaUrl);

            return result != null ? result.ToString() : html;

        private static string GetFriendlyMediaUrl(IMediaFile mediaFile)
            return "/Renderers/ShowMedia.ashx?id=" + mediaFile.CompositePath;
            // return "/media" + mediaFile.FolderPath + "/" + mediaFile.FileName;

2. Edit /Renderers/Page.aspx.cs

Find lines:

        using (Profiler.Measure("Changing 'internal' page urls to 'public'"))
            xhtml = PageUrlHelper.ChangeRenderingPageUrlsToPublic(markupBuilder.ToString());            

And change them to:

        using (Profiler.Measure("Changing 'internal' page urls to 'public'"))
            xhtml = PageUrlHelper.ChangeRenderingPageUrlsToPublic(markupBuilder.ToString());
            xhtml = Composite.App_Code.MediaUrlReplacer.MakeMediaUrlsFriendly(xhtml);

After those 2 steps, all media urls on site should look like


3. Once you have it done, edit GetFriendlyUrl() method in MediaUrlReplacer.cs, so it returns
   return "/media" + mediaFile.FolderPath + "/" + mediaFile.FileName;
Not all the media urls should look like

4. Use UrlRouting make urls in the previous point work: add redirect from "/media/" to "/Renderers/ShowMedia.ashx?id=MediaArchive://"

I hope you'll succeed, note that after installing an upgrade package you may have to do the step 2 once again






May 12, 2011 at 3:04 PM
Edited May 12, 2011 at 6:06 PM

maybe the preferred way to replace html in a rendered document would be to attach a Filter to HttpContext.Response.Filter. Since you can easily replace the default rendering-engine with either one that supports Masterpages or one that is 100% MVC a change to /Renderers/Page.aspx.cs could be lost.

May 13, 2011 at 4:18 PM

Hi @napernik

I followed the steps, until step 4 every thing is woking perfectly.  it has been a big help for me, THANK YOU VERY MUCH

now, I am trying UrlRouting to work on IIS 7.5  so far no luck with UrlRewriter.Net,  I'll google it more



May 18, 2011 at 4:54 PM

Hi @maydin later is better than never

I rewritten the example so now you can just add 2 lines to web.config, and copy file to App_Code to get it working.


In web.config, edit 

1) Add attribute runAllManagedModulesForAllRequests="true" - so handlers will always be executed



       <modules runAllManagedModulesForAllRequests="true">

2) Add an http module  <add name="ShorterMediaUrls" type="Composite.Examples.ShortMediaUrls.MediaRequestsHttpModule, App_Code" />



   <modules runAllManagedModulesForAllRequests="true">

        <add name="ShorterMediaUrls" type="Composite.Examples.ShortMediaUrls.MediaRequestsHttpModule, App_Code" />


you should also have IIS 7.x integrated pipeline mode enabled

May 18, 2011 at 10:05 PM

i guess i should just put something like this in the Contrib-project so everyone can take advantage of friendly mediaurls as well

May 19, 2011 at 12:22 PM

Just updated the CompositeContrib project where i added such a MediaUrlFilter. To enable it just add the following line to your modules-section in web.config. It has been tested on IIS7 integrated pipeline, and you do NOT need to set runAllManagedModulesForAllRequest to true for this module to work.

<add name="MediaUrlFilter" type="CompositeC1Contrib.Web.MediaUrlFilterModule, CompositeC1Contrib" />

Get the newest version here

May 19, 2011 at 1:30 PM

Sorry for spamming, i should just have added this right away in the first commit, but here it is. For those who prefer a GUID based friendly url instead of exposing the whole path can set an option for that.

  • http://site.local/SubFolderApp/media/dubbedub/some_folder/some_other_folder/Jellyfish.jpg - this is the default format
  • http://site.local/SubFolderApp/media/6d4ecd56-e965-48c5-a811-bdd08b454986/Jellyfish.jpg - if you prefer this, set useFolderPathsForMediaUrls to false in appSettings
May 20, 2011 at 6:55 PM

Thank you guys

Jun 24, 2011 at 12:46 PM

I checked in some changes. In the next version media urls will be stored as:


instead of


and will be renderered as:


which is similar to CompositeC1Contrib's behaviour with useFolderPathsForMediaUrls="true"

Jun 24, 2011 at 5:54 PM

Hi @napernik,

This is great, thanks alot.

By the way, I have another problem that i am using CompositeC1Contrib NicerUrls feature,  I also installed Composite.News package.  Inna told me these 2 packages are not working together.

She suggested me to d/l the news package and modify it. I dont have any clue about how to modify the News package, I cannot make Composite.News package and CompositeC1Contrib NicerUrls work together.

I already posted my problem but no help so far. I though you may help me. can you take a look at it. 

Thanks in advance napernik

Have a nice weekend