New Training Classes for Fall 2010

Two new North America Umbraco Certification training classes are being offered for the fall of 2010.

Long Island, NY

For the first time ever, Umbraco Certification classes are being offered in the greater New York area.  Join us at the Hilton Long Island/Huntington, where we will be offering Level 1 class on September 13 & 14 and Level 2 class on September 15 & 16.

Interest has been high in New York for Umbraco Certification and we expect these classes to sell out soon.  September is coming quickly.  Don't delay, get your seats today.

You can find more information and sign up for the classes here:

http://umbraco-longisland.eventbrite.com

Tallahassee, FL

Florida is also seeing its first Umbraco Certification class in November.  Join us in Florida's beautiful State Capital with Level 1 classes taking place November 2 & 3 and Level 2 classes taking place November 4 & 5.

November is a great time to be in Florida and we are already seeing lots of interest in this class.  Don't put off signing up or you may end up missing out on this opportunity for Training in the Sunshine State.

You can find more information and sign up for the classes here:

http://umbraco-tallahassee.eventbrite.com

Contact Us

If you have any questions about these classes or if you are interested in hosting a class in your area please don't hesitate to contact us.

Webangelo is now offering Umbraco Training in North America

Christopher Rushing has been approved to offer Umbraco certified training for North America!  This combines his love of Umbraco with his enjoyment of sharing knowledge with others.

North American Umbraco Training Team

The North American Umbraco Training Team currently consists of Paul Sterling an Umbraco HQ member and core team member and our very own Christopher Rushing.  Not only will public training courses be offered in various places in the US and Canada, but the team will also work to let more people know about Umbraco here in North America.

More Umbraco Courses coming soon

In coordination with Paul Sterling, new courses are being set up in key areas for the fall.  Keep an eye on this blog and the Official Umbraco North America Training page for more details.

Unscheduled Training also Available

Public Training is by far the best experience for learning Umbraco as it brings together a mix of backgrounds in one room learning and sharing with each other.  Unfortunately sometimes folks are unable to attend a scheduled public training due to timing or a variety of factors.  Never fear!  We may be able to bring the training to you!  If you have a room available and are willing to host a public training in your area we are interested in hearing from you.  If you can't do that, just contact us.  We'll work hard to find the right scenario for you.

Implemented Umbraco 4.1 Beta II in MySQL

So I finally had some time to implement 4.1 Beta II in a test site.  For various reasons I decided to use MySQL.  I'm still running it through the paces, but here are some quick notes on my implementation experience.

Install

After copying the files to my test site location (shared hosting) and setting the permissions I tried to browse to the site to initialize the install scripts.  Unfortunately I immediately received a number of errors which some of the postings on our.umbraco.org indicated were related to the medium trust install even though no trust settings were set and the Umbraco Setting [umbracoUseMediumTrust] was set to false. As my host allows full trust I added a <trust level="Full" /> tag and was fine.

The rest of the configuration went as it usually does and I was able to successfully install the Umbraco Instance.

Site Setup

After install I immediately started adding Document Types and Templates and installing my favorite Packages.  Everything went smoothly until I tried to add my home page to the content.  The UI generated an error bubble regarding a missing table.

It turns out that the install scripts for the 4.1 Beta II for MySQL are missing the Create Table calls for the CMSPREVIEWXML table.  So I took the MSSQL scripts and ported the related calls to MySQL so I could run them there.  Below is my script.  Be aware that it is probably not the official Umbraco version that they will have in the final install, but it seems to have worked for me.

CREATE TABLE CMSPREVIEWXML(
 nodeId int NOT NULL,
 versionId CHAR(36) NOT NULL,
 timestamp DATETIME NOT NULL,
 xml LONGTEXT NOT NULL
);


ALTER TABLE CMSPREVIEWXML ADD CONSTRAINT PK_cmsContentPreviewXml PRIMARY KEY CLUSTERED (nodeId, versionId);

Installing Packages

One final note is that not every package will work with version 4.1 Beta II.  Make sure you test any package you add while you are playing with Beta II.

Ajax - Don't You Love Me?

As the .Net 3.5 Framework becomes more prevalent in the wild (and now .Net 4.0) we're starting to see some versioning issues with the ASP.NET AJAX modules. These issues can raise their heads in numerous ways, but the basic issue is the same, version conflicts. Umbraco also sees some of these issue occasionally, resulting in some head-scratchers in the forum.

Background

Prior to .Net 3.5, AJAX was a separate install which had to be downloaded and integrated separately. Many tools and sites built prior to .Net 3.5 or targeting .Net 2.0 or .Net 3.0 which wanted AJAX functionality often used this previous version, the most common still in the wild being 1.0.61025.0. This is often seen in the following references in the web.config...

  <configSections>
    <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
      <sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
        <section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication" />
        <sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
          <section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="Everywhere" />
          <section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication" />
          <section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication" />
        </sectionGroup>
      </sectionGroup>
    </sectionGroup>
  </configSections>
  <system.web>
    <httpModules>
      <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    </httpModules>
    <httpHandlers>
      <remove path="*.asmx" verb="*" />
      <add path="*.asmx" verb="*" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      <add path="*_AppService.axd" verb="*" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      <add path="ScriptResource.axd" verb="GET,HEAD" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    </httpHandlers>
    <compilation defaultLanguage="c#" debug="false" batch="false">
      <assemblies>
        <add assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" />
        <add assembly="System.Web.Extensions.Design, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      </assemblies>
    </compilation>
  </system.web>

Also if you running on IIS 7.0 and using the new Integrated Mode you might also see the following:

  <!-- IIS 7 Integrated Mode Configuration -->
  <system.webServer>
    <modules>  
      <remove name="ScriptModule"/>
      <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    </modules>
    <handlers accessPolicy="Read, Write, Script, Execute">
      <remove name="WebServiceHandlerFactory-Integrated"/>
      <remove name="ScriptHandlerFactory"/>
      <remove name="ScriptHandlerFactoryAppServices"/>
      <remove name="ScriptResource"/>
      <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    </handlers>
  </system.webServer>

Unfortunately, with .Net 3.5 and now 4.0 web applications having AJAX support included, issues are cropping up with one version of the .Net AJAX assemblies being used in the main web application and others being used in modules or packages.

Symptoms

The two main errors that I've seen are the following:

When installing Umbraco on a Windows 7 box or Windows Server 2008 you might see the following even though you have a newer version of Systen.Web.Extensions on the box.

Could not load file or assembly 'System.Web.Extensions,  Version=1.0.61025.0,  Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its  dependencies.

A stranger issue is when you see something similar the following:

[InvalidCastException:      Unable to cast object of type 'System.Web.Configuration.ScriptingScriptResourceHandlerSection' to type 'System.Web.Configuration.ScriptingScriptResourceHandlerSection'.        

or

... type (System.Web.UI.UpdatePanel) is not  compatible with the type of control (System.Web.UI.UpdatePanel)

What's Going On?

In the first case we simply have a case where the older ASP.Net AJAX 1.0 framework isn't installed on the machine in question but is being referenced somewhere.  You could install it, of course, and you may need to, however once you do, if you have the .Net 3.5 Framework installed  as well, you may one day find yourself dealing with the other symptoms described, so read on to avoid that future headache.

The other two errors (and other similar ones) are version conflicts.  A quick gloss  on this.  A long time ago (in OS years) there was a situation called DLL Hell in which the installation scripts for one program would overwrite dlls needed by another program with newer versions or even versions made for another OS causing unexpected failures.  To help avoid this issue, Microsoft started allowing multiple versions of the same dll to be installed at the same time.  Compiled assemblies reference a specific version of a dll to avoid this versioning issue.

For our specific discussion, this means that you can have two versions of the System.Web.Extensions.dll at the same time.  Therefore in your ASP.Net web application (i.e. Umbraco) you may have components referencing a newer version of a dll than is referenced in the web.config.  This can cause the strange scenario where your external page or control (.aspx / .ascx) references a type and gets the 1.X version but the code behind references the same object but knows about a 3.5 version of the type.  So, as far as the computer knows, the two items are not the same, thus those Type and Cast exceptions.

Solution

Missing DLLs

For the missing dlls issue, you have a couple of things you can try.  The solution for Versioning (below) may be sufficient, especially if you update the machine.config.  Another option, if you have access to the source you can update the references and recompile.  If those aren't viable or don't work, you may have to install the previous version of the ASP.Net AJAX framework, but if you do this, make sure you set up a binding redirect as discussed next.

Versioning

Once you have the proper files you should consider adding entries to either the web.config (to fix this web app) or the machine.config (to bind for all web apps) to bind calls to the System.Web.Extensions and the System.Web.Extensions.Design to the latest assemblies.  To do this add the following to the .config file to make sure that you are using the ASP.Net AJAX 3.5 versions of the files no matter where they are referenced in your web application.

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

As later versions of the .Net Framework gain popularity, you may need to update these references on older applications to keep your front-end and back-end in sync.

For more information on assembly binding see these Microsoft Articles.

http://msdn.microsoft.com/en-us/library/433ysdt1%28v=VS.71%29.aspx

http://msdn.microsoft.com/en-us/library/aa720323%28v=VS.71%29.aspx

Blog4Umbraco Post Date

As the first two posts for this blog were more business focused than technology focused, I wanted to do a little digging for this post and get into some code.

"Fortunately" I came across a need for my blog which, if the Umbraco Forum is any indication, has vexed couple of other people. That is the need to have an alternate Post Date other than the Created Date. This is more than just changing the date, but it is also a matter of changing the structure of the date folders within which it resides.

Background

This blog uses the Blog4Umbraco package put together by the estimable Tim Geyssens. It is MIT licensed Open Source and you can download the source from a link on the Blog4Umbraco project in Codeplex.

One useful part of the package is the feature which automatically creates date folders for a blog post giving one the handy /year/month/day/postname path. It does this by using the Umbraco event model to capture the New Event which is fired when a new document is created. Within the event handler, it checks to see if the post is currently in a Date Folder, and if not, it creates a folder structure for the /year/month/day as necessary (based on the CreateDate at the time the New Document was created) and moves the post there. In addition, many of the XSLT macros for ordering and rolling up posts rely on the CreateDate to determine the order.

These facts have the following ramifications:

  1. Document path is set at the time of creation and is based on the CreateDate, so your path will be based on that, regardless of when you publish it.
  2. Changing the CreateDate by itself will not affect the path, since the path is set when the document is first created and the document must be created before you can reference the createdate in code in order to change it.
    1. This is why importing blogs will often run into this issue,
  3. Changing the path but not changing the CreateDate will cause your documents to sometimes be ordered in a different order than your published dates if the default XSLT files are used.

Requirements

So to address the shortfalls of using the CreateDate I want to create an alternate Post Date which will be used for Blog dating and ordering and which will determine the folder path to the Blog.

To create an alternate post date I have to handle not only the date structure, but also the XSLT which displays that date as the Date Posted instead of the the CreateDate and also orders the posts based on that date. In addition, it should pre-populate the new field with the create date originally so that the XSLT has a value to work with. Finally, to have an optimal solution, it should only attempt to move the blog when necessary.

Solution

The first part of this solution and the key to the rest of it is to create a new property on the Blog Post Document Type called whatever you want (I called it Post Date) but with an alias of PostDate.  Use the DatePicker DataType for convenience.

PostDateEx

Once we have this in place, we'll need to do a few things to make it useful.  First we'll want to populate it automatically with the Create Date upon generating a new post.  Since we will later be updating our XSLT to sort our entries using this field, we want to make sure it has a value.  Second, we'll want to move the post to the appropriate folder structure based upon this new Post Date, but only as when it changes.

For both of these requirements, the handy Document Events are the way to go.  Umbraco Events allow you to listen for actions Umbraco is taking like creating new pages.  Then you can run your custom code to interact with Umbraco while this is happening.  (For those of you experienced in .Net Event Handlers, that is what they are).  The Umbraco Wiki has some pages on how to make use of these events, so I won't go into great detail, but it is really easy if you have any .Net experience.  [If you just want to use the dll that I've coded, I've included it with the class file at the bottom of this post.  Just drop it in your bin directory and Umbraco will know it is there.  Usual caveats of "No Guarantees...'' and "Do so at your own risk".]

Auto-populate the Post Date

The first event we want to use if the Document.New event.  This will allow us to autopopulate our new Post Date field with the Create Date.

void Document_New(Document sender, umbraco.cms.businesslogic.NewEventArgs e)
{
    if (sender.ContentType.Alias == "BlogPost")
     {
       if (sender.getProperty("PostDate") != null)
         {
               sender.getProperty("PostDate").Value = sender.CreateDateTime.Date;
         }
     }
}

Notice the first If-statement.  You will see this critical If-statement in many examples of event handling in Umbraco.  It is important to understand that Umbraco fires an event whenever an appropriate action occurs regardless of whether it is germane to what you are doing.  In this case the Document.New event will be fired every time a new document is created, regardless of whether it is a Blog Post or a News Article or some other new page on your site.  The sender.ContentType.Alias property is a good way to make sure that you are only taking further action if it is related to what you are trying to accomplish.  If you are not sure of the appropriate Document Alias, you can find it by going to the Settings Section of your Umbraco Admin, expand the Document Types folder and click on the document type you are trying to handle.  You will see the Alias (and be able to update it) on the screen that is loaded.

Document Alias

Move the Document to the right Folder path

Ok, now we've populated our PostDate field.  How do we move our post to the correct folder path?  Also, just as importantly, how do we avoid trying to move it when we don't need to?

Fortunately, for moving the folder, the Blog4Umbraco code shows us how it is being placed in the folder path in the first place.  We just have a few tweaks for this part.  First, we want to use the Document.BeforePublish event and not the new event.

void Document_BeforePublish(Document sender, umbraco.cms.businesslogic.PublishEventArgs e)
{
//... Our code will go here.
}

Next, we only want to run the code if we need to.  So we'll check for the Post Date and make sure it has changed since the last time the page was published.

//Don't forget that above this is:
//if (sender.ContentType.Alias == "BlogPost")
if (sender.getProperty("PostDate") != null) //If no post date, skip
{
if (sender.Parent != null) //If top of tree, something is wrong. Skip.
{
try
{
DocumentVersionList[] postVersions = sender.GetVersions();
bool _versionCheck = true;
DateTime postDate;
postDate = System.Convert.ToDateTime(sender.getProperty("PostDate").Value);
if (postVersions.Length > 1) //If it has been published, check post date info
{
//Length -1 is current version Length -2 is past version (if it exists)
Guid previousVersion = postVersions[postVersions.Length - 2].Version;
Document doc = new Document(sender.Id, previousVersion);
DateTime previousPostDate = System.Convert.ToDateTime(doc.getProperty("PostDate").Value);
_versionCheck = (postDate != previousPostDate);
}
if (_versionCheck) //Only do the date folder movement if the PostDate is changed or is new Post.
{
//... More Code
}
}
}
}

Next, we want to use the post date and not the created date.

string[] strArray = { postDate.Year.ToString(), postDate.Month.ToString(), postDate.Day.ToString() };

Next, we are likely in a Date Folder, so well need to find the top of the blog so that we can create the correct Date Folders in the correct places.

if (strArray.Length == 3)
{
Node topBlogLevel = new Node(sender.Parent.Id);
//Traverse up the tree to Find the Blog Node since we are likely in a Date Folder path
while (topBlogLevel != null && topBlogLevel.NodeTypeAlias != "Blog")
{
if (topBlogLevel.Parent != null)
{
topBlogLevel = new Node(topBlogLevel.Parent.Id);
}
else
{
topBlogLevel = null;
}
}
if (topBlogLevel != null)
{
//Create Appropriate Date Folders
}
}

Finally, check for and create the post folders similar to the way the Blog4Umbraco does it when first creating a post.  Given that my code is very similar to what Tim did [read: brazen code reuse] I won't post it here, but as I mentioned, I've included that class file, modified XSLT, modified BlogPost.master and dll at the bottom of this post.

Final Comments

This is one solution to moving Blog Posts to new Date Folder paths.  Some things to understand before you implement this solution.

  1. Although this should work for importation, it hasn't been tested.  The biggest issue, in my opinion, will be threading.  If this is being called asynchronously, it is theoretically possible for duplicate folders to be created since a second thread may find a date folder isn't there and try to create it while a first thread is in the process of doing the same.  Although it would slow things down a little, some Mutex calls around the Folder Discovery part may be necessary.
  2. Use at your own risk.  This was only tested against my personal install(s) of blog4Umbraco 2.0.26.  Additionally, it modifies the xslt and BlogPost.master so future updates to the blog engine may overwrite these changes.  I'm going to submit this as a patch to the codeplex project, so it may make it in.  If it does, you may have to remove the homemade version so it doesn't try to do this twice.

BTW, I started this blog post March 30th.

You can download the code and binary here.

The Feature Comparison Fallacy

There are a number of blog posts and web pages available that take various CMS products and compare their features.  Some are focused on the writers specific needs while others try to give a more general overview.  These types of comparisons can be a very helpful first step in understanding what is out there in the marketplace for these products.

Unfortunately, it can be too easy to just take these lists, match them up with your  external needs and pick the one that has the greatest number of green checkmarks.  If you do this, then I would contend that you are making two potentially very costly mistakes.  First, you are treating all needs as equal, which is a suspect assumption at best.  Second, you are not giving enough consideration to the long-term costs.

Not all features are created equal

It may be tempting to look at your needs and say,

"Ahh, CMS X has a forum and a blog and a control that puts dancing ballerinas on my pages, all built in.  That's exactly what I need, we'll use them."

This approach may actually decrease your time-to-market since you won't have to create any of those features yourself or look into add-ons, so it may look wise at first blush.  But before you commit to a CMS based on external needs, ask yourself these questions:

  1. Does the end-user experience on my website matter to me?
  2. Do I expect to continually need to add content overtime?
  3. Do I expect to ever need more functionality?

If you answered "Yes" to any of these then you need to look deeper at what a CMS is really providing you.  (And if you answered "No" to any of these, you should look deeper at whether your expectations from your site are reasonable.  In my experience #1 should be an automatic "Yes" and #2 and #3 happen much more often than expected and cause the largest amount of unplanned costs in a website.)

End-user Experience

It may seem that end-user experience is dependent upon the design and functionality of your site, and to a degree this is true.  But given that a CMS is the backbone of your site, you have to take its performance into account.  You may have the best site in the world, in regards to usability and functionality, but if the backbone is sluggish, your end-users will become frustrated.  This will result in less goal conversions (i.e. sales or donations, etc...) and thus will affect your business in a big way.  Do you know the typical performance of the CMS you are considering?  Is a quicker time-to-market worth the user frustration in the end?

Ease of Administration

Let's face it, features are all well and good, but the purpose of a Content Management System (CMS) is... (prepare to be shocked)... content management.  And when we are dealing with content management we are usually dealing with  an organization's employees at varying technical skill levels.  In fact, since much content is business driven and not IT driven, those who would be best at creating the content are often business users and not technical staff.

Unfortunately, that is often not what happens in the real world.  Often, due to the challenges of working with a CMS, content management falls to a technical user and not the actual source of the content, the business specialist.  This increases costs, since technical staff are often a more expensive resource and maintaining content isn't really the best use of their time.

Many business have accepted that this is how it works, but it doesn't have to be.  Ease of creating content should be a large part of your decision for choosing a CMS.

Ease of Functional Change

As much as we try to forecast business needs, no one is completely prescient.  Therefore, one thing we must always take into consideration in every business decision is the potential for change.  This is especially true in the technology sector and doubly so for customer facing technologies like a CMS.

Sure you may have needed the dancing ballerinas when you started, but what if ballerinas go out of style?  What if you need to add Lords-a-leaping or Drummers-drumming?  What if, in fact, you need to do a complete overhaul?

The fact is that changes will come and your ability to adapt will affect your ability to meet your clients needs in the long run.  Again, since the CMS is the backbone of your externally facing, client-visible presence, the ability to modify the functionality is critical.  It is imperative to evaluate how difficult it would be to change something if it became necessary.

The Cost of Short-Term thinking

The second issue I mentioned way back at the beginning of this post, was long -term costs. From my experience long-term costs often overshadow the initial cost of deployment of an IT product.  The less you plan with these long-term needs in mind, the more this cost disparity will be.

As I hope you can see from my previous points, there are some features in a CMS that affect long-term costs more than others.  The more difficult a CMS is to work with and modify and the less user-friendly it is, the larger your long-term costs will tend to be.  The worse the end-user experience the smaller gain your organization will receive from it.  A small investment in mitigating these concerns will pay huge dividends in the long run.

So where does that leave us?

As anyone who takes a look at our services and this blog will soon see, the Umbraco CMS was the choice for us for all of the reasons stated above as well as some subjective considerations mentioned in my first post.  We believe it would be a good choice for your organization as well, which is why we've staked our business on it.

That said, we understand that some other requirements may take your organization in a different direction.  Regardless whether Umbraco is your choice for a CMS or not, I ask that you please take these considerations into account.  One of the reasons Webangelo and this blog exist is to promote thoughtful decisions in the web and development world.  We may one day be a potential client/constituent of yours and we hope you will make our experience a pleasant one.

Why Umbraco

Welcome to the inaugural post of the Going Deeper Blog.  I'm Christopher Rushing CEO and founder of Webangelo, LLC.

Since one of the focuses of this blog is Umbraco, I decided to start the blog off with an explain of why Webangelo has focused on the Umbraco CMS.

The Problem

For every solution, there must be a problem that it solves, right?  So to understand why Webangelo only uses Umbraco for Website Development you must understand what challenge(s) Umbraco solves for us.

Webangelo, LLC is an extension of my personal commitment to quality and value.  As such, I wanted to create an environment in which I could use my skill sets to greatest advantage for my clients and also give them a good return on their investment with Webangelo.

Thus I had the following challenges I needed to tackle.

  1. I want to provide a good return on investment (ROI) for my clients.  What is the best way for me to do that when developing web sites / tools?
  2. I have a large personal investment in the .Net framework.  How do I leverage that skill set for my clients?
  3. I've run into situations before where I had to pass off troubleshooting to another company since I didn't have access to the full code.  How do I avoid that in the future?
  4. No one knows everything.  How do I get plugged into a helpful community that can support me?

The Solution: Umbraco

Sure the title gives away the answer, but here is what led up to it.

ROI - Providing value for my clients

Anyone who has been in web development for a while (or any sort of development for that matter) will see two aspects of the process which in fact fuel much of the progress in the IT sector.  First, one will find oneself doing the same basic things over and over  (and over and over...) again, thus making automation of those tasks a beneficial undertaking.  Secondly, although the basics are the same, there is enough variation that attempts to automate the basics or hide the technical aspects of something often run into limitations that require some additional technical expertise to work around.  So even as we improve things  and make them easier for the non-technical user, we never quite make the technical aspect obsolete.

So one key to ROI is identifying what requires a technical resource and what can now be done by a Power User or even a non-technical user.  Although having clients come to me every time they need basic content changed on their site would provide an ongoing source of income, it isn't the most efficient or effective way to provide web content.  The solution to this problem in the web world is usually some sort of Content Management System (CMS) which separates (to some extent) the content and site structure from the technical implementation.

For a web site there are two classic ways to do this.  First is a desktop tool that the client can purchase for their machines which will handle the HTML, CSS and to some extent, site structure.  These tools vary in their complexity and focus, but all suffer from the same basic drawback.  You need to have that tool on your system to update the content (unless you have the technical knowledge to alter the files directly, usually with a text editor, but that usually carries risks of its own).

Second is a web-based CMS.  These also vary in their complexity, but all of them seek to provide a way to manage the content of a site from any browser.  Although many of the desktop tools are quite useful, I didn't want to be tied to a proprietary desktop based solution.  Therefore, for Webangelo, I wanted to focus on a web-based CMS.

There were other ROI considerations, but these will be best answered by moving on to the other challenges I wanted to solve.

Leveraging .Net

As Webangelo was starting out as an extension of myself (although I of course expect it to grow), I wanted to make good use of my existing .Net skillset which would also provide some more of that ROI for my customers.  This naturally limited the number of applicable CMS entries to ones in which my .Net skillset could play a key role.

Avoiding Proprietary Software (as much as possible)

One of my stronger skills is in Root Cause Analysis which is the process of finding out what really caused a problem so that one can 1) fix it and 2) make sure it doesn't happen again.  There have been a number of cases in which I have been tracking down a problem when I ran smack-dab into some proprietary code which stopped me cold.  Life is then further complicated by the way in which some companies seem to be more interested in stating that nothing is wrong with their code rather than trying to find out if something is.  After many such frustrating sessions, I wanted to avoid this issue if at all possible as this just puts you as a middleman between your client and the maker of the proprietary software.

Although there is a limit to this in the .Net world (since the .Net Framework is itself proprietary), I wanted to have access to troubleshoot problems if something didn't work as expected.  Given how fundamental a CMS is to a website, I wanted access at the deepest level possible.  This lead to Open Source.

Unfortunately, many (i.e. most) Open Source CMS tools are in a language other than .Net.  Imagine my pleasure, then when I came across Umbraco, which not only fit the bill as .Net and Open Source (and C#, but we won't go into that), it was also well thought out and actually a pleasant environment in which to work.  (Yes there are other .Net Open Source CMS tools, but the choice between them is a post for another day).

And Then There's the Community

The final reason for my choice of Umbraco was the helpful community.  Between twitter and the our.umbraco.org forums, assistance abounds.  The combination of the two is a one-two punch that usually knocks out problems quickly.

Final Thoughts

So, this is the overview of why I picked Umbraco.  The final thing to note is that I wanted something in which we could gain an expertise.  By focusing on Umbraco and getting certification, I can be confident that Webangelo is providing the best service we can for our clients, which was the most important requirement of all.

I'm sure I'll have more comments on these topics over time.