Tag Archives: featured

orchard

Orchard Module to Prevent (Indefinite) JS/CSS Caching

A couple of days ago, I saw this tweet

 

A few months ago, I wrote a ‘Resource Timestamper’ Orchard module to add a timestamp to invalidate cache on the client.

Browsers cache resources such as JavaScript and CSS. This is a good thing, but this caching prevents browsers from requesting updated versions of resources. Although doing a ‘hard refresh’ of a page can force a reload of scripts and styles, we can’t expect users to do that to circumvent the problem.

It turns out that resources can be updated using a query string parameter. A client browser considers these as two different requests for the same physical resource:

<link type="text/css" rel="stylesheet" href="somecss.css?1"/>
<link type="text/css" rel="stylesheet" href="somecss.css?2"/>

Using a different query string each time the file is served gets around the caching issue, but loses all benefits of caching.  Better yet, generate a new query string value only when the file has changed.

The Resource Timestamper module modifies resource URLs generated with Orchard’s standard Resource Manager class.  To add a timestamp, call the SetAttribute method with parameters of ‘data-timestamped’, and ‘true’.  Here’s an example from ‘The Theme Machine’s’ Layout.cshtml file:

Style.Include("site.css").SetAttribute("data-timestamped", "true");

On the client, a URL is generated:

http://localhost:30321/OrchardLocal/Themes/TheThemeMachine/styles/site.css?v=635151301095348769

Prior to the timestamp being applied, the URL is converted to an absolute URL.  Why? Well, when writing the module, I realised that trying to append a query string to a relative URL (such as /OrchardLocal/Themes/TheThemeMachine/styles/site.css) didn’t work; the query string was being removed.  I see I’m not the only one who’s noticed Style.Include stripping query strings.

Absolute and relative URLs are often a personal preference, but one issue with absolute URLs is that they must be changed when deploying to a production system, or to another domain.  The plugin uses details of the current request, so there is no need to update the code.

The code generates a timestamp for the resource, and only generates a new timestamp when the file changes in some way.  That way, you get the benefit of caching without the problem of updating the file.

Code Analysis

The single class , FcmResourceManager (Fcm is an abbreviation for my company, Fresh Click Media), derives from Orchard’s ResourceManager class.  To actually use this class, rather than the default ResourceManager, an OrchardSuppressDependency attribute is used:

[OrchardSuppressDependency("Orchard.UI.Resources.ResourceManager")]

The class has a number of Orchard dependencies to get its work done:

private readonly IClock _clock;
private readonly ICacheManager _cacheManager;
private readonly IWebSiteFolder _websiteFolder;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly Work<WorkContext> _workContext;

These members are assigned using constructor injection.

The crucial method override is called BuildRequiredResources:

public override IList<ResourceRequiredContext> BuildRequiredResources(string stringResourceType)
{
    var resources = new List<ResourceRequiredContext> base.BuildRequiredResources(stringResourceType));
    foreach (var resource in resources)
    {
        if (resource.Settings.Attributes == null)
            continue;
        if ((from a in resource.Settings.Attributes.ToList()
            where a.Key == "data-timestamped"
            select a).Any())
        {
            resource.Resource.SetUrl(GetCachedUrl(resource));
        }
    }
    return resources;
}

It is this method that is called, and gives us an opportunity to manually set the new URL for the given resource.  This is only done is the ‘data-timestamped’ attribute is found.  In this scenario, the GetCachedUrl method is called.

The GetCachedUrl is shown below:

private string GetCachedUrl(ResourceRequiredContext resource)
{
    if (resource.Resource.Url.StartsWith("http://") || resource.Resource.Url.StartsWith("https://"))
    {
        return resource.Resource.Url;
    }
    string path = GetResourcePath(resource);
    // it's a local file:
    return _cacheManager.Get("Fcm.ResourceCache." + path, ctx =>
    {
        ctx.Monitor(_websiteFolder.WhenPathChanges(path));
        return GetUpdatedUrl(path);
    });
}

The method ignores absolute URLs.  For relative URLs, the path of the file is ascertained.  Orchard’s ICacheManager returns the value of GetUpdatedUrl(…) for a cache key made up of a combination of ‘Fcm.ResourceCache’ and the file’s path.  The cache is invalidated when the path of the file changes.  In this situation the path changes when the file is updated.

The GetUpdatedUrl method takes the original path of the resource, and converts to an absolute URL.

Download and Install

Once you download the module, you can install in the usual way.  The usual way? Go here for more information about installing Orchard modules.

Once the module has been installed, you should see a reassuring message as shown below.  Enable the ‘Resource Timestamper’ feature.

resource timestamper install

One final thing

I hope you find the module useful.  It was written for Orchard 1.5, but has been tested on Orchard 1.7.1 (latest at the time of writing).  It shouldn’t cause you any issues, but you should test it fully on a local environment before deploying it to a production environment. Think that covers it.

keyboard

jQuery Popup Keyboard Screencast

Hey everyone – I’ve just recorded my first ever screencast over at screenr.com. I talk about a jQuery popup keyboard plugin that I wrote a while back.

If you haven’t already checked out screenr, be sure to head over and check it out – it’s a fantastic way to record screencasts up to 5 minutes in length and requires no extra software or faffing about. Recording a screencast is definitely a skill in itself, and since this is my first, I hope you’ll excuse the odd ‘um’ and ‘ah’, but I hope I get the general message across. Five minutes seems like a generous amount of time, but it really does go quickly when you’re recording!

Some points that I didn’t have time to go into on the screencast:

  1. The plugin was initially developed with jQuery 1.2.6 (the most up to date version at the time), but having tested with jQuery 1.3.2 (that latest version as I write this), everything seems fine.
  2. The plugin has been tested in IE7, Firefox and Safari – everything seems to work well.
  3. I haven’t tested the plugin in IE6; I suspect there may be issues with select items and the popup keyboard.

You can download a copy of the screencast project (ZIP file, 8k) shown to have a look in greater detail.

masks

Programmatic impersonation in C#

Impersonation

I recently deployed a WPF app on a server that allowed the user to stop and start some application-related services. The purpose of the app was to allow users with administrative rights an easy way to manage the services that they needed to manage. Granted, they could manage the services through the services MMC, but the little WPF app was a requirement, and it’s our job as developers to make things easier for our clients – right?

All went well until a change of requirements meant that a user without administrative rights needed to use the program to stop and start the required services. When I tried to use the app, I got an exception – quite rightly, stopping and starting the services required admin rights. We needed the restricted user to be able to log on and use the app, but still needed to restrict their permissions.

So – step in programmatic impersonation in C# – a way to give restricted users the power that that’s required, all within the confines of your application.

The first thing to point out is that I got quite a bit of this code from a google search, but I had to do a bit of work to get things in a state that I found really useful.

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Runtime.InteropServices;
using System.Linq;
using System.Security.Principal;
using System.Text;
namespace ServiceControllerApp.Security
{
    public class Impersonator : IDisposable
    {
        private WindowsImpersonationContext _impersonatedUser = null;
        private IntPtr _userHandle;
        public Impersonator()
        {
            _userHandle = new IntPtr(0);
            string user = "servicecontroller";
            string userDomain = ConfigurationManager.AppSettings["MachineDomain"];
            string password = "yourpassword";
            bool returnValue = LogonUser(user, userDomain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref _userHandle);
            if (!returnValue)
                throw new ApplicationException("Could not impersonate user");
            WindowsIdentity newId = new WindowsIdentity(_userHandle);
            _impersonatedUser = newId.Impersonate();
        }
        #region IDisposable Members
        public void Dispose()
        {
            if (_impersonatedUser != null)
            {
                _impersonatedUser.Undo();
                CloseHandle(_userHandle);
            }
        }
        #endregion
        #region Interop imports/constants
        public const int LOGON32_LOGON_INTERACTIVE = 2;
        public const int LOGON32_LOGON_SERVICE = 3;
        public const int LOGON32_PROVIDER_DEFAULT = 0;
        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        public static extern bool LogonUser(String lpszUserName, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public extern static bool CloseHandle(IntPtr handle);
        #endregion
    }
}

Impersonator is a simple class that uses interop to call Win32 LogonUser and CloseHandle functions. We have to use interop because .NET doesn’t provide the equivalent methods.

The code shown above has a user, domain and password actually in the code – for some situations this is a security risk, so the credentials should be obtained in another manner, but for my needs, it was satisfactory, and their direct inclusion simplifies this example.

The class has a WindowsImpersonationContext to manage the impersonation, and the constructor sets up the required logon rights using the LogonUser interop.

Crucially, the impersonation must end, with an equivalent Log Off – and the class implements IDisposable to call the required log off code. Using the class is easy.

using (Impersonator impersonator = new Impersonator())
{
    // code in here
}

The good thing is that because the class implements IDisposable, you don’t have to pepper your code with the log off code equivalent. I hope it’s of use to somebody wishing to implement impersonation.