If you’ve done any amount of web forms development, you certainly couldn’t live without controls like the Repeater or ListView (although some might argue that the ListView control replaces the Repeater control). I had an interesting feature I was developing that ended up with a Repeater control containing a nested user control of sorts.

I had a couple goals in mind. The first was to be able to render some of the bound data straight to the Repeater control, the more typical usage pattern. The second was to be able to pass along some of the bound data to a nested user control within the Repeater. I’ve simplified the concept below:

<asp:Repeater ID="ProfileRepeater" runat="server" OnItemDataBound="ProfileRepeater_ItemDataBound">
	<ItemTemplate>
		<div>
			<%# Eval("Name") %>'s Profile
			<CBControls:Profile ID="UserProfile" runat="server" />
		</div>
	</ItemTemplate>
</asp:Repeater>

With the UI markup clarified above, the databinding was a fairly typical setup leveraging an anonymous type as follows:

protected void Page_Load(object sender, EventArgs e)
{
		//Retrieving all profiles from our hypothetical data provider
		IEnumerable<Profile> profileData = Profile.GetAll();

		//Binding the profiles to our UserProfile control
		UserProfile.DataSource = profileData
			.Select(data => new {
				Name = data.firstName + " " + data.lastName,
				Age = data.age,
				Location = data.location,
				Hometown = data.hometown
			});

		UserProfile.DataBind();
}

So the idea was to bind, say the “Name” to the Repeater, but I wanted the rest of the data (“Age”, “Location” and “Hometown”) to be consumed by the nested user control. The key to accomplishing this is via the OnItemDataBound event, as specified above in the markup. The implementation for this is as follows:

protected void ProfileRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
	if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
	{
		Profile ctrl = e.Item.FindControl("UserProfile") as Profile;

		if (ctrl != null)
		{
			//.NET 3.5 Solution
			ctrl.Age = DataBinder.Eval(e.Item.DataItem, "Age");
			ctrl.Location = DataBinder.Eval(e.Item.DataItem, "Location");
			ctrl.Hometown = DataBinder.Eval(e.Item.DataItem, "Hometown");

			//.NET 4.0 Solution using the new "dynamic" keyword to assist with anonymous type passing
			dynamic currentProfileData = e.Item.DataItem as dynamic;
			ctrl.Age = currentProfileData.Age;
			ctrl.Location = currentProfileData.Location;
			ctrl.Hometown = currentProfileData.Hometown;
		}
	}
}

You’ll notice I have provided both the .NET 3.5 and .NET 4.0 solutions for how one would go about this. In my particular case, the project is leveraging .NET 3.5, but if this were .NET 4.0, things could be accomplished slightly more elegantly using the “dynamic” keyword.

Regardless of which framework you’re using, as the method depicts, it is here where we are passing along the data to the nested user control by assigning it to the controls exposed properties. For those of you who prefer to strongly type everything, you’d simply replace the “dynamic” keyword with your own type (the same type that you would project your databinding to in Page_Load) and you’d be good to go!

There’ve been numerous times I’ve been involved with projects where there was a need for dynamically generating email content and sending it on its way.  Throughtout these projects, I’ve seen various different approaches to solving this business need, some of which include:

  1. Shoving markup within resource files with token placeholders such as “@@FirstName@@”, followed by a round of regular expression replacing throughout before sending.
  2. Using the more recent T4 text templates, which I personally found to be rather cumbersome for such a simple concept.  These might be more useful for non-webby types of needs.
  3. A varied flavor of #1, but replace resource file with database table (don’t ask).

Needless to say I was recently faced with a project in need of such a task.  In this particular situation, I had wired up some front-end logic to quietly call a WCF web service via jquery through ajax.  I thought about some alternatives for generating the final email output that would lend themselves to be both flexible yet lightweight and came up with a nifty compromise that works excellently.  Please keep in mind that I’ve trimmed some aspects of the code down, as not to divulge project-specific information but the core concepts are present.

Code within WCF service

//Creating an instance of a basic page and adding our emailTemplate control to it
Page page = new Page();
EmailTemplate emailTemplate = (EmailTemplate)page.LoadControl("/UserControls/General/EmailTemplate.ascx");

//Setting data within our emailTemplate
emailTemplate.FromName = fromNameClean;
emailTemplate.GroupName = groupNameClean;
//......

//Telling our control to bind the data to its view layer
emailTemplate.BindData();

//Retrieving the final rendered markup from our control (body of the email in HTML format)
string body = emailTemplate.RenderControl();

Code for our custom extention method RenderControl()

/// <summary>
/// Provides an overload for web controls to return the html representation of the final rendered output in string format.
/// </summary>
public static string RenderControl(this Control control)
{
	StringBuilder sb = new StringBuilder(); 

	using (StringWriter sw = new StringWriter(sb))
		using (HtmlTextWriter tw = new HtmlTextWriter(sw))
			control.RenderControl(tw); 

	return sb.ToString();
}

Code for our EmailTemplate user control code behind

public partial class EmailTemplate : System.Web.UI.UserControl
{
	public void BindData()
	{
		fromName.Text = FromName;
		groupName.Text = GroupName;
		//......
	}

	public string FromName
	{
		get
		{
			return _fromName;
		}
		set
		{
			_fromName = value;
		}
	}

	private string _fromName;

	public string GroupName
	{
		get
		{
			return _groupName;
		}
		set
		{
			_groupName = value;
		}
	}

	private string _groupName;
}

For my more astute readers, you might have noticed that there’s no page lifecycle methods in our user control, as there’s really no need since this user control is being treated very similarly to the MVC view model construct, albeit slightly varied due to the nature of web forms.

As for the markup layer of our EmailTemplate control, there’s nothing particularly special to notate, just some basic html with your server controls you plan on binding your data to.

Some of the benefits to this approach that come to mind include:

  1. Extremely low overhead in terms of code.
  2. Ability to adjust markup without rebuilding your code (compared to solutions such as resource files), unless of course your changes include additional dynamic data that needs binding.
  3. Ease of understanding across developers, as the email templates are represented as simple light-weight user controls.

Cheers,
Chris