Archive

Archive for February, 2011

Using Web Forms user controls in an ASP.NET MVC project

February 28, 2011 14 comments

We have an existing ASP.NET Web Forms project that we’re in the process of slowly converting to ASP.NET MVC. We do not have the manpower to simply rewrite the entire website from scratch, so one of our goals is to slowly convert the website piece by piece. This means that the existing Web Forms project will need to coexist with emerging MVC project.

In the current Web Forms project, we have a number of user controls that are used on all our pages. In order to maintain backwards compatibility with our Web Forms pages, we couldn’t rewrite the controls as MVC helpers without having to duplicate code.

I created this helper that allows us to reuse Web Forms user controls on views:

public static class UserControlHelper
{
    public static HtmlString RenderControl<T>(this HtmlHelper helper, string path)
        where T : UserControl
    {
        return RenderControl<T>(helper, path, null);
    }
 
    public static HtmlString RenderControl<T>(this HtmlHelper helper, string path, Action<T> action)
        where T : UserControl
    {
        Page page = new Page();
        T control = (T)page.LoadControl(path);
        page.Controls.Add(control);
 
        if (action != null)
            action(control);
 
        using (StringWriter sw = new StringWriter())
        {
            HttpContext.Current.Server.Execute(page, sw, false);               
            return new HtmlString(sw.ToString());
        }
    }
}

By instantiating a Page and adding the user control to it, we can render the result as a string. To use the helper on a view, we can call it like this:

@(Html.RenderControl<MyCustomControl>("~/Test/MyCustomControl.ascx"))

The entire method call needs to be surrounded with parentheses, otherwise the angle brackets will confuse the Razor view engine. If the user control has properties that need to be set, we can call the method overload and pass it an expression:

@(Html.RenderControl<MyCustomControl>("~/Test/MyCustomControl.ascx", x => x.Name = "Malvin"))
 
@(Html.RenderControl<MyCustomControl>("~/Test/MyCustomControl.ascx", x =>
    {
        x.Name = "Malvin";
        x.Age = 25;
    }))

Razor declarative helpers

February 28, 2011 2 comments

I’m currently converting an old ASP.NET MVC 2 project to MVC 3. In my MVC 2 project, I created HTML helpers to generate small bits of HTML.

public static HtmlString SampleHtmlHelper(this HtmlHelper helper, string input)
{
    string result = "<div>";
    result += "<p>Current time: " + DateTime.Today.ToShortDateString() + "</p>";
    result += "<p>Input: " + input + "</p>";
    result += "</div>";
     
    return new HtmlString(result);
}

These helper classes would reside in a Helpers folder that I create.

To use the helper, I’d call it in a view like this:

<h2>Demo</h2>
 
@Html.SampleHtmlHelper("hello world")]

ASP.NET MVC 3 with the Razor view engine introduces a new way of creating declarative helpers that allows me to take advantage of the Razor syntax instead of appending strings together.

@helper SampleHelper(string input)
{
    <div>
        <p>Current date: @DateTime.Today.ToShortDateString()</p>
        <p>Input: @input</p>
    </div>
}

This helper would be placed in a view page in the App_Code folder.

I can treat each helper as a static method based on the view page name:

<h2>Demo</h2>
 
@Demo.SampleHelper("hello world")

I can convert most of my older HTML helpers to declarative helpers, but I’ve come across cases where I needed to continue creating helpers in code. I find that helpers that contain a lot of logic do not fit well with the Razor syntax.

public static HtmlString SampleHtmlHelper<TModel, TReturn>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TReturn>> expression)
    where TModel : class
{
    MemberExpression memberExpression = GetMemberExpression(expression);
    string name = memberExpression == null ? null : memberExpression.Member.Name;
 
    Func<TModel, TReturn> function = expression.Compile();
    TReturn value = function(helper.ViewData.Model);
 
    string result = "<div>";
    result += "<p>" + name + ": " + value + "</p>";
    result += "</div>";
 
    return new HtmlString(result);
}

Being able to leverage the Razor syntax for helpers is a real bonus. I don’t see a need to use partial views anymore. When I needed to decide whether to use a helper or a partial view, it would be determined by how much markup I needed to generate. I would typically use a HTML helper if the amount of markup wasn’t a burden or if it contained logic. But with the new declarative helpers, this isn’t an issue anymore. Are there any benefits that a partial view has over declarative helpers?

Strongly typed dictionaries

February 28, 2011 2 comments

I recently stumbled across the DictionaryAdapter component, which is part of the Castle Project. Some of the issues with storing settings in a centralized configuration file is that you’ll typically need to access these values using magic strings and receive back untyped data.

<appSettings>
  <add key="MyFile" value="C:\temp\file.txt" />
  <add key="NumberOfItems" value="23" />
  <add key="SomeReallyLongAndUglyItemName" value="hello world" />
</appSettings>

The DictionaryAdapter solves these issues by creating a strongly typed wrapper around these key/value stores or dictionaries. We simply create an interface that matches what we expect to receive back:

public interface IApplicationConfiguration
{
    string MyFile { get; set; }
    int NumberOfItems { get; set; }

    [Key("SomeReallyLongAndUglyItemName")]
    string HelloText { get; set; }
}

NumberOfItems is now strongly typed and the property HelloText maps to the key SomeReallyLongAndUglyItemName.

DictionaryAdapterFactory factory = new DictionaryAdapterFactory();
var config = factory.GetAdapter<IApplicationConfiguration>(ConfigurationManager.AppSettings);

Console.WriteLine(config.MyFile);
Console.WriteLine(config.NumberOfItems);
Console.WriteLine(config.HelloText);

The default convention matches the name of the property of the interface to the key in the dictionary. There are various attributes that are available that allows you to map different keys to different properties.  For example, the Key attribute above allows you to map a property to an unrelated key in the dictionary. More information on attributes can be found on the Castle Project wiki.

Using the DictionaryAdapter to create strongly typed wrappers for configuration allows my tests that are dependent on these dictionaries to be more flexible.

var stub = MockRepository.GenerateStub<IApplicationConfiguration>();
stub.Stub(x => x.HelloText).Return("woot");

IDictionary from anonymous type

February 28, 2011 8 comments

In ASP.NET MVC, we can specify what attributes appear on our HTML elements by passing an anonymous type as an argument.

@Html.TextBox("my-textbox", "hello world", new { @class = "css-class", custom = "custom" })

In this example, we’re specifying that the input element will have a class attribute and a custom attribute when rendered.

Inspired by this, I needed a way to convert an anonymous type to an IDictionary<string, object>. I created this extension method that allows an object to be converted to a dictionary.

public static class ExtensionMethods
{
    public static IDictionary<string, object> ToDictionary(this object data)
    {
        BindingFlags publicAttributes = BindingFlags.Public | BindingFlags.Instance;
        Dictionary<string, object> dictionary = new Dictionary<string, object>();

        foreach (PropertyInfo property in data.GetType().GetProperties(publicAttributes))
        {
            if (property.CanRead)
                dictionary.Add(property.Name, property.GetValue(data, null));
        }

        return dictionary;
    }
}

This extends the object type and adds a ToDictionary extension method.

var anonymous = new { First = "John", Last = "Doe" };
IDictionary<string, object> dictionary = anonymous.ToDictionary();

Alternately, if we’re working in an ASP.NET MVC project, we can use RouteValueDictionary to convert an anonymous type to a dictionary.

var anonymous = new { First = "John", Last = "Doe" };
RouteValueDictionary dictionary = new RouteValueDictionary(anonymous);

string firstName = dictionary["First"].ToString();
string lastName = dictionary["Last"].ToString();

Invalid SSL certificate

February 28, 2011 1 comment

While trying to invoke a web service in one of my development environments, I received this exception:

Could not establish trust relationship for the SSL/TLS secure channel.

There are a number of reasons why this may happen, but in my particular case I was using a self-signed SSL certificate for testing. To bypass the invalid certificate for testing, we can replace the certificate validation with our own:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

This implementation returns true, regardless if the certificate is valid or not.  One thing to keep in mind is that this setting will affect all subsequent requests from the current application domain.

Hello World

February 28, 2011 7 comments
Console.WriteLine("Hello World");