Showing posts with label MVC4. Show all posts
Showing posts with label MVC4. Show all posts

Sunday, February 17, 2013

Cache Repository for MVC

First and foremost, the CacheRepository is NOT web specific!

The CacheRepository library contains the abstract CacheRepositoryBase class, which can be implemented by any caching system that you choose. The CacheRepository.Web NuGet package includes a WebCacheRepository implementation that leverages System.Web.Caching.Cache

CacheRepository.Web

Get all of the source code, unit tests, and a complete MVC4 sample application (preconfigured to include dependency injection with Unity) from GitHub. Or to just jump in and start using it, grab the CacheRepository.Web package from NuGet.

ICacheRepository

The ICacheRepository interface has all the standard Get, Set, Remove and Clear methods. Additionally, these methods have been expanded to include enum parameters to group manage cache expiration.

Best of all, it includes GetOrSet methods. These methods will try to get the value of the specified key, and when it can not find that value it will then be loaded via the passed in Func. A key feature here is the fact that the setter of the GetOrSet will lock on load to prevent redundant data loads. (More details about this below.)

public interface ICacheRepository
{
    object Get(string key);
    T Get<T>(string key);
 
    T GetOrSet<T>(string key, Func<T> loader);
    T GetOrSet<T>(string key, Func<T> loader, DateTime expiration);
    T GetOrSet<T>(string key, Func<T> loader, TimeSpan sliding);
    T GetOrSet<T>(string key, Func<T> loader, CacheExpiration expiration);
    T GetOrSet<T>(string key, Func<T> loader, CacheSliding sliding);
 
    void Set<T>(string key, T value);
    void Set<T>(string key, T value, DateTime expiration);
    void Set<T>(string key, T value, TimeSpan sliding);
    void Set<T>(string key, T value, CacheExpiration expiration);
    void Set<T>(string key, T value, CacheSliding sliding);
 
    void Remove(string key);
    void ClearAll();
}

ThreadSafe GetOrSet

As any good cache should, the CacheRepository is thread safe and can be treated as a singleton.

Even better, the GetOrSet methods lock on set. This means that 10 threads could be trying to load the same cache value simultaneously, but only one will actually trigger a load and set. This helps redundant resource loads and database calls and keep your application running optimally.

private T GetOrSet<T>(string key, Func<T> loader,
    DateTime? expiration, TimeSpan? sliding)
{
    // Get It
    T value;
    var success = TryGet(key, out value);
 
    // Got It or No Loader
    if (loader == null || success)
        return value;
 
    // Load It
    return LockedInvoke(key, () =>
    {
        // Get It (Again)
        success = TryGet(key, out value);
 
        if (!success)
        {
            // Load It (For Real)
            value = loader();
 
            // Set It
            if (value != null)
                Set(key, value, expiration, sliding);
        }
 
        return value;
    });
}

Configurable Expiration Enums

Instead of being forced to set each of your cache expirations separately, you now have the option to use an enum value to group your cache expirations. Enums are available for both absolute expiration and sliding expiration.

You may override the duration of each cache key in your app config; this is really useful for when you want to uniformly modify your cache expirations in your QA or testing environments. Additionally, you may override the CacheRepositoryBase.GetConfigurationValue method to pull this configuration for anywhere you want, not just the ConfigurationManager.

public enum CacheExpiration
{
    VeryShort = 10,     // Ten Seconds
    Short = 60,         // One Minute
    Medium = 300,       // Five Minutes
    Long = 3600,        // One Hour
    VeryLong = 86400    // One Day
}

<configuration>
  <appSettings>
    <add key="CacheExpiration.VeryShort" value="15" />
    <add key="CacheExpiration.Short" value="90" />

ByType Extensions

Transparent cache key management is offered through a series of ICacheRepository extension methods. This makes caching even easier, as you don't need to worry about cache key collisions.

Using these extension methods, you many cache a Cat object with an Id of 1 and a Dog object with an Id of 1 in the same manner. The extension methods will create a key prefix based on the type and then use the specified identified as the suffix.

[Fact]
public void SameKeyDifferentType()
{
    var setCat = new Cat { Name = "Linq" };
    CacheRepository.SetByType(1, setCat);
 
    var setDog = new Dog { Name = "Taboo" };
    CacheRepository.SetByType(1, setDog);
 
    var getCat = CacheRepository.GetByType<Cat>(1);
    Assert.Equal(setCat.Name, getCat.Name);
 
    var getDog = CacheRepository.GetByType<Dog>(1);
    Assert.Equal(setDog.Name, getDog.Name);
}

Web Implementation & Dependency Injection via Unity

The CacheRepository.Web NuGet package includes a WebCacheRepository implementation that leverages System.Web.Caching.Cache. This is a very simple, but very effective, production ready implementation of the CacheRepositoryBase.

It should also be noted that this implementation is not only useful in ASP.NET, the System.Web.Caching.Cache is located in the System.Web library, but it still available outside of a web context. This means that this implementation can be used in other applications, including but not limited to Windows Services.

public class WebCacheRepository : CacheRepositoryBase
{
    private readonly Cache _cache;
        
    public WebCacheRepository()
    {
        _cache = HttpContext.Current == null
            ? HttpRuntime.Cache
            : HttpContext.Current.Cache;
    }

Wiring the cache repository to be injected into your controllers via Unity is also very easy. Just register the WebCacheRepository for the ICacheRepository interface, and be sure to provide a ContainerControlledLifetimeManager for optimal performance.

To use the implementation below, you will need to include the Unity.MVC3 NuGet Package to gain access to the UnityDependencyResolver.

public static void Initialise()
{
    var container = BuildUnityContainer();
    
    DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
 
private static IUnityContainer BuildUnityContainer()
{
    var container = new UnityContainer();
 
    container.RegisterType<ICacheRepository, WebCacheRepository>(
        new ContainerControlledLifetimeManager());           
 
    return container;
}

If you missed the links above, here they are again:

Shout it

Enjoy,
Tom

Sunday, May 20, 2012

MvcBundleConfig NuGet Package

MvcBundleConfig is now available on NuGet!

MvcBundleConfig is a very simple project that adds configuration and debugging features to MVC 4's bundling framework. Once you create a new MVC4 web application and install the MvcBundleConfig NuGet Package, then you need only update our layout to use the new bundle extension methods, and you are ready to go!

Please note that the System.Web.Optimization NuGet package is still in beta, and thus that dependency is not included in the current version of the NuGet package. However, if you have created a new MVC4 project then that assembly should already be included.

Sample Installation Steps

  1. Create a new ASP.NET MVC 4 Project
  2. Select Manage NuGet Packages
  3. Search for and install MvcBundleConfig
  4. Update the Layout
kick it on DotNetKicks.com

Enjoy,
Tom

Saturday, March 31, 2012

Configuring Bundles in MVC 4

We write a lot of JavaScript.

Thus the bundling, compression, and minification of JavaScript is important to the speed and performance of modern websites. This is why I love and have been a big advocate of tools like Combres, and also why I was so excited to hear that such features were (finally) coming built in to ASP.NET MVC 4.

Introducing MvcBundleConfig

MvcBundleConfig is a very simple minimalist project I wrote to add configuration and debugging features to MVC 4's bundling framework, and achieves all 6 six of the goals listed below. It requires only MVC4 to run, and you need only add one config file to your project, one line of code to your application start, and you are off and running.

NuGet Package: https://nuget.org/packages/MvcBundleConfig/

Source on GitHub: https://github.com/tdupont750/MvcBundleConfig

Before we get to the demonstration at the bottom, let's review the needs and wants of a good minification framework.

What I NEED in a minification tool:

  1. Compress resources into single files.
    • Multiple request take time and resources, neither of which are things that any of us have to spare. By compressing resources into single requests and can limit the overhead and load time on both our clients and our servers.
  2. Minify JavaScript and CSS content.
    • Minification removes as many unnecessary white spaces and characters as possible from your resource files, reducing file size by up to 80% on average. When then compounded with gzip, we can reduce the file size another 50%. This means that our web applications can be brought down to clients 90% faster.
  3. Make use of both client and server side caching.
    • Making 90% less requests is nice, and making those requests 90% smaller is even better, but only ever having to request or serve them once is the key to true performance. Unfortunately client and server caching can be a bit complex due to quirks of different technologies and browsers. A good minification framework should abstract these concerns away from us.
  4. Ability to turn off during debugging.
    • As fantastic as everything that we have listed about is for a production website, it is a nightmare for a development website. Debugging JavaScript is no less complicated or time consuming than debugging C#, and we need to be able to use a debuggers and other client side tools that are inhibited by minification. A good minification framework must expose a debugging mode that skips compression pipeline.

What I WANT in a minification tool:

  1. Simple and dynamic configuration.
    • I hate hardcoded configuration. It bloats my code, and it requires bin drops to deploy. Meanwhile I really like the ability to add simple configuration files to my site as often as I can. Config files are explicit, abstract, and can be updated at any time. Win.
  2. Take a few dependencies as possible.
    • I mentioned above that I like Combres and it has a reasonably sized code base, unfortunately the fact that it's NuGet package pulls down half a dozen additional dependencies makes it feel quite heavy. The fewer dependencies a framework takes the better.

MvcBundleConfig Examples

Bundles.config

<?xml version="1.0"?>
<bundleConfig ignoreIfDebug="true" ignoreIfLocal="true">
  <cssBundles>
    <add bundlePath="~/css/shared">
      <directories>
        <add directoryPath="~/content/" searchPattern="*.css" />
      </directories>
    </add>
  </cssBundles>
  <jsBundles>
    <add bundlePath="~/js/shared" minify="false">
      <files>
        <add filePath="~/scripts/jscript1.js" />
        <add filePath="~/scripts/jscript2.js" />
      </files>
    </add>
  </jsBundles>
</bundleConfig>

Global.asax.cs

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
    BundleTable.Bundles.RegisterTemplateBundles();
 
    // Only code required for MvcBundleConfig wire up
    BundleTable.Bundles.RegisterConfigurationBundles();
}

_Layout.cshtml

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width" />
        <title>@ViewBag.Title</title>
 
        @* Call bundle helpers from MvcBundleConfig *@
        @Html.CssBundle("~/css/shared")
        @Html.JsBundle("~/js/shared")
    </head>
    <body>
        @RenderBody()
    </body>
</html>

In the Browser

NuGet Package: https://nuget.org/packages/MvcBundleConfig/

Source on GitHub: https://github.com/tdupont750/MvcBundleConfig

kick it on DotNetKicks.com

Enjoy,
Tom

Real Time Web Analytics