28 February 2010 - 11:30 PM / by Dominic Pettifer. 6 Comments for Dependency Injection in ASP.NET MVC 2 – Part 1: Controllers.
Technical Article - In the first part of three, I show you how to perform Dependency Injection in ASP.NET MVC 2 using the Castle Windsor IOC (Inversion of Control) Container. In part 1 we look at injecting dependencies into your Controllers.
Using the principle of Dependency Injection, we can inject a concrete implementation into our ASP.NET MVC Controllers, but where the Controller only references an Interface not the concrete class. The benefits of this approach in a nut shell is that it allows us to decouple our codebase to make it more maintainable, and unit testable. Note the following contrived example:
public class ProductsController : Controller
{
protected IProductsRepository ProductsRepository = null;
public ProductsController(IProductsRepository productsRepository)
{
ProductsRepository = productsRepository;
}
public ActionResult ListProducts()
{
IList<Products> products = ProductsRepository.ListAllProducts();
return View(products);
}
}Note we're using an IProductsRepository interface, but the concrete implementation might be an NHibernateProductsRepository or a LinqToSqlProductsRepository. We can use the IOC container to very easily swap out the implementation if we ever needed to change data access technologies, without changing any of the code that relies on the data access layer.
In the real world, obviously it's rare to change data access technologies during product development, but if you follow the DIP (Dependency Injection Principle) throughout your codebase, you'll inevitably find somewhere where you need to swap out implementations. The ability to swap implementations isn't the main reason to use DIP though, other reasons include allowing a more decoupled and maintainable codebase, and to facilitate unit testing. You could easily unit test the above code for instance, by injecting in a mocked IProductsRepository implementation, instead of one that needs to hit a database.
In the above example we're injecting the dependencies into the constructor (Constructor Injection), and indeed this is the recommended approach in most cases, as you’re saying that this class in dependant on this interface. But it's also possible to use Property Injection, just ensure the property is public.
If you're still unsure of the benefits of Dependency Injection, read up on the SOLID principles.
If you were to run the above code, it would throw an exception, because the way ASP.NET MVC instantiates Controllers, it expects there to be a default no-arg constructor.
Thankfully, Microsoft made the ASP.NET MVC framework extensible enough that we can change the way it instantiates Controllers. What we need to do is to get our IOC container, Castle Windsor, to instantiate the Controller. Castle Windsor will then automatically resolve any dependencies the Controller (or whatever it’s instantiating) has, such as the IProductsRepository type. Even better the IOC container can resolve any dependencies the dependencies themselves have, all the way down the dependency tree.
First create an IocHelper class:
public static class IocHelper
{
private static IWindsorContainer _container = null;
private static object _syncObject = new object();
public static IWindsorContainer Container()
{
if (_container == null)
{
lock (_syncObject)
{
if (_container == null)
{
_container = new WindsorContainer(new XmlInterpreter("ioc.xml"));
}
}
}
return _container;
}
public static void DisposeContainer()
{
if (_container != null)
{
lock (_syncObject)
{
if (_container != null)
{
_container.Dispose();
_container = null;
}
}
}
}
}This class provides a static accessor to our IOC container. We only ever instantiate a single container for the entire application lifetime.
Now ASP.NET MVC instantiates controllers using its own DefaultControllerFactory, we need to create our own Controller Factory that derives from DefaultControllerFactory and overrides the default controller instantiation behaviour:
public class IocControllerFactory : DefaultControllerFactory
{
public IocControllerFactory()
{
var controllerTypes = from t in AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes())
where typeof(IController).IsAssignableFrom(t)
select t;
foreach (Type type in controllerTypes)
{
IocHelper.Container().AddComponentLifeStyle(type.FullName, type, LifestyleType.Transient);
}
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType != null)
{
return (IController)IocHelper.Container().Resolve(controllerType);
}
return base.GetControllerInstance(requestContext, controllerType);
}
}The controller factory works by looking through the types in all the currently loaded Assemblies, and gets any that implement the IController interface, so you're free to carve up your Visual Studio Solution into whatever Projects you like, the IocControllerFactory will find your controllers. Looping through all types in all loaded Assemblies is a slow operation (about 50 milliseconds in my app), but it only happens once on start-up. The GetControllerInstance is responsible for instantiating the Controller for each HTTP request, and is instantaneous.
Next we need to register the new IocControllerFactory, do this in your web apps Global.asax.cs file:
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
// ... router registration code (snip) ... //
}
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new IocControllerFactory());
}
}Now we need to create an XML file where we tell the IOC container what the concrete implementations are, eg. what is the concrete type for IProductsController. You may have noticed that in the IocHelper class we created the Container itself with the line:
_container = new WindsorContainer(new XmlInterpreter("ioc.xml"));ioc.xml is the file where we specify the dependencies, located in the root of the web app folder. People sometimes put these in the web.config file, but I prefer keeping them separate to keep your web.config file nice and clean, we can also swap dependencies while the app is still running (modifying the web.config resets the web AppDomain).
Create an ioc.xml file next to your web.config file, then place the following into it:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<components>
<!-- Repositories -->
<component id="ProductRepository"
service="MyMvcApp.Repository.IProductRepository, MyMvcApp"
type=" MyMvcApp.Repository.Impl.NHibernateProductRepository, MyMvcApp"
lifestyle="PerWebRequest">
</component>
<!-- End of Repositories -->
</components>
</configuration>Make sure the Namespaces and Assemblies are set according to your project. The 'service' attribute specifies the Interface or Abstract class (IProductRepository), 'type' specifies the concrete implementation to be used (NHibernateProductRepository).
If your concrete type has its own dependencies, you can specify them as well:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<components>
<component id="NHibernateDataContextProvider"
service=" MyMvcApp.NHibernate.INHibernateDataContextProvider, MvcLibrary"
type=" MyMvcApp.NHibernate.Impl.WebSessionProvider, MvcLibrary"
lifestyle="PerWebRequest">
</component>
<!-- Repositories -->
<component id="ProductRepository"
service="MyMvcApp.Repository.IProductRepository, MyMvcApp"
type=" MyMvcApp.Repository.Impl.NHibernateProductRepository, MyMvcApp"
lifestyle="PerWebRequest">
<parameters>
<ProviderFactory>${NHibernateDataContextProvider}</ProviderFactory>
</parameters>
</component>
<!-- End of Repositories -->
</components>
</configuration>The 'lifestyle' specifies how long the concrete type is kept alive for, options are Transient, Singleton, PerWebRequest, Gay, Straight, and Hedonist (OK I made the last three up). PerWebRequest keeps the instance alive for the currently executing HTTP request, and is removed at the end. For this to work we need add an HttpModule to your web.config file for Castle Windsor to clear the instance at the end of the HTTP request like so:
<httpModules>
<!— other modules, snip -->
<add name="PerRequestLifestyle"
type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.MicroKernel"/>
</httpModules>Also add this module to the IIS 7 HttpModule section for running under IIS 7 on Windows Server 2008/Vista/7.
Don't forget your Repository implementation:
public class NHibernateProductsRepository : IProductsRepository
{
protected INHibernateDataContextProvider SessionProvider = null;
public NHibernateProductsRepository(INHibernateDataContextProvider dataContextProvider)
{
SessionProvider = dataContextProvider;
}
public IList<Product> ListAllProducts()
{
ISession session = SessionProvider.GetSession();
return session.CreateCriteria<Product>().List<Product>();
}
}And the interface:
public interface IProductRepository
{
IList<Product> ListAllProducts();
}The Repository Pattern, coined by Martin Fowler (I think) in his book Patterns of Enterprise Application Architecture, is a way of decoupling your entities (Customer, Product etc.) from any data access code, and abstracting away the actual data storage implementation. Read more about it here or here.
Castle Windsor is a very powerful IOC container with many options for wiring up dependencies. Read more about Castle Windsor here.
There are other IOC containers out there for the .NET framework, for instance Ninject lets you specify your dependencies in code instead of verbose XML configuration files. Unity is an official Microsoft IOC container. Indeed there is more to the Dependency Injection Principle than I've been able to cover here, I encourage you to explore this very powerful paradigm in software engineering and write more elegant, maintainable and unit testable code.
In the next blog post I hope to cover wiring up dependencies during ModelBinding.
Everything is nice but the point of discussion may be whether to put
"IocHelper.Container().AddComponentLifeStyle(type.FullName, type, LifestyleType.Transient);"
to ControllerFactory or not.
Developing similar mechanisms on top of ASP.NET MVC, I ended up using Common ServiceLocator while having own implementation of IServiceRegistrar which auto-registers (by scanning assemblies) anything (including controllers) outside of controller factory but during the MvcStarterTask initialization (which is IStarterTask implementation - or IBootstrapperTask in your case).
The benefit is that my factory is completely agnistic of any kind of "service registrar" itself while my MvcStarterTask provides centralized MVC configuration in a way I need. Moreover, ASP.NET MVC 3 will try to hook up the registered "IController"s inside the DefaultControllerFactory using exactly that Common ServiceLocator.
Posted on 1 October 2010 - 8:30 PM / by Vasilio
There have been some criticisms of the Common Service Locator pattern, namely from Mark Seemann's blog here http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx
It's not something I've researched enough myself to have an informed opinion on, but it's well worth reading his views on it.
Posted on 2 October 2010 - 4:51 PM / by Dominic Pettifer (Administrator)
Dominic,
Thanks for the link, I read that but, heh, there is about another service locator :)
Common ServiceLocator isn't just a classic "Service Locator" pattern. It provides interface - the IServiceLocator, just to make your application unaware of concrete IoC container technology.
Your IoC Helper class is much more like that old good service locator, about which Mr. Seemann talks.
My IServiceLocator implementation (which is StructureMap adapter) acts just like a wrapper around my StructureMap container. And I put it inside any class that wants to create some objects. In case we have no Common Service Locator, I'd just put an "IContainer container" as a constructor parameter of such a class. With CSL I put "IServiceLocator locator".
It simple - I never use static service locators mentioned by Mark Seemann. And I never lose those "auto-wiring" DI capabilities of my container. With that said - I have clear testing scenarios - I can instantiate containers (IContainer) along with Service Locators (IServiceLocator). IServiceLocator itself, when created, takes an IContainer dependency as a constructor parameter.
Moreover, CSL's IServiceLocator doesn't have anything about "service registration" (as in Mark Seemanns post) - it's just not a locator's option, it belongs to kinda IServiceRegistrar. It just resolves instances for you (which are anyway somehow registered in your container).
To summarize use cases: I use IServiceLocator exactly when I whould use my IoC container AS a "service locator" while preferring constructor-DI in most cases (example is your ControllerFactory - you just can't inject controllers with factory's constructor - instead you use your container in "service-locator" style to resolve the controllers inside the factory).
Posted on 5 October 2010 - 2:19 PM / by Vasilio
In 1990, <b><a href="http://www.buyairjordans.net/">jordan shoes on sale</a></b> Li Moucheng her third husband. She <b><a href="http://www.buyairjordans.net/air-jordan-retro-8-C39.html">jordan 8 for sale</a></b> thought <b><a href="http://www.buyairjordans.net/air-jordan-retro-7-C38.html">Cheap Jordan 7</a></b> <b><a href="http://www.buyairjordans.net/air-jordan-retro-7-C38.html">Jordan 7 For Sale</a></b> that finally <b><a href="http://www.buyairjordans.net/air-jordan-retro-7-C38.html">Buy Jordan 7</a></b>
Posted on 15 October 2011 - 2:02 AM / by ugg bailey button
Search engine optimization (SEO Company USA) can be defined as an activity that undertakes web promotion of websites/portals and web pages. The quality SEO services ensure ranking of a website in popular search engines such as Yahoo, Google, Bing and MSN.
Search engine optimization (SEO Company USA) can be defined as an activity that undertakes web promotion of websites/portals and web pages. The quality SEO services ensure ranking of a website in popular search engines such as Yahoo, Google, Bing and MSN.
[url=http://www.seosoftwareservices.com]SEO India[/url]
Posted on 3 January 2012 - 12:47 PM / by WEB Development India
This information seems to be useful for me, thanks for the publication!
Posted on 25 January 2012 - 4:59 PM / by custom college essays
but <a title="nfl women jerseys baltimore ravens" href="http://www.jerseyswall.com/discount-guileless-nfl-women-jerseys-baltimore-ravens.htm" target="_blank">nfl women jerseys baltimore ravens</a> if you want to prevent being <a title="nike air max tailwind" href="http://www.www.nikewall.com/nike-air-max-tailwind-shoes-at-cut-price.htm" target="_blank">nike air max tailwind</a> taken from the scammers be sure <a title="christian louboutin point toe pumps" href="http://www.heelsforsale.com/christian-louboutin-point-toe-pumps-quick-ship.htm" target="_blank">christian louboutin point toe pumps</a> to find legitimate wholesale suppliers by <a title="jordan 11 fusion jordan 13" href="http://www.www.nikewall.com/better-compare-nike-air-jordan-11-fusion-jordan-13-shoes.htm" target="_blank">jordan 11 fusion jordan 13</a> purchasing a reputable wholesale product directory. <a title="nike air shox women shoes" href="http://www.nikewall.com/wholesale-nike-air-shox-women-shoes.htm" target="_blank">nike air shox women shoes</a> you won't be sorry.learn more <a title="detroit lions jerseys" href="http://www.westonsale.com/nfl-detroit-lions-jerseys.htm" target="_blank">detroit lions jerseys</a> about finding legitimate wholesale suppliers, drop <a title="air yeezy women" href="http://www.westonsale.com/air-yeezy-women-shoes.htm" target="_blank">air yeezy women</a> shipping, and selling through auctions.provide guidance. smart <a title="mbt wingu shoes women" href="http://www.shoeswall.com/mbt-wingu-shoes-women-manufacturer.htm" target="_blank">mbt wingu shoes women</a> wholesalers spend time educating their customers.
Posted on 13 June 2011 - 9:28 AM / by air jordan
but <a title="nfl women jerseys baltimore ravens" href="http://www.jerseyswall.com/discount-guileless-nfl-women-jerseys-baltimore-ravens.htm" target="_blank">nfl women jerseys baltimore ravens</a> if you want to prevent being <a title="nike air max tailwind" href="http://www.www.nikewall.com/nike-air-max-tailwind-shoes-at-cut-price.htm" target="_blank">nike air max tailwind</a> taken from the scammers be sure <a title="christian louboutin point toe pumps" href="http://www.heelsforsale.com/christian-louboutin-point-toe-pumps-quick-ship.htm" target="_blank">christian louboutin point toe pumps</a> to find legitimate wholesale suppliers by <a title="jordan 11 fusion jordan 13" href="http://www.www.nikewall.com/better-compare-nike-air-jordan-11-fusion-jordan-13-shoes.htm" target="_blank">jordan 11 fusion jordan 13</a> purchasing a reputable wholesale product directory. <a title="nike air shox women shoes" href="http://www.nikewall.com/wholesale-nike-air-shox-women-shoes.htm" target="_blank">nike air shox women shoes</a> you won't be sorry.learn more <a title="detroit lions jerseys" href="http://www.westonsale.com/nfl-detroit-lions-jerseys.htm" target="_blank">detroit lions jerseys</a> about finding legitimate wholesale suppliers, drop <a title="air yeezy women" href="http://www.westonsale.com/air-yeezy-women-shoes.htm" target="_blank">air yeezy women</a> shipping, and selling through auctions.provide guidance. smart <a title="mbt wingu shoes women" href="http://www.shoeswall.com/mbt-wingu-shoes-women-manufacturer.htm" target="_blank">mbt wingu shoes women</a> wholesalers spend time educating their customers.
Posted on 27 September 2011 - 4:53 AM / by Anonymous
Zhaojun motorcycle does not start, ugg australia uk
Posted on 15 October 2011 - 2:14 AM / by ugg uk
<b><a href="http://www.uggboots--uk.co.uk/">uggs sale</a></b> will <b><a href="http://www.uggaustralia-ukshop.co.uk/">ugg boots for kids</a></b> quarrel. However, <b><a href="http://www.uggaustraliaboots.org.uk/">ugg australia uk</a></b> Chen <b><a href="http://www.uggaustraliaboots.org.uk/">ugg australia boots</a></b> <b><a href="http://www.uggboot-baileybutton.co.uk/">uggs boots sales</a></b> <b><a href="http://www.uggbaileybutton.me.uk/">uggs boots for women</a></b> Rooster read <b><a href="http://www.uggbaileybutton.me.uk/">ugg bailey button</a></b> private <b><a href="http://www.uggboots--uk.co.uk/">uggs girls</a></b> <b><a href="http://www.uggboots--uk.co.uk/">ugg boots uk</a></b> school still humility: Because <b><a href="http://www.uggboot-baileybutton.co.uk/">where to buy ugg boots</a></b> <b><a href="http://www.uggaustralia-ukshop.co.uk/">ugg kensington</a></b> one thing <b><a href="http://www.uggbaileybutton.me.uk/">ugg clearance boots</a></b> and <b><a href="http://www.uggaustraliaboots.org.uk/">boot ugg uk</a></b> noi... <b><a href="http://www.uggaustralia-ukshop.co.uk/">ugg australia uk shop</a></b> <b><a href="http://www.uggboot-baileybutton.co.uk/">ugg boot bailey button</a></b>
Posted on 15 October 2011 - 5:08 AM / by ugg boots outlet
louis vuitton outlet http://www.officialoutletlouisvuitton.com louis vuitton outlet http://www.lowlouisvuittonoutlets.com louis vuitton outlet http://www.officiallouisvuittonoutletu.com louis vuitton outlet http://www.louisvuittonoutletusas.com louis vuitton outlet http://www.louisvuittonluxuryoutlets.com ugg boots clearance http://www.officialuggsbootssclearance.com ugg outlet http://www.uggsbootofficialoutlets.com http://www.louisvuittonofficialoutletu.com louis vuitton outlet
Posted on 5 January 2012 - 2:39 AM / by louis vuitton outlet
he <strong><a href="http://www.nikefreerun2dk.com/dame-nike-free-30-c-6.html" title="Billig Nike Free">Billig Nike Free</a></strong> emergence of these <strong><a href="http://www.nikefreerun2dk.com/dame-nike-free-2012-c-4.html" title="Nike Free Running">Nike Free Running</a></strong> things. This time hit, Needless to say, <strong><a href="http://www.nikefreerun2dk.com/dame-nike-free-30-c-6.html" title="Nike Free 3.0">Nike Free 3.0</a></strong> I can not let <strong><a href="http://www.nikefreerun2dk.com/dame-nike-free-2012-c-4.html" title="Nike Free Run 2">Nike Free Run 2</a></strong> it <strong><a href="http://www.nikefreerun2dk.com/" title="Nike Free Tilbud">Nike Free Tilbud</a></strong> gently. <strong><a href="http://www.nikefreerun2dk.com/dame-nike-free-2012-c-4.html" title="Nike Free Dame">Nike Free Dame</a></strong> I made <strong><a href="http://www.nikefreerun2dk.com/herre-nike-free-run-plus-c-9.html" title="nike free run">nike free run</a></strong> the...
Posted on 30 January 2012 - 2:34 AM / by nike free run
The [url=http://www.juicybag.org/]juicy bag[/url] with abundant affection. These [url=http://www.uk-barbourjacket.net/]quilted jackets barbour[/url] with the artistic design. With these [url=http://www.uk-barbourjacket.net/]barbour jacket[/url] do attending actual timeless. Thus, these [url=http://www.juicybag.org/]juicy couture[/url] attending altered from the accustomed [url=http://www.juicybag.org/]Juicy outlet[/url] in market. Featuring the lining abounding with [url=http://www.uk-barbourjacket.net/barbour-mens-jacket-c-18.html]Barbour jackets for men[/url] online. You can get the [url=http://www.juicybag.org/juicy-backpack-c-6.html]juicy backpack[/url]. It adds abundant absorption to [url=http://www.uk-barbourjacket.net/]Barbour jackets[/url] sale.
Posted on 22 December 2011 - 7:35 AM / by quilted jackets barbour
http://www.giantsfanshop.com/eli-manning-jersey
http://www.giantsfanshop.com/mario-manningham-jersey
http://www.giantsfanshop.com/michael-strahan-jersey
http://www.giantsfanshop.com/tiki-barber-jersey
http://www.giantsfanshop.com/
http://www.giantsfanshop.com/ahmad-bradshaw-jersey
Posted on 2 February 2012 - 7:16 AM / by Eli Manning Jersey
Wonderful post! I wish I had your insight on this topic and could write as well as you. I hope many people get the opportunity to enjoy this great content.
Posted on 30 December 2011 - 5:56 AM / by Screen printed t-shirts
Thank you for this post. That’s all I can say. You clearly know what you are doing, you’ve covered so many bases.Thanks!
Posted on 19 January 2012 - 7:37 AM / by london marketing internship
"There are other IOC containers out there for the .NET framework, for instance Ninject lets you specify your dependencies in code instead of verbose XML configuration files."
CastleWindsor also lets you do this. I used the following code for my own example:
var container = new WindsorContainer();
container.Register(Component.For<IRepository>()
.ImplementedBy<DefaultRepository>()
.LifeStyle.Singleton)
.Register(Component.For<IValidator>()
.ImplementedBy<DefaultValidator>()
.LifeStyle.Singleton)
ControllerBuilder.Current.SetControllerFactory(new IocControllerFactory(container));
Posted on 1 June 2010 - 1:31 PM / by Alan
a total of 9 times NBA Defensive first team, this is the best Jordan 12 For Sale air jordan sale historical record.
27, NBA player Michael Jordan has created the highest efficiency value of 27.9.
28, Jordan 8 consecutive single-season scoring average over 30, better than Wilt Chamberlain, 7, ranked the history ...
Posted on 19 May 2011 - 4:03 AM / by Jordan 12
rfume world, <a href="http://www.nikejordanoutlet.net/jordan-fusion-C56.html" title="Jordan Fusion">Jordan Fusion</a> its product lines <a href="http://www.nikejordanoutlet.net/" title="Cheap Air Jordan">Cheap Air Jordan</a> continue to follow the scent of three: Boss, Hugo, and BALDESSARINI, representing three brands in three different temperament and belief in life .
<br> <br>
<br> <br> 2000 years of BOSS perfume for women in the market, the introduction of the first female boss woman...
Posted on 3 June 2011 - 3:24 AM / by Jordan Shoes
I'm just wondering how do you manage your connection to a real time database. I am following other examples and I don't seem to get the database connection right for a real time example
thank you
(I hope my question es clear enough)
Posted on 12 April 2010 - 1:23 AM / by Alvaro Romero Perez
Look in IOC.Data.RepositoryImpl.FakeCategoryRepository
He's currently not using a database, but rather some factory to produce items.
Like he mentioned, the implementation can easily be swapped out with one that work against a real database. That's the beauty of using a repository pattern and dependency injection.
Posted on 2 May 2010 - 10:08 AM / by Krokonoster
[url=http://www.nikeam.com]Air shoes[/url]
[url=http://www.nikeam.com]Nike Air shoes[/url]
<a href="http://www.nikeam.com">Air shoes</a>
<a href="http://www.nikeam.com">Nike Air shoes</a>
Posted on 28 May 2011 - 8:58 AM / by Air shoes
Newest styles of <a href="http://www.christianlouboutinreplicacl.com/"><strong>christian louboutin high heels</strong></a> in hot sale now, <a href="http://www.christianlouboutinreplicacl.com/"><strong>Christian Louboutin Knockoffs</strong></a> shoes sale now, buy <a href="http://www.christianlouboutinreplicacl.com/"><strong>christian louboutin replica</strong></a> in our online uk store .your shoes sales prices will save.
Posted on 22 September 2011 - 2:30 AM / by christian louboutin replica
<b><a href="http://www.ugg-for-sale.co.uk/">ugg boots uk</a></b> quarter <b><a href="http://www.ugg-for-sale.co.uk/">ugg boots sale</a></b> of rural residents for the whole family, <b><a href="http://www.uggbootsaustralia.me.uk/">ugg australia sale uk</a></b> guaranteeing <b><a href="http://www.ugg-for-sale.co.uk/">ugg boots sale uk</a></b> payment on $ <b><a href="http://www.uggbootsaustralia.me.uk/">ugg australia</a></b> 240...
Posted on 16 November 2011 - 5:54 AM / by cheap uggs
And YouTube still auto-fucking-plays videos!! This is TWO-THOUSAND-AND-FUCKING-TWELVE FFS!!!
about 20 hours ago from webOn a side-note, YouTube's commenting system is god-awful atrocious dreadful horrible horrible horrible!! Constant meaningless error messages
about 20 hours ago from webJavaScript is slow mmmkay http://t.co/NbB4eQjw - Actually, no, it's not http://t.co/kpGEIoPO #nodejs
about 20 hours ago from webTFS: It's super expensive, so it must be brilliant, right? Like Sharepoint #tekpubtfstitlesuggestion
5:22 PM February 3rd from web