Logo

Maarten Balliauw {blog}

ASP.NET, ASP.NET MVC, Azure, PHP, OpenXML, VSTS, ...

About the author

Maarten Balliauw is an MVP ASP.NET and is currently employed as .NET Software Engineer at RealDolmen. His interests are mainly web applications developed in ASP.NET (C#) or PHP.
More about me More about me
Send mail E-mail me


Microsoft Most Valuable Professional - MVP - ASP.NET

Subscribe to my RSS feed Follow me on Twitter! View Maarten Balliauw's profile on LinkedIn RealDolmen - Rock-solid passion for ICT
I'm a speaker at TechDays Belgium and TechDays Finland

Search

Latest Twitter

    Follow me on Twitter...

    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

    © Copyright Maarten Balliauw 2010

    Let me Bing that for you

    Have you ever been bugged with stupid questions? Do you get tired of people asking stuff that is only one search engine query away? Chances are you answered both of these questions with “yes!”. Together with Phil Haack and Juliën Hanssens, I created LetMeBingThatForYou.com, a website that generates a search engine query for people who ask you questions they could easily answer by themselves.

    Yes, the idea is a copy of LetMeGoogleThatForYou.com. However, we thought Bing deserved something similar. We even got Bing’s picture of the day working. How cool is that?

    Find Chuck Norris

    One last note: this project is not associated with Microsoft nor Bing. We’re doing this project for fun.

    kick it on DotNetKicks.com


    Categories: ASP.NET | C# | Fun | General | ICT | Internet | MVC

    Remix 2009 session - Slides and code

    As promised during the session at Remix 2009, here’s my example code and slide deck.

    Abstract: "Building a Twitter clone in 60 minutes, featuring what's new in ASP.NET MVC 2 preview 1 and focusing on some of the core ASP.NET MVC features like security and routing."

    Example code can be downloaded here: ASP.NET MVC Wisdom - ReMix.zip (8.91 mb)

    Thank you for attending!


    Application-wide action filters in ASP.NET MVC

    Ever had a team of developers using your ASP.NET MVC framework? Chances are you have implemented some action filters (i.e. for logging) which should be applied on all controllers in the application. Two ways to do this: kindly ask your developers to add a [Logging] attribute to the controllers they write, or kindly ask to inherit from SomeCustomControllerWithActionsInPlace.

    If you have been in this situation, monday mornings, afternoons, tuesdays and other weekdays are in fact days where some developers will forget to do one of the above. This means no logging! Or any other action filters that are executed due to a developer that has not been fed with enough coffee… Wouldn’t it be nice to have a central repository where you can register application-wide action filters? That’s exactly what we are going to do in this blog post.

    Note: you can in fact use a dependency injection strategy for this as well, see Jeremy Skinner’s blog.

    Download the example code: MvcGlobalActionFilter.zip (24.38 kb)

    kick it on DotNetKicks.com

    The idea

    Well, all things have to start with an idea, otherwise there’s nothing much left to do. What we’ll be doing in our solution to global action filters is the following:

    1. Create a IGlobalFilter interface which global action filters have to implement. You can discuss about this, but I think it’s darn handy to add some convenience methods like ShouldBeInvoked() where you can abstract away some checks before the filter is actually invoked.
    2. Create some IGlobalActionFilter, IGlobalResultFilter, IGlobalAuthorizationFilter, IGlobalExceptionFilter interfaces, just for convenience to the developer that is creating the global filters. You’ll see the use of this later on.
    3. Create a GlobalFilterActionInvoker, a piece of logic that is set on each controller so the controller knows how to call its own action methods. We’ll use this one to inject our lists of global filters.
    4. Create a GlobalFilterControllerFactory. I’m not happy with this, but we need it to set the GlobalFilterActionInvoker instance on each controller when it is created.

    IGlobalFilter, IGlobalActionFilter, …

    Not going to spend too much time on these. Actually, these interfaces are just descriptors for our implementation so it knows what type of filter is specified and if it should be invoked. Here’s a bunch of code. No comments.

    public interface IGlobalFilter
    {
        bool ShouldBeInvoked(ControllerContext controllerContext);
    }

    public interface IGlobalAuthorizationFilter : IGlobalFilter, IAuthorizationFilter

    public interface IGlobalActionFilter : IGlobalFilter, IActionFilter { }

    public interface IGlobalResultFilter : IGlobalFilter, IResultFilter { }

    public interface IGlobalExceptionFilter : IGlobalFilter, IExceptionFilter { }

    And yes, I did suppress some Static Code Analysis rules for this :-)

    GlobalFilterActionInvoker

    The GlobalFilterActionInvoker will take care of registering the global filters and making sure each filter is actually invoked on every controller and action method in our ASP.NET MVC application. Here’s a start for our class:

    public class GlobalFilterActionInvoker : ControllerActionInvoker
    {
        protected FilterInfo globalFilters;

        public GlobalFilterActionInvoker()
        {
            globalFilters = new FilterInfo();
        }

        public GlobalFilterActionInvoker(FilterInfo filters)
        {
            globalFilters = filters;
        }

        public GlobalFilterActionInvoker(List<IGlobalFilter> filters)
            : this(new FilterInfo())
        {
            foreach (var filter in filters)
                RegisterGlobalFilter(filter);
        }

        public FilterInfo Filters
        {
            get { return globalFilters; }
        }

        // - more code -

    }

    We’re providing some utility constructors that take a list of global filters and add it to the internal FilterInfo instance (which is an ASP.NET MVC class we can leverage in here). RegisterGlobalFilter() will do the magic of adding filters to the right collection in the FilterInfo instance.

    public void RegisterGlobalFilter(IGlobalFilter filter)
    {
        if (filter is IGlobalAuthorizationFilter)
            globalFilters.AuthorizationFilters.Add((IGlobalAuthorizationFilter)filter);

        if (filter is IGlobalActionFilter)
            globalFilters.ActionFilters.Add((IGlobalActionFilter)filter);

        if (filter is IGlobalResultFilter)
            globalFilters.ResultFilters.Add((IGlobalResultFilter)filter);

        if (filter is IGlobalExceptionFilter)
            globalFilters.ExceptionFilters.Add((IGlobalExceptionFilter)filter);
    }

    One override left in our implementation: ControllerActionInvoker, the class we are inheriting from, provides a method named GetFilters(), which is used to get the filters for a specific controller context. Ideal one to override:

    protected override FilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {
        FilterInfo definedFilters = base.GetFilters(controllerContext, actionDescriptor);

        foreach (var filter in Filters.AuthorizationFilters)
        {
            IGlobalFilter globalFilter = filter as IGlobalFilter;
            if (globalFilter == null ||
                (globalFilter != null && globalFilter.ShouldBeInvoked(controllerContext)))
            {
                definedFilters.AuthorizationFilters.Add(filter);
            }
        }

        // - same for action filters -

        // - same for result filters -

        // - same for exception filters -

        return definedFilters;
    }

    Basically, we are querying our IGlobalFilter if it should be invoked for the given controller context. If so, we add it to the FilterInfo object that is required by the ControllerActionInvoker base class. Piece of cake!

    GlobalFilterControllerFactory

    I’m not happy having to create this one, but we need it to set the GlobalFilterActionInvoker instance on each controller that is created. Otherwise, there is no way to specify our global filters on a controller or action method… Here’s the class:

    public class GlobalFilterControllerFactory : DefaultControllerFactory
    {
        protected GlobalFilterActionInvoker actionInvoker;

        public GlobalFilterControllerFactory(GlobalFilterActionInvoker invoker)
        {
            actionInvoker = invoker;
        }

        public override IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
        {
            IController controller = base.CreateController(requestContext, controllerName);
            Controller controllerInstance = controller as Controller;
            if (controllerInstance != null)
            {
                controllerInstance.ActionInvoker = actionInvoker;
            }
            return controller;
        }
    }

    What we do here is let the DefaultControllerFactory create a controller. Next, we simply set the controller’s ActionInvoker property to our GlobalFilterActionInvoker .

    Plumbing it all together!

    To plumb things together, add some code in your Global.asax.cs class, under Application_Start:

    protected void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);

        ControllerBuilder.Current.SetControllerFactory(
            new GlobalFilterControllerFactory(
                new GlobalFilterActionInvoker(
                    new List<IGlobalFilter>
                    {
                        new SampleGlobalTitleFilter()
                    }
                )
            )
        );
    }

    We are now setting the controller factory for our application to GlobalFilterControllerFactory, handing it a GlobalFilterActionInvoker which specifies one global action filter: SampleGlobalTitleFilter.

    Sidenote: SampleGlobalTitleFilter

    As a sidenote, I created a sample result filter named SampleGlobalTitleFilter, which is defined as a global filter that always appends a string (“ – Sample Application”) to the page title. Here’s the code for that one:

    public class SampleGlobalTitleFilter : IGlobalResultFilter
    {
        public bool ShouldBeInvoked(System.Web.Mvc.ControllerContext controllerContext)
        {
            return true;
        }

        public void OnResultExecuted(System.Web.Mvc.ResultExecutedContext filterContext)
        {
            return;
        }

        public void OnResultExecuting(System.Web.Mvc.ResultExecutingContext filterContext)
        {
            if (filterContext.Controller.ViewData["PageTitle"] == null)
                filterContext.Controller.ViewData["PageTitle"] = "";

            string pageTitle = filterContext.Controller.ViewData["PageTitle"].ToString();

            if (!string.IsNullOrEmpty(pageTitle))
                pageTitle += " - ";

            pageTitle += "Sample Application";

            filterContext.Controller.ViewData["PageTitle"] = pageTitle;
        }
    }

    Conclusion

    Download the sample code: MvcGlobalActionFilter.zip (24.38 kb)

    There is no need for my developers to specify SampleGlobalTitleFilter on each controller they write. There is no need for my developers to use the ControllerWithTitleFilter base class. People can come in and even develop software without drinking 2 liters of coffee! Really, development should not be hard for your developers. Make sure all application-wide infrastructure is there and our people are ready to go. And I’m really loving ASP.NET MVC’s extensibility on that part!

    kick it on DotNetKicks.com


    Categories: ASP.NET | C# | Fun | General | ICT | Internet | MVC | Software

    A view from the cloud (or: locate your ASP.NET MVC views on Windows Azure Blob Storage)

    Hosting and deploying ASP.NET MVC applications on Windows Azure works like a charm. However, if you have been reading my blog for a while, you might have seen that I don’t like the fact that my ASP.NET MVC views are stored in the deployed package as well… Why? If I want to change some text or I made a typo, I would have to re-deploy my entire application for this. Takes a while, application is down during deployment, … And all of that for a typo…

    Luckily, Windows Azure also provides blob storage, on which you can host any blob of data (or any file, if you don’t like saying “blob”). These blobs can easily be managed with a tool like Azure Blob Storage Explorer. Now let’s see if we can abuse blob storage for storing the views of an ASP.NET MVC web application, making it easier to modify the text and stuff. We’ll do this by creating a new VirtualPathProvider.

    Note that this approach can also be used to create a CMS based on ASP.NET MVC and Windows Azure.

    kick it on DotNetKicks.com

    Putting our views in the cloud

    Of course, we need a new ASP.NET MVC web application. You can prepare this for Azure, but that’s not really needed for testing purposes. Download and run Azure Blob Storage Explorer, and put all views in a blob storage container. Make sure to incldue the full virtual path in the blob’s name, like so:

    Azure Blob Storage Explorer

    Note I did not upload every view to blob storage. In the approach we’ll take, you do not need to put every view in there: we’ll support mixed-mode where some views are deployed and some others are in blob storage.

    Creating a VirtualPathProvider

    You may or may not know the concept of ASP.NET VirtualPathProviders. Therefore, allow me to quickly explain quickly: ASP.NET 2.0 introduced the concept of VirtualPathProviders, where you can create a virtual filesystem that can be sued by your application. A VirtualPathProvider has to be registered before ASP.NET will make use of it. After registering, ASP.NET will automatically iterate all VirtualPathProviders to check whether it can provide the contents of a specific virtual file or not. In ASP.NET MVC for example, the VirtualPathProviderViewEngine (default) will use this concept to look for its views. Ideal, since we do not have to plug the ASP.NET MVC view engine when we create our BlobStorageVirtualPathProvider!

    A VirtualPathProvider contains some methods that are used to determine if it can serve a specific virtual file. We’ll only be implementing FileExists() and GetFile(), but there are also methods like DirectoryExists() and GetDirectory(). I suppose you’ll know what all this methods are doing by looking at the name…

    In order for our BlobStorageVirtualPathProvider class to access Windows Azure Blob Storage, we need to reference the StorageClient project you can find in the Windows Azure SDK. Next, our class will have to inherit from VirtualPathProvider and need some fields holding useful information:

    public class BlobStorageVirtualPathProvider : VirtualPathProvider
    {
        protected readonly StorageAccountInfo accountInfo;
        protected readonly BlobContainer container;
        protected BlobStorage blobStorage;

        // ...

        public BlobStorageVirtualPathProvider(StorageAccountInfo storageAccountInfo, string containerName)
        {
            accountInfo = storageAccountInfo;
            BlobStorage blobStorage = BlobStorage.Create(accountInfo);
            container = blobStorage.GetBlobContainer(containerName);
        }

        // ...

    }

    Allright! We can now hold everyhting that is needed for accessing Windows Azure Blob Storage: the account info (including credentials) and a BlobContainer holding our views. Our constructor accepts these things and makes sure verything is prepared for accessing blob storage.

    Next, we’ll have to make sure we can serve a file, by adding FileExists() and GetFile() method overrides:

    public override bool FileExists(string virtualPath)
    {
        // Check if the file exists on blob storage
        string cleanVirtualPath = virtualPath.Replace("~", "").Substring(1);
        if (container.DoesBlobExist(cleanVirtualPath))
        {
            return true;
        }
        else
        {
            return Previous.FileExists(virtualPath);
        }
    }

    public override VirtualFile GetFile(string virtualPath)
    {
        // Check if the file exists on blob storage
        string cleanVirtualPath = virtualPath.Replace("~", "").Substring(1);
        if (container.DoesBlobExist(cleanVirtualPath))
        {
            return new BlobStorageVirtualFile(virtualPath, this);
        }
        else
        {
            return Previous.GetFile(virtualPath);
        }
    }

    These methods simply check the BlobContainer for the existance of a virtualFile path passed in.  GetFile() returns a new BlobStorageVirtualPath instance. This class provides all functionality for really returning the file’s contents, in its Open() method:

    public override System.IO.Stream Open()
    {
        string cleanVirtualPath = this.VirtualPath.Replace("~", "").Substring(1);
        BlobContents contents = new BlobContents(new MemoryStream());
        parent.BlobContainer.GetBlob(cleanVirtualPath, contents, true);
        contents.AsStream.Seek(0, SeekOrigin.Begin);
        return contents.AsStream;
    }

    We’ve just made it possible to download a blob from Windows Azure Blob Storage into a MemoryStream and pass this on to ASP.NET for further action.

    Here’s the full BlobStorageVirtualPathProvider class:

    public class BlobStorageVirtualPathProvider : VirtualPathProvider
    {
        protected readonly StorageAccountInfo accountInfo;
        protected readonly BlobContainer container;

        public BlobContainer BlobContainer
        {
            get { return container; }
        }

        public BlobStorageVirtualPathProvider(StorageAccountInfo storageAccountInfo, string containerName)
        {
            accountInfo = storageAccountInfo;
            BlobStorage blobStorage = BlobStorage.Create(accountInfo);
            container = blobStorage.GetBlobContainer(containerName);
        }

        public override bool FileExists(string virtualPath)
        {
            // Check if the file exists on blob storage
            string cleanVirtualPath = virtualPath.Replace("~", "").Substring(1);
            if (container.DoesBlobExist(cleanVirtualPath))
            {
                return true;
            }
            else
            {
                return Previous.FileExists(virtualPath);
            }
        }

        public override VirtualFile GetFile(string virtualPath)
        {
            // Check if the file exists on blob storage
            string cleanVirtualPath = virtualPath.Replace("~", "").Substring(1);
            if (container.DoesBlobExist(cleanVirtualPath))
            {
                return new BlobStorageVirtualFile(virtualPath, this);
            }
            else
            {
                return Previous.GetFile(virtualPath);
            }
        }

        public override System.Web.Caching.CacheDependency GetCacheDependency(string virtualPath, System.Collections.IEnumerable virtualPathDependencies, DateTime utcStart)
        {
            return null;
        }
    }

    And here’s BlobStorageVirtualFile:

    public class BlobStorageVirtualFile : VirtualFile
    {
        protected readonly BlobStorageVirtualPathProvider parent;

        public BlobStorageVirtualFile(string virtualPath, BlobStorageVirtualPathProvider parentProvider) : base(virtualPath)
        {
            parent = parentProvider;
        }

        public override System.IO.Stream Open()
        {
            string cleanVirtualPath = this.VirtualPath.Replace("~", "").Substring(1);
            BlobContents contents = new BlobContents(new MemoryStream());
            parent.BlobContainer.GetBlob(cleanVirtualPath, contents, true);
            contents.AsStream.Seek(0, SeekOrigin.Begin);
            return contents.AsStream;
        }
    }

    Registering BlobStorageVirtualPathProvider with ASP.NET

    We’re not completely ready yet. We still have to tell ASP.NET that it can possibly get virtual files using the BlobStorageVirtualPathProvider. We’ll do this in the Application_Start event in Global.asax.cs:

    protected void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);

        // Register the virtual path provider with ASP.NET
        System.Web.Hosting.HostingEnvironment.RegisterVirtualPathProvider(new BlobStorageVirtualPathProvider(
            new StorageAccountInfo(
                new Uri("http://blob.core.windows.net"),
                false,
                "your_storage_account_name_here",
                "your_storage_account_key_here"),
                "your_container_name_here"));
    }

    Add your own Azure storage account name, key and the container name that you’ve put your views in and you are set! Development storage will work as well as long as you enter the required info.

    Running the example code

    Download the sample code here: MvcViewInTheCloud.zip (58.72 kb)

    Some instructions for running the sample code:

    • Upload all views from the ____Views folder to a blob container (as described earlier in this post)
    • Change your Azure credetials in Application_Start

    kick it on DotNetKicks.com


    Categories: ASP.NET | Azure | C# | Fun | General | ICT | Internet | MVC | Webfarm

    Replacement during my vacation: Wilson

    This morning, I arrived at work after a great week of skiing in Pitztal, Austria. Unfortunately, I found my chair occupied by a new colleague looking a bit like Wilson. Good to see he enjoyed working early, like I do. But still, that was my seat and PC he was using… Thank you, dear colleagues, to see myself replaced by a plastic, smiling ball…

    Wilson, my replacement

    kick it on DotNetKicks.com


    Categories: Fun | General | Personal | Offtopic

    Having fun with project managers! (or: why you should lock your desktop)

    Have you ever left your computer unattended? (I do hope that!) Do you lock your desktop when this occurs? (I hope so either!) Not locking your desktop can be a risk. Your data might get stolen, someone might install a trojan, ...

    My project manager is one of those people who do not lock their computer when away. After having explained that this is a very simple thing he still seems to forget it everytime. Since a few weeks, we are using some more persuasive manners to teach him to press the Windows-key + L whenever he leaves his computer. Some practical jokes...

    1. Are those icons?

    • Create a screenshot of the user's desktop
    • Set this screenshot as the desktop background
    • Remove all real icons from the user's desktop (copy them somewhere to cause no real harm!)
    • Wait till the user gets back and starts clicking on his desktop "icons"... NOT Cool

    2. Cake for everyone!

    • Open the user's e-mail client
    • Send a message to the entire team saying "I'm treating everyone with cake!" (other option: "I'm buying a beer for everyone!")
    • Keep reminding the user of his nice e-mail Cool

    3. Right-click here...

    Here's a simple one: switch the user's mouse buttons (control panel - mouse properties - buttons). Also press the CTRL + ALT + Down-arrow. If you're lucky and the user has an Intl graphics card, his desktop will also be upside down.

    4. www.website.com...

    • If you have administrative rights on the user's PC, find and edit his host file (c:\windows\system32\drivers\etc\hosts)
    • Add a new entry which map his favourite website to something completely different. For example, map www.google.com to the IP address 208.77.188.166.

    5. Other funny things

    We've tried the above pranks, but no luck yet... Locking his desktop remains something that's not important to him (probably because he always has to laugh with practical jokes). Here's a list of some other jokes we might try in the near future...

    Any other suggestions, preferrably not harmful? Please let me know!

    kick it on DotNetKicks.com


    Categories: Fun | General | ICT | Personal

    Microsoft Tafiti just released

    I'm sure you have already heared of SilverLight before, right? If not: it's Microsoft's answer to Adobe Flash, providing the same features + XAML-like markup + easier databinding + ... Now you're up to date: the Redmond people have just released a new site, Microsoft Tafiti, which is basically Live Search combined with a rich SilverLight interface. Tafiti means "do research" in Swahili. Don't think I'm a native Swahili speaker though, I found this here 8-)

    The screenshot I made was first rendered in FireFox. No need to worry your SilverLight application not going to work on other systems than Windows + IE!

    If this is the way the web is evolving, I like it! Slick graphics, but not the "feeling" you are working in a browser plugin.


    My job?

    Seems that, according to this Wikipedia entry, I work at Microsoft:

    To clarify this: I do not work at Microsoft, but at Dolmen, one of the top Belgian IT firms. I do work with Microsoft technology and tend to promote their technology too, but no job at Microsoft.

    (Thank you Wouter for showing me this)


    Categories: Personal | General | Internet | Fun