Hugoware

The product of a web developer with a little too much caffeine

Posts Tagged ‘Framework

Cobalt Beta – jQuery Style MVC View Templating!

leave a comment »

In a recent blog post I shared a preview of the Cobalt project I’ve been working on. Today, the source code has been uploaded to git-hub and the first beta binaries are being released!

Not sure what Cobalt is? Watch a screencast showing how you can use Cobalt in your MVC projects.
Watch the video now!

If you’ve seen any of my previous blog posts then you realize I’m not much of a fan of the current way to populate templates in ASP.NET MVC. I’ve tried a handful of different ways to improve the experience but so far nothing really felt like an improvement.

Cobalt uses CSS selectors to find and update content, much like the way that jQuery works. Cobalt works *with* ASP.NET MVC (and WebForms) so you can include it in an already existing project and use it right away!

So what does Cobalt look like? Here is an example of an MVC View…

<%@ Page Language="C#" 
    Inherits="System.Web.Mvc.ViewPage<IEnumerable<ProductDetail>>" %>
<%  
    this.Ready(() => {

        //select by tag names
        this.Find("form")
            .Attribute(new {
                action = this.Url.Action("CheckOut")
            });
        
        //find and set values for elements
        string current = this.Find("h3").Text();
        this.Find("#title").Text(current.ToUpper());
        
        //select classes and certain pseudo selectors
        this.Find(".list :even").AddClass("alt-item");
        
        //create new elements on the fly
        var link = this.Create("<a/>")
            .Text("Read About Us")
            .Attribute("href", this.Url.Action("AboutUs"));
        this.Find("p").Append(link);
       
        //create custom elements (like CustomControls)
        Stylesheet sheet = new Stylesheet("~/site.css");
        sheet.AddToPage();
        
    });
    
%>

<html>
    <head>
        <title>Sample</title>
    </head>
    <body>
        <form method="post" >
            <h3>Temp Title</h3>
            <p>The description goes here</p>
            <ul class="list" >
                <li>Item 1</li>
                <li>Item 2</li>
                <li>Item 3</li>
                <li>Item 4</li>
                <li>Item 5</li>
            </ul>
        </form>
    </body>
</html>

You can see that much like jQuery we have to queue up the work we need to execute once the document is ready.

I have a lot of documentation to write and a lot of screencasts to record, but don’t forget about the preview video which should get you started. For now, here are a list of the more important details.

The Important Stuff!

  • You must call CobaltManagement.Initialize() in your Global.asax file in the Init method (just override it and call it).
    public override void Init() {
        base.Init();
        CobaltManagement.Initialize();
    }
    
  • Cobalt uses HtmlAgilityPack to handle parsing of html content. I’m not happy with the framework so it will be one of the first things to be phased out, but for now you need to make sure to download it if you get the source code instead of the binaries.
  • You must use this.Ready from your pages and controls to wrap your commands. Otherwise your commands will run before the document is ready and fail.
  • Cobalt is aware of context, so if you use this.Find within a UserControl then you’re only going to select elements within that control. If you need to access the Page level from a UserControl then you can call this.Page.Find to change the scope of the command.
  • Cobalt supports a decent amount of selectors. Below is a list of currently available options.
    • Combinators: ‘ ‘, >, +
    • Shortcut Attributes: #elementId, .cssClass, $elementName
    • Attribute Matching (ex. [@name=’value’]): equals (=), starts with (|=), ends with ($=), contains (~=)
    • Pseudo: first, last, even, odd, nth(#), lt(#), lte(#), gt(#), gte(#), text, password, button, checkbox, radio, submit, file

Keep in mind this is very much beta code – I was literally working on changes today :). If you’re feeling brave then download the source and dig right in!

Download Beta

Cobalt (Source Code)

Advertisements

Written by hugoware

May 31, 2010 at 11:38 pm

Flow Based MVC Controllers

with 2 comments

I’ve been working on a project lately that has required that a controller follows a series of logical steps before it reaches the end. I don’t want users to access the last step until earlier steps have finished. The process also branches into separate paths depending on their selections.

One of the things that bugged me is I hated having so much logic devoted to checking to see if steps had been done before I continued. For example, checking if an image had been uploaded OR if they selected one from a gallery. Most likely I could simply create a property that checked for the state of things, but I wanted to come up with a reusable way to manage the flow of a controller.

The Flow

So here is an example of what kind of flow would go through this. This controller allowed a customer to provide a custom image or choose one from a gallery. The requirements at the end change depending on what a user selects.

Right now I’ve only developed some rough code — but here is a basic idea of how the flow can be controlled automatically.

The Basics

This first example shows the basic idea behind identifying a method as requiring a step to complete. An attribute can be applied to


//for now, the flow process uses extension methods instead of an inherited class
using MvcFlow.FlowExtensionMethods;

//A controller for MVC
public class ShopController : Controller {

    //required override to check steps automatically
    protected override void OnActionExecuting(ActionExecutingContext filterContext) {
        //extension method to check an action in the flow
        this.ProcessStep(filterContext);
    }

    //this step has no requirements so it can be browsed to at any time
    public ActionResult Index() {
        returns this.View();
    }

    //this has no requirements but it does APPLY a step if the validation is successful
    public ActionResult ValidateUser(string username, string password) {
        if (this.PasswordIsCorrect(username, password)) {

            //an extension method to update the steps for the flow
            this.ApplyStep(Steps.UserValidated);
            return this.RedirectToAction("SelectType");
        }
        //if the process doesn't apply the next allowed step then it can't proceed
        else {
            return this.RedirectToAction("Index");
        }
    }

    //this step cannot be executed until Steps.UserValidated has been applied
    //which is done in the successful validation step
    [StepRequires(Steps.UserValidated)]
    public ActionResult SelectType() {
        return this.View();
    }

    //snip...

The important thing to notice is that there are only three things required to make this process work.

  • Override the OnActionExecuting method to perform the validation. By overriding this step we can make sure an action is allowed to be executed — and if not, redirect the user.
  • Add an attribute to describe step requirements. The attribute StepRequires allowed us to define what steps must have been completed before they can execute this action.
  • Apply steps after successful validations. If requirements have been met then the step can be saved and a new set of actions will open up.

Removing And Branching

Here is another example of the code that shows how flow can be managed…


//snip...

//this step requires validation has happened -- but it also removes if 
//they have selected certain future steps. This means if someone browses back
//to the page then they are required to answer the question again
[StepRequires(Step.ValidatedUser)]
[StepRemoves(Step.SelectCustom | Step.SelectGallery)]
public ActionResult ChooseType() {
    return this.View();
}

// BRANCH 1
// Custom --------------------------

//Applies the SelectCustom option -- but also removes the option for
//the other branch (if it was even found)
[StepRequires(Step.ValidatedUser)]
[StepRemoves(Step.SelectGallery)]
public ActionResult SelectCustom() {
    this.ApplyStep(Step.SelectCustom);
    return this.RedirectToAction("UploadImage");
}

//This step requires that both the validation and select custom steps have been applied
[StepRequires(Step.ValidateUser | Step.SelectCustom)]
public ActionResult UploadImage() {
    return this.View();
}

// BRANCH 2
// Gallery --------------------------

//Applies the SelectGallery option -- but also removes the option for
//the other branch (if it was even found)
[StepRequires(Step.ValidatedUser)]
[StepRemoves(Step.SelectCustom)]
public ActionResult SelectGallery() {
    this.ApplyStep(Step.SelectGallery);
    return this.RedirectToAction("ShowGallery");
}

//This step requires that both the validation and select gallery steps have been applied
[StepRequires(Step.ValidateUser | Step.SelectGallery)]
public ActionResult ShowGallery() {
    return this.View();
}

Unfortunately, the attributes are a bit difficult to read but the general idea is to break the flow of the controller into two parts — each existing separate from each other but within the same controller.

You’ll notice in these steps we can use our enumerated type to create more than one requirement for an action (for example Step.ValidatedUser | Step.SelectCustom ). We can also use the RemovesStep attribute to automatically move back the current point of the flow.

Too Confusing?

I wrote a lot of the code to do this process today but I’m looking for some thoughts about this process. Is this too much work? Too confusing? Not really helpful?

Do you spend enough time managing flow in your applications that a framework like this could help?

Written by hugoware

December 2, 2009 at 10:05 pm