Logo

Maarten Balliauw {blog}

ASP.NET, ASP.NET MVC, Windows Azure, PHP, ...

About the author

Maarten Balliauw is currently employed as a Technical Evangelist at JetBrains. His interests are mainly web applications developed in ASP.NET (C#) or PHP and the Windows Azure cloud platform.
More about me More about me
Send mail E-mail me


ASP.NET MVC Quickly Pro NuGet Subscribe to my RSS feed Follow me on Twitter! View Maarten Balliauw's profile on LinkedIn
Maarten Balliauw - MVP - Most Valuable Professional
Maarten Balliauw - ASPInsider

Search

Archive

Disclaimer

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

© Copyright Maarten Balliauw 2013


How we built TwitterMatic.net - Part 1: Introduction

TwitterMatic “Once upon a time, Microsoft started a Windows Azure developing contest named new CloudApp();. While it first was only available for US candidates, the contest was opened for international submissions too. Knight Maarten The Brave Coffeedrinker and his fellow knightsmen at RealDolmen decided to submit a small sample application that could be hosted in an unknown environment, known by the digital villagers as “the cloud”. The application was called TwitterMatic, named after the great god of social networking, Twitter. It would allow digital villagers to tell the latest stories, even when they were asleep or busy working.”

There, a nice fairy tale :-) It should describe the subject of a blog post series that I am starting around the techncal background of TwitterMatic, our contest entry for the new CloudApp(); contest. Now don't forget to vote for us between 10 July and 20 July!

Some usage scenario’s for TwitterMatic:

  • Inform your followers about interesting links at certain times of day
  • Stay present on Twitter during your vacation
  • Maintain presence in your activity stream, even when you are not available
  • Never forget a fellow Twitterer's birthday: schedule it!
  • Trick your boss: of course you are Tweeting you're leaving the office at 8 PM!

Perfect excuses to build our application for the clouds. Now for something more interesting: the technical side!

If you are impatient and immediately want the source code for TwitterMatic, check http://twittermatic.codeplex.com.

kick it on DotNetKicks.com

TwitterMatic architectural overview

Since we’re building a demo application, we thought: why not make use of as much features as possible which Windows Azure has to offer? We’re talking web role, worker role, table storage and queue storage here!

  • The web role will be an application built in ASP.NET MVC, allowing you to schedule new Tweets and view archived scheduled Tweets.
  • The worker role will monitor the table storage for scheduled Tweets. If it’s time to send them, the Tweet will be added to a queue. This queue is then processed by another thread in the worker role, which will publish the Tweet to Twitter.
  • We’ll be using OAuth, delegating authentication for TwitterMatic to Twitter itself. This makes it easier for us: no need to store credentials, no need to maintain a user database, …
  • The web role will perform validation of the domain using data annotations. More on this in one of the next parts.

For people who like images, here’s an architecture image:

TwitterMatic Architecture

What’s next?

RealDolmen Windows Azure The next parts of this series around Windows Azure will be focused on the following topics:

Stay tuned during the coming weeks! And don’t forget to start scheduling Tweets using TwitterMatic.

kick it on DotNetKicks.com


Categories: ASP.NET | Windows Azure | C# | General | MVC | Projects

Announcing: Azure User Group Belgium

After the summer, I'll be joining Kurt Claeys and Yves Goeleven and for the start of the Azure User Group Belgium (or AZUG.BE).  AZUG.BE is a Belgian user group with focus on development and architecture of the Microsoft Azure Services Platform. Azure is a cloud hosted development platform for internet oriented applications aimed at high scalability and based on .NET technology.

azuglogo

Our goal is to share knowledge and experiences with the .NET community in development and architecture in the Azure Services Platform and the .NET Services technology. As new programming skills and a new architectural approach are needed we are inviting you to become member of this user group to prepare you for building this new style of applications.

We’ll have regular public meetings (free of charge) providing demos, training, presentations and discussions on the technology part of Azure. First public meeting is planned in september 09. E-mail us at newsletter@azug.be with the word subscribe as subject. We’ll inform you on what, when and where.

Interested in participating as boardmember ? Shoot a mail at board@azug.be.

Hope to see you!


Categories: Windows Azure | C# | General | Projects

ASP.NET MVC Domain Routing

Routing Ever since the release of ASP.NET MVC and its routing engine (System.Web.Routing), Microsoft has been trying to convince us that you have full control over your URL and routing. This is true to a certain extent: as long as it’s related to your application path, everything works out nicely. If you need to take care of data tokens in your (sub)domain, you’re screwed by default.

Earlier this week, Juliën Hanssens did a blog post on his approach to subdomain routing. While this is a good a approach, it has some drawbacks:

  • All routing logic is hard-coded: if you want to add a new possible route, you’ll have to code for it.
  • The VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) method is not implemented, resulting in “strange” urls when using HtmlHelper ActionLink helpers. Think of http://live.localhost/Home/Index/?liveMode=false where you would have just wanted http://develop.localhost/Home/Index.

Unfortunately, the ASP.NET MVC infrastructure is based around this VirtualPathData class. That’s right: only tokens in the URL’s path are used for routing… Check my entry on the ASP.NET MVC forums on that one.

Now for a solution… Here are some scenarios we would like to support:

  • Scenario 1: Application is multilingual, where www.nl-be.example.com should map to a route like “www.{language}-{culture}.example.com”.
  • Scenario 2: Application is multi-tenant, where www.acmecompany.example.com should map to a route like “www.{clientname}.example.com”.
  • Scenario 3: Application is using subdomains for controller mapping: www.store.example.com maps to "www.{controller}.example.com/{action}...."

Sit back, have a deep breath and prepare for some serious ASP.NET MVC plumbing…

kick it on DotNetKicks.com

Defining routes

Here are some sample route definitions we want to support. An example where we do not want to specify the controller anywhere, as long as we are on home.example.com:

routes.Add("DomainRoute", new DomainRoute(
    "home.example.com", // Domain with parameters
    "{action}/{id}",    // URL with parameters
    new { controller = "Home", action = "Index", id = ""// Parameter defaults
));

Another example where we have our controller in the domain name:

routes.Add("DomainRoute", new DomainRoute(
    "{controller}.example.com",     // Domain with parameters< br />    "{action}/{id}",    // URL with parameters
    new { controller = "Home", action = "Index", id = ""// Parameter defaults
));

Want the full controller and action in the domain?

routes.Add("DomainRoute", new DomainRoute(
    "{controller}-{action}.example.com",     // Domain with parameters
    "{id}",    // URL with parameters
    new { controller = "Home", action = "Index", id = ""// Parameter defaults
));

Here’s the multicultural route:

routes.Add("DomainRoute", new DomainRoute(
    "{language}.example.com",     // Domain with parameters
    "{controller}/{action}/{id}",    // URL with parameters
    new { language = "en", controller = "Home", action = "Index", id = ""// Parameter defaults
));

HtmlHelper extension methods

Since we do not want all URLs generated by HtmlHelper ActionLink to be using full URLs, the first thing we’ll add is some new ActionLink helpers, containing a boolean flag whether you want full URLs or not. Using these, you can now add a link to an action as follows:

<%= Html.ActionLink("About", "About", "Home", true)%>

Not too different from what you are used to, no?

Here’s a snippet of code that powers the above line of code:

public static class LinkExtensions
{
    public static string ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, bool requireAbsoluteUrl)
    {
        return htmlHelper.ActionLink(linkText, actionName, controllerName, new RouteValueDictionary(), new RouteValueDictionary(), requireAbsoluteUrl);
    }

    // more of these...

    public static string ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, bool requireAbsoluteUrl)
    {
        if (requireAbsoluteUrl)
        {
            HttpContextBase currentContext = new HttpContextWrapper(HttpContext.Current);
            RouteData routeData = RouteTable.Routes.GetRouteData(currentContext);

            routeData.Values["controller"] = controllerName;
            routeData.Values["action"] = actionName;

            DomainRoute domainRoute = routeData.Route as DomainRoute;
            if (domainRoute != null)
            {
                DomainData domainData = domainRoute.GetDomainData(new RequestContext(currentContext, routeData), routeData.Values);
                return htmlHelper.ActionLink(linkText, actionName, controllerName, domainData.Protocol, domainData.HostName, domainData.Fragment, routeData.Values, null);
            }
        }
        return htmlHelper.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes);
    }
}

Nothing special in here: a lot of extension methods, and some logic to add the domain name into the generated URL. Yes, this is one of the default ActionLink helpers I’m abusing here, getting some food from my DomainRoute class (see: Dark Magic).

Dark magic

You may have seen the DomainRoute class in my code snippets from time to time. This class is actually what drives the extraction of (sub)domain and adds token support to the domain portion of your incoming URLs.

We will be extending the Route base class, which already gives us some properties and methods we don’t want to implement ourselves. Though there are some we will define ourselves:

public class DomainRoute : Route

    // ...

    public string Domain { get; set; }

    // ...

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        // Build regex
        domainRegex = CreateRegex(Domain);
        pathRegex = CreateRegex(Url);

        // Request information
        string requestDomain = httpContext.Request.Headers["host"];
        if (!string.IsNullOrEmpty(requestDomain))
        {
            if (requestDomain.IndexOf(":") > 0)
            {
                requestDomain = requestDomain.Substring(0, requestDomain.IndexOf(":"));
            }
        }
        else
        {
            requestDomain = httpContext.Request.Url.Host;
        }
        string requestPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;

        // Match domain and route
        Match domainMatch = domainRegex.Match(requestDomain);
        Match pathMatch = pathRegex.Match(requestPath);

        // Route data
        RouteData data = null;
        if (domainMatch.Success && pathMatch.Success)
        {
            data = new RouteData(this, RouteHandler);

            // Add defaults first
            if (Defaults != null)
            {
                foreach (KeyValuePair<string, object> item in Defaults)
                {
                    data.Values[item.Key] = item.Value;
                }
            }

            // Iterate matching domain groups
            for (int i = 1; i < domainMatch.Groups.Count; i++)
            {
                Group group = domainMatch.Groups[i];
                if (group.Success)
                {
                    string key = domainRegex.GroupNameFromNumber(i);
                    if (!string.IsNullOrEmpty(key) && !char.IsNumber(key, 0))
                    {
                        if (!string.IsNullOrEmpty(group.Value))
                        {
                            data.Values[key] = group.Value;
                        }
                    }
                }
            }

            // Iterate matching path groups
            for (int i = 1; i < pathMatch.Groups.Count; i++)
            {
                Group group = pathMatch.Groups[i];
                if (group.Success)
                {
                    string key = pathRegex.GroupNameFromNumber(i);
                    if (!string.IsNullOrEmpty(key) && !char.IsNumber(key, 0))
                    {
                        if (!string.IsNullOrEmpty(group.Value))
                        {
                            data.Values[key] = group.Value;
                        }
                    }
                }
            }
        }

        return data;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        return base.GetVirtualPath(requestContext, RemoveDomainTokens(values));
    }

    public DomainData GetDomainData(RequestContext requestContext, RouteValueDictionary values)
    {
        // Build hostname
        string hostname = Domain;
        foreach (KeyValuePair<string, object> pair in values)
        {
            hostname = hostname.Replace("{" + pair.Key + "}", pair.Value.ToString());
        }

        // Return domain data
        return new DomainData
        {
            Protocol = "http",
            HostName = hostname,
            Fragment = ""
        };
    }

    // ...
}

Wow! That’s a bunch of code! What we are doing here is converting the incoming request URL into tokens we defined in our route, on the domain level and path level. We do this by converting {controller} and things like that into a regex which we then try to match into the route values dictionary. There are some other helper methods in our DomainRoute class, but these are the most important.

Download the full code here: MvcDomainRouting.zip (250.72 kb)

(if you want to try this using the development web server in Visual Studio, make sue to add some fake (sub)domains in your hosts file)

kick it on DotNetKicks.com


Categories: ASP.NET | C# | General | MVC | Projects

Document Interoperability Workshop, London, May 18 2009

Microsoft building London, Cardinal Place After a pleasant flight with VLM airlines (Antwerp – London City), traveling under half of the city of London, I arrived at the Microsoft offices in Victoria for their third (?) DII workshop, of which I attended a previous one in Brussels last year.

If you are wondering: “What are you doing there???”, here’s a short intro. I’ve been working on Microsoft interop projects for quite a few years now, like PHPExcel, PHPPowerPoint, PHPLinq, PHPAzure, … When working on PHPExcel and PHPPowerpoint, I hit the term “document interoperability” quite a lot. OpenXML (the underlying file format) is well documented, but there is some work on making sure the generated document by any of those tools is fully compatible with the standard. And that’s what these DII workshops are all about.

The previous DII workshop mentioned the OpenXML document viewer, which converted DOCX to HTML. Great to see there’s a new version available today, read more at the interop blog from Microsoft.

This blog post gives an overview of my experience during the DII day.

By the way, here’s a cool blog post about interop on an Excel document between PHP, JAVA and .NET. Nice read!

Validation of OpenXML resources

Some talks on the topic, one by Alex Brown, introduced what would be needed to make sure a document is conform the standard. This is quite a complicated topic, because validation should occur at multiple levels: ZIP package level, relations, XML markup, … Using W3C’s XProc is one of the possible solutions to this, where a pipeline of different validations on XML can be linked and executed. Cool thing is that it is a non-Microsoft approach to validating documents.

Another problem facing: there’s lots of things not in an XML schema, for example custom XML data in Word documents. How to validate those? Schematron is the answer to that (nice read).

Making sure documents are accessible in the future

Matevz Gacnik had a great presentation on all the problems there are to make sure documents stored in a document management system are accessible in the future. There are some technical issues to this (making sure you do not lose information: keep the text and do not convert everything to TIFF), but there are some legal issues as well: the document should be signed, you can not store alternative copies of a document, …

From legal back to technical: Matevz also showed us some technical implementations of their OpenXML based document management system (eDMS): cool! They parse content, add extra information using custom XML and bookmarks, … Great showoff for what you can do with OOXML.

Discussion: OpenXML SDK

Next, we had a discussion on the OOXML SDK. Some opinions are that XML markup is more clear and as verbose as the SDK, other opinions are that there are people on this world that don’t like XML and want to use code anyway. I think I’m going with the latter idea. But there’s one point that remains: source code for working with the SDK is still very verbose and I don’t like to type a lot. Luckily there’s the document reflector in the SDK too, which writes a lot of code for you based on a document that you want to be generated.

InteroperabilityPHPPowerPoint

Thanks to the people at Microsoft, I also had an opportunity to do a short demo of PHPPowerPoint. The demo scenario was quite simple: I did a short overview of the architecture behind PHPPowerPoint and a demo of the SDK and what it currently can do.

Community interoperability

Gerd Schürmann from Fraunhofer institute did a talk on their role in document interoperability in Germany and how they advise the government using different R&D projects and proof-of-concept projects. Their main purpose is to be a neutral mediator in open-source use. For this, they participate in lots of community projects like SourceForge, BerliOS, … As an example, Gerd showed us a community site demonstrating various scenarios around eID in Germany.

PLANETS and document conversion tools

Wolfgang Keber did his talk on PLANETS & document conversion tools. PLANETS is a tool that is aiming at preserving your digital assets by making sure they can always be converted into other document formats. There are some subprojects available, for example one that characterises a document. It determines what document format a file is in, and also determines if, for example, tables are used. These characteristics can then be used to convert the document into a required format using any conversion tool available (extensibility!). For example, libraries can use PLANETS to automatically characterise and convert old scanned books in, for example, TIFF, to PDF or OOXML.

c1 Extensibility within Standards

One of the great talks at the DII event was Stephen Peront ‘s talk on extensibility, targeting the less-known part of the OpenXML standard: markup compatibility. Basically, this allows you to embed your own custom XML markup inside OpenXML documents without disturbing the application that is opening your document (if done right). This presentation led to discussion about whether this is a good thing or a bad thing. Some say that extending a standard is creating a new standard while others agree that this markup compatibility manner of adding extra information to a document is a good thing. My guess is that this really depends on what you are doing. Adding some extra attributes should be cool. Adding extra nested elements embedding OOXML elements embedding more custom tags may be a road you don’t really want to take.

Other coverage

Other coverage on the DII event in London:


Categories: Events | General | OpenXML | PHP | Projects

Announcing PHP SDK for Windows Azure

As part of Microsoft’s commitment to Interoperability, a new open source project has just been released on CodePlex: PHP SDK for Windows Azure, bridging PHP developers to Windows Azure. PHPAzure is an open source project to provide software development kit for Windows Azure and Windows Azure Storage – Blobs, Tables & Queues. I’m pleased that Microsoft has chosen RealDolmen and me to work on the PHP SDK for Windows Azure.

logomicrosoft logorealdolmen

Windows Azure provides an open, standards-based and interoperable environment with support for multiple internet protocols.  This helps reduce the cost of running a mixed IT environment.  Azure building block services use XML, REST and SOAP standards so they can be called from other platforms and programming languages.  Developers can create their own services and applications that conform to internet standards. Next to the new PHP SDK for Windows Azure, Microsoft also shipped Java and Ruby SDK for .NET Services demonstrating how heterogeneous languages and frameworks could take advantage of interoperable Identity Service (Access Control) & Service Bus using SOAP and REST-based frameworks.

  • Overview
    • Enables PHP developers to take advantage of the Microsoft Cloud Services Platform  – Windows Azure
    • Provides consistent programming model for Windows Azure Storage (Blobs, Tables & Queues)
  • Features
    • PHP classes for Windows Azure Blobs, Tables & Queues (for CRUD operations)
    • Helper Classes for HTTP transport, AuthN/AuthZ, REST & Error Management
    • Manageability, Instrumentation & Logging support

The logical architecture of PHP SDK for Windows Azure is as follows: it provides access to Windows Azure's storage, computation and management interfaces by abstracting the REST/XML interface Windows Azure provides into a simple PHP API.

logical_architecture

An application built using PHP SDK for Windows Azure can access Windows Azure's features, no matter if it is hosted on the Windows Azure platform or on an in-premise web server.

deployment_scenario

You can contribute, provide feature requests & test your own enhancements to the toolkit by joining the user forum.

kick it on DotNetKicks.com


PHPPowerPoint 0.1.0 (CTP1) released!

PHPPowerPoint logo People following me on Twitter could have already guessed, but here’s something I probably should not have done for my agenda: next to the well known PHPExcel class library, I’ve now also started something similar for PowerPoint: PHPPowerPoint.

Just like with PHPExcel, PHPPowerPoint can be used to generate PPTX files from a PHP application. This can be done by creating an in-memory presentation that consists of slides and different shapes, which can then be written to disk using a writer (of which there’s currently only one for PowerPoint 2007).

Simple PHPPowerPoint demo Here’s some sample code:

/* Create new PHPPowerPoint object */
$objPHPPowerPoint = new PHPPowerPoint();

/* Create slide */
$currentSlide = $objPHPPowerPoint->getActiveSlide();

/* Create a shape (drawing) */
$shape = $currentSlide->createDrawingShape();
$shape->setName('PHPPowerPoint logo');
$shape->setDescription('PHPPowerPoint logo');
$shape->setPath('./images/phppowerpoint_logo.gif');
$shape->setHeight(36);
$shape->setOffsetX(10);
$shape->setOffsetY(10);
$shape->getShadow()->setVisible(true);
$shape->getShadow()->setDirection(45);
$shape->getShadow()->setDistance(10);

/* Create a shape (text) */
$shape = $currentSlide->createRichTextShape();
$shape->setHeight(300);
$shape->setWidth(600);
$shape->setOffsetX(170);
$shape->setOffsetY(180);
$shape->getAlignment()->setHorizontal( PHPPowerPoint_Style_Alignment::HORIZONTAL_CENTER );
$textRun = $shape->createTextRun('Thank you for using PHPPowerPoint!');
$textRun->getFont()->setBold(true);
$textRun->getFont()->setSize(60);
$textRun->getFont()->setColor( new PHPPowerPoint_Style_Color( 'FFC00000' ) );

/* Save PowerPoint 2007 file */
$objWriter = PHPPowerPoint_IOFactory::createWriter($objPHPPowerPoint, 'PowerPoint2007');
$objWriter->save(str_replace('.php', '.pptx', __FILE__));

Advanced sample A more advanced sample is also included in the download, where a complete presentation is rendered using PHPPowerPoint.

Now go grab the fresh sample on CodePlex and be the very first person downloading and experimenting with it. Feel free to post some feature requests or general remarks on CodePlex too.

I want to thank my employer, RealDolmen, for letting me work on this during regular office hours and also the people at DynamicLogic who convinced me to start this new project.


Categories: General | OpenXML | PHP | Projects | Software

New CodePlex project: MvcSiteMap – ASP.NET MVC sitemap provider

NavigationIf you have been using the ASP.NET MVC framework, you possibly have been searching for something like the classic ASP.NET sitemap. After you've played with it, you even found it useful! But not really flexible and easy to map to routes and controllers. To tackle that, last year, somewhere in August, I released a proof-of-concept sitemap provider for the ASP.NET MVC framework on my blog.

The blog post on sitemap provider I released back then has received numerous comments, suggestions, code snippets, … Together with Patrice Calve, we’ve released a new version of the sitemap provider on CodePlex: MvcSiteMap.

This time I’ll not dive into implementation details, but provide you with some of the features our sitemap provider erm… provides.

First things first: registering the provider

After downloading (and compiling) MvcSiteMap, you will have to add a reference to the assembly in your project. Also, you will have to register the provider in your Web.config file. Add the following code somewhere in the <system.web> section:

<siteMap defaultProvider="MvcSiteMap">
    <providers>
        <add name="MvcSiteMap"
             type="MvcSiteMap.Core.MvcSiteMapProvider" 
             siteMapFile="~/Web.Sitemap"
             securityTrimmingEnabled="true"
             cacheDuration="10"/>
    </providers>
</siteMap>

We’ve just told ASP.NET to use the MvcSiteMap sitemap provider, read sitemap nodes from the Web.sitemap file, use secrity trimming and cache the nodes for 10 minutes.

Defining sitemap nodes

Defining sitemap nodes is quite easy: add a Web.sitemap file to your project and popukate it with some nodes. Here’s an example:

<?xml version="1.0" encoding="utf-8" ?>
<siteMap>
  <mvcSiteMapNode title="Home" controller="Home" action="Index" isDynamic="true" dynamicParameters="*">
    <mvcSiteMapNode title="About Us" controller="Home" action="About" />

    <mvcSiteMapNode title="Products" controller="Products">
      <mvcSiteMapNode title="Will be replaced in controller"
                      controller="Products" action="List"
                      isDynamic="true" dynamicParameters="id"
                      key="ProductsListCategory"/>
    </mvcSiteMapNode>
    <mvcSiteMapNode title="Account" controller="Account">
      <mvcSiteMapNode title="Login" controller="Account" action="LogOn" />
      <mvcSiteMapNode title="Account Creation" controller="Account" action="Register" />
      <mvcSiteMapNode title="Change Password" controller="Account" action="ChangePassword" />
      <mvcSiteMapNode title="Logout" controller="Account" action="LogOff" />
    </mvcSiteMapNode>
  </mvcSiteMapNode>
</siteMap>

Too much info? Let’s break it down. The sitemap consists of several nodes, defined by using a <mvcSiteMapNode> element. Each node can contain other nodes, as you can see in the above example. A node should also define some attributes: title and controller. Title is used by all sitemap controls of ASP.NET, controller is used to determine the controller to link to. Here’s a list of possible attributes:

Attribute Required? Description
title Yes Title of the node.
controller Yes Controller the node should link to.
action Optional Action method of the specified controller the node should link to.
key Optional A key used to identify the node. Can be specified but is generated by the MvcSiteMap sitemap provider when left blank.
isDynamic Optional Specifies if this is a dynamic node (explained later)
dynamicParameters When isDynamic is set to true. Specifies which parameters are dynamic. Multiple can be specified using a comma (,) as separator.
visibility Optional When visibility is set to InSiteMapPathOnly, the node will not be rendered in the menu.
* Optional Any other parameter will be considered to be an action method parameter.

Regarding the wildcard (*), here’s a sample sitemap node:

<mvcSiteMapNode title="Contact Maarten" controller="About" action="Contact" who=”Maarten” />

This node will map to the URL http://…./About/Contact/Maarten.

Using the sitemap

We can, for example, add breadcrumbs to our master page. Here’s how:

<asp:SiteMapPath ID="SiteMapPath" runat="server"></asp:SiteMapPath>

Looks exactly like ASP.NET Webforms, no?

Dynamic parameters

You got to click it, before you kick it. In the table mentioned above, you may have seen the isDynamic and dynamicParameters attributes. This may sound a bit fuzzy, but it’s actually quite a powerful feature. Consider the following sitemap node:

<mvcSiteMapNode title="Product details" controller="Product" action="Details" isDynamic=”true” dynamicParameters=”id” />

This node will actually be used by the sitemap controls when any URL refering /Products/Details/… is called:

  • http://…./Products/Details/1234
  • http://…./Products/Details/5678
  • http://…./Products/Details/9012

No need for separate sitemap nodes for each of the above URLs! One node is enough to provide your users with a consistent breadcrumb showing their location in your web application.

The MvcSiteMapNode attribute

Who said sitemaps should always be completely defined in XML? Why not use the MvcSiteMapNode attribute we created:

[MvcSiteMapNode(ParentKey="ProductsListCategory", Title="Product details", IsDynamic=true, DynamicParameters="id")]
public ActionResult Details(string id)
{
    // ...
}

We are simply telling the MvcSiteMap sitemap provider to add a child node to the node with key “ProductsListCategory” which should have the title “Product details”. Controller and action are simply determined by the sitemap provider, based on the action method this attribute is declared on. Dynamic parameters also work here, by the way.

Do you have an example?

Yes! Simply navigate to the MvcSiteMap project page on CodePlex and grab the latest source code. The sitemap provider is included as well as an example website demonstrating all features.

kick it on DotNetKicks.com


Categories: ASP.NET | C# | General | MVC | Projects

Accessing Windows Azure Blob Storage from PHP

Pfew! A week of Microsoft TechDays here in Belgium with lots of talks on new Microsoft stuff, Azure included. You may know I already experimented with Windows Azure and ASP.NET MVC. Earlier this week, I thought of doing the same with Windows Azure and PHP...

What the ...?

imageAt Microsoft PDC 2008, the Azure Services Platform was announced in the opening keynote. Azure is the name for Microsoft’s Software + Services platform, an operating system in the cloud providing services for hosting, management, scalable storage with support for simple blobs, tables, and queues, as well as a management infrastructure for provisioning and geo-distribution of cloud-based services, and a development platform for the Azure Services layer.

You can currently download the Windows Azure SDK from www.azure.com and play with it on your local computer. Make sure to sign-up at the Azure site: you might get lucky and receive a key to test the real thing.

And what does PHP have to do with this?

As a reader of my blog, this should not be a question. I'm on the thin line between the Microsoft development environment (.NET) and PHP development environment, and I really like bridging the two together (think PHPExcel, PHPLinq). And cheap, distributed hosting of data (be it file or databases) is always interesting to use, especially in web applications where you may store anything your users upload. I have created a Zend Framework Proposal for this, let's hope this blog post ends as a contribution to the Zend Framework.

Show me the good stuff!

Will do! Currently, I have only implemented Azure blob storage in PHP, so that's what the following code snippets will be using. Enough blahblah now, here's how you connect with Azure:

$storage = new Zend_Azure_Storage_Blob();

This actually sets up a connection with the local Azure storage service from the Windows Azure SDK. You can, however, also pass in an account name and shared key from the real, cloud hosted Azure, too. Next: I want to create a storage container. A storage container is a logical group in which I can store any data. Let's name the container "azuretest":

$storage->createContainer('azuretest');

Easy? Yup! Azure now has created some space on their distributed storage for my files to be dumped in. Speaking of which: let's upload a file!

$storage->putBlob('azuretest', 'images/WindowsAzure.gif', './WindowsAzure.gif');

There we go. I've uploaded my local WindowsAzure.gif file to the azuretest container and named the file "images/WindowsAzure.gif'". Don't be confused: it is NOT stored in the images/ folder (there's no such thing on Azure), this is really the full filename. But don't worry, you can mimic a regular filesystem with folders, for example by retrieving all files that are prefixed with "images/":

$storage->listBlobs('azuretest', '/', 'images/');

Piece of cake!

I wanna play!

Sure, who doesn't? Here's a preview of the classes I've been creating: Zend_Azure_CTP.zip (11.51 kb)

Now let's hope my Zend Framework Proposal gets accepted so this can be a part of the Zend Framework. In the meantime, I'll continue with this and also implement Azure table storage: cheap, distributed database features in the cloud.

kick it on DotNetKicks.com


Saving a PHPExcel spreadsheet to Google Documents

As you may know, PHPExcel is built using an extensible model, supporting different input and output formats. The PHPExcel core class library features a spreadsheet engine, which is supported by IReader and IWriter instances used for reading and writing a spreadsheet to/from a file.

PHPExcel architecture

Currently, PHPExcel supports writers for Excel2007, Excel5 (Excel 97+), CSV, HTML and PDF. Wouldnt it be nice if we could use PHPExcel to store a spreadsheet on Google Documents? Let’s combine some technologies:

Creating a custom GoogleDocs writer

First, we need an implementation of PHPExcel_Writer_IWriter which will support writing stuff to Google Documents. Since Google accepts XLS files and Zend_Gdata provides an upload method, I think an overloaded version of PHPExcel’s integrated PHPExcel_Writer_Excel5 will be a good starting point.

class PHPExcel_Writer_GoogleDocs extends PHPExcel_Writer_Excel5 implements PHPExcel_Writer_IWriter {
        // ...
}

Since Google requires to log in prior to being able to interact with the documents stored on Google Documents, let’s also add a username and password field.

class PHPExcel_Writer_GoogleDocs extends PHPExcel_Writer_Excel5 implements PHPExcel_Writer_IWriter {
    private $_username;
    private $_password;

    public function setCredentials($username, $password) {
        $this->_username = $username;
        $this->_password = $password;
    }
}

Next, let’s override the save() method. This method will save the document as an XLS spreadsheet somewhere, upload it to Google Docs and afterwards remove it from the file system. Here we go:

public function save($pFilename = null) {
        parent::save($pFilename);
        $googleDocsClient = Zend_Gdata_ClientLogin::getHttpClient($this->_username,
                $this->_password, Zend_Gdata_Docs::AUTH_SERVICE_NAME);
        $googleDocsService = new Zend_Gdata_Docs($googleDocsClient);
        $googleDocsService->uploadFile($pFilename, basename($pFilename), null,
                Zend_Gdata_Docs::DOCUMENTS_LIST_FEED_URI);

        @unlink($pFilename);
}

Nothing more! This should be our new writer class.

Using the GoogleDocs writer

Now let’s try saving a spreadsheet to Google Docs. First of all, we load a document we have stored somewhere on the file system:

$objReader = PHPExcel_IOFactory::createReader('Excel2007');
$objPHPExcel = $objReader->load("05featuredemo.xlsx");

Next, let’s use PHPExcel’s IOFactory class to load our PHPExcel_Writer_GoogleDocs class. We will also set credentials on it. Afterwards, we save.

$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'GoogleDocs');
$objWriter->setCredentials('xxxxxxxx@gmail.com', 'xxxxxxxx');
$objWriter->save('somefile.xls');

This should be all there is to it. Google Docs will now contain our spreadsheet created using PHPExcel.

Google Docs Image

Note that images are not displayed due to the fact that Google Docs seems to remove them when uploading a document. But hey, it’s a start!

You can download the full example code here (26.29 kb). Make sure you have PHPExcel, Zend Framework and Zend Gdata classes installed on your system.


Categories: General | OpenXML | PHP | Projects

PHPLinq 0.4.0 released on CodePlex!

PHPLinq I’m pleased to announce that PHPLinq 0.4.0 has been released on CodePlex. PHPLinq is currently one year old, and I decided to add a huge step in functionality for the 0.4.0 release. This blog post will focus on the current status of PHPLinq and what it is capable of doing for you in a PHP project.

 

What is PHPLinq?

PHPLinq is a class library for PHP, based on the idea of Microsoft’s LINQ technology. LINQ is short for language integrated query, a component in the .NET framework which enables you to perform queries on a variety of data sources like arrays, XML, SQL server, ... These queries are defined using a syntax which is very similar to SQL.

Using PHPLinq, the same functionality is created in PHP. Since regular LINQ applies to enumerators, SQL, datasets, XML, ..., I decided PHPLinq should provide the same infrastructure. Here’s an example PHPLinq query, which retrieves all names with a length less than 5 from an array of strings:

// Create data source
$names = array("John", "Peter", "Joe", "Patrick", "Donald", "Eric");

$result = from('$name')->in($names)
            ->where('$name => strlen($name) < 5')
            ->select('$name');

Notice the in()-function? This is basically a clue for PHPLinq to determine how t query data. In this case, PHPLinq will work with a string array, but is perfectly possible to hint PHPLinq with a database table, for example. I’ll show you more on that later in this post.

PHPLinq components

This functionality is achieved by the fact that each PHPLinq query is initiated by the PHPLinq_Initiator class. Each PHPLinq_ILinqProvider implementation registers itself with this initiator class, which then determines the correct provider to use. This virtually means that you can write unlimited providers, each for a different data type!

PHPLinq architecture

What can I do with PHPLinq?

Basically, PHPLinq is all about querying data. No matter if it’s an array, XML tree or a database table, PHPLinq should be able to figure out what to do witht the data, without you being required to write complex foreach loops and stuff like that.

Querying data from an array

Let’s have a look at an example. The following array will be a dataset which we’ll be working with. It is a list of Employee objects.

// Employee data source
$employees = array(
    new Employee(1, 1, 5, 'Maarten', 'maarten@example.com', 24),
    new Employee(2, 1, 5, 'Paul', 'paul@example.com', 30),
    new Employee(3, 2, 5, 'Bill', 'bill.a@example.com', 29),
    new Employee(4, 3, 5, 'Bill', 'bill.g@example.com', 28),
    new Employee(5, 2, 0, 'Xavier', 'xavier@example.com', 40)
);

I would like to have the name and e-mail address of employees named “Bill”. Here’s a PHPLinq query:

$result = from('$employee')->in($employees)
            ->where('$employee => substr($employee->Name, 0, 4) == "Bill"')
            ->select('new {
                    "Name" => $employee->Name,
                    "Email" => $employee->Email
                  }'
);

Wow! New things here! What’s this $employee => … thing? What’s this new { … } thing? The first is a lambda expression. This is actualy an anonymous PHP function we are creating, accepting a parameter $employee. This function returns a boolean (true/false), based on the employee’s name. The new { … } thing is an anonymous class constructor. What we are doing here is defining a new class on-the-fly, with properties Name and Email, based on data from the original $employee.

Here’s the output of the above query:

Array
(
    [0] => stdClass Object
        (
            [Name] => Bill
            [Email] => bill.a@example.com
        )
    [1] => stdClass Object
        (
            [Name] => Bill
            [Email] => bill.g@example.com
        )
)

How cool is that! Things are getting a lot cooler when we use PHPLinq together with the Zend Framework’s Zend_Db_Table

Querying data from a database

PHPLinq has a second PHPLinq_ILinqProvider built in. This provider makes use of the Zend Framework Zend_Db_Table class to provide querying capabilities. First things first: let’s create a database table.

CREATE TABLE employees (
    Id                INTEGER NOT NULL PRIMARY KEY,
    DepartmentId    INTEGER,
    ManagerId        INTEGER,
    Name            VARCHAR(100),
    Email            VARCHAR(200),
    Age                INTEGER
);

We’ll be using this table in a Zend_Db_Table class:

// EmployeeTable class
class EmployeeTable extends Zend_Db_Table {
    protected $_name = 'employees'; // table name
    protected $_primary = 'Id';
}
$employeeTable = new EmployeeTable(array('db' => $db));
$employeeTable->setRowClass('Employee');

Allright, what happened here? We’ve created a database table, and told Zend_Db_Table to look in the employees table for data, and map these to the Employee class we created before. The Zend_Db_Table employee table will be accessible trough the $employeesTable variable.

Ok, let’s issue a query:

$result = from('$employee')->in($employeesTable)
            ->where('$employee => substr($employee->Name, 0, 4) == "Bill"')
            ->select('new {
                    "Name" => $employee->Name,
                    "Email" => $employee->Email
                  }'
);

Here’s the output of the above query:

Array
(
    [0] => stdClass Object
        (
            [Name] => Bill
            [Email] => bill.a@example.com
        )
    [1] => stdClass Object
        (
            [Name] => Bill
            [Email] => bill.g@example.com
        )
)

Did you notice this query is actually the same as we used before? Except for the $employeesTable now being used instead of $employees this query is identical! The only thing that is different, is how PHPLinq handles the query internally. Using the array of objects, PHPLinq will simply loop the array and search for correct values. Using Zend_Db_Table, PHPLinq actually builds a SQL query which is executed directly on the database server, delegating performance and execution to the database engine.

We can have a look at the generated query by setting an option on PHPLinq, which will tell PHPLinq to pass the generated query to PHP’s print function.

PHPLinq_LinqToZendDb::setQueryCallback('print');

Let’s run the previous query again. The console will now also display the generated SQL statement:

SELECT "$employee".* FROM "employees" AS "$employee" WHERE (SUBSTR('$employee'."Name",  0,  4)  =  "Bill")

Cool! Are you kidding me?!? PHPLinq just knew that the PHP code in my where clause translates to the above SQL statement! It’s even cooler than this: PHPLinq also knows about different databases. The above example will translate to another query on a different database engine. For that, let’s look at another example. Here’s the PHPLinq query:

$result = from('$employee')->in($employeeTable)
            ->where('$employee => trim($employee->Name) == "Bill"')
            ->select('$employee->Name');

The generated SQL statement in SQLite:

SELECT "$employee".* FROM "employees" AS "$employee" WHERE (TRIM('$employee'."Name")  =  "Bill")

The generated SQL statement in Microsoft SQL Server (only knows LTRIM() and RTRIM(), not TRIM()):

SELECT "$employee".* FROM "employees" AS "$employee" WHERE (LTRIM(RTRIM('$employee'."Name"))  =  "Bill")

I don't know about you, but I think this is very useful (and COOL!)

Querying data from an XML source

Here’s another short example, just to be complete. Let's fetch all posts on my blog's RSS feed, order them by publication date (descending), and select an anonymous type containing title and author. Here's how:

$rssFeed = simplexml_load_string(file_get_contents('http://blog.maartenballiauw.be/syndication.axd'));
$result = from('$item')->in($rssFeed->xpath('//channel/item'))
            ->orderByDescending('$item => strtotime((string)$item->pubDate)')
            ->take(2)
            ->select('new {
                            "Title" => (string)$item->title,
                            "Author" => (string)$item->author
                      }'
);

Where to go now?

There’s lots of other features in PHPLinq which I covered partially in previous blog posts (this one and this one). For full examples, download PHPLinq from www.phplinq.net and see for yourself.

By the way, PHPExcel (another project of mine) and PHPLinq seem to be listed in Smashing Magazine's Top 50 list of extremely useful PHP tools. Thanks for this recognition!