Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Put images on CDN, using MVC3 on IIS7

I need to use CDN for all images on my site. So, Ive decided to use IIS Url-rewriting module, because edit manually all my site views - its impossible for me.

So Ive made rules for IIS, eg:

<rule name="cdn1" stopProcessing="true">

   <match url="^Content/Images.*/(.*\.(png|jpeg|jpg|gif))$" />

   <action 
      type="Redirect" 
      url="http://c200001.r9.cf1.rackcdn.com/{ToLower:{R:1}}" 
      redirectType="Permanent" />

</rule>

Its worked, but as you can see there is redirect type is used (301 Permanent). And I think its affects site performance. Maybe it is possible to edit Request.Output to replace image URL?

Please advice, how can I use CDN for images, do not edit my views and avoid redirects?

Any help will be appreciated

like image 225
bogert Avatar asked Jul 31 '11 22:07

bogert


2 Answers

I agree with Steve. You have the URL rewriter doing 301 redirects, but for every image the page needs, the browser still makes a request to the server first to discover that it's 301 redirected to a CDN Url. The only thing you're saving at this point is the downloading of the content.

Instead of doing that, you can just put a response filter in place that will modify the URLs of the assets before the Response is sent to the client browser. That way, the client browser never has to make any calls to your server for static assets:

protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
    filterContext.RequestContext.HttpContext.Response.Filter = new CdnResponseFilter(filterContext.RequestContext.HttpContext.Response.Filter);
}

And then the CdnResponseFilter:

public class CdnResponseFilter : MemoryStream
{
    private Stream Stream { get; set; }

    public CdnResponseFilter(Stream stream)
    {
        Stream = stream;
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        var data = new byte[count];
        Buffer.BlockCopy(buffer, offset, data, 0, count);
        string html = Encoding.Default.GetString(buffer);

        html = Regex.Replace(html, "src=\"/Content/([^\"]+)\"", FixUrl, RegexOptions.IgnoreCase);
        html = Regex.Replace(html, "href=\"/Content/([^\"]+)\"", FixUrl, RegexOptions.IgnoreCase);              

        byte[] outData = Encoding.Default.GetBytes(html);
        Stream.Write(outData, 0, outData.GetLength(0));
    }

    private static string FixUrl(Match match)
    {
        //However the Url should be replaced
    }
}

The result of this is that all content assets that look like <img src="\Content\whatever.jpg" /> will be converted to <img src="cdn-url.com\Content\whatever.jpg" />

like image 179
Mike Richards Avatar answered Oct 21 '22 11:10

Mike Richards


Given that the original URLs are coming from your content and not, for example, from bookmarks, I think you'll have trouble avoiding a request to your site and a redirect; a potentially significant performance impact that could negate the benefits of using a CDN.

It would be better if your could apply URL rewriting to the HTML that is transmitted to the browser, rather than when a request comes in.

Trouble is, I don't know how (unless you're using ISA server, in which case I could tell you, but I suspect you're not)!

You could create a custom ActionFilter and override OnResultExecuted, but you'd need to annotate your controller with the filter attribute.

like image 41
Steve Morgan Avatar answered Oct 21 '22 13:10

Steve Morgan