Back in the day when we started designing our last project we’ve been presented with a following problem – a big number of templates with slightly different sidebars.

Hmm…

Is sidebar a part of content? No, rather not. We don’t want the editors to have to setup the sidebar for every article they write (and the site has a few dozens of articles created on it every day).

Is sidebar more of a template thing? Well… more like it, but still… we have articles all over the site with different sidebar elements when the articles are in different parts of the site (ok so we could add rules what controls display in which part of the site). But wait! There’s more! The sidebar will be different for every language (region). Now we’re talking a dozen of templates or a rules engine just to make the sidebar different. Customising the template with properties isn’t ideal either as it makes EPiServer UI very cluttered. Additionally we want to change sidebars across many templates so the whole branch/section of the site will be able to share the same sidebar.

To a degree this is an academic discussion as we’ve been through it with the previous version of the site and we already knew that integrating this stuff into templates just won’t work and we will be in a world of pain just changing the templates over and over adding little tweaks and changes while the customer ads promotions and performs ad campaigns. Well, we can do it, of course, but it’s not a work a programmer will enjoy, and we all want to do new and more exciting things, don’t we?

We have an internally developed  module to make something like that, that is fully home-grown by another internal team (we now have 3 “squads” capable or making incredible things with EPiServer and we tend to share a lot of technologies and try to rotate people around to adopt the good habits and experiences) and I was (and still am) VERY impressed by it. The technology uses EPiServer pages for defining every module (which are located somewhere outside the site root branch. and then you can mix and match them either declaratively in the code) or by handpicking them in the UI. It’s really cool, though, during the discussions it turned out that we might have to add big chunks of functionality and might end up with separate branches of module-pages for different languages/regions, but… frankly… about that time an article by Ted Nyberg reminded me about a technology I have read about quite a while ago in an article by Stein-Viggo Grenersen and ooohhhhhh… I got seduced. I really wanted to try if for a long time and Ted’s article made it a snap to try and get convinced, and more important… convince Stu ;) that it’s the right way to explore.

So I started to dig.

Read the rest of this article »

Back in the day when we started designing our last project we?ve been presented with a following problem ? a big number of templates with slightly different sidebars.

Hmm?

Is sidebar a part of content? No, rather not. We don?t want the editors to have to setup the sidebar for every article they write (and the site has a few dozens of articles created on it every day).

Is sidebar more of a template thing? Well? more like it, but still? we have articles all over the site with different sidebar elements when the articles are in different parts of the site (ok so we could add rules what controls display in which part of the site). But wait! There?s more! The sidebar will be different for every language (region). Now we?re talking a dozen of templates or a rules engine just to make the sidebar different. Customising the template with properties isn?t ideal either as it makes EPiServer UI very cluttered. Additionally we want to change sidebars across many templates so the whole branch/section of the site will be able to share the same sidebar.

To a degree this is an academic discussion as we?ve been through it with the previous version of the site and we already knew that integrating this stuff into templates just won?t work and we will be in a world of pain just changing the templates over and over adding little tweaks and changes while the customer ads promotions and performs ad campaigns. Well, we can do it, of course, but it?s not a work a programmer will enjoy, and we all want to do new and more exciting things, don?t we?

We have an internally developed  module to make something like that, that is fully home-grown by another internal team (we now have 3 ?squads? capable or making incredible things with EPiServer and we tend to share a lot of technologies and try to rotate people around to adopt the good habits and experiences) and I was (and still am) VERY impressed by it. The technology uses EPiServer pages for defining every module (which are located somewhere outside the site root branch. and then you can mix and match them either declaratively in the code) or by handpicking them in the UI. It?s really cool, though, during the discussions it turned out that we might have to add big chunks of functionality and might end up with separate branches of module-pages for different languages/regions, but? frankly? about that time an article by Ted Nyberg reminded me about a technology I have read about quite a while ago in an article by Stein-Viggo Grenersen and ooohhhhhh? I got seduced. I really wanted to try if for a long time and Ted?s article made it a snap to try and get convinced, and more important? convince Stu ;) that it?s the right way to explore.

So I started to dig.

Read the rest of this article »

The problem that can make a grown up man cry?

You?re editing your EPiServer 4 project and suddenly the edit mode stops working. the server reports compilation errors. something along the lines:

Compiler error: CS0433: Type ?EPiServer.Global? exists in ?c:\WINDOWS\assembly\GAC_MSIL\EPiServer\5.1.422.122__8fe83dea738b45b7\EPiServer.dll? and ?c:\WINDOWS\assembly\GAC\EPiServer\4.61.5.83__8fe83dea738b45b7\EPiServer.dll?

The solution is to go to your web.config and edit the compilation section. The section will most probably look something like this:

<configuration> <system.web> <compilation defaultLanguage="c#" debug="true"> <assemblies> <add assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add assembly="System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/> <add assembly="System.Web.Extensions.Design, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add assembly="EPiServer, Version=5.1.422.122, Culture=neutral, PublicKeyToken=8FE83DEA738B45B7"/> <add assembly="Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add assembly="EPiServer.BaseLibrary, Version=5.1.422.122, Culture=neutral, PublicKeyToken=8FE83DEA738B45B7"/> <add assembly="System.Configuration.Install, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/> <add assembly="EPiServer.Configuration, Version=5.1.422.122, Culture=neutral, PublicKeyToken=8FE83DEA738B45B7"/> <add assembly="EPiServer.Implementation, Version=5.1.422.122, Culture=neutral, PublicKeyToken=8FE83DEA738B45B7"/> <add assembly="EPiServer.XForms, Version=5.1.422.122, Culture=neutral, PublicKeyToken=8FE83DEA738B45B7"/> <add assembly="EPiServer.Events, Version=5.1.422.122, Culture=neutral, PublicKeyToken=8FE83DEA738B45B7"/> <add assembly="EPiServer.Lucene, Version=5.1.422.122, Culture=neutral, PublicKeyToken=8FE83DEA738B45B7"/> <add assembly="ElektroPost.Licensing, Version=5.1.422.122, Culture=neutral, PublicKeyToken=8FE83DEA738B45B7"/> <add assembly="System.Data.OracleClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> <add assembly="EPiServer.Wsrp, Version=5.1.422.122, Culture=neutral, PublicKeyToken=8FE83DEA738B45B7"/> <add assembly="EPiServer.WebParts, Version=5.1.422.122, Culture=neutral, PublicKeyToken=8FE83DEA738B45B7"/> <add assembly="EPiServer.UI, Version=5.1.422.122, Culture=neutral, PublicKeyToken=8FE83DEA738B45B7"/> <add assembly="EPiServer.Web.WebControls, Version=5.1.422.122, Culture=neutral, PublicKeyToken=8FE83DEA738B45B7"/> </assemblies> </compilation> </system.web> </configuration>

in my case only the 4th line referencing the EPiServer.dll was interfering with the editing working, but this can easily be trimmed to only first 3 options, so once you’re done with removing CMS5 entries it could look something like:

<configuration> <system.web> <compilation defaultLanguage="c#" debug="true"> <assemblies> <add assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add assembly="System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/> <add assembly="System.Web.Extensions.Design, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> </assemblies> </compilation> </system.web> </configuration>

The root of the problem supposedly lies in EPiServer SDK integrated with Visual Studio and it?s Visual Studio that puts those lines there once you attempt to add a new element with one of its toolbars or use the Insert->New item? from File menu or context menu in Project Explorer.

Thanks to the guys on #epicode IRC channel for helping out quickly with the problem.

Posted in .Net Framework, ASP.NET, EPiCode, EPiServer, Software Development, Web applications
1 Star2 Stars3 Stars4 Stars5 Stars (1 votes, average: 3.00 out of 5)
Loading...
| 78 Comments »

The configuration of the module is a descendant of any EPiServer Virtual Path Provider configuration. This aspect is fairly well described on EPiServer pages.

A sample configuration for the TextImageVirtualPathProvider can look as follows

<configuration> <episerver> <virtualPath <providers> <add showInFileManager="false" virtualName="Text Images" virtualPath="~/TextImages/" bypassAccessCheck="false" name="TextImages" type="Cognifide.ImageVirtualPathProvider.TextImageVirtualPathProvider,Cognifide.ImageVirtualPathProvider" physicalPath="C:\temp\TextImages" allowedReferers="(localhost)" allowNullReferrer="false" replacementStrings="$colon$,:,$gt$,>,$dot$,.,$quot$,&quot;,$amp$,&amp;,$star$,*,$eol$,&#10;,"/> </providers> </virtualPath> </episerver> </configuration>

 

where:

  • physicalPath is where the cached version of images will be stored
  • shownInFileManager is “false” as there is nothing to present for the user in the file manager.
  • allowedReferrers is the regular expression containing the filter for sites that are allowed to access the path provider and get images. This has been added so that your server does not turn into the internet’s text-image open service :)
  • allowNullReferrer should be set to false in production environment but allows for testing by directly creating URL’s without using a page to fill in the referrer.
  • replacementStrings – this one actually turned out to be very useful since some characters are invalid and not even reaching the VPP if EPiServer or ASP detects them. so to allow for characters like colon or < or even a dot (which would make it hard to form regular expression if it was explicitly available) or * you need to create an escape token for them. The string is a coma separated list of token,value,token,value,…
  • virtualPath is something you need to change if you want your VPP to serve images under a different root level folder. (e.g. if you have a page with that name already)

 

Additionally for IIS6 (most common scenario) you need to add <location> node to configuration for the VPP to work.

<configuration>
  <location path=TextImages>
    <system.web>
      <!– Setup the StaticFileHandler for the wildcard mapping to work in IIS6–>
      <httpHandlers>
        <add path=* verb=GET,HEAD type=System.Web.StaticFileHandler validate=true />
      </httpHandlers>
    </system.web>
    <staticFile expirationTime=-1.0:0:0 />
  </location>
</configuration>


Unless you want to change the location of the virtual path provider can be found under, there is nothing you need to change here.

The code is accessible on EPiCode, but you can also download a compiled binary here. All you need to do then is to unzip the archive to the “bin” folder within your site and set the web.config values to your preference.

The configuration of the module is a descendant of any EPiServer Virtual Path Provider configuration. This aspect is fairly well described on EPiServer pages.

A sample configuration for the TextImageVirtualPathProvider can look as follows

<configuration> <episerver> <virtualPath <providers> <add showInFileManager="false" virtualName="Text Images" virtualPath="~/TextImages/" bypassAccessCheck="false" name="TextImages" type="Cognifide.ImageVirtualPathProvider.TextImageVirtualPathProvider,Cognifide.ImageVirtualPathProvider" physicalPath="C:\temp\TextImages" allowedReferers="(localhost)" allowNullReferrer="false" replacementStrings="$colon$,:,$gt$,>,$dot$,.,$quot$,&quot;,$amp$,&amp;,$star$,*,$eol$,&#10;,"/> </providers> </virtualPath> </episerver> </configuration>

 

where:

  • physicalPath is where the cached version of images will be stored
  • shownInFileManager is ?false? as there is nothing to present for the user in the file manager.
  • allowedReferrers is the regular expression containing the filter for sites that are allowed to access the path provider and get images. This has been added so that your server does not turn into the internet?s text-image open service :)
  • allowNullReferrer should be set to false in production environment but allows for testing by directly creating URL?s without using a page to fill in the referrer.
  • replacementStrings ? this one actually turned out to be very useful since some characters are invalid and not even reaching the VPP if EPiServer or ASP detects them. so to allow for characters like colon or < or even a dot (which would make it hard to form regular expression if it was explicitly available) or * you need to create an escape token for them. The string is a coma separated list of token,value,token,value,?
  • virtualPath is something you need to change if you want your VPP to serve images under a different root level folder. (e.g. if you have a page with that name already)

 

Additionally for IIS6 (most common scenario) you need to add <location> node to configuration for the VPP to work.

<configuration>
  <location path=TextImages>
    <system.web>
      <!– Setup the StaticFileHandler for the wildcard mapping to work in IIS6–>
      <httpHandlers>
        <add path=* verb=GET,HEAD type=System.Web.StaticFileHandler validate=true />
      </httpHandlers>
    </system.web>
    <staticFile expirationTime=-1.0:0:0 />
  </location>
</configuration>


Unless you want to change the location of the virtual path provider can be found under, there is nothing you need to change here.

The code is accessible on EPiCode, but you can also download a compiled binary here. All you need to do then is to unzip the archive to the ?bin? folder within your site and set the web.config values to your preference.

The configuration of the module is a descendant of any EPiServer Virtual Path Provider configuration. This aspect is fairly well described on EPiServer pages.

A sample configuration for the TextImageVirtualPathProvider can look as follows

<configuration> <episerver> <virtualPath <providers> <add showInFileManager="false" virtualName="Text Images" virtualPath="~/TextImages/" bypassAccessCheck="false" name="TextImages" type="Cognifide.ImageVirtualPathProvider.TextImageVirtualPathProvider,Cognifide.ImageVirtualPathProvider" physicalPath="C:\temp\TextImages" allowedReferers="(localhost)" allowNullReferrer="false" replacementStrings="$colon$,:,$gt$,>,$dot$,.,$quot$,&quot;,$amp$,&amp;,$star$,*,$eol$,&#10;,"/> </providers> </virtualPath> </episerver> </configuration>

 

where:

  • physicalPath is where the cached version of images will be stored
  • shownInFileManager is ?false? as there is nothing to present for the user in the file manager.
  • allowedReferrers is the regular expression containing the filter for sites that are allowed to access the path provider and get images. This has been added so that your server does not turn into the internet?s text-image open service :)
  • allowNullReferrer should be set to false in production environment but allows for testing by directly creating URL?s without using a page to fill in the referrer.
  • replacementStrings ? this one actually turned out to be very useful since some characters are invalid and not even reaching the VPP if EPiServer or ASP detects them. so to allow for characters like colon or < or even a dot (which would make it hard to form regular expression if it was explicitly available) or * you need to create an escape token for them. The string is a coma separated list of token,value,token,value,?
  • virtualPath is something you need to change if you want your VPP to serve images under a different root level folder. (e.g. if you have a page with that name already)

 

Additionally for IIS6 (most common scenario) you need to add <location> node to configuration for the VPP to work.

<configuration>
  <location path=TextImages>
    <system.web>
      <!– Setup the StaticFileHandler for the wildcard mapping to work in IIS6–>
      <httpHandlers>
        <add path=* verb=GET,HEAD type=System.Web.StaticFileHandler validate=true />
      </httpHandlers>
    </system.web>
    <staticFile expirationTime=-1.0:0:0 />
  </location>
</configuration>


Unless you want to change the location of the virtual path provider can be found under, there is nothing you need to change here.

The code is accessible on EPiCode, but you can also download a compiled binary here. All you need to do then is to unzip the archive to the ?bin? folder within your site and set the web.config values to your preference.

The module code is already available on Epicode SVN, the relevant wiki pages will be following as soon as documentation is complete.

The use case is as follows:

  • The client wants the site to look exactly as in a template provided as a image,
  • the text is using a non standard font that is not available on 60% of Windows machines,
  • the site does not use flash.
  • the site needs to be equally good looking in IE6 (more about it later)

The solution was to generate images, but how to do it the right way? This has presented us with a once-in-a-lifetime :) opportunity to create a virtual path provider, do something good and learn something new & cool in the process.

Creating a new virtual path provider.

this functionality in itself is fairly well documented on MSDN one thing to pay attention to is to remember to pass the control to the next provider in the provider queue if your provider does not want to serve the request, so in my case:

public override VirtualFile GetFile(string virtualPath) { if (IsPathVirtual(virtualPath)) VirtualFile file = new TextImageVirtualFile(this, virtualPath); return file; else return Previous.GetFile(virtualPath); }

this is necessary so you don’t have to have all-or nothing solution (your provider either serving everything the user requests or not being accessible at all) and honestly I’ve spent quite a while before I found out that… I was just being silly – thinking the technology by itself will resolve that ;)

If your Virtual path provider does not actually implement directories you don’t have to make the very provider to do a lot of complicated things. you are perfectly fine to limit the implementation to providing a custom constructor so that EPiServer passes you the configuration data and a couple of methods to tell whether a file is what you want to handle or not

// this one is actually really cool - whatever values you set in your web.config // will be passed to you in the collection so you can really make your VPP
// as configurable as necessary public TextImageVirtualPathProvider(string name, NameValueCollection configAttributes)
// This one resolves if the file can be generated public override bool FileExists(string virtualPath) { /* ... */ } // Pretty much only passes the info that directory was not found // found if the virtual path matches a path that we should handle public override bool DirectoryExists(string virtualDir) { /* ... */ } // Retrieves the virtual file that generates the image if the // Virtual path matches our pattern or disregards the request if it doesn't public override VirtualFile GetFile(string virtualPath) { /* ... */ } // Again this is only a pass through method as we don't support directories public override VirtualDirectory GetDirectory(string virtualDir) { /* ... */ }

Now that we have ASP passing the request to us we need to wonder how to format the request in a way that is intuitive to the user, I wanted the URL to be straightforward and follow the path of EPiServer’s friendly URL-S so that they are easily formed by editors. So how about:

http://my.server.com/color/font-name/font-size/The%20text%20i%20want%20to%20print.gif

Ok.. well…, that won’t fly for GIFs – the font will be plain ugly if I don’t use antialiasing and if I do I will have an ugly black background underneath it. The solution to that would be using translucent PNG (which the VPP supports) but IE6 does not support those with transparency without ugly hacks. So I need to replace the blacks with a hint so that it generates a background colour when it merges the background with the font for antialiasing. For the sake of this article let’s assume it was an easy switch (IT WASN’T!) and let’s extend the URL to:

http://my.server.com/color/antialias-hint-color/font-name/font-size/The%20text%20i%20want%20to%20print.gif

But I need the font to be bold! Ok… ok…

http://my.server.com/color/antialias-hint-color/font-name/font-size/font-formatting/The%20text%20i%20want%20to%20print.gif

Can I have the image rotated too? Sigh….

http://my.server.com/color/antialias-hint-color/font-name/font-size/font-formatting(optional)/transformatio(optional)/The%20text%20i%20want%20to%20print.gif

The image rotation follows the RotateFlipType enumeration so you can specify any string that is defined in the MSDN documentation for the enumeration.

A sample result for the URL:

http://my.server.com/TextImages/Blue/white/Courier%20New/40/BUI/rotate270flipnone/Hello$eol$from$eol$Cognifide!.gif

Will look as follows

Hello$eol$from$eol$Cognifide! 

For the curious

The final string format matching regular expression looks as follows:

Regex regex = new Regex( @"^(?<colour> # The first match - starting form the beginning of the string
([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[a-zA-Z]*)) # match either a 6 hex digit string or a name of a known color - this is for text color / # now we expect the first separating slash (?<hint> # next match group is about background hint for antialiasing ([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[a-zA-Z]*)) # match either a 3 or 6 hex digit string or a name of a known color - this is for antialiasing color hint / # again separating slash (?<font>[\w\s]*) # font family name - accept white spaces / # yet another separating slash (?<size>[\d]{0,3}) # font size / # oh noes! another slash! ((?<style>[BIUSRN\s]*) # font style Bold, Italic, Underline, Strikethrough /){0,1} # this group is optional. ((?<transform>[\w]*) # transformation name as specified with System.Drawing.RotateFlipType - this group is optional /){0,1} # this group is optional too. (?<text>[\s\S]*[^\.]) # the text to render - basically anything but a dot - use relacement strings for dots [\.] # separating dot - now that's a nice change! (?<extension>(png|gif)) # the file extension - so that we know whether to generate png or gif $ # everything comes to an end ", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.CultureInvariant);

 

Usability concerns

The Colours can be provided as both named Colours (red, green, etc..) or html hex formatted colours (e.g. ff00bb, fob, fff, badfoo) both 6 and 3 hex digits strings are accepted.

The URL accepts spaces, and whatever text string that cannot be passed as a part of the url or is invalidated by EPiServer can be escaped by defining a token for it in web.config so for example as you can see in the above url the end of line “\n” character has been escaped into $eol$.

Obviously the font selection is limited to what is installed on your server.

Performance concerns

The basic concern that comes to mind is – how does this impact the server performance if the image is generated every time? Even though the performance impact seemed to be negligible I’ve decided to cache content. These things simply pile up if you have a high load site so why take the chance? Once an URL is called it is saved on first generation asserting the uniqueness of each parameter. Colours like black and 000 will be treated as same colour and cached only once.

Security concerns

So what was done to prevent our server to be an open server for generating images for everyone on the Internet? The VPP only allows for the images to be generated if the request referrer is in a domain or a host that is specified in the web.config. Additionally for testing you can enable the referrer to be null (direct call to images, as opposed to referring to them from a page).

Also as a seconds line of defence, it’s wise to define the cache folder on a share with a quota so we don’t get our server filled up with images should the referrer limiting measure fail for some reason.

The module code is already available on Epicode SVN, the relevant wiki pages will be following as soon as documentation is complete.

The use case is as follows:

  • The client wants the site to look exactly as in a template provided as a image,
  • the text is using a non standard font that is not available on 60% of Windows machines,
  • the site does not use flash.
  • the site needs to be equally good looking in IE6 (more about it later)

The solution was to generate images, but how to do it the right way? This has presented us with a once-in-a-lifetime :) opportunity to create a virtual path provider, do something good and learn something new & cool in the process.

Creating a new virtual path provider.

this functionality in itself is fairly well documented on MSDN one thing to pay attention to is to remember to pass the control to the next provider in the provider queue if your provider does not want to serve the request, so in my case:

public override VirtualFile GetFile(string virtualPath) { if (IsPathVirtual(virtualPath)) VirtualFile file = new TextImageVirtualFile(this, virtualPath); return file; else return Previous.GetFile(virtualPath); }

this is necessary so you don?t have to have all-or nothing solution (your provider either serving everything the user requests or not being accessible at all) and honestly I?ve spent quite a while before I found out that? I was just being silly ? thinking the technology by itself will resolve that ;)

If your Virtual path provider does not actually implement directories you don?t have to make the very provider to do a lot of complicated things. you are perfectly fine to limit the implementation to providing a custom constructor so that EPiServer passes you the configuration data and a couple of methods to tell whether a file is what you want to handle or not

// this one is actually really cool - whatever values you set in your web.config // will be passed to you in the collection so you can really make your VPP
// as configurable as necessary public TextImageVirtualPathProvider(string name, NameValueCollection configAttributes)
// This one resolves if the file can be generated public override bool FileExists(string virtualPath) { /* ... */ } // Pretty much only passes the info that directory was not found // found if the virtual path matches a path that we should handle public override bool DirectoryExists(string virtualDir) { /* ... */ } // Retrieves the virtual file that generates the image if the // Virtual path matches our pattern or disregards the request if it doesn't public override VirtualFile GetFile(string virtualPath) { /* ... */ } // Again this is only a pass through method as we don't support directories public override VirtualDirectory GetDirectory(string virtualDir) { /* ... */ }

Now that we have ASP passing the request to us we need to wonder how to format the request in a way that is intuitive to the user, I wanted the URL to be straightforward and follow the path of EPiServer?s friendly URL-S so that they are easily formed by editors. So how about:

http://my.server.com/color/font-name/font-size/The%20text%20i%20want%20to%20print.gif

Ok.. well?, that won?t fly for GIFs – the font will be plain ugly if I don?t use antialiasing and if I do I will have an ugly black background underneath it. The solution to that would be using translucent PNG (which the VPP supports) but IE6 does not support those with transparency without ugly hacks. So I need to replace the blacks with a hint so that it generates a background colour when it merges the background with the font for antialiasing. For the sake of this article let?s assume it was an easy switch (IT WASN?T!) and let?s extend the URL to:

http://my.server.com/color/antialias-hint-color/font-name/font-size/The%20text%20i%20want%20to%20print.gif

But I need the font to be bold! Ok? ok?

http://my.server.com/color/antialias-hint-color/font-name/font-size/font-formatting/The%20text%20i%20want%20to%20print.gif

Can I have the image rotated too? Sigh?.

http://my.server.com/color/antialias-hint-color/font-name/font-size/font-formatting(optional)/transformatio(optional)/The%20text%20i%20want%20to%20print.gif

The image rotation follows the RotateFlipType enumeration so you can specify any string that is defined in the MSDN documentation for the enumeration.

A sample result for the URL:

http://my.server.com/TextImages/Blue/white/Courier%20New/40/BUI/rotate270flipnone/Hello$eol$from$eol$Cognifide!.gif

Will look as follows

Hello$eol$from$eol$Cognifide! 

For the curious

The final string format matching regular expression looks as follows:

Regex regex = new Regex( @"^(?<colour> # The first match - starting form the beginning of the string
([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[a-zA-Z]*)) # match either a 6 hex digit string or a name of a known color - this is for text color / # now we expect the first separating slash (?<hint> # next match group is about background hint for antialiasing ([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[a-zA-Z]*)) # match either a 3 or 6 hex digit string or a name of a known color - this is for antialiasing color hint / # again separating slash (?<font>[\w\s]*) # font family name - accept white spaces / # yet another separating slash (?<size>[\d]{0,3}) # font size / # oh noes! another slash! ((?<style>[BIUSRN\s]*) # font style Bold, Italic, Underline, Strikethrough /){0,1} # this group is optional. ((?<transform>[\w]*) # transformation name as specified with System.Drawing.RotateFlipType - this group is optional /){0,1} # this group is optional too. (?<text>[\s\S]*[^\.]) # the text to render - basically anything but a dot - use relacement strings for dots [\.] # separating dot - now that's a nice change! (?<extension>(png|gif)) # the file extension - so that we know whether to generate png or gif $ # everything comes to an end ", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.CultureInvariant);

 

Usability concerns

The Colours can be provided as both named Colours (red, green, etc..) or html hex formatted colours (e.g. ff00bb, fob, fff, badfoo) both 6 and 3 hex digits strings are accepted.

The URL accepts spaces, and whatever text string that cannot be passed as a part of the url or is invalidated by EPiServer can be escaped by defining a token for it in web.config so for example as you can see in the above url the end of line ?\n? character has been escaped into $eol$.

Obviously the font selection is limited to what is installed on your server.

Performance concerns

The basic concern that comes to mind is ? how does this impact the server performance if the image is generated every time? Even though the performance impact seemed to be negligible I?ve decided to cache content. These things simply pile up if you have a high load site so why take the chance? Once an URL is called it is saved on first generation asserting the uniqueness of each parameter. Colours like black and 000 will be treated as same colour and cached only once.

Security concerns

So what was done to prevent our server to be an open server for generating images for everyone on the Internet? The VPP only allows for the images to be generated if the request referrer is in a domain or a host that is specified in the web.config. Additionally for testing you can enable the referrer to be null (direct call to images, as opposed to referring to them from a page).

Also as a seconds line of defence, it?s wise to define the cache folder on a share with a quota so we don?t get our server filled up with images should the referrer limiting measure fail for some reason.

The module code is already available on Epicode SVN, the relevant wiki pages will be following as soon as documentation is complete.

The use case is as follows:

  • The client wants the site to look exactly as in a template provided as a image,
  • the text is using a non standard font that is not available on 60% of Windows machines,
  • the site does not use flash.
  • the site needs to be equally good looking in IE6 (more about it later)

The solution was to generate images, but how to do it the right way? This has presented us with a once-in-a-lifetime :) opportunity to create a virtual path provider, do something good and learn something new & cool in the process.

Creating a new virtual path provider.

this functionality in itself is fairly well documented on MSDN one thing to pay attention to is to remember to pass the control to the next provider in the provider queue if your provider does not want to serve the request, so in my case:

public override VirtualFile GetFile(string virtualPath) { if (IsPathVirtual(virtualPath)) VirtualFile file = new TextImageVirtualFile(this, virtualPath); return file; else return Previous.GetFile(virtualPath); }

this is necessary so you don?t have to have all-or nothing solution (your provider either serving everything the user requests or not being accessible at all) and honestly I?ve spent quite a while before I found out that? I was just being silly ? thinking the technology by itself will resolve that ;)

If your Virtual path provider does not actually implement directories you don?t have to make the very provider to do a lot of complicated things. you are perfectly fine to limit the implementation to providing a custom constructor so that EPiServer passes you the configuration data and a couple of methods to tell whether a file is what you want to handle or not

// this one is actually really cool - whatever values you set in your web.config // will be passed to you in the collection so you can really make your VPP
// as configurable as necessary public TextImageVirtualPathProvider(string name, NameValueCollection configAttributes)
// This one resolves if the file can be generated public override bool FileExists(string virtualPath) { /* ... */ } // Pretty much only passes the info that directory was not found // found if the virtual path matches a path that we should handle public override bool DirectoryExists(string virtualDir) { /* ... */ } // Retrieves the virtual file that generates the image if the // Virtual path matches our pattern or disregards the request if it doesn't public override VirtualFile GetFile(string virtualPath) { /* ... */ } // Again this is only a pass through method as we don't support directories public override VirtualDirectory GetDirectory(string virtualDir) { /* ... */ }

Now that we have ASP passing the request to us we need to wonder how to format the request in a way that is intuitive to the user, I wanted the URL to be straightforward and follow the path of EPiServer?s friendly URL-S so that they are easily formed by editors. So how about:

http://my.server.com/color/font-name/font-size/The%20text%20i%20want%20to%20print.gif

Ok.. well?, that won?t fly for GIFs – the font will be plain ugly if I don?t use antialiasing and if I do I will have an ugly black background underneath it. The solution to that would be using translucent PNG (which the VPP supports) but IE6 does not support those with transparency without ugly hacks. So I need to replace the blacks with a hint so that it generates a background colour when it merges the background with the font for antialiasing. For the sake of this article let?s assume it was an easy switch (IT WASN?T!) and let?s extend the URL to:

http://my.server.com/color/antialias-hint-color/font-name/font-size/The%20text%20i%20want%20to%20print.gif

But I need the font to be bold! Ok? ok?

http://my.server.com/color/antialias-hint-color/font-name/font-size/font-formatting/The%20text%20i%20want%20to%20print.gif

Can I have the image rotated too? Sigh?.

http://my.server.com/color/antialias-hint-color/font-name/font-size/font-formatting(optional)/transformatio(optional)/The%20text%20i%20want%20to%20print.gif

The image rotation follows the RotateFlipType enumeration so you can specify any string that is defined in the MSDN documentation for the enumeration.

A sample result for the URL:

http://my.server.com/TextImages/Blue/white/Courier%20New/40/BUI/rotate270flipnone/Hello$eol$from$eol$Cognifide!.gif

Will look as follows

Hello$eol$from$eol$Cognifide! 

For the curious

The final string format matching regular expression looks as follows:

Regex regex = new Regex( @"^(?<colour> # The first match - starting form the beginning of the string
([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[a-zA-Z]*)) # match either a 6 hex digit string or a name of a known color - this is for text color / # now we expect the first separating slash (?<hint> # next match group is about background hint for antialiasing ([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[a-zA-Z]*)) # match either a 3 or 6 hex digit string or a name of a known color - this is for antialiasing color hint / # again separating slash (?<font>[\w\s]*) # font family name - accept white spaces / # yet another separating slash (?<size>[\d]{0,3}) # font size / # oh noes! another slash! ((?<style>[BIUSRN\s]*) # font style Bold, Italic, Underline, Strikethrough /){0,1} # this group is optional. ((?<transform>[\w]*) # transformation name as specified with System.Drawing.RotateFlipType - this group is optional /){0,1} # this group is optional too. (?<text>[\s\S]*[^\.]) # the text to render - basically anything but a dot - use relacement strings for dots [\.] # separating dot - now that's a nice change! (?<extension>(png|gif)) # the file extension - so that we know whether to generate png or gif $ # everything comes to an end ", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.CultureInvariant);

 

Usability concerns

The Colours can be provided as both named Colours (red, green, etc..) or html hex formatted colours (e.g. ff00bb, fob, fff, badfoo) both 6 and 3 hex digits strings are accepted.

The URL accepts spaces, and whatever text string that cannot be passed as a part of the url or is invalidated by EPiServer can be escaped by defining a token for it in web.config so for example as you can see in the above url the end of line ?\n? character has been escaped into $eol$.

Obviously the font selection is limited to what is installed on your server.

Performance concerns

The basic concern that comes to mind is ? how does this impact the server performance if the image is generated every time? Even though the performance impact seemed to be negligible I?ve decided to cache content. These things simply pile up if you have a high load site so why take the chance? Once an URL is called it is saved on first generation asserting the uniqueness of each parameter. Colours like black and 000 will be treated as same colour and cached only once.

Security concerns

So what was done to prevent our server to be an open server for generating images for everyone on the Internet? The VPP only allows for the images to be generated if the request referrer is in a domain or a host that is specified in the web.config. Additionally for testing you can enable the referrer to be null (direct call to images, as opposed to referring to them from a page).

Also as a seconds line of defence, it?s wise to define the cache folder on a share with a quota so we don?t get our server filled up with images should the referrer limiting measure fail for some reason.

Episerver’s brand new blogger

I’m really glad to notice that Marek is getting into blogging about EPiServer. Marek is a really bright developer and a colleague at Cognifide with a number of successful EPiServer projects in his portfolio, we’ve worked together on Faceted Navigation (he’s the brain behind all the nifty editors in it) that I’m working on open sourcing of currently, and on the Setanta Sports Portal and the Setanta corporate site projects. Now he’s out in the wild writing about it. Go ahead and read his analysis on the performance of Episerver 4.x versus CMS 5. It appears that the CMS is getting… nah… I won’t spoil it for you… Read all about it on Marek’s brand new blog!

Posted in ASP.NET, Blogging, EPiCode, EPiServer, Faceted Navigation, Open Source, Software Development
1 Star2 Stars3 Stars4 Stars5 Stars (1 votes, average: 5.00 out of 5)
Loading...
| Leave a Comment »