A little bit of fun development

I installed Windows 8 recently and I wanted to check it out and I went to go look at my second monitor to see what time it was and :: frowny face :: that’s right, I forgot. No desktop gadgets, so no timer/clock. Hrmph

Then it occurred to me, “oh yeah, I know how to make that” so I proceeded to grab vs express 2012 from the windows store.

Install on all of our was flawlessly, though I am some what disappointed that they won’t be releasing the windows 8 express version until after the dust from the full blown visual studio 2012 has died down.

Anyway my only options were windows store xaml apps, so I went with a blank one and have a full screen clock now… Fun anyway, tomorrow I’ll try and get it not full screen.

🙂

Impressed but not impressively- A friend’s interview code sample

So a friend of mine is currently employed at a large multi-national IT contracting company. Well, that’s not entirely true, the company does staff augmentation for many sectors, IT being one of them, and while they can provide full software development life cycle services, they are typically staff augmentation.

That being said, he’s a developer. And a developer who came to developing later in life after learning, living, and dumping a previous career. He’s been doing professional development (i.e. it is his sole income) for 6 years and of the many developers I know he’s a natural, learns quick and the “right way” and the why’s. I’d hire the man for a senior developer position in a minute.

However, the economy being what it is, he is currently working a junior developer position. By which I mean doing senior developer work for junior developer money. Hey, it’s beats unemployment, no doubt, however things could be better along the compensation lines. As I’ve said, the man does not play around and he’d be a bargain at 3 times his salary (straight up.)

Well like any sane person (well as sane as one can be and still want to be a software developer), he’s taking the initiative and looking around for other employment where the compensation will be more commensurate with his efforts, and the challenges will be developmental and not overcoming ridiculous arbitrary management process (again, you’ll have to take my word that the problems are ridiculous and that he can not change them.)

So one of the places his recruiter is submitting his resume to is requiring he write a small windows console application that satisfies the following requirements:

  • Counts from between 1 and 100 inclusively
  • When the number is evenly divisible by 3, it should print “One
  • When the number is evenly divisible by 5, it should print “Two
  • When the number is evenly divisible by 3 and 5, it should print “OneTwo
  • When the number is not evenly divisible by 3 or 5, it should print the number
  • Ok, fair enough. I love that they asked for a code sample. At the end of the day, writing the code is part and parcel for software developers and I feel that the trend of those “what did you have to do”, “what were the results of doing it”, and “what could you have done differently” interviews… Sure you need to make sure the person is a good fit for the team as far as socializing, personality, not an asshat, but if they are a good fit, can they design and/or write the code.

    Well, I’ll say you have to at least consider it for a second but the above is not that challenging. Basically it will show you know how to nest/cascade if’s and perhaps know about the modulo operator.

    I would have been more impressed if they asked for a super and derived classes using interfaces to model a car, motorcyle, and airplane. But, I don’t know the company’s true needs so I’ll give them the benefit of the doubt.

    Anyway, good luck my man!

    Below is what I did… I feel it could be more performant but is pretty readable and gentle enough on resources for most stuff (I had to take a swing right?!?) …

    static void Main(string[] args)
    {
        StringBuilder valueBuilder = new StringBuilder();
        for (int counter = 1; counter <= 100; counter++)
        {
            if (counter % 3 == 0) valueBuilder.Append(“One”);
                if (counter % 5 == 0) valueBuilder.Append(“Two”);
                if (valueBuilder.Length == 0) valueBuilder.Append(counter.ToString());
                Console.WriteLine(valueBuilder.ToString());
                valueBuilder.Clear();
            }
        }
    }

    jQuery Autocomplete against an MVC driven JSON data provider

    First, a disclaimer, this is basically some prototyping I did to discover how feasible this stuff is in reality. It is not an attempt to provide any sort of framework for consumption of others, but arguably the concepts could be used to that end. Feel free to appropriate any of it at will in any way you see fit. All shout-outs accepted 😀

    For the sake of having some context around what I am doing, I have a Data Layer provided by the Microsoft Entity Framework running against an existing database. My MVC application only currently deals with a Client model which is related to the Clients table in my database (I take no responsibility for database naming conventions here, I worked with what I had.) I have a Client Controller, a Client Model (very simplified First, and Last Names; Id, and ClientCode properties relating to columns of similar names in the database), and various Client Views (not surprisingly, an Index, Detail, Edit, Create, and Delete views.)

    With the above in place I decided to make a simple Client Picker that would work by the user typing the Client’s Last Name into a textbox and it would autocomplete and narrow the choices as the user typed. The final picked Client should be rendered in the Textbox as “Lastname, Firstname, [ClientCode]”

    Well first things first, below is the code for the JsonMarshaller class which wraps calling DataContractJsonSerializer. Basically, you pass it a class that is adorned with a DataContractAttribute and it spits out the contents of the class as a Json encoded string.

    using System;
    using System.IO;
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Json;
    using System.Text;
    using System.Xml;

    namespace MvcSandbox.Library.Helpers
    {
    public class JsonMarshaller
    {
    public static string CreateJsonString(object objectToSerialize)
    {
    var dataContractAttribute = Attribute.GetCustomAttribute(objectToSerialize.GetType(), typeof(DataContractAttribute));

    var output = new StringBuilder();
    var json = new DataContractJsonSerializer(objectToSerialize.GetType());
    var ms = new MemoryStream();
    XmlDictionaryWriter writer = JsonReaderWriterFactory.CreateJsonWriter(ms);

    json.WriteObject(ms, objectToSerialize);
    writer.Flush();

    byte[] buffer = ms.GetBuffer();
    var bytes = new byte[ms.Length];
    for (long l = 0; l < ms.Length; l++)
    {
    bytes[l] = buffer[l];
    }

    return Encoding.Default.GetString(bytes).Trim();
    }
    }
    }

    At this point let’s wire the JsonMarshaller into an MVC web application. For the sake of argument, I created a Controller to handle this. There is no reason it could not have been handled by the existing Client controller, and to be honest this is where I feel it should be for a consistent URL scheme. But when I started I wanted something slightly different from the standard Client views this was a case of me fighting what MVC was trying to give me by default, structure based on what it did (working with a client) then how it did it (being a data service).

    To illustrate, to view a client detail the url would be
    http://localhost/Clients/Detail/45

    and I wanted to get a list of clients with last names starting with “Min” to look like:
    http://localhost/Services/Clients/min

    In the end I would have rather it be:
    http://localhost/Clients/min

    In it’s current state I ended up with:
    http://localhost/Services/GetClientsByLastName/min

    Routing semantics, do what’s best for your app, I just wanted to explain what I’ve got going on here to avoid confusion as MVC is a big believer in naming by convention.

    Below are the Client Model and the Services Controller:

    Client Model

    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using MvcSandbox.Library.DataAccess;
    using MvcSandbox.Library.Model;
    using MvcSandbox.Library.Repositories;

    namespace MvcSandbox.Models
    {
    [DataContract]
    public class ClientModel : ModelBase
    {
    [DataMember]
    public int ClientId { get; set; }

    [DataMember]
    public string FirstName { get; set; }

    [DataMember]
    public string LastName { get; set; }

    [DataMember]
    public string ClientCode { get; set; }

    public ClientModel() { }

    public ClientModel(int clientId)
    {
    LoadFromDataEntity((Clients)Repository.Get(clientId));
    }

    public ClientModel(Clients client)
    {
    LoadFromDataEntity(client);
    }

    public static List GetAllClients()
    {
    return (from Clients client in new ClientRepository().FindAll(20)
    select new ClientModel
    {
    ClientCode = client.ClientCode,
    ClientId = client.ClientID,
    FirstName = client.FirstName,
    LastName = client.LastName
    }).ToList();
    }

    private void LoadFromDataEntity(Clients client)
    {
    DataEntity = client;

    if (client == null)
    {
    ClearModelFields();
    return;
    }

    ClientId = DataEntity.ClientID;
    FirstName = DataEntity.FirstName;
    LastName = DataEntity.LastName;
    ClientCode = DataEntity.ClientCode;
    }

    public override void UpdateDataEntityFromModel()
    {
    DataEntity.ClientID = ClientId;
    DataEntity.FirstName = FirstName;
    DataEntity.LastName = LastName;
    DataEntity.ClientCode = ClientCode;
    }

    public override void ClearModelFields()
    {
    FirstName = string.Empty;
    LastName = string.Empty;
    ClientCode = string.Empty;
    ClientId = 0;
    }
    }
    }

    The Client Model Base Class

    using System;
    using System.Data.Objects.DataClasses;
    using System.Runtime.Serialization;
    using MvcSandbox.Library.Helpers;
    using MvcSandbox.Library.Repositories;

    namespace MvcSandbox.Library.Model
    {
    [DataContract]
    public abstract class ModelBase : IModel
    where T : EntityObject
    where TU : RepositoryBase
    {
    protected TU Repository = Activator.CreateInstance(typeof(TU)) as TU;
    protected T DataEntity;

    #region Abstract Members

    public abstract void ClearModelFields();

    public abstract void UpdateDataEntityFromModel();

    #endregion

    #region Virtual Members

    public virtual void Save()
    {
    UpdateDataEntityFromModel();
    Repository.Save();
    }

    public virtual string ToJson()
    {
    return JsonMarshaller.CreateJsonString(this);
    }

    #endregion
    }
    }

    Services Controller

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.UI.WebControls;
    using MvcSandbox.Library.DataAccess;
    using MvcSandbox.Library.Helpers;
    using MvcSandbox.Library.Model;
    using MvcSandbox.Models;

    namespace MvcSandbox.Controllers
    {
    public class ServicesController : Controller
    {
    public ActionResult GetClientsByLastName(string id)
    {
    var clientLists = new ModelList();

    if (String.IsNullOrEmpty(id))
    {
    ViewBag.Output = clientLists;
    }
    else
    {
    string lastName = id;

    var entities = new it01_FSC1Entities();

    var cls = (from client in entities.Clients
    where client.LastName.StartsWith(lastName.Trim())
    orderby client.LastName
    select new ClientModel()
    {
    ClientCode = client.ClientCode,
    ClientId = client.ClientID,
    FirstName = client.FirstName,
    LastName = client.LastName
    }).Take(20);

    clientLists.Items.AddRange(cls);
    }

    Response.ContentType = "application/json";
    Response.ContentEncoding = Encoding.UTF8;

    ViewBag.Output = JsonMarshaller.CreateJsonString(clientLists);
    return View();
    }
    }
    }

    Nothing really magical there. I would like to go on record stating that calling the data access layer directly in my Controller was an ugly time-saver, I haven’t moved it over to my ClientRepository where it belongs. The Repository insulates my front end / model code from being tied to the database structure. It uses the Entity Framework classes to populate models for me. The Model Base class illustrates some underpinnings of it which aren’t really relevant to the point of this post.

    So basically, the Controller grabs the data, populates a class with a DataContract so I can use the JsonMarshaller to Json encode it. Of note in the controller is where it set’s the Response’s content-type to “application/json” and content-encoding to UTF-8. jQuery love’s it some UTF-8.

    Once we have the results Json encoded, it sets an item in the ViewBag for use by the GetClientsByLastName View to pump the Json out to the client.

    @{
    Layout = null;
    }
    @Html.Raw(ViewBag.Output)

    Heh, so little code on that last piece ‘eh 😀

    At this point we are ready to consume the HTTP GET enabled data provider with a ClientSearch partial view. Which, is essentially a blue bar with a autocomplete enabled textbox on it to search for a client by last name.

    This was the difficult piece. In retrospect, not because it was difficult but because with jQuery, if you’re not writing it everyday, you are forgetting how to write it everyday. And it’s been a while since I’ve been living the jQuery life, however, like a bicycle, you just get back on and pour through docs and examples until it sticks again.

    Without further ado, the ClientSearch partial view:

    <script language="javascript" type="text/javascript">
    var clientSourceArray = [];

    function GetClientData(searchTerm) {
    var url = "http://localhost:1909/Services/GetClientsByLastName/" + searchTerm;
    clientSourceArray = [];

    var jqxhr = $.ajax({
    url: url,
    type: 'GET',
    dataType: 'json',
    async: false,
    success: function (data, status, xhr) {
    $.each(data, function (i, clients) {
    $.each(clients, function (i, client) {
    var clientValue = client.LastName + ', ' + client.FirstName + ' [' + client.ClientCode + ']';
    clientSourceArray.push(clientValue);
    });
    });
    }
    });

    return clientSourceArray;
    }

    $(document).ready(function () {

    //set up the autocomplete form
    $("#ClientLastName").autocomplete({
    source: function (searchTerm, callback) { callback(GetClientData(searchTerm.term)); },
    delay: 100,
    minLength: 2
    });

    //set up the watermarks
    var watermark = "Start Typing a Client's Lastname...";
    var inputElement = $("#ClientLastName");
    if (inputElement.val() == "") {
    inputElement.css("color", "#555555");
    inputElement.css("font-style", "italic");
    inputElement.val(watermark);
    }
    inputElement.focus(function () {
    if (this.value == watermark) {
    $(this).css("color", "");
    $(this).css("font-style", "");
    this.value = "";
    }
    }).blur(function () {
    if (this.value == "") {
    this.value = watermark;
    $(this).css("color", "#555555");
    $(this).css("font-style", "italic");
    }
    });
    });
    </script>

    <div class="client-search-bar">@Html.TextBox("ClientLastName", "", new Dictionary() { {"class", "client-last-name-input"} })</div>

    So now a few comments about that, first, I’m looking for a code highlighter that works better and easier then the one I have…

    Well the actual “html” portion is pretty easy, 1 div that uses the MVC HTML helper class to generate a textbox. I’ll also ignore the Watermarking code because it’s unrelated short of making a nicer looking textbox (arguably.)

    The bulk of the work is done by the GetClientData() function, it makes an asynchrounous AJAX call to get the Json encoded data for the autocomplete control and the setting up of the actual autocomplete. Which in the end being pretty trivial as it can take a function that takes a searchTerm and a “Add an item to the list to be searched” callback function. The way it is written here, it works but it could be more succinctly done had I truly been in the jQuery zen place. As demonstrated on http://net.tutsplus.com/tutorials/javascript-ajax/how-to-use-the-jquery-ui-autocomplete-widget/ in particular, Step 4: “Attaching the Autocomplete”

    //attach autocomplete
    $("#to").autocomplete({

    //define callback to format results
    source: function(req, add){

    //pass request to server
    $.getJSON("friends.php?callback=?", req, function(data) {

    //create array for response objects
    var suggestions = [];

    //process response
    $.each(data, function(i, val){
    suggestions.push(val.name);
    });

    //pass array to callback
    add(suggestions);
    });
    }

    Yeah, well I’ll clean that up later. In the end it wasn’t that bad aside from my jQuery rustiness.

    Hope this helps you, I know the journey has helped me!

    DataContractJsonSerializer / Linq oddity? Nope, it’s just me :-(

    [Once again the code is on my other machine but…]

    So using Microsoft’s Entity Framework with .NET 4 as a data access layer, I select some entity Client objects properties that meet my criteria and take 20 via linq. Something to the effect of:

    var clientList = (rom client in entities.Clients where
    client.LastName.StartsWith(“min”) select new ClientInfo() { LastName = client.LastName, FirstName = client.FirstName}).Take(20)

    So far so good, nothing magical here. I then assign add it as a range to a new List<ClientInfo>

    var clientInfos = new List<ClientInfo>();
    clientInfos.AddRange(clientList);

    When the DataContractJsonSerializer hits that list, it correctly does it, however it manages to add in quite a few characters (that’s a null character) into the string which prevents it from properly being parsed by the built in jQuery JSON functions.

    Scratch that, I’m likely reading an entire memory stream in instead of just the used portion.

    Well, in the end, it’s a good idea to double check your thought process lest you be missing the real problem. I had hacked around my initial noticing of the ’s by replacing them out of the string so I could move on and come back later and figure out what was wrong. Done and done. I’ll verify it of course but I bet you a dollar that’s it. Funny how things come to you out of the blue, like when you’re trying to complain about an oddity. Chances are, the oddity is you Open-mouthed smile

    Json responses in a MVC web application

    I am sure this is obvious to every web developer using Microsoft’s MVC implementation with asp.net, but for those looking to move from standard asp.net to an MVC platform, this might not come to mind.

    The scenario is, you want to provide application data to a browser-side UI (for use with auto-complete textboxes, asynchronously updating UI controls (no server-side post-backs, things you use jQuery or AJAX for.)

    You’ve got a few options:

    • ASP.NET Web Service
    • ASP.NET Web Page (.aspx)  that returns raw data with an appropriate content-type
    • ASP.NET HTTP Handler (.ashx) that returns raw data with an appropriate content-type
    • WCF Web Service hosted under IIS
    • in fact there are a ton of custom solutions you could use as well, I’m going to ignore them and stick with the Microsoft family of solutions.

    First, I’m going to throw out the ASP.NET Web Page option. Sure you can do it but it’s exactly the same the HTTP Handler but more efficient and only require the “code-behind” portion of a page, not the .aspx portion as you are returning raw data in whatever format (Json, Xml, csv, whatever.)

    Now you have to consider your system interaction a bit. If you have multiple applications consuming the data, WCF is most likely the way to go. It supports multiple protocols (http, tcp/ip, msmq, etc.) If you have a native client and a web application consuming the data. It’s the way to go.

    A standard ASP.NET Web Service would also be usable by both but would only support HTTP, but since you can get that functionality with a WCF service, it’s the way things are moving in Microsoft Land. Having said that, configuration of the services, behaviors, end-points is a pain in the @$$! From experience I can say it was easy to use the proxy classes generated by the service proxy but I am having a very hard time getting it to accept HTTP GET requests. If this was any of the other of the options, it would have been a no brainer (due to their limitations.) Complex problems take complex configuration solutions, nature of the beast.

    It’s worth mentioning that native client’s can also consume http web services relatively easily, so if you have a lot of knowledge investment in standard web services and you only need to support web based clients then this isn’t a wrong choice at all.

    If you find yourself in a situation where only your web application is going to be consuming your application data you can fall through to the simplest form. Make a Page or Handler in your application and directly serve it. Tapping in to get or post variables, cookies, session, it’s all there at your fingertips. It’s my favorite when I only have to worry about feeding the UI due to it’s ease of use.

    Enter the land of MVC

    First let’s just get it over with, you absolutely can use a .ashx page in a MVC web application on ASP.NET. You will need to add a new route to send it traffic but after that it works the same.

    But since that flies in the face of MVC’s “do it this way, you’ll be happier in the end” (as some like to call “Best Practices” Smile) How can you do it the way MVC wants you to.

    Simply as it turns out!

    Well, first you make a new Controller and give it an Action. For my case I made a DataServiceController with a Action of “GetClientByLastName”. That does the work of fetching the data.

    My model is a string containing a List of Client POCO classes which has been serialized to Json (through the magic of .NET 4.0’s inclusion of DataContractJsonSerializer.) so I don’t need a custom model.

    Then make a view with no format and not strongly typed and simply @HTML.Raw() write it out. You’ll also want to set the page response’s content-type to reflect what you’re be outputting. I did this in the Controller, I’m sure there are more way to do it.

    Anyway, in the end, using easily coded, standard MVC stuff, I am able to get a Json fromatted list of client’s to work with from my UI simply by fetching from:

    [warning, this link won’t resolve] http://mydomin.com/clients/min

    And I get a list of at most 20 client’s whose last name begin with “min”. Slick enough for me. Anyway hope it helps, I’ll update this when I have some code samples but the concept is easy. I’m embarrassed it took me so long to put two and two together.

    YSlow, an awesome tool that always makes you feel sad

    I just ran YSlow on my site… It’s a great tool with real help on speeding up your site. But invariably, it always punches ya in the gut when your head is turned with a D or F.

    The downside of not writing your own publishing platform, various systems do things differently and some are more flexible than others.

    I’m using WordPress here now and it was pretty easy to switch on the Google analytics, but it did essentially require me modifying the Theme’s code, and I was very surprised there wasn’t a built in way to add custom scripts to headers / footers.

    At any rate, I will affect what I can but here’s my site’s report card as of now, it ranked a C with a 97 score, I inadvertently cut that off the screenshot. It breaks down below. Overall, could be worse.

    I will follow up with some tweaks over the next few weeks as I experiment with the SEO and Caching modules WordPress supports.

    blog.johnminadeo.com's YSlow score
    My blog's score, passing but could be better

    Tortoise SVN and BeyondCompare

    Since I always forget the settings, here they are 🙂

    From: http://www.scootersoftware.com/download.php?c=kb_vcs
    [May 25th 2010]


    TORTOISESVN

    Diff

    1. Select Settings from Explorer's TortoiseSVN submenu.
    2. Switch to the Diff Viewer tab.
    3. Change the radio buttons from TortoiseMerge to External.
    4. In the path edits, enter:
      "C:Program FilesBeyond Compare 3BComp.exe" %base %mine /title1=%bname /title2=%yname /leftreadonly

    To use Beyond Compare for image comparisons either replace the file C:Program FilesTortoiseSVNbinTortoiseIDiff.exe with a copy of BComp.exe, or click the Advanced button on theDiff Viewer tab and add each image type's extension with the same command line as above.

    3-Way Merge (v3 Pro)

    1. Select Settings from Explorer's TortoisSVN submenu.
    2. Switch to the Merge Tool tab.
    3. Change the radio buttons from TortoiseMerge to External.
    4. In the path edits, enter:
      "C:Program FilesBeyond Compare 3BComp.exe" %mine %theirs %base %merged /title1=%yname /title2=%tname /title3=%bname /title4=%mname

    2-Way Merge (v3 Std, v2)

    Use the same steps as above, but use the command line:
    "C:Program FilesBeyond Compare 3BComp.exe" %mine %theirs /savetarget=%merged


    Here are some screenshots of the UI, from the Start button or Context menu, then the settings screen for diff and merge

    context-menu settings

    merge

    Hopefully seeing the light with Ektron CMS400.NET 8

    Well, as you may be able to tell, I have been, eating, drinking, and breathing Ektron lately. And I think I am beginning to see the light, by which I mean, how Ektron wants you to work within itself. It’s a pretty powerful system.

    What I ended up with is creating a “Widget” content directory, and a directory within for each widget that I am backing the configuration with the results of a Smartform instance. So, I created a Smartform per Widget, and assigned that widget to be the default and only Smartform for that directory, and requiring only Smartform content in that directory. The net result is, I can now hook into the existing  way to simply call that directory with a “add” command via http request, and popup the authentic CMS400 smart form content editor, my widget just needs to create the content and persist the new content id.

    That way, when the widget is dropped on the page, in edit view, you can create the configuration Smartform, and then subsequently, you are displayed the XSL representation with a Ektron Edit “button” to bring down the standard Ektron contextual edit options. Downside is having the right named controls to receive updates from the Ektron Editor Add New form closing. It’s a little messy but there is precedent reference code to look at in some other widgets (hint: ContentBlock).

    Additionally, I still need to create a page that will render a widget dynamically, actually, each widget will need a default template such that when the content itself is referenced alone (like an embed link) it will provide an appropriate rendering. The default behavior is to pass it though a rough xml render with nodes and elements and attributes, in a digestible format.

    What you really need is what this page looks like alone, which doesn’t exist without the context of the widget, which needs to live on a page. Attaching it to a template with a dynamically populated Smartform of the correct type will yield a stand alone page for that Smartform instance. Complete with master page support at the .aspx level.

    One could provide a pretty XSLT to render the Smartform’s configuration XML more attractively then the default, but for design / content author mode the default is passable, just not that pretty.

    All in all it feels pretty right. It is an odd situation though, I’m providing Widgets to Content Authors, so since they are exposed to these Ektron built in editors, the consistency greatly affects the end result. Typically the widgets are meant to interface with external systems or provide relatively autonomous functionality and configuration wouldn’t be content. But my audience is a technical staff that will put the pages together using these widgets, and their customers will add the content in the pre-created locations and widget sets, so a more in depth configuration methodology was required. Turning out pretty well.

    All in all, I like it, while it has some room for improvement. I think they should create a community edition.

    More on Ektron CMS400.NET

    So far, most of the difficulties in customizing a Ektron is that a lot of the abstractions in a standard web application are already encapsulated by the system. For example, containers and controls such as images, content blocks, pages, forms, the CMS already has a pretty rich set of data attached to these. The problem is, where the rubber hits the road, you need to provide a widget that will run in the Ektron platform and use the Ektron structures for persistence, and the UI rules will demand a title, body and image for numerous UI blocks, but Widget1 will only use an image, and Widget2 requires and image and body, but not a title, whereas Widget3 requires all 3. Ektron provides a “Smartform” concept that lets you define a structure of data via a graphical WYSIWYG form builder which represnets itself as XML. Once you have a Smartform, you can associate it with a content directory, then new instances of the smartform can be created and populated by the user then saved as a content item.

    So great, I have a Audio Player widget, that takes has a resource selector smartform input control, which allows the user to pop up a graphical Content Folder browser, which can be limited to certain types of content and allow the user to pick. His choice is persisted when the new instance of the smartform is titled and saved.

    Now I need to build 2 jukebox widgets, “Jukebox A” that has requires a audio resource and a body which is a standard HTML content resource (in ektron); and “Jukebox B” that just takes the audio resource. So, I can make a “Jukebox Item” Smartform, which has both an audio resource and a body resource and create 2 new smartform instances, based on the “Jukebox Item”. Roadblock… Since A requires both, and B only needs the one, the smartform allows us to require it, but we can’t put the same requirement on the body, because not both widgets will use it. Leaving you with the sad solution of spreading validation (and persistence) over the underlying items and the final widget edit UI. Custom HTML can be provided in the smartforms so custom javascript validation and manipulation could be performed, but doing that is the exception to the rule, not the standard way of doing it in Ektron.

    Another problem using the smartforms are the when the resource picker control is used, it presents itself in terms of the CMS system’s content, where you’d like to restrict a resource to another smartform instance in particular such that if you have a Image Carousel Item and a New Item, you could restrict the content shown to contents that use that form as their base. Having said that, the content chooser is part of the workarea code, so it could be modified. The WorkArea is the code for the CMS system. It can be completely customized, the question is how far out of the box do you want to go, especially if you need to upgrade to a new version down the road.

    It just seems like these would not be new complaints. I’m no SharePoint expert but this is why they have content types that can be created and treated like first class citizens, the less customizing of the actual CMS system, the better.

    It’s not terrible, but something to consider.

    A few thoughts on Ektron CMS400.NET

    So I recently started a new job at a decently sized software consultancy (excellent news and a great opportunity to be sure!) and my first project is at a large hospital in Cincinnati, Ohio. They currently are using Ektron CMS400.NET 7.x host the site in question. While I have heard of Ektron in the past, I have not had that much time to work with it up until this point.

    Disclaimer: I do not work for or represent Ektron Inc. in any way shape or form. I simple am a developer tasked with creating custom components that work within the client’s installation of the product and in general the entire client customization and implementation. I do have experience with a number of Content Management Systems on a variety of platforms, but I am in no means an expert and I am delighted to learn new products and platforms.

    Let’s start with a little background. Ektron CMS400.NET is developed by Ektron Inc. (http://www.ektron.com/), located in Nashua, NH. Their flagship product is CMS400.NET and it’s a pretty light-weight and pretty powerful Content Management System. Ektron hosts a set of developer community for forums and blogs, etc. And they have a ton of documentation (literally, if you  printed it out, it would likely weigh a ton) and videos, as well as tutorials. Essentially everything you’d hope to be in place for an indication of a well kept software project, and it’s here in spades. It’s relatively affordable when weighing it’s features and price with it’s competitors.

    Now for the nitty grity bits. CMS400.NET is a .NET 2.0 Website project (ala Visual Studio 2005), it survives an upgrade to 2008 and 2010, I’ve tried them both with little to fix up. It’s written predominantly in VB.Net though does have a vbcode and cscode folders in the site’s app_code directory to allow extensibility in either. And of course custom class libraries can be written in any managed language and referenced from the website. The installation comes with a few Install Ektron Site options such as “CMS400 Developer Site”, “CMS400 Minimum Site”, etc. And will install the site into IIS, SQL Server (and it will offer the option to install SQL Server Express during the installation if it isn’t already present). The Developer site comes with a main Ektron Developer Documentation site, and a demo site for some medical company. The Minimum set up simply installs an empty Ektron installation, fully configured and ready for complete custom content. The Api is pretty extensive, I will give them that, hands down. I will complain about their documentation, they have a ton, and maybe every single piece of the platform is documented, it is literally too much to take in and there isn’t a homogenous set of documentation for it. But it is fully loaded. There are some CMS / Ektron specific words you may need to know if your not familiar with the syntax of the documentation (i.e. taxonomy, cms, smartforms, etc). Ramp up time getting familiar with the platform while creating a useable Ektron widget to personal spec was about two weeks, which I don’t think is unreasonable).

    My primary dislikes are the Website Project visual studio application over the Web Application project choice. Now it comes as a fully functional website CMS web system. So classes typically sit in the app_code directory and are compiled but their source code is never published. So you drop your business objects in there and proceed to code some widgets. For ektron to recognize widgets, they must be in the root of a widget directory in the website folder hierarchy. So you discover you need to touch up the base class, your change recompiles the app_code, which the entire rest of the site relies on, so then it is recompiled. If you can stay out of the app_code you can recompile the website in a much shorter time. However, I’m a back-end guy so most of my time is in the plumbing that causes the nightmare recompilation. Ok, it’s maybe 3 minutes, but damn… feels like forever.

    Beyond that, I have no gripes, it’s supports pretty much everything you want, in context content editing, metadata customization, easy widget infrastructure (they’re literally .ascx web user control files) and it’s a website, so you can fine tune the entire site. You don’t get the source code to the API but at that point you’d be adding your own so it doesn’t matter, but would have been a nice touch. Maybe I just missed that piece of documentation 😮

    Anyway, I’ll end it on a 2 thumbs up. I would recommend it to a company that couldn’t afford SharePoint, could customize the asp.net site, had a content editor plan in place.