Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

@Html and beyond

I like the way MVC builds the content of my web-apps. I write plain HTML, and the @Html helper object will build all Html controls needed for in and output of the dynamic data. The nice thing is that the HtmlHelper object is strongly typed, all properties of the view’s model are available as lambda expressions.

<tr>

    <td>

        @Html.LabelFor(m => m.AanmeldingsKlacht)

    </td>

    <td>

        @Html.TextBoxFor(m => m.AanmeldingsKlacht)

    </td>

</tr>

 

Nice clean code.

Things are getting harder when you need more than the standards the HtmlHelper class gives you.

Extending the HtmlHelper

The way to extend the HtmlHelper is by using extension methods. An extension method extends an existing class without inheriting from it like in “classical” oop. Which extension methods are added to an object is ruled by the namespaces used in the code using the extended class.

The methods of the HtmlHelper class should return strings typed as MvcHtmlStrings. A standard string would be Html encoded by the view engine. An MvcHtmlString is literealy rendered into the view. The way to go is to extend the HtmlHelper class with methods which will build plain Html.

As an example of this is Purple, a very simple extension method which does demonstrate the principles and possibilities.

public static MvcHtmlString Purple<TModel, TProperty>(

this HtmlHelper<TModel> htmlHelper,

Expression<Func<TModel, TProperty>> expression)

{

    return new MvcHtmlString(

string.Format(“<span style=’background-color: blueviolet’>{0}</span>”,

                htmlHelper.EditorFor(expression)));

}

 

Note the following points

  • The return type is MvcHtmlString, as discussed above
  • The method is generic. <TModel> is the type of the model of the view where the method is used. <TProperty> is the type of the model’s property.
  • The method is static. The method’s class also has to be static
  • The first parameter this HtmHelper<TModel> hooks the the method into the HtmlHelper object
  • The second parameter expression describes the lambda of the property
  • The htmlHelper object itself, with its rich collection  of methods and properties is available. Here it builds an EditorFor the expression.
  • The result is embedded in a plain Html span with a  “nice”  background

Now when the view uses the class containing this method I can do this:

<tr>

    <td>

        @Html.LabelFor(m => m.HulpvraagInitiatief)

    </td>

    <td>

        @Html.Purple(m => m.HulpvraagInitiatief)

    </td>

</tr>

 

And now the textbox, or whatever other control is built, has a nice purple background. Of course this is not be the way to achieve that effect. But I do hope it clarifies the way the htmlhelper works.

A custom HtmlHelper

We now have a way to extend the HtmlHelper with new methods. These methods can have custom parameters. But what if I needed a custom HtmlHelper with some extra properties which are needed in many instances of many methods ? As a casus I will explore fiddling with the Html Id’s of the controls built.

In the default behavior all EditorFor controls built get an id which is equal to the name of the property. Which is great, when posting back the form TryUpdateModel will bind all posted values to an instance of the model. All of this goes horribly wrong when several instances of a view are rendered on one and the same page. Not just contents gets jumbled up, scripts will go haywire as well.

It is possible to give each control an unique Id by setting it’s HtmlAttributes. Some, like the Telerik suite, even have a method to assign a name. Assigning these Id’s is a hassle and he controller receiving the postdata will also have a lot of work to do to extract all posted values.

Here’s the plan:

  • Build an extended HtmlHelper which takes an Id to uniquify names
  • Give this class EditorFor methods which build controls with an unique name
  • Let the class create the postdata

The class will be generic, typed to the Model

public class MyHtmlbuilder<TModel>

{

    private readonly int _id;

    private readonly HtmlHelper<TModel> _htmlHelper;

 

    public MyHtmlbuilder(int id, HtmlHelper<TModel> htmlHelper)

    {

        _id = id;

        _htmlHelper = htmlHelper;

    }

}

 

In the constructor it receives the Id needed for unique names and the original HtmlHelper object.

To hook into the existing helper and model the builder is again created from an extension method.

 

public static MyHtmlbuilder<TModel> MyHtml<TModel>(this HtmlHelper<TModel> htmlHelper, int id)

{

    return new MyHtmlbuilder<TModel>(id, htmlHelper);

}

 

Having my helper in place I can give it methods to build Html. To create the unique names I need yet another extension method. This one is on the lambda expression to find the property name using reflection.

 

private static string NameBuilder<TModel, TProperty>(this Expression<Func<TModel, TProperty>> expression, int id)

{

    var me = expression.Body as MemberExpression;

    if (me == null)

    {

        throw new ArgumentException(“You must pass a lambda of the form: ‘(object) => object.Property'”);

    }

    return string.Format(“{0}{1}”, me.Member.Name, id);

}

 

The Html building methods are quite simple. Building a dropdownlist for a property:

 

public MvcHtmlString DropDownListFor<TProperty>(Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectListItems)

{

    var id = expression.NameBuilder(_id);

    return _htmlHelper.DropDownListFor(expression,

selectListItems,

new { id }) ;

}

The namebuilder method builds an unique name. The original htmlhelper does the real work. Using my name in the Html-attributes.

 

I can also build third party controls here. Here’s a Telerik datepicker:

 

public MvcHtmlString DatePickerFor(Expression<Func<TModel, DateTime>> expression)

{

    return

        new MvcHtmlString(_htmlHelper.Telerik()

                    .DatePickerFor(expression)

                    .OpenOnFocus(true)

                    .Name(expression.NameBuilder(_id)).ToHtmlString());

}

 

Note that Telerik has it’s own method for setting the name. It’s controls are extremely picky over unique names.

I leave it up to you to add the builder methods you need. Working with this kind of code is somewhat puzzling in the beginning, all the this’s and generics take some time to sink in. But when working with it it soon falls into place. It made me even more delighted over the powers of the C# language.

The helper can do more than building just Html. It’s also great for building script. Posting the form-data as they are will lead to all the funny names leaking back to the controller. It would be great to have the original simple names. To control this you have to post from script.

    $.post(‘/EersteLijnsTraject/Bewaren/?idTraject=@Model.Id’,

        {

            MyPostValue : $(‘#MyPostValue@(Model.Id)‘).val()

   }

        

 

Here a form variable named MyPostValue is posted with its value coming from a control named MyPostValueX. This works but is ugly code which is hard to write and maintain.

Here my custom helper comes to the rescue. It uses a class to build the postdata. The class takes the id in its constructor and uses a stringbuilder to build the script. The Add method adds a model member to the post. Using the pattern described above based on a lambda on the generic TModel type of the data.

public class PostDataBuilder<TModel>

{

    private readonly StringBuilder _sb = new StringBuilder();

    private readonly int _id;

 

    public PostDataBuilder(int id)

    {

        _id = id;

    }

 

    // Add form field to postdata

    public PostDataBuilder<TModel> Add<TProperty>(Expression<Func<TModel, TProperty>> expression)

    {

        var propName = expression.NameBuilder();

        // JQuery  i.e. : BeginDatum : $(‘#BeginDatum1′).val()

        _sb.Append(string.Format(“{0} : $(‘#{0}{1}’).val()”, propName, _id));

        // comma separated

        _sb.Append(‘,’);

        return this;

    }

    // Generate

    public HtmlString Render()

    {

        /*  Resulting in

            BeginDatum : $(‘#BeginDatum1′).val(),

            EindDatum : $(‘#EindDatum1′).val(),               

            DBC : $(‘#DBC1′).val()                

 

            */

        return new HtmlString(_sb.ToString(0, _sb.Length – 1));

    }

}

 

The Render methods builds the desired script snippet.

$.post(‘/EersteLijnsTraject/Bewaren/?idTraject=@Model.Id’,

    {

 

        @(myHtml.PostData().Add(m => m.DatumAanmelding)

                                    .Add(m => m.HulpvraagInitiatief)

                                    .Add(m => m.Aanmelding)

                                    .Add(m => m.AanmeldingsKlacht)

                                    .Add(m => m.DiagnoseSet)

                                    .Add(m => m.Werkzaamheden)

                                    .Add(m => m.Tests)

                                    .Add(m => m.BehandelMethodiek)

                                    .Add(m => m.MedicatieGebruik)

                                    .Render())

        },

        // return function

        function(data) {

 

 

This code is a lot better to read and maintain. Thanks to the lambdas. As an extra bonus posting this way does not require an html-form.

Wrapping up and winding down

Building a custom HtmlHelper is, when you understand how, no big job. Give these snippets of my experiments it should be no big problem to create your own.

It takes these steps to use your own custom helper in a view

  • Make sure the code is included the uses
  • Create a helper in the head of the page
  • Use its methods

Here’s a slightly stripped version of one of our pages using EposHtml, our custom HtmlHelper 

@model ELPTrajectModel

@using Epos4.Website.EposZilos.Helpers

@using Epos4.Website.EposZilos.Models

 

@{

    var eposHtml = Html.EposHtml(Model.Id);

}

 

<script type=”text/javascript”>

function Bewaar@(Model.Id)() {

    $.post(‘/EersteLijnsTraject/Bewaren/?idTraject=@Model.Id,

        {

 

            @(eposHtml.PostData().Add(m => m.DatumAanmelding)

                                     .Add(m => m.HulpvraagInitiatief)

                                     .Add(m => m.Aanmelding)

                                     .Add(m => m.AanmeldingsKlacht)

                                     .Add(m => m.DiagnoseSet)

                                     .Add(m => m.Werkzaamheden)

                                     .Add(m => m.Tests)

                                     .Add(m => m.BehandelMethodiek)

                                     .Add(m => m.MedicatieGebruik)

                                     .Render())

            },

            // return function

            function(data) {

                var grid = $(‘#EersteLijnsTrajecten’).data(‘tGrid’);

                grid.pageTo(grid.currentPage);

            });

    }

</script>

 

 

<table>

    <tr>

        <td>

            @Html.LabelFor(m => m.DatumAanmelding)

        </td>

        <td>

            @eposHtml.DatePickerFor(m => m.DatumAanmelding)

        </td>

    </tr>

…………………………….

    <tr>

        <td>

        </td>

        <td>

            <button type=”button” onclick=”Bewaar@(Model.Id)()”>

                Bewaar</button>

        </td>

    </tr>

</table>

 

You don’t want to see the pages before the custom Helper Glimlach  The way the name of the save method is “uniquified” might give a clue. Anyway, I hope to have inspired you to explore the HtmlHelper as well.

Posted in Uncategorized | 2 Comments

2013

Almost 2013 and my blog still ain’t dead yet. The turning of the year I looks like a good moment for another ride on one of my favorite hobby-horses: looking into the future through the eyes of the past. In my youth pretending to be a cowboy turned into another Texan adventure: exploring space. The images in this post are from a 1959 Golden Press book on the future of space exploration. In 1963 a translation hit the Dutch market which appeared just in time to be swallowed by me.

HNY1

These days there’s nothing futuristic about it, both technologically and social just antique.

It got even better when describing a ‘rocket freight liner’

HNY2

Notice the (mail) bags on the left. The only thing missing is a “Wells Fargo Stage Coach” emblem.

I could go on and on. The lesson I learned once again is that foreseeing the future is not just hard, it’s next to impossible. It still is today. Who would seven years ago could have predicted the current state of (FI) JavaScript or Microsoft ? So next year we can just keep exploring and imagining. And most of all, stay critical on prediction.

And in case you make it into space, don’t forget your soda and sandwich:

HNY3

Happy new year.

Posted in Uncategorized | 1 Comment

A crash course into Mac recovery for Windows users and other dummies

A while ago I posted on taming a Mac to do Visual Studio development, including the settings to completely satisfy Resharper. We’ve been a happy couple since.  Until recently, when I lost my Macbook’s disk drive. It took me some time to find out what was wrong. OS X has no blue screens, it just shows a beachball (spinning pizza’s), due to the smoothness of the OS it took time to pinpoint the problem to the physical disk itself.

It is a legend that OSX is simple, diving into the internal workings you will meet a complete Unix system with all the endless list of mysterious parameters. It is also a legend 3d party tools have nothing to offer not included in the OS. Onyx is free, quite nice and integrates Unix documentation. Nevertheless nothing helped to fix the problem. The day my Mac would no longer boot I had to try to salvage some last pieces of work and planned to replace the disk.  Which was, in the end, quite easy but my experience with Windows machines was, in the beginning, not the best place to start.

The first try was to boot from the original install disks. Doing that the Mac beeped loudly and refused to do anything else. As it turned out you cannot boot a Mac with a disk containing another version of the OS than the machine’s latest version. OS-X 10.7 and 10.8 come as internet downloads. The upgrade made the install discs useless.

When choosing where to boot from (hold the option key when switching on) several options turn up :

  • Boot from the mac’s volume
  • Boot from CD
  • Boot from the recovery disc
  • Boot from the internet

The recovery disc is a second volume on the hard disc. In case that volume is also unreadable booting from (Apple’s servers) on the internet looks quite interesting. I have not tried that myself as my recovery disc was still readable.

The recovery disk offers the opportunity to reinstall the OS from the internet. It communicates with the Appstore and your Mac’s ID, no need to buy a new license. Unlike Windows there is no option to reinstall without preserving anything on the disk. I still needed a way to salvage my data.

The good thing is that you can install OS X on any volume attached at boot time. I plugged in an external USB drive and installed OSX there. Which resulted in a perfect working Mac with the original broken internal hard disk mounted as an extra volume. It was readable although it took a lot of patience to wait for the results. After copying my lost data (a complete VMware Fusion virtual hard disc) it was time to replace the disk drive itself.

A modern macbook looks pretty closed but replacing the internal hard drive is easy provided you have the right screwdrivers. As a new drive I took an SSD.  Best thing ever happened to the Mac. Especially a disc intensive app like VMware Fusion shines with that.

Reinstalling apps on a Mac is a no brainer. As there is no registry or anything like that it is a matter of copy and paste. An app like Monotouch needs some attention due to its many dependencies on other software. It cannot be installed more than two times. The good thing is that it did not consider the new disc as a fresh installation. The Mac is identified by something independent of disc or OSX installation. Soon everything was up and running without any trouble.

In the end I wish I had known all of this before. Or had an open mind on things possible instead of one narrowed by the way things work with Windows.

Posted in Uncategorized | 3 Comments

Facebook’s experience sucks (Comments of an app-builder on #ProjectXHaren)

Disclaimer: this post might seem over-opinionated and, at first sight, slightly off-topic. But things happened just to close to let them rest. Please read on.

Twelve years ago I moved away from the busy part of Holland to the quiet village of Haren, The rapid evolving internet made physical distance to my customers less important. It was a move I never regretted. Over the years living here was good and I had a lot of good internet experiences, both professional and personal. Last year I even got myself a Facebook account. Never did that much with it, one of the reasons is its bad user experience. Navigating around FB is chaotic. I uploaded some foto’s which I couldn’t trace afterwards but keep popping up in my “friends” pages. That kind of frustration. I never got the feeling I was in control of my own “wall”. I will get back on that later.

Last weekend made me long back to the pre-internet days. Friday night our lovely village was visited by a ProjectX party, which started on Facebook and made Haren known all over the world. Leaving the village in shock, over 30 people physically injured and over a million euro’s of physical damage. The psychological damage is still unknown, writing this down should help. The morning after was also great, everybody was busy cleaning up the mess, having a coffee outside and talking. Thus reclaiming our living space.

Who is to blame ? How did this happen ? Noteworthy from the viewpoint as software developer is what triggered it. It was a small mistake in an inhabitant posting a Facebook event (marking it as public) which went viral. And here I want to point a finger. As I wrote before the Facebook user experience is bad, it is chaotic and the moment it is posted you lose control. The mistake made was just waiting to happen.

User experience is IMHO something which deserves far more attention. Also here on CB. It is great to be on good speaking terms with a domain expert and have a smooth and maintainable infrastructure for your software. But when the UI, the only thing the end user sees, is no good the software will not work. It will be overstressed by the user firing invalid data at it, again and again. It will starve because the end users refuse to use and feed it with data. It will become unpopular because it does different things then expected.

Back to Facebook. Recently it collected an incredible amount of money. By far enough to hire some people who really understand user experience and give the site and apps a good makeover. In case FB doesn’t pick this up themselves this is IMHO a golden opportunity for a new startup. Just like FB swallowed Hyves, FB can be swallowed. On the very short term I would suggest a small patch, asking for a confirmation like “Do really want this to go viral”.

I am not blaming Facebook on what happened in Haren. I am blaming them for a having bad apps. For now the Facebook experience just sucks, especially in Haren.

I want to finish with a small Limerick. In Dutch, author unknown:

Er was eens een meisje uit haren,
die wilde opvallend verjaren…
ze plaatste een linkje,
vergat daar een vinkje,
en nu zit heel Haren op de blaren…

Posted in Uncategorized | 4 Comments

Domain Model over Database Schema. Using fluent nHibernate to generate the database

In domain driven design everything centers on your domain model. Domain objects are persisted to a database. What that database exactly looks like is not known to the model. Nevertheless the database has its technical aspects. To name some

  • Primary and foreign keys to guard integrity
  • Enforce values
  • Efficient storage to limit disk usage and IO
  • Indices to speed up reads

These are aspects unknown to the domain model.

The domain model is mapped to the database using an OR-mapper such as nHibernate. At first sight building the domain model and building the database are two tasks using fluent nhibernate to bridge the two worlds in mapping files. Working domain driven it would be nice to just work on the domain model and generate the database from there. The good thing is that this is possible using fluent nHibernate. The bad thing is that it requires some fiddling to fulfill the aspects I’ve just mentioned. Documentation on this is scattered over the web. In this post I’ll describe how we generate and maintain our database straight from the domain model.

All the basics of using fluent nHibernate are very well documented here.

Generate and update a schema

The fluent API has a method to create or update a database schema.

public static void CreateDataBase(string connectionString)

{

    Configuration config = Fluently.Configure().

        Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.Is(connectionString))).

        Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly())).

        CurrentSessionContext<ThreadStaticSessionContext>().

        BuildConfiguration();

    var schemaExport = new SchemaExport(config);

    schemaExport.Create(false, true);

}

 

For a more detailed explanation of the parts read the wiki. The mappings are generated and passed to a new SchemaExport object. The Create method actually creates the database. Depending on the parameters the database is created (overwriting any existing db) or the database is updated. The latter is not that very useful, as only new tables and columns are added, any updates on existing ones are ignored.

The nice thing is that all primary and foreign keys are created in the resulting database. The property marked as Id in the mapping has become the primary key of the table. All References in the mapping have become (nullable) foreign keys.

The bad thing is that as a whole the database schema is not suited as a real production, or even testing, database.  Amongst many other things: all strings have been mapped to nullable nvarchars of length 255

In the remainder of this post I’ll sum up ways to fine tune the mappings to be able to generate a database which does meet all requirements.

Not null columns

Whether a column can be null can be explicitly mapped with .Not.Nullable()

Map(c => c.ResultaatCode).CustomType<ResultaatCodeCOV>().Not.Nullable();

 

This applies to any type, also on foreign keys

References(a => a.Patient).Not.Nullable();

 

Varchar columns

By default fluent nhibernate maps strings to nvarchars-255. You must have very specific reasons to use nvarchars instead of varchars. Besides that 255 is not a “one size fits all” value. The type of the column can be specified using the CustomType mapping method. Which takes a string to specify the type.

We have built a tiny helper function in our mapping base class

public static string VarChar(int length)

{

    return string.Format(“AnsiString({0})”, length);

}

 

Note that the name of the type“Ansistring”, might not work in every brand of database. It does in sql server, you’ll have to find your own magic string for your brand…  The method is used in the mappings. Here it used to define a not nullable varchar column of length 100.

Map(b => b.Naam).CustomType(VarChar(100)).Not.Nullable();

 

Special attention should be give to text columns without a fixed length. In sql server they are typed as varchar(max). When mapping such a column with fluent nhibernate the following is required

Map(b => b.Notities).CustomType(StringClob).CustomSqlType(SqlVarCharMax);

 

The parameter values are defined in our mapping base class

public const string StringClob = “StringClob”;

public const string SqlVarCharMax =“varchar(max)”;

 

The extra CustomSqlType() is not important for generating the database but essential when using it. Omitting it will result in saved values to be cut of to the first 4000 characters. Don’t ask me why, we did experience the problem, did find out the problem was real and did solve it this way.

Date columns

By default datetime fields are mapped to a datetime column. In a lot of cases a date column is far more appropriate. Not just for saving some disk space (and io speed). When querying for a date it is far more easy to compare a date to a date then finding the range of datetime’s which fall on a specific date.

We also have a const for mapping dates with the CustomType method .

public const string Date = “date”;

 

Which is used to map properties where only the date part is important.

Map(b => b.DatumPlan).CustomType(Date).Not.Nullable();

 

Which will result in a non null date column.

Keys

A key has a name. By default a random name is generated every time a new key is created. The bad thing about that is, besides being not very descriptive, that a tool like sqlCompare will always see a new key after every new schema generation. The nice thing is that you can specify the name of the foreign key names in the mapping.

References(a => a.Patient).Not.Nullable().ForeignKey(“FK_Aanmelding_Patient”);

An unique constraint is enforced in the database by a uniquekey, this key can be composed out of multiple columns. Also these keys can defined in the mappings, using the UniqueKey method. Passing the same name to multiple properties will result in a composite unique key

var keyName = string.Format(“CodeBeginDatum_{0}, tableName);

Map(c => c.Code).CustomType(VarChar(12)).UniqueKey(keyName).Not.Nullable();

Map(c => c.BeginDatum).CustomType(Date).UniqueKey(keyName).Not.Nullable();

 

Here the combination of the columns Code and BeginDatum is unique.

 

Indices

Indices are different from keys. Keys define constraints (and are often indexed), indices are only useful to the database engine to speed up performance. Nevertheless, also indices can be defined in a mapping

References(d => d.ZorgTraject).Not.Nullable().Index(“DBCZorgTraject”).ForeignKey(“FK_DBC_ZorgTraject”);

 

Here a foreign key is indexed. Easy as that.

Deploying the database

A domain model will change over time. So will the mappings. As said before fluent nHibernate is quite good in creating a new virgin database but not good at all in modifying an existing one. In which SQL-compare absolutely shines. Especially when you watch things like the names of the foreign keys rolling out changes is no big deal.

This is our recipe

  • Generate a fresh database as described in this post
  • Create a snapshot with SQLcompare
  • Copy the snapshot to the testing/production server
  • Use SQLcompare to modify the database

The nice thing with a snapshots is that it can bridge db-server versions. Our development machines run sql 2008 R2, the production server is running R1 and this way we still have no reason to buy the upgrade.

Winding down

This is by far not the full story. Fluent nHibernate has much more to offer, including the conventions API which could be a way to further explore the possibilities. For now this works well. We have a rich domain model which now also completely drives the database design.

As a final note: perhaps the usage of some Dutch in column names might irritate you. But using these names is (still) on purpose. When I write “BeginDatum” this refers to a very specific meaning of a date in that domain entity, not to something as vague a “Begin date”. Also here: it’s all about the DM.

Posted in Uncategorized | 13 Comments