# Thursday, October 15, 2009

The Alternative Network Group seems to be getting more exciting all the time. Seb is doing a great job organising beers and workshops. I would like to suggest a third type of event: AltNetDemos.

I seem to have lots of half-baked, prototype ideas in a month. Some of these make it into open source projects, screencasts, blog posts and tweets. However, it would be great to demo some things live to people.I’m imagining 5-10 minutes with a laptop and projector in front of 30+ people. Let’s say we get 5 people per session to demo and follow up with drinks/food. This provides time for discussions about whatever people find interesting (like the start of an AltNetBeers evening). These events can be a great way to generate buzz for new open source projects, bounce ideas around and generally geek out with shiny technology!

So what do reckon?

Thursday, October 15, 2009 2:40:39 PM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [3]  | 

When creating web applications I like to extract common pieces of mark-up into helper functions. I use Hasic which means helper functions are just simple VB functions that return XElement objects.

However, dynamic web pages often use javascript to add elements at runtime. Consider a page with a table of data which has an form to add rows. We want to add rows without reloading the whole page. So we use AJAX to post the new data, then, in javascript, create the new table row and append to the table.

So we have a repetition of the same HTML template; server-side and client-side.

Using Hasic we can eliminate this repetition. The following class field defines an HTML template:

Shared customerRow As New HtmlTemplate(Of String, String)("customerRow", Function(first, last) _
  <tr>
    <td><%= first %></td>
    <td><%= last %></td>
  </tr>)

Let’s break this down. We are creating an HTML template that takes two string arguments and returns an XElement. We have named it “customerRow” and given a lambda expression that returns the HTML. That second argument is an Expression(of Func(of String, String, XElement)). So the HtmlTemplate is able to parse the expression tree and generate an equivalent javascript function.

Within my page (server-side) I can use the template like a function (by using an indexer property).

Protected Overrides Function Contents() As XElement
  Return _
  <_>
    <table id="customers">
      <tr><th>First name</th><th>Last name</th></tr>
      <%= customerRow("Andrew", "Davey") %>
      <%= customerRow("John", "Smith") %>
    </table>
    <div>
      <button id="add">Add Row</button>
    </div>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
    <%= InlineJavascript(customerRow.Javascript) %>
    <script type="text/javascript">
$(function() {
    $('#add').click(
        function addRow() {
            $('#customers').append(customerRow('John','Smith'));
        }
    );
});
    </script>
  <_>
End Sub

The above code also includes the javascript for the page. Notice the customerRow.Javascript property. This returns the javascript function as a string. InlineJavascript is a helper that wraps up the javascript into a CDATA making the angle brackets safe. The javascript function looks like this:

function customerRow(first,last) {
  return '<tr><td>' + last + '</td><td>' + first + '</td></tr>';
}

The name of the function is what we gave to the HtmlTemplate constructor. Concat-ing strings may not be the best way, but it works for this prototype.

I hope you can see the value here. The template function is written only once. DRY win :)

hasic | html | javascript | vb.net | web
Thursday, October 15, 2009 12:39:59 PM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [1]  | 
# Sunday, October 11, 2009

Say hello to ProntoCMS a new open-source web content management system.

The project is hosted here: http://code.google.com/p/prontocms/

Pronto is built on ASP.NET MVC and uses JQuery and FCKeditor. It is very light-weight and ideal for small websites.

The code in subversion contains a couple of (very minimal) sample projects. Hopefully I will get around to writing some documentation soon.

Please take a look at the code and let me know what you think.

.net | cms | prontocms | web
Sunday, October 11, 2009 1:47:03 PM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [3]  | 
# Saturday, October 10, 2009

Thanks to everyone who left encouraging comments on my previous post about a new CMS I’ve created.

I have decided that I will be open sourcing the project. However I now need a snappy name for it. Naming is so hard for some reason!

Any ideas are greatly appreciated. The CMS is light-weight, very simple, runs on asp.net mvc and has plenty of ajax goodness.

.net | cms | mvc | oss | web
Saturday, October 10, 2009 6:24:40 PM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
# Thursday, October 08, 2009

Over the course of a couple of website developments I created a simple content management system. I know there are loads our there already, but I wanted something simple and easy for non-techie users. It runs on ASP.NET MVC, has an elegant extensibility model and produces clean HTML 5. I very happy with it and plan to use it on all upcoming simple websites.

The system is file based, so no SQL database is needed. This makes it ideal for running in shared hosting. It’s perfect for the ~10 page website. But there’s no reason it can’t scale up to larger sites too.

So I’m obviously enamoured with my own work :) but is it worth sharing? I would love to get the code out there for people to poke at. However, is it really worth my time doing so – setting up a project, documentation etc? My recent open sourced work seems to have taken off like a lead balloon (Snooze, Hasic, etc)! Do you want to see my new CMS? Or shall I just keep it to myself?

.net | c# | cms | mvc | web
Thursday, October 08, 2009 3:55:37 PM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [5]  | 

Hasic is a kick-ass view engine for ASP.NET MVC, with a completely different approach. It uses VB.NET's XML literals instead of nasty strings like most other view engines.

That's right, VB! If you are already closing your web browser upon reading that then shame on you. I'm not saying your whole app is in VB, just the views.

Using VB means this stuff comes for free:

  • Syntax colouring
  • Full intellisense in Visual Studio
  • Compiled views
  • Extensibility using regular CLR classes, functions etc

I’m looking for feedback. So please try out Hasic and let me know what you think – thanks!

.net | mvc | vb.net | web
Thursday, October 08, 2009 3:30:43 PM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
# Friday, March 13, 2009

Another approach I'm investigating for HTML form generation is using VB's XML literals.

Check out this screencast for a demo: http://screencast.com/t/WSoDB4B9M2

 

XML literals + Expression Trees gives us some serious power!

.net | html | screencast | vb.net | web | xml
Friday, March 13, 2009 6:44:33 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 

HTML forms seem to be general enough to warrant a better abstraction than manually creating the HTML, or even using simple HTML helpers. Ideally the semantics of the form should be enough to generate all the HTML content.

I have been prototyping some ideas in this area. Here is some code that demonstrates a simple (but incomplete) login form.

class LoginData
{
    public string Username { get; set; }
    public string Password { get; set; }
    public bool Persist { get; set; }
}
 
 
class LoginForm : Form<LoginData>
{
    public LoginForm()
    {
        FieldContainer = new DivFieldContainer();
 
        Add(d => d.Username);
        Add(d => d.Password).AsPassword();
        Add(d => d.Persist).WithLabel("Stay logged in on this computer");
    }
}
 
class Program
{
    static void Main(string[] args)
    {
        var data = new LoginData() { Username = "test" };
        var form = new LoginForm();
 
        var html = form.Create(data);
        Console.WriteLine(html.ToString());
    }
}

This generates the following HTML.

<form method="POST" action="http://localhost/">
  <div>
    <label for="Username">Username</label>
    <input id="Username" type="text" name="Username" value="test" />
  </div>
  <div>
    <label for="Password">Password</label>
    <input id="Password" type="password" name="Password" />
  </div>
  <div>
    <input id="Persist" type="checkbox" name="Persist" />
    <label for="Persist">Stay logged in on this computer</label>
  </div>
</form>

There is a clear separation of the data from the form meta-data. This lets me do interesting things like applying conventions, for example, the generation of label text from property names. I want to use mostly global conventions for a form, and then override a few specific fields where needed.

I think validation can also fit nicely into this approach. Validation logic can be put on the data model. The form model can then specify how errors are added to the HTML.

Has anyone else seen anything like this before? I don’t want the reinvent the wheel. Or at least I can steal some good ideas ;)

.net | c# | html | web
Friday, March 13, 2009 11:51:16 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [1]  | 
# Monday, January 19, 2009

Don't call SmtpClient.SendMail directly within your controller actions because it directly couples your controller to SmtpClient.

Don't even create an interface IMailer and wrapping implementation of this to SmtpClient.

Instead, create a new ActionResult subclass called EmailResult. Make this class have the properties From, To, Subject and BodyData. In the ExecuteResult method use the ViewEngine infrastructure to render a view of the BodyData into your own StringWriter. You can then send the resulting content via email using SmtpClient.

.net | asp | mvc | web
Monday, January 19, 2009 4:39:44 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Monday, December 08, 2008

Avoid using HttpContext in controller actions to make testing much easier. Therefore all inputs to an action needs to be passed as parameters. In my new REST framework that builds on ASP.NET MVC I have created some useful model binders to make this easy.

[ResourceUriTemplate("")]
public class RootUri : ResourceUri
{
    public ResourceResponse Get([HttpCookie] string visited, [AppSetting] int visitTimeout)
    {
    ...
    }
}

The HttpCookieAttribute looks for a cookie called "visited". The AppSettingAttribute looks in web.config for an appSetting with the key "visitTimeout". The method is now easy to test and has very readable definition. :)

 

Both attributes will cast the raw string found into the required type by using a TypeConverter.

The AppSettingAttribute constructor can also take a key name if you want something different from the parameter name.

The code is in SubVersion, but I'll repeat some here to show just how easy it was:

namespace Snooze
{
    public class AppSettingAttribute : CustomModelBinderAttribute
    {
        public AppSettingAttribute()
        {
        }

        public AppSettingAttribute(string key)
        {
            _key = key;
        }

        string _key;

        public override IModelBinder GetBinder()
        {
            return new AppSettingModelBinder(_key);
        }
    }

    public class AppSettingModelBinder : IModelBinder
    {
        public AppSettingModelBinder(string key)
        {
            _key = key;
        }

        string _key;

        public ModelBinderResult BindModel(ModelBindingContext bindingContext)
        {
            string setting = WebConfigurationManager.AppSettings[_key ?? bindingContext.ModelName];
            object value;
            if (bindingContext.ModelType == typeof(string))
            {
                value = setting;
            }
            else
            {
                value = TypeDescriptor.GetConverter(bindingContext.ModelType).ConvertFromString(setting);
            }
            return new ModelBinderResult(value);
        }
    }
}

.net | mvc | REST | web
Monday, December 08, 2008 8:55:53 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [1]  |