How To Create Your Own Asp.Net Mvc View Engine From Scratch

By Mike on 18 April 2013

There are a number of reasons you might want to create your own view engine for Asp.Net Mvc. Mine was that I wanted to have finer control over configuration. You can do a lot with the default view engine but you have to use the golden hammer of inheritance. And for some 'advanced' features like theming you need to modify it (how lucky that asp.net mvc is open source).

Anyway, regardless the reasons why you want to create your own view engine, here's how to build one from scratch. Warning: Code heavy post.

In Asp.Net MVc the view engine has 2 concerns: to locate a view and to instantiate a view. Note that it has nothing to do with the template parsing and rendering so the same view engine can be used to render Razor, Webforms, Spark etc. It's important to understand the difference between the view engine and the template engine.

Here, I want to create a flexible view engine, that is, it can be easily configured via conventions and can support any template engine.

public class FlexibleViewEngine:IViewEngine
{
    public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
    {    
    }
    
     public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
    {
    }
    
    public void ReleaseView(ControllerContext controllerContext, IView view)
    {
    }
}

These are the methods required by IViewEngine. You can see the ViewEngineResult which will be returned in both success and failure scenario. The difference is the when failed, it will contain a collection of searched view path, the ones you see in the yellow screen of death when asp.net mvc can't find a view.

I've said above that this view engine will know how to work with any template engine and this means that it will require view factories injected in it. For easy config, I've decided to have a FlexibleViewEngineSettings object where factories can be added.

public class FlexibleViewEngineSettings
    {
       
        public List<IViewFactory> ViewFactories { get; private set; }

      
        public List<IFindViewConvention> Conventions { get; private set; }
        
    }

 The Conventions list holds the conventions used to locate views.

The view engine accepts an action that can be used to add view factories and view locator conventions.

private FlexibleViewEngineSettings _settings=new FlexibleViewEngineSettings();

    //constructor
    public FlexibleViewEngine(Action<FlexibleViewEngineSettings> config=null)
    {
        if (config != null)
        {
            config(_settings);
        }
        
    }

How does a convention looks like?

public interface IFindViewConvention
    {
        bool Match(ControllerContext context, string viewName);
        string GetViewPath(ControllerContext controllerContext, string viewName);
        string GetMasterPath(ControllerContext controllerContext, string masterName);
    }

Each concrete convention must decide when to apply and how to create a path for a given view or layout. One example can be the case of an Ajax heavy site that still wants to be indexed by search engines. When a search crawler is detected, a special SEO tailored view can be used.

A view factory interface looks like this

public interface IViewFactory
    {
        bool IsSuitableFor(string fileExtension);
        IView Create(ViewCreationData settings);
        IView CreatePartial(ViewCreationData settings);
    }

The concrete factory will be used only for view paths ending with a suitable extension. This means that conventions (the view path generator) and factories work together. Although a partial view is a view, it's necessary to have separate methods because a partial view has special needs, for example, in razor case it should ignore _ViewStartPage .

Ok, so now we have conventions and view factories in our settings. Let's see how they are used by the view engine.

The main idea is that for a given view it processes all the conventions and uses the first which returns a valid view path. It then uses that path to search for a view factory which can handle the file extension. After that it asks the factory to create a IView instance which is returned via the ViewEngineResult object.

 If a returned view path isn't valid, it's added to a list of searched paths. If no conventions returned a valid path or there are no view factories which can handle it, an 'error' ViewEngineResult is returned containing the list of searched paths. That's all, pretty easy.

And once the view engine is built along with some conventions and view factories, just hook it up

ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(new FlexibleViewEngine(v =>
        {
            v.Conventions.Add(new MyViewConvention());
            //another view factory
            v.ViewFactories.Add(new MyViewTemplateFactory());
        }));

I've included a Razor view factory and the Asp.Net Mvc view conventions (cshtml only and with theme support) by default, so this configuration is for only when you want to use your own conventions or another template engine.

Here's an example of how to write a view factory

public class RazorViewFactory:IViewFactory
    {
        private string[] _extensions = new []{"cshtml","vbhtml"};
        public bool IsSuitableFor(string fileExtension)
        {
            return _extensions.Contains(fileExtension);
        }

        public IView Create(ViewCreationData settings)
        {
            return new RazorView(settings.Context, settings.ViewPath,settings.MasterPath, true,_extensions);
        }

        public IView CreatePartial(ViewCreationData settings)
        {
            return new RazorView(settings.Context, settings.ViewPath, null, false, _extensions);
        }
    }

That's all! You can check the entire FlexbileViewEngine code here

Asp.Net Mvc Apply Filters By Convention

By Mike on 9 April 2013

After using conventions to define routes, how about using conventions to apply filters? I mean, I have to decorate every controller in the Admin section with at least 2 attributes: [RequirePermission(UserRights.Login)] and [OverrideTheme("admin")]. I'm using the Handler convention so basically I have as many controllers as I have actions. I also want to enable [SmartAction] for all POSTs and to have some specialized Ajax Only Controllers.

The default way is to clutter each action (or controller) with a stack of attributes or worse, to have a base Controller with these attributes and the inherit from it. I consider the inheritance solution to be a poor one, this is one of the cases where you shouldn't use it.

We need a better way and luckily, it's trivial to implement one. The idea is very simple: I want to apply a filter according to a convention. Of course, I start with an interface to define a filter policy. All the filters are considered to be global filters.

public interface IFilterPolicy
    {
        int? Order { get; }
        /// <summary>
        /// Filter instance
        /// </summary>
        object Instance { get; }
        
        bool Match(MethodInfo action);
    }

This policy is then used by a filter provider to know when to return the filter. As I've said, it's trivial.

internal class FiltersWithPoliciesProvider:IFilterProvider
    {
        Dictionary<string,IEnumerable<Filter>> _filters=new Dictionary<string, IEnumerable<Filter>>();
        public FiltersWithPoliciesProvider(IEnumerable<FilterActionInfo> filters)
        {
            foreach (var filter in filters)
            {
                _filters.Add(filter.Key,filter.Filters);
            }
        }
        
        
               public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
        {
            var key = FilterActionInfo.CreateKey(actionDescriptor.ControllerDescriptor.ControllerType,
                                                 actionDescriptor.ActionName);
            IEnumerable<Filter> filters;
            if (!_filters.TryGetValue(key, out filters))
            {
                filters=new Filter[0];
            }
            return filters;
        }
    }

For a quick and elegant setup

//setup DI container
    builder.RegisterAssemblyTypes(ThisAssembly).Where(t => t.DerivesFrom<IFilterPolicy>()).AsSelf();

   //tell FiltersPolicy where to find actions and policies
     FiltersPolicy.Config.RegisterControllers(asm);
     FiltersPolicy.Config.RegisterPolicies(asm);
     
     //tell FilterPolicy to build and register the provider
     FiltersPolicy.Config.RegisterProvider(FilterProviders.Providers);

Now let's write some conventions

//All admin views are using the Admin theme
 public class AdminThemeIsFixed:IFilterPolicy
    {
        public AdminThemeIsFixed()
        {
            Instance = new OverrideThemeAttribute("admin");
        }
        public bool Match(MethodInfo action)
        {
            return action.DeclaringType.Namespace.Contains("Admin");
        }

        public int? Order { get; private set; }

        /// <summary>
        /// Filter instance
        /// </summary>
        public object Instance { get; private set; }
    }
 
 //All controllers from Admin must be authorized
  public class AllAdminActionsRequiresLogin:IFilterPolicy
    {
        public AllAdminActionsRequiresLogin()
        {
            Instance = new RequiresPermissionAttribute(UserRight.Login);
        }
        public bool Match(MethodInfo action)
        {
            return action.DeclaringType.Namespace.Contains("Admin");
        }

        public int? Order { get; private set; }

        /// <summary>
        /// Filter instance
        /// </summary>
        public object Instance { get; private set; }
    }
    
    //All actions from controllers having ajax in name are constraint to ajax requests
  public class AjaxControllersConvention:IFilterPolicy
    {
        public AjaxControllersConvention()
        {
            Instance = new AjaxAttribute();
        }
        public bool Match(MethodInfo action)
        {
            return action.DeclaringType.Name.Contains("Ajax");
        }

        public int? Order { get; private set; }

        /// <summary>
        /// Filter instance
        /// </summary>
        public object Instance { get; private set; }
    }

There you have it, the easiest way to apply filters selectively via conventions. Now, your controllers are less cluttered and you don't have to remember all the attributes or to misuse inheritance.
 
 Note that this doesn't interfere with the global asp.net mvc filters, so you can register some filters to apply to every action while other are applied according to a convention. You can check out the whole source here.

Asp.Net Mvc Routing By Convention

By Mike on 8 April 2013

My brief adventure with FubuMvc had a greater impact on me than I expected. I happily adopted some of its features to use with Asp.Net Mvc. One thing that I liked a lot was configuration by convention. And that didn't mean: "Here's the convention, now use it" but the ability to define your very own conventions. This way everybody can do things how they want and everyone is happy. Win-win.

I adopted the handler convention as it cleans up the code a bit, but I needed a way to define the routes. Writing them by hand is not an option and using generic routes like "{controller}/{action}" means a lot of fun debugging them.

I know about Attribute Routing but decorating each action or controller every time is not a good solution for me. I mean there is only 1 attribute, but one for routing, another one for authorization, another one for theming etc and you have to remember a small stack of attribute to put on top of every controller.

What I need is a way to define some rules that can be applied automatically. For example I wanted to:

  • generate the routes from the actions and use the naming convention to format the url. So having the controller "Pages" action "GetBy_Id_Page" would generate the url "pages/{id}/{page}". All POST actions would be simply called "Post" or should start with that prefix.
  • every url must be prefixed with the "{tenant}" parameter and the route should contain the default value for it.
  • every Admin action should contain 'Admin' in the url or even better, the urls should be namespace based i.e the url hierarchy should respect the namespace hierarchy.

Taking a hint from Fubu, I came up with a simple way to define routing policies. I considered 3 cases:
- Generate 1 or more routes from an action
- Format url according to a criteria
- Apply a general policy for all routes

This system is just an alternative way to define routing and it doesn't interfere with the manual route definition or any other way. It only provides a way to use conventions in order to define the routes.

So, for my project I ended up defining these routing policies:

  • HandlerRouteConvention (source here)
  • NamespacePrefixedUrls
    public class NamespacePrefixedUrls:IRouteUrlFormatPolicy
        {
            public bool Match(ActionCall action)
            {
                return true;
            }
    
            public string Format(string url, ActionCall actionInfo)
            {
                var prefix = actionInfo.Settings.StripNamespaceRoot(actionInfo.Controller.Namespace);
                prefix = prefix.Replace('.', '/').TrimStart('/');
                if (prefix.IsNullOrEmpty())
                {
                    return url;
                }
                return prefix.ToLowerInvariant() + "/" + url;
            }
        }
  • EveryRouteHasTenantPrefix
    public class EveryRouteHasTenantPrefix : IRouteGlobalPolicy
        {
    
            public void ApplyTo(Route route)
            {
                route.Url = "{tenant}/" + route.Url;
                route.Defaults["tenant"] = "main";
            }
        }

The entire code to define routes using policies

var routes = RouteTable.Routes;
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
     
    var policy = new RoutingPolicy();
    policy.RegisterControllers(typeof(Routing).Assembly);
    policy.GlobalPolicies.Add(new EveryRouteHasTenantPrefix());
    policy.UrlFormatPolicies.Add(new NamespacePrefixedUrls());
    policy.RegisterHandlerConvention();
    policy.Apply(routes);

If I know I'll be needing more policies over time I can harness the power of the DI Container

//register any convention with the DI Container (autofac)
  builder.RegisterAssemblyTypes(ThisAssembly).Where(t => t.DerivesFrom<IRouteConvention>()).AsSelf();
  builder.RegisterAssemblyTypes(ThisAssembly).Where(t => t.DerivesFrom<IRouteUrlFormatPolicy>()).AsSelf();
  builder.RegisterAssemblyTypes(ThisAssembly).Where(t => t.DerivesFrom<IGlobalRoutePolicy>()).AsSelf();            
 
 
 //tell RoutingPolicy to scan and register any policy it finds
  var policy = new RoutingPolicy();
  policy.RegisterControllers(typeof(Routing).Assembly);
  policy.RegisterPolicies(typeof(Routing).Assembly);
  policy.Apply(routes);

Now, the only thing left is to write the policies and they will be used automatically. You can check out the source code for the 'routing by convention' system here.

Simplify Coding with Caveman Tools

By Mike on 9 February 2013

I think I've started Caveman Tools around 2009 or so as the library where I'd dump extension methods and other helpers for common tasks. In the mean time it grew to contain lots of big and small utils and now I think my productivity would drop (and the boring factor would rise like inflation in times of depression) without it. I want to share with you a few of the helpers, little bits that simplify some tasks.

Guard Clauses

Nothing magical, just semantic shortcuts to avoid the boringness of 'if (!argument condition) throw Exception()'.

user.MustNotBeNull();
title.MustNotBeEmpty();
tile.MustMatch(@"[a-z]+");
list.MustNotBeEmpty();
value.MustBe<int>();

//exotic
strategy.MustImplement<IStrategy>();

 

LogHelper

Even when doing simple apps I want some logging, at least to show some stuff in Diagnostics window or to Console. Doing Debug.WriteLine is not that fun, especially if I want to 'upgrade' later to a real logging solution. With LogHelper things are simple:

//Setup - yes, one line
LogHelper.OutputTo(s=>Debug.WriteLine(s));
//or
LogHelper.OutputToConsole();


//Usage 
LogHelper.DefaultLogger.Info("something");


//as a dependency
public class MyClass
{
    public MyClass(ILogWriter log){}
}

var c=new MyClass(LogHelper.DefaultLogger);

All I have to do when I want to 'upgrade' to using NLog (for example) is to wire-up NLog to LogHelper and I'm good to go.

 

Fun with Lists

var old = new List<int>();
 var fresh = new[] {1, 2};
 
 var diff=fresh.Compare(old); // diff will contain what items were added or removed
 
//new items from fresh will be added to old
//items from old, but not available in fresh will be removed
 old.Update(fresh); 
 
old.AddIfNotPresent(someItem);//self explaining

//RemoveAll() method added to IList
Ilist<int> list;
list.RemoveAll(predicate);

 

Working with Percentages

Every time when I was dealing with something involving percentages I was confused about that decimal: is it already divided by 100 or I have to divide it? Percentage struct to the rescue.

var taxRate=new Percentage(3);//3%
Percentage salesTaxRate = 2;//2% , implicit from decimal

var tax=taxRate.ApplyTo(1000); //tax=30

//operator overload
var totalTaxRate=taxRate + salesTaxRate; 
Console.WriteLine(totalTaxRate.ToString());// outputs 5%

 

Reflection

//fun with attributes
type.GetSingleAttribute<MyAttribute>();
type.HasCustomAttribute<MyAttribute>();
type.GetCustomAttributes<MyAttribute>();

//type utils
if (type.Implements<Interface>()) { };

var argType=type.GetGenericArgument(0);//gets first generic argument

if (type.IsNullable()){};

if (type.IsNullableOf<int>()) {};

if (type.CanBeCastTo<int>()) {};

 

Time Utils

TimeSpan ts = 1.ToSeconds();
var half = ts.Multiply(.5f);
Console.WriteLine(TimeSpan.FromDays(2).ToHuman());//outputs "2 days ago" . english only

 

Other

//instead of the ugly: (expression.Body as MemberExpression).Member.Name
expression.Body.As<MemberExpression>().Member.Name;

//instead of (int)object
object.Cast<int>()

//useful when you need the id-name combo, common in view models
IdName topic=new IdName(){Id=1,Name="Tools"}

There are other interesting helpers but they're a bit specific, dealing with LCG (Light Code Generation) or Expressions Trees, so that's all for now.

DRY Asp.Net Mvc Controllers

By Mike on 9 January 2013

Since reading Jimmy Boggard's post, I've been trying to DRY things in the Asp.Net Mvc land. Truth is, in every POST action you have to verify if the model is valid. Is not much code but it's repetitive and you do it because you have to. It's not like you can continue the action with an invalid model.

What if the controller would verify automatically that the model is valid and if it isn't , to return directly the view. So the controller action wouldn't be even called for an invalid model.

That is instead of this

public class HomeController:Controller
{

  [HttpPost] 
 public ActionResult CreatePost(Post model)
  {
    if (!ModelState.IsValid)
    { 
        model.Categories=GetAllCategories();  
        return View(model);
    }

    ProcessAndSaveModel(model);
    
    if (someError)
    {
       ModelState.AddModelError("key","something happened");
       model.Categories=GetAllCategories();
       return View(model);
    }
    return RedirectToAction("index");
  }

}

we would have this

[SmartController]
public class HomeController:Controller
{
  
 [HttpPost]
 public ActionResult CreatePost(Post model)
 {
   ProcessAndSaveModel(model);

   if (someError) ModelState.AddModelError("key","something happened");

  return RedirectToAction("index");
 }
 
}

Instead of 9 lines of code, we have now only 3. We've reduced the action size by 2/3! All just by decorating the controller with the SmartControllerAttribute. Pretty good!

In fairness, there is a bit more code involved but not as part of the controller. Some functionality was moved outside the controller but this just makes things more decoupled. The point is that in the first example we have 2 things repeating themselves:

  •  checking if the model is valid and
  •  populating the model before returning the View result.

In the second example, nothing repeats itself. Both examples have identical functionality.

Before diving in, let me tell that the SmartController is available as part of the newly released CavemanTools.Mvc (use Nuget to get it).

Although you've seen the SmartController, the actual feature is in fact implemented by the SmartActionAttribute. As you might have guessed the difference between them is that one works at the controller level (applies to all actions) while the other works at the action level (only the decorated action gets the feature).

How does it work? The Smart functionality is an action filter running before and after the action. It checks the modelstate validity and if it fails it uses a predefined policy, which by default is to return a view with the same name as the action. If before the action, the action won't be invoked at all. If the validation fails after the action, then the result returned by the action is ignored.

So you don't have to do the checks yourself. The action will be invoked ONLY if validation succeeds and the result will be executed ONLY if the second validation succeeds.

What about the case where a model needs to be populated? In many scenarios, the view model needs more than the info received from the request. In this example, our Post model needs the categories set. How does the magic works?

When preparing the model for a failed validation, the SmartAction checks if there is a class which can populate the model. That is, it asks the DI Container if it has an ISetupModel<T>, in this case an ISetupModel<Post>, like this (a trivial example, an actualy setup usually involves more than 1 line)

public class PostModelSetup:ISetupModel<Post>
{
  IRepository _repo;
   public PostModelSetup(IRepository repo) 
  {
    _repo=repo;
  }
 public void Setup(Post post)
 {
     post.Categories=_repo.GetAllCategories();
 }
}

If it exists, the object is used to populate the categories automatically. This is the functionality removed from the initial controller. Now we can use it anywhere we need to setup the Post model. When a GET request comes for the CreatePost we use this object to create the Post model like this

[SmartController]
public class HomeController:Controller
{
  /* .. Constructor with dependencies ... */
  
  
  public ActionResult CreatePost()
 {
  var model= new PostModelSetup(repository).Create();
  model.SelectedCategoryId= 2;
  return View(model);
 }


//This action is unchanged 
 [HttpPost]
 public ActionResult CreatePost(Post model)
 {
   ProcessAndSaveModel(model);

   if (someError) ModelState.AddModelError("key","something happened");

  return RedirectToAction("index");
 }
}

We achieved DRY for the setup of the model also. Without these, you would have to repeat yourself in 3 places: once in the GET CreatePost and twice in the POST CreatePost.

You can read about more Smart features here. Keep your controllers DRY!

Easy Authorization For Multi Tenant Asp.Net Mvc Applications

By Mike on 23 February 2012

The latest (1.3) release of Caveman Tools toolkit, includes functionality to make authorization with groups and rights a breeze (take a look at the tutorial). However for the next release, I've added support for authorization in multiple scopes, which will make it much easier for multi tenant applications to deal with request authorization. This post refers to the version 1.3.5 (unreleased yet) of CavemanTools.

I'm talking about web application hosting scenario, similar to what wordpress.com, bloger, getsatisfaction, github or bitbucket do, where people register with them to have their own instance of the specific service. However, every member is also a user of the global service (not limited to an account only) but their rights are specific to an account. So you can be the admin of your account, but you're a simple user for the other accounts.

Let's say for example, you're a github user browsing https://github.com/SamSaffron/dapper-dot-net . The account name is SamSaffron and let's suppose its id is 497. You, as a github user can browse the dapper-dot-net repository but you can't do much, your rights don't allow it. However, Sam has admin rights on this account, but if he goes to https://github.com/restsharp/RestSharp , he's just a simple user there. So Sam is a global github user with specific rights depending on what github location he's visiting.


If you're building such an application, Caveman Tools makes it a breeze to handle the above scenario. Scoped authorization means that the authorization is handled according to an active scope (or context). If there is no scope set, then it's assumed there is a global scope.

Your application membership schema needs to implement the concepts of users belonging to groups (or roles, but I call them groups in Caveman Tools) which can be associated or not with an account . A group holds rights valid for the account associated with it. If no account exists, it's assumed the group is global and the rights apply in every scope.

First, Caveman Tools provides an interface for you to implement.

In this is example, Sam is member of the global group with id 1 and of the group with id 2 which is associated with the 'SamSaffron' account id 497. The DefaultAuthorizationScopeId suports integers as ids, but you can implement your own type of scope id by extending the AuthorizationScopeId abstract class. The GetDefaultGroup methods returns the group for anonymous users.

public class TestUserRepo:interface IUserRightsRepository
{
    public IEnumerable<IUserContextGroup> GetGroupsById(IEnumerable<int> ids)
        {
            return new[]
                       {
                           new UserContextGroup(1, new ushort[] (UserRights.Browse),  //can browse public repositories
                           new UserContextGroup(2,new ushort[]{UserRights.DoEverything}){ScopeId = new DefaultAuthorizationScopeId(497)}, //admin for account 497
                       };
        }

        public IUserContextGroup GetDefaultGroup()
        {
            return new UserContextGroup(0,new ushort[0]);
        }

}


When a user logs in, you should retrieve his id and the groups the user belongs to. Next, you setup the authentication cookie (you must use this helper)

Response.SetAuthCookie(userId, name, groups);

Enable the CavemanUserContext in order for all the good stuff to happen.

GlobalFilters.Filters.Add(new CavemanUserContext());

 It's important to always establish the scope of a request i.e what account the user is browsing. When someone goes  to the GitHub's homepage, that's the global scope, but when browsing https://github.com/restsharp/RestSharp, the scope is restsharp. Usually you get the scope name from the url, then look for its corresponding id in the database (in this example the id of restsharp is 508) .  Once you know the scope id, you just need to set it.    

AuthenticationUtils.SetAuthScope(new DefaultAuthorizationScopeId(508));                 

That's all the setup needed.     
     
To require authorization, you  can use the DemandRightAttribute (on the controller or on a method)

[DemandRight(UserRights.DoEverything)]
public class AdminController:Controller {}

Or manually

this.GetUserContext().HasRightTo(UserRights.DoEverything)

The authorization takes into account the current scope: if no scope if set, then only the global rights are checked, but if there is a scope, then both the rights associated with the scope and global rights are checked.  So Sam is allowed to access https://github.com/SamSaffron/Admin , but he's denied access to https://github.com/restsharp/Admin.

If you're interested in the internals of how CavemanTools handles authorization, check out the source code.

The SingletonsRegistry utility class

By Mike on 19 February 2012

In my previous post I've concluded that if you need singletons, a DI container is suitable for that but if you don't want to use a DI container, you could either not care and use anything you want or you could store the singletons in static variables.

So for those times when a DI container is unavailable , I've made a simple utility class which will ease the pain.

public static class SingletonsRegistry
    {
       static Dictionary<Type,object>  _singletons= new Dictionary<Type, object>();

        static object SyncRoot
        {
            get { return ((IDictionary) _singletons).SyncRoot; }
        }

        public static void Register<T>(T instance) where T:class
        {
            lock (SyncRoot)
            {
            if (_singletons.ContainsKey(typeof(T))) throw new InvalidOperationException(string.Format("An instance of type {0} is already registered",typeof(T).Name));            
                _singletons.Add(typeof(T), instance);    
            }
            
        }
        
              public static T Get<T>() where T:class
        {
            if (_singletons.ContainsKey(typeof(T))) return _singletons[typeof (T)] as T;
            return null;
        }

        
        public static void Unregister<T>(bool dispose=false) where T:class
        {
            var tp = typeof (T);
            lock (SyncRoot)
            {
                if (!_singletons.ContainsKey(tp)) return;
                var obj = _singletons[tp];
                if (dispose && tp.Implements<IDisposable>())
                {
                    (obj as IDisposable).Dispose();
                }
                _singletons.Remove(tp);
            }
        }
    }

Usage

var inst=new MyClass();
SingletonsRegistry.Register(inst);

//use it
SingletonsRegistry.Get<MyClass>().DoSomething();

//let's suppose we no longer need it at one point
SingletonsRegistry.Unregister<MyClass>()

And this class will be part of the next release of Caveman Tools toolkit.