FormatException inside the PortableAreaMap of MvcContrib

Friday, November 18, 2011

Portable Areas are a powerful feature of MvcContrib and provide a solution to distribute MVC areas as assemblies. Which is handy for a lot of things. This post is not about that, but a tiny bug we found this week at work. At our client we still use version 2.0.96.0 of MvcContrib but it appears to be still a problem in the latest version 3.0.51.0.

When working with masterpages most of the time you will want to use the master of the host to be used as the master of all embedded views. I will not go into detail on how to accomplish this (see examples on the web). The code performing the mapping of the views with the master pages results in a exception when using curly braces inside your view (i.e. for loop). If you do you will get a FormatException like below:

Input string was not in a correct format.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.FormatException: Input string was not in a correct format.
Source Error:

Line 59: 			Stream newStream = new MemoryStream(result.Length);
Line 60: 			StreamWriter writer = new StreamWriter(newStream);
Line 61: 			writer.Write(result, 0, result.Length);
Line 62:             
Line 63: 			writer.Flush();

Source File: …\MVCContrib.source\src\MVCContrib\PortableAreas\PortableAreaMap.cs Line: 61
Stack Trace:

[FormatException: Input string was not in a correct format.]
   System.Text.StringBuilder.AppendFormat(IFormatProvider provider, String format, Object[] args) +9354495
   System.String.Format(IFormatProvider provider, String format, Object[] args) +107
   System.IO.TextWriter.Write(String format, Object arg0, Object arg1) +78
   MvcContrib.PortableAreas.PortableAreaMap.Transform(Stream stream) in C:\Users\mbu13564\Downloads\…
   MvcContrib.UI.InputBuilder.ViewEngine.AssemblyResourceStore.GetResourceStream(String resourceName) in ….
   MvcContrib.UI.InputBuilder.ViewEngine.AssemblyResourceVirtualFile.Open() in C:\Users\mbu13564\Downloads\…
   more..

The exception is thrown because of the use of the wrong write method of the streamwriter class. This write method uses the string.format method which treats curly braces as special characters. As a workaround for this scenario you can use double curly braces which is nasty but works.

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Dummy.Master" Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Home Dummy Title
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <% for (int i = 0; i < 10; i++) {{ %>
       loop <%=i%><br />
    <% }} %>
</asp:Content>

Of course this doesn't work for every scenario so it's beter to fix the problem in the source by choosing a other write method of the streamwriter class. This is simply done by adding .ToCharArray() to the result string inside the Transform method of the PortableAreaMap class.

using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;

namespace MvcContrib.PortableAreas
{
	public class PortableAreaMap
	{
		//other code
		public Stream Transform(Stream stream)
		{
			string result = string.Empty;

			using (StreamReader reader = new StreamReader(stream))
			{
				result = TransformMarkup(reader.ReadToEnd());
			}

			Stream newStream = new MemoryStream(result.Length);
			StreamWriter writer = new StreamWriter(newStream);
			writer.Write(result.ToCharArray(), 0, result.Length);
            
			writer.Flush();
			newStream.Position = 0;
			
			return newStream;
		}
		//other code
      }
}

After doing some research this bug was already mentioned on January 27th of this year, but still has to be fixed. I will upvote this defect so hopefully this will be fixed in a next release. In the meantime use the dirty workaround or fix it yourself.

Comments (3) -

Peter BNetherlandsPeter B said:

So now we are even talking to each other in weekends, hmm... Wink

The workaround sure isn't pretty, but even worse is that the original problem returns as soon as the "Auto Format Document" function of Visual Studio does its job, putting a line break between every pair of double curlies... Had that happen already!

So fixing source is definitely the only way to go.

Martijn BurgersNetherlandsMartijn Burgers said:

@PeterB I don't mind Smile. In case of the example of the for loop you're right. When formatting the document it could breakup things again. But in case you use a curly brace as a literal there is no problem using the workaround.

Peter BNetherlandsPeter B said:

A better & even simpler solution is:
writer.Write(result);

This prevents the extra "copy" operation that ToCharArray() would cause.

The 0 and .Length parameters aren't needed. In the original version they are even to blame for the problem; the author believed that they were necessary, but in doing so ended up calling this method: "public virtual void Write(string format, object arg0, object arg1);" from (abstract class) TextWriter - which, as it's parameter names imply, does Format things with the curlies.

Comments are closed