Archives
-
FormatWith 2.0 - String formatting with named variables
The problem with string formatting is that {0}, {1}, {2}, etc, aren't very descriptive. Figuring out what the numbers represent means either deducing their values from their usage context in the string or examining the arguments passed to String.Format. Things become more difficult when you are working with a format string stored in an external resource as the second option no longer available.
FormatWith 2.0
I have updated the original FormatWith with an overload that takes a single argument and allows the use of property names in the format string.
MembershipUser user = Membership.GetUser();
Status.Text = "{UserName} last logged in at {LastLoginDate}".FormatWith(user);
It also works with anonymous types:
"{CurrentTime} - {ProcessName}".FormatWith(new { CurrentTime = DateTime.Now, ProcessName = p.ProcessName });
And even allows for sub-properties and indexes:
var student = new
{
Name = "John",
Email = "john@roffle.edu",
BirthDate = new DateTime(1983, 3, 20),
Results = new[]
{
new { Name = "COMP101", Grade = 10 },
new { Name = "ECON101", Grade = 9 }
}
};
Console.WriteLine("Top result for {Name} was {Results[0].Name}".FormatWith(student));
// "Top result for John was COMP101"
There isn't much to the code itself. Most of the heavy lifting is done in a regular expression and the .NET DataBinder class.
To start with a regular expression picks all the {Property} blocks out of the string. The the property expression inside the brackets is then evaluated using the DataBinder class on the object argument to get the property value. That value is then put into a list of values and the {Property} block is replaced in the string with the index of the value in the list, e.g. {1}. Finally the rewritten string, which now looks like any other format string, and the list of evaluated values are passed to String.Format.
public static string FormatWith(this string format, object source)
{
return FormatWith(format, null, source);
}
public static string FormatWith(this string format, IFormatProvider provider, object source)
{
if (format == null)
throw new ArgumentNullException("format");
Regex r = new Regex(@"(?<start>\{)+(?<property>[\w\.\[\]]+)(?<format>:[^}]+)?(?<end>\})+",
RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
List<object> values = new List<object>();
string rewrittenFormat = r.Replace(format, delegate(Match m)
{
Group startGroup = m.Groups["start"];
Group propertyGroup = m.Groups["property"];
Group formatGroup = m.Groups["format"];
Group endGroup = m.Groups["end"];
values.Add((propertyGroup.Value == "0")
? source
: DataBinder.Eval(source, propertyGroup.Value));
return new string('{', startGroup.Captures.Count) + (values.Count - 1) + formatGroup.Value
+ new string('}', endGroup.Captures.Count);
});
return string.Format(provider, rewrittenFormat, values.ToArray());
}
-
FormatWith - String.Format Extension Method
I have a love/hate relationship with String.Format.
On one hand it makes strings easier to read and they can easily be put in an external resource.
On the other hand every bloody time I want to use String.Format, I only realize when I am already halfway through writing the string. I find jumping back to the start to add String.Format is extremely annoying and that it breaks me out of my current train of thought.
FormatWith
FormatWith is an extension method that wraps String.Format. It is the first extension method I wrote and is probably the one I have used the most.
Logger.Write("CheckAccess result for {0} with privilege {1} is {2}.".FormatWith(userId, privilege, result));
An extension method with the same name as a static method on the class causes the C# compiler to get confused, which is the reason why I have called the method FormatWith rather than Format.
public static string FormatWith(this string format, params object[] args)
{
if (format == null)
throw new ArgumentNullException("format");
return string.Format(format, args);
}
public static string FormatWith(this string format, IFormatProvider provider, params object[] args)
{
if (format == null)
throw new ArgumentNullException("format");
return string.Format(provider, format, args);
}
Update:
You may also be interested in FormatWith 2.0.
-
Blog Redesign
If you regularly visit my blog (subscribe already!) you may have noticed the design has been updated.
Here is a comparison between the old and the new. Click for a bigger image:
I threw out the old design and started with a template called EliteCircle, which I have made some fairly substantial updates to. I was a little hesitant about changing the CSS too much, the last time I had done any serious CSS work was over two years ago, but everything ending up going smoothly.
Changes
The previous look was simple which I liked, but it was gradually getting overrun by tag and archive links. Tags are now displayed in a screen real estate efficient cloud, and archive links have been moved to a separate page.
The design is slightly wider. The previous design's minimum resolution was 800x600, which according to Google Analytics is used by just 0.3% of visitors these days. The new minimum resolution is now 1024x768. With the wider design I have increased the content text to match.
In the new design I have also removed a lot of what I think is unnecessary information from the blog. The focus of a blog should be the content. Details like what categories a post is in or exactly what time a comment was made aren't of interested to the average visitor and have been removed to reduce screen clutter.
Overall I am really happy with the new design and I think it is a big improvement over what was here before.
Obligatory
As always with a redesign, if you spot anything weird or broken, or just think something looks bad, let me know. Thanks!
-
Being A Microsoft Developer - Getting Harder Every Year
Intergenite Andrew Tokeley recently blogged about how a Microsoft developer has to know so much more to be considered a senior dev (or even intermediate!) compared to just 5 years ago.
This graph of the number .NET types in the framework made by Brad Abrams illustrates the point pretty well:
I started .NET development in 2003 with .NET 1.1. Fast forward to 2008 and the number of types in the .NET framework has tripled!
Remembering how overwhelmed I felt when I first approached .NET back in 2003, I can't imagine how a junior developer today must feel.
-
Silverlight 2.0 presentation
Thanks to everyone who came along to the Wellington Dot User Group meeting this evening for my presentation on Silverlight 2.0. We were close to standing room only, which is an indicator of the great interested within the local .NET community around Silverlight.
If you are interested in developing with Silverlight, then http://www.silverlight.net is the one stop shop to help you get started. Silverlight.net is the official Microsoft Silverlight website and it has the Silverlight runtime, tools, examples and an active community if you are in need of assistance.
Feedback on the presentation has been great and I hope everyone who attended feels ready to jump into the world of Silverlight development!
-
TextGlow Coverage Roundup
- www.textglow.com - The TextGlow press release displayed in TextGlow (+1 for recursiveness!)
Blog posts
- Intergen Blog - Announcing TextGlow - a world first from Intergen, NZ
- James Newton-King - Silverlight 2.0 + OOXML = TextGlow
- Chris Auld - Silverlight 2.0 + Office Open XML == TextGlow
- Tim Sneath - A Great Early Silverlight 2 Showcase: TextGlow
- Gray Knowlton - Silverlight viewer for Open XML
- Oliver Bell - New Zealand’s Intergen Deliver OpenXML Viewing Using Silverlight
- Gavin Barron - Intergenite delivers in browser viewer for docx
Videos
- YouTube - Intergen TextGlow: Open XML Document (DOCX) in Silverlight
- VisitMIX - Straight from Word to Web without Office: Intergen
Radio (!?!)
- Radio NZ - This Way Up
NZ Media
- Computerworld - Intergen launches new software in Las Vegas
- Computerworld - MIX08 'fizzes' over Intergen applications
- InfoTech - Silverlight shed on Word docs
- Otago Daily Times - NZ company launches software in Las Vegas
- Geekzone - Intergen releases Office Open XML web application
(plus lots lots more from around the world)
-
Silverlight 2.0 + OOXML = TextGlow
Over the last couple of months I have had the opportunity to work on an exciting project called TextGlow.
TextGlow is a Silverlight 2.0 application for viewing Word 2007 documents on the Internet. With TextGlow it is possible to instantly view a document within a web page, with no Microsoft Office applications installed. Since Silverlight is cross platform the user doesn't even have to be running Windows!
How it Works
The first step to TextGlow displaying a document is going out and downloading it. TextGlow is a Silverlight application and runs completely client side, and that means it needs a local copy to work with. This process happens automatically using the new WebClient class in Silverlight 2.0. Like you would expect from a class called WebClient it provides simple web request, but what makes WebClient great are the download progress events it provides. Making a progress bar to show the status of a download is a snap.
Next the various files inside the document are extracted. An OOXML document (docx) is actually just a zip file containing XML and other resource files, such as any images that might appear in the document. Fortunately Silverlight has built in zip file support using the Application.GetResourceStream method.
Now that TextGlow has the OOXML it parses the XML and builds an object model of the document. To parse the XML I used LINQ to XML, which is new in Silverlight 2.0. After an initial learning curve (mainly suppressing the memory of many years of working with horrible DOM APIs [;)]), I found LINQ to XML to be wonderful to work with. I blogged about a couple of the cool features I discovered while working with LINQ to XML along the way.
Using the object model of the document TextGlow then creates WPF controls to display the content. Writing custom Silverlight WPF controls to render the content was definitely the hardest aspect of the project. When I started work on it with the Silverlight 1.1 Alpha there were no layout controls like StackPanel or Grid. Everything was absolutely position and I had to write my own flow layout controls. Paragraphs and complex flowing text was also surprisingly difficult to get right in Silverlight. Fortunatly Silverlight 2.0 includes controls like these and makes writing an application like TextGlow much easier.
The final step in display a document is simply WPF plying its magic and rendering the WPF controls. The user now has the Word 2007 document render on their screen using nothing but the power of Silverlight.
Thanks to...
TextGlow has be a great application to work on and it was awesome being able to design and build my own idea.
Thanks to Nas for mocking up the UI. If the UI was left up to me TextGlow would make Notepad look good [;)]
Big thanks to Chris Auld for providing a launch pad for the idea and then providing regular injections of enthusiasm into the project.
If you're interested in seeing more of TextGlow, visit www.textglow.com
Update:
-
The Paradox of Choice
I haven't read The Paradox of Choice but this talk by the author makes me want to.
Interesting!
-
Json.NET 2.0 Beta 2
I am really happy with how Json.NET 2.0 and LINQ to JSON is turning out. This release offers big improvements both in the syntax for writing JSON and querying JSON. I have also finally put in some real effort into fixing up some the niggling issues from previous versions of Json.NET.
Creating JSON Improvements
One of the suggestions I received from the first 2.0 beta was creating JSON objects from anonymous objects.
With LINQ to JSON it is now possible to do this:
JObject o = JObject.FromObject(new
{
channel = new
{
title = "James Newton-King",
link = "http://james.newtonking.com",
description = "James Newton-King's blog.",
item =
from p in posts
orderby p.Title
select new
{
title = p.Title,
description = p.Description,
link = p.Link,
category = p.Categories
}
}
});
Pretty neat. Using regular .NET objects is also possible.
The way it works is FromObject is just a wrapper over the JsonSerializer class and reuses its logic. The difference compared to regular serialization is that the serializer is writing to a JsonTokenWriter instead of a JsonTextWriter. These classes are both new in this release and inherit from the now abstract JsonWriter.
I think it is really cool the way LINQ to JSON, JsonWriter and JsonSerializer dovetail together here. Once JsonWriter had been split apart and I could plug in different JsonWriters into JsonSerializer depending upon what output I wanted, adding this feature took no time at all [:)]
Querying JSON Improvements
I felt the querying API in beta 1 was too wordy and explicit. Beta 2's is more concise and it should hopefully be easier to use.
Before:
var categories =
from c in rss.PropertyValue<JObject>("channel")
.PropertyValue<JArray>("item")
.Children<JObject>()
.PropertyValues<JArray>("category")
.Children<string>()
group c by c into g
orderby g.Count() descending
select new { Category = g.Key, Count = g.Count() };
After:
var categories =
from c in rss["channel"]["item"].Children()["category"].Values<string>()
group c by c into g
orderby g.Count() descending
select new { Category = g.Key, Count = g.Count() };
I am still putting some thought into this area but I think it is a definite improvement.
Deserializing Anonymous Types
It is now possible to deserialize directly to an anonymous type with the new DeserializeAnonymousType method. A new method was required because the only way I found to get access to type information about an anonymous type is to have is as an argument.
public static T DeserializeAnonymousType<T>(string value, T anonymousTypeObject)
{
return DeserializeObject<T>(value);
}
If there is a better way let me know!
Dates
Dates in JSON are hard.
The first issue is that there is no literal syntax for dates in the JSON spec. You either have to invent your own or break from the spec and use the JavaScript Date constructor, e.g. new Date(976918263055).
Historically Json.NET defaulted to using the JS Date constructor but in this release the default format has changed to using the approach taken by Microsoft. The "\/Date(1198908717056+1200)\/" format is conformant with the JSON spec, allows timezone information to be included with the DateTime and will make Json.NET more compatible with Microsoft's JSON APIs. Developers that want to continue to use the JavaScript Date constructor format of Json.NET 1.x, a JavaScriptDateTimeConverter has been added.
The second issue with dates in JSON (and also in .NET it turns out!) are timezones. I have never written an application that needed to worry about timezones before and I have learn't a lot of the past couple of days [:)]
Previously Json.NET was returning local ticks when it really should have been using UTC ticks. That has now been corrected.
Other miscellaneous Date changes in this release are another new date converter, IsoDateTimeConverter, which reads to and from the ISO 8601 standard (1997-07-16T19:20:30+01:00) and support for reading, writing and serializing the new DateTimeOffset struct.
Changes
All changes since the last release:
- New feature - Added FromObject to JObject, JArray for creating LINQ to JSON objects from regular .NET objects.
- New feature - Added support for deserializing to an anonymous type with the DeserializeAnonymousType method.
- New feature - Support for reading, writing and serializing the new DateTimeOffset type.
- New feature - Added IsoDateTimeConverter class. Converts DateTimes and DateTimeOffsets to and from the ISO 8601 format.
- New feature - Added JavaScriptDateTimeConverter class. Converts DateTimes and DateTimeOffsets to and from a JavaScript date constructor.
- New feature - XmlNodeConverter handles serializing and deserializing JavaScript constructors.
- New feature - Ability to force XmlNodeConverter to write a value in an array. Logic is controlled by an attribute in the XML, json:Array="true".
- New feature - JsonSerializer supports serializing to and from LINQ to JSON objects.
- New feature - Added Depth property to JsonReader.
- New feature - Added JsonTextReader/JsonNodeReader and JsonTextWriter/JsonNodeWriter.
- Change - More concise LINQ to JSON querying API.
- Change - JsonReader and JsonWriter are now abstract.
- Change - Dates are now serialized in a JSON complient manner, similar to ASP.NET's JavaScriptSerializer or WCF's DataContractJsonSerializer.
- Change - JsonSerializer will serialize null rather than throwing an exception.
- Change - The WriteTo method on LINQ to JSON objects now support JsonConverters.
- Fix - JsonTextReader correctly parses NaN, PositiveInfinity and NegativeInfinity constants.
- Fix - JsonSerializer properly serializes IEnumerable objects.
- Removed - AspNetAjaxDateTimeConverter. Format is no longer used by ASP.NET AJAX.
- Removed - JavaScriptObject, JavaScriptArray, JavaScriptConstructor. Replaced by LINQ to JSON objects.
Json.NET 2.0 Beta 2 Download - Json.NET source code and binaries