Using HtmlHelpers to generate Custom TextArea (Part 2)

This is Part 2 in a (very) mini series on HtmlHelper methods. Here is the link for Part 1, Using HtmlHelpers to generate HTML elements

This article is about creating a HtmlHelper for a TextArea although the same principles apply for other input controls as well. For this example I have created a simple Employee model class.

namespace HtmlHelpersDemo.Models
{
    public class Employee
    {
        public string Title { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
}

Nothing special about the controller. An Employee object is instantiated and passed to the view. Following MVC conventions the Index view from the Home folder is rendered.

using HtmlHelpersDemo.Models;
using System.Web.Mvc;

namespace HtmlHelpersDemo.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View(new Employee());
        }
    }
}

Before looking at the new TextAreaFor HtmlHelper method we will look at how it is called. The method is written as an extension to the Mvc HtmlHelper class (System.Web.Mvc) which allows it to be called the same way the built in TextAreaFor methods are called using @Html..
The first example passes values in a htmlattributes parameter in the form of a class and a data_ref attribute which has an underscore rather than hyphen.

@model HtmlHelpersDemo.Models.Employee
@using HtmlHelpersDemo.Code;
@{
    ViewBag.Title = "Index";
}
<h2>Index</h2>

@Html.TextAreaFor(m => m.FirstName, new { @class = "input" , data_ref="123"}, false)

@Html.TextAreaFor(m => m.FirstName,  false)

Here is the code that does all the work. As mentioned this is written as a HtmlHelper extension method so the first parameter is not actually passed in from the calling code. Rather it defines the class the method is associated with and provides us with a local reference to manipulate, in this instance the local name of HtmlHelper is htmlHelper.

using System;
using System.Linq.Expressions;
using System.Web.Mvc;
using System.Web.Routing;

namespace HtmlHelpersDemo.Code
{
    public static class TextAreaExtensions
    {
        public static MvcHtmlString TextAreaFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, object htmlAttributes, bool IsReadonly)
        {
            var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
			attributes["class"] = "form-control" + " " + attributes["class"];

            if (IsReadonly)
            {
                attributes.Add("readonly", IsReadonly);
            }

            MvcHtmlString html = default(MvcHtmlString);
            RouteValueDictionary routeValues = new RouteValueDictionary(attributes);
            html = System.Web.Mvc.Html.TextAreaExtensions.TextAreaFor(htmlHelper, expression, routeValues);
			TextAreaFor()
            return html;
        }

        public static MvcHtmlString TextAreaFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, bool IsReadonly)
        {
            return htmlHelper.TextAreaFor(expression, null, IsReadonly);
        }
    }
}

Lets disect what the method is doing. The first line calls a built in method passing in the htmlAttributes parameter. This method replaces underscore characters with hyphens which is how the data_ref is translated to data-ref when rendered.

var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

As all text area controls is this application requires the form-control css class, it is being added to the attributes in this method along with any other css class passed in throught the htmlattributes parameter.

attributes["class"] = "form-control" + 
    (!string.IsNullOrEmpty( attributes["class"] as string) ? " "+ attributes["class"] : "");

If the IsReadOnly parameter is set, the readonly state of the control is assigned to the attribues object.

if (IsReadonly)
{
	attributes.Add("readonly", IsReadonly);
}

The final four rows create a TextArea input control from the attributes and route values if there are any.

MvcHtmlString html = default(MvcHtmlString);
RouteValueDictionary routeValues = new RouteValueDictionary(attributes);
html = System.Web.Mvc.Html.TextAreaExtensions.TextAreaFor(htmlHelper, expression, routeValues);
return html;

There rendered html for the two examples above looks like this.

<textarea class="form-control input" cols="20" data-ref="123" id="FirstName" name="FirstName" rows="2">
</textarea>

<textarea class="form-control" cols="20" id="FirstName" name="FirstName" rows="2">
</textarea>

Using HtmlHelpers to generate HTML elements (Part 1)

When working in a Microsoft MVC application, creating forms containing form elements is made easier due to the number of available HtmlHelper methods for a TextBox, DropDownList, TextArea etc. Although HtmlHelpers are not only available for form controls, there are helpers for links, view rendering, validation and more built in to the MVC libraries.

At some point there will not be a HtmlHelper that does just what is needed and want to share a few examples of customer HtmlHelpers.

Example 1. Label Helper
This example generates html label page elements. Creating the label is as simple as building a string containing the html to be displayed on the page.

using System.Web.Mvc;

namespace HtmlHelpersDemo.Code
{
    public static class Helpers
    {
        public static MvcHtmlString Label(string labelText)
        {
            return new MvcHtmlString(string.Format("<label>{0}</label>", labelText));
        }

        public static MvcHtmlString Label(string labelText, string forAssociatdControl)
        {
            return new MvcHtmlString(string.Format("<label for='{0}'>{1}</label>", forAssociatdControl, labelText));
        }
    }
}

These methods return an instance of type MvcHtmlString class which represents an HTML-encoded string. MvcHtmlString is a member of System.Web.Mvc namespace (in System.Web.Mvc.dll).

Usage
To display a label we add a using statement at the beginning of our view.

@using HtmlHelpersDemo.Code;
@{
    ViewBag.Title = "Home Page";
}

@Helpers.Label("First Name:")

@Helpers.Label("Last Name:", "SomeControl")

When rendered the page contains the labels as expected.
html-helper-label-code

This is quite a simple example but the method could be applied to creating a html table row or even the whole table.

Date Formatting and Calling C# Script From XSLT in BizTalk 2013 Map

I needed to set a field value to a formatted date string in a map. As we are using BizTalk 2013R1 we are restricted to XSLT1.0 which makes date formatting more difficult (XSLT2.0 has better support for dates). However this got me thinking of the different ways this could be achieved. For demonstartion purposes lets say I have the below schema

biztalk-date-functoid
the last three fields are the fields of interest and are set up with the data types as in this table

Field Data Type
ApprovedOn xs:dateTime
CreatedDate xs:date
CreatedTime xs:time

Setting the ApprovedOn field to the current datetime value is quite straight forward with a C# scripting functoid.

biztalk-date-functoid-linked
Setting the CreatedDate and CreatedTime fields can be done in a similar way and just requires a C# scripting functoid for each field that returns the date in the relevant format.

The CreatedDate C# scripting functoid

public string CurrentDate()
{
    return DateTime.Now.ToString("dd-MM-yyyy");
}

The CreatedTime C# scripting functoid

public string CurrentTime()
{
    return DateTime.Now.ToString("HH:mm:ss");
}

This is the result of testing the map with a valid input file.

<Employee>
  <ForeName>Percy</ForeName> 
  <ApprovedOn>29/09/2016 11:59:43</ApprovedOn> 
  <CreatedDate>29-09-2016</CreatedDate> 
  <CreatedTime>11:59:43</CreatedTime> 
</Employee>

Moving on to the orignal problem I was trying to solve
The destination schema contains an element which itself contains three child elements

biztalk-employeeoutput-schema

defined with the following data types

Field Data Type
Date xs:date
Time xs:time
Type xs:string

In the real life scenario the Type field is calculated from a number of fields in the source schema. To keep this example focused I have hard coded the Type field using a String Concatenate functoid. The output of the Concatenate is an input parameter to a scripting functoid that builds the Action destination element using an Xslt template. The value for the Type field could have been hardcoded in the scripting functoid but linking this way demonstrates parameter handling in an Xslt template.

biztalk-map-complete

So here we have a scripting funcoid (with the exclamation warning) containing inline C# code that consists of a singel FormatCurrentDateTime method.  This method has a single string parameter which will format the returned string.

public string FormatCurrentDateTime(string format)
{
    return DateTime.Now.ToString(format);
}

BizTalk adds the C# script in a block at the bottom of the xslt when the map is compiled. This can be seen by compiling the assembly containing maps, and using the Show all Files command in Visual Studio Solution Explorer to look at the corresponding .btm.cs file to see what has been added.
There is also a scripting functoid containing an xsl template. This template accepts a single parameter for the Type element. There are also two variables initialised by calling the FormatCurrentDateTime method passing in a string defining the format of the DATETIME returned.  Note the use of userCSharp: prefix on the method call.

<xsl:template name="mapActionTemplate">
    <xsl:param name="type" />
    <xsl:variable name="date" select="userCSharp:FormatCurrentDateTime('yyyy-MM-dd')"/>
    <xsl:variable name="time" select="userCSharp:FormatCurrentDateTime('HH:mm:ss')"/>
        <xsl:element name="Action">
            <xsl:attribute name="Type">
                <xsl:value-of select="$type" />
            </xsl:attribute>
            <Date>
                <xsl:value-of select="$date" />
            </Date>
            <Time>
                <xsl:value-of select="$time" />
            </Time>
        </xsl:element>
</xsl:template>

For additional information on maps see this series of articles on Bizbert.

Credit to the original article:
Useful Cheat Code in Mapping (Calling C# code from XSLT) « BizTalk Server Tutorial