External css, sprite Question

Apr 9, 2011 at 3:18 PM
Edited Apr 9, 2011 at 5:33 PM

Hi,

I have some images defined in an external css using background-image: url(); who i would like to combine to a sprite and refer it from within the css

 

I found an article about something like this here http://weblogs.asp.net/zowens/archive/2008/03/05/css-sprite-for-asp-net.aspx when it was possible to get an image with an action result

but i was wondering if this was somehow possible to accomplice with this library somehow?

 

My website is in an Shared environment and therefore using the auto generated URL to the image is not possible as it would change when hitting a new web server.

maybe if it was possible to use a query string to get the image or if the mvc route could pick it up?

The only way i know to fix the name change from server to server is to use static names.

 

Regards

Robert

Apr 9, 2011 at 4:08 PM

Can you please clarify? I am assuming "Shred" was intended to be "Shared"; if not can you please define the term?

Xpedite will check to see if the referenced resource is a local or remote resource and process accordingly. As such, referencing an external resource will pull down a local copy and cache it on the underlying server instance. Is the issue that the external CSS file doesn't use fully qualified names, so the images aren't processed as expected? Any additional info would be appreciated.

Thanks,

Chris

Apr 9, 2011 at 5:26 PM
Edited Apr 9, 2011 at 5:32 PM

hi

yes i mean Shared

 

Ex i use this

 

<%= Html.CompositeImageResource("CombinedImages", New Resource() {
                                      New Resource("IcoMail", "/Resources/img1.png"),
                                      New Resource("IcoTele", "/Resources/img2.png"),
                                      New Resource("IcoMobile", "/Resources/img3.png")
                                  })
    %>

then if i use this with the html helper it will look like this

 

<%= Html.CssSprite("CombinedImages", "IcoMail", "blablabla", "IcoMail")%> <-- this code works on the page level and print out a working image.
This will be resolved to xpedite.EncodedString.xcr <-- Then if i use it in the css it will be background-image: url(xpedite.EncodedString.xcr);

the problem im facing is when im in a Shared hosting environment the EncodedString is not the same across servers in my hosting there is 10 servers who serves my page sometime i will get on
the server 1 and there the EncodedString ex will be abc1 but if i get to server 2 the EncodedString will be dfg12 note its not the same as the server 1 and this will break the background-image: url(xpedite.abc1.xcr);

the shared host clears the memory cache every 3 minutes, i don't know if the clearing is affecting the library.

when i tested the address who i got from server 1 and requested the same resource and came on ex server 2 then i got 404 not found.

 

 what do you mean with "external CSS file doesn't use fully qualified names"? i copied the URL who was gendered from the library and passed it to the css img url.


Regards
Robert
Apr 9, 2011 at 6:43 PM

Okay, I follow you now.

With regard to the caching, Xpedite will use either a file based dependency or a sliding expiration (defaulted to 60 minutes - and now that I think about it, really should be a setting). File based cache dependencies are used for the underlying individual resources (i.e., the individual minified CSS/JS/Image resources that make up a composite resource). The sliding expirations are used for the composite resources themselves. Depending on how the cache is being cleared, you should be fine as the resource technically only needs to live in the cache between the time the request is first made and the page is fully served. That being said, if using absolute cache expiration times there is a small risk that the cache will be cleared prior to all page resources being served. Stress testing will confirm if you will have any issues. I should also note, that generating the CSS Sprites is not a cheap activity, so unless you have a large number of sprites and memory is an issue, I would avoid clearing these out too frequently.

As for the joys of not having session affinity, that is an interesting problem. Resource definitions are built up on the page request/render. When a resource is defined, Xpedite will check to see if a definition is already stored in the cache and use that definition if available; otherwise Xpedite will kick off a background process to generate the composite resource (using a blocking async task to ensure that the resource has finished being generated by the time the resource is requested). In your environment (and correct me if I am wrong), you have a user requesting a page directed to Server A (thus all definitions are generated on Server A). When the client subsequently requests the referenced page resources, some or all or those resource requests are redirected to Server B, C, D, etc (presumablely via load-balancer?). Unfortunately, those servers do not know about the given resource definitions and are then returning a 404?

The Xpedite URLs do not actually contain the resource definition, rather act as the cache reference key for a given resource. The URL is only made up of a hash of the referenced file paths and their associated timestamps. If a resource is made up of the same physical files with the same timestamps, then the same URL will be generated. Most likely the timestamps are out of sync on each server. Regardless, it wouldn't be safe to rely on that behavior (again as the resource is only created when a page is first requested).

Libraries like Combres rely on physical xml resource definitions actually sitting on each server, and that may be better suited for your environment if session affinity is a really not an option. Out of curiosity, is your app completely stateless?

Finally, ignore the remark about qualified URLs (related only to cases where doing something with new Resource("IcoMail", "http://myserver/Resources/img1.png"),
 

Apr 9, 2011 at 7:25 PM
Edited Apr 9, 2011 at 7:38 PM

Hi

The environment my website is in do not allow me to control the time the application cache is cleared and the capacity of ram is low maybe between ~50-68 <-- do not remember 100%.

yes the server is completely stateless, it may not be created on serverA but on a random server from the servers serving the website and then the timestamps will not be the same.

yes the resource returns a 404 because the timestamps as you said is not the same on the servers therefore copying a generated URL then passing it to the address bar with a different IP will result in a 404.

 

I wonder if it is possible to extend the library to allow plugin in a custom cache provider.

Because the only cache i have 100% control of is the file based output cache provider who i use both programmatic and on page level. Taken from here: http://www.eggheadcafe.com/tutorials/aspnet/56161e9e-7fa3-48e8-9dfe-9f7a28f4d58e/filebased-cache-for-web.aspx.

if this was possible then maybe it would solve my problem with the stateless server request's and the rebuilding every 3 minute.

 

Regards

Robert

Apr 9, 2011 at 7:44 PM

Xpedite is currently built on top of the System.Web.Caching.Cache and abstracted out with the following interface:

internal interface IWebCache
{
  IResourceContainer Get(String key);
  void AddWithNoDependency(String key, IResourceContainer value);
  void AddWithFileDependency(String key, IResourceContainer value, String filename);
  void AddWithFileDependencies(String key, IResourceContainer value, String[] filenames);
  void AddWithCacheDependencies(String key, IResourceContainer value, String[] cacheKeys); void Remove(String key);
}

Enabling someone to provide a custom implementation of IWebCache if desired would be easy enough. The interface would have to be made public and some form of WebCacheFactory would have to be added with a backing configuration setting that would default to the existing implementation of WebCache. The WebContext would then just have to instantiate the appropriate cache wrapper via the WebCacheFactory. That should really be all that is required.

So sounds easy enough. If you want to create a Fork to give it a try and if it works (or looks like it will work) I can incorporate it in to the main trunk (sounds like a useful feature).

Apr 9, 2011 at 7:57 PM
Edited Apr 9, 2011 at 8:02 PM

Hi

I can give it a try this is something i would need to use with this library, however i do not have the 100% knowledge on how WebCacheFactory works and some other stuff i have to do some tries and find some info about it first.

And as im still studying i have to complete some works and exams before i can start with a new project.

 

Regards

Robert

Apr 9, 2011 at 8:04 PM

Fair enough, and I am happy to help however I can.

I suggest starting a fork only because I am fairly busy with work this week, so I can't actually dive in to Xpedite code until next weekend.

 

Apr 9, 2011 at 8:10 PM

Hi

ehm i do not understand the meaning of fork

do you mean like a test demo or ?

 

Regards

Robert

Apr 9, 2011 at 8:19 PM
Edited Apr 9, 2011 at 8:20 PM

Basically, create a copy of the source to test your proposed changes.

To create a fork means to branch off (work on an independant copy of) the main source code (trunk).

Even if you aren't to sure how to integrate with the Xpedite code, I might suggest testing if you can create some form of mapping between the output cache provider you are using and the IWebCache interface mentioned above. If it looks like the existing IWebCache method definitions will work for you, then I can worry about integrating the code.

Apr 9, 2011 at 8:36 PM

Thanks for the explanation, i will first try to map the cache provider to the iWebCache interface and if possible i will try to map it to the Xpedite code if i succeed with the first maping.