Tales from the Evil Empire

Bertrand Le Roy's blog

News


Bertrand Le Roy

BoudinFatal's Gamercard

Tales from the Evil Empire - Blogged

Blogs I read

My other stuff

Archives

April 2010 - Posts

What happens to C# 4 optional parameters when compiling against 3.5?

Here’s a method declaration that uses optional parameters:

public Path Copy(
Path destination,
bool overwrite = false,
bool recursive = false)

Something you may not know is that Visual Studio 2010 will let you compile this against .NET 3.5, with no error or warning.

You may be wondering (as I was) how it does that. Well, it takes the easy and rather obvious way of not trying to be too smart and just ignores the optional parameters. Well, actually optional parameters have always existed in VB.NET (and thus also in the CLR), it's just that C# has not been supporting them so far. So that code will compile to an optional parameter as they have existed for a while. For example, the overwrite parameter will have an Optional atribute and a DefaultParameterValue(false) attribute. Note that you could have added those attributes with previous versions of C#, it's just that the syntax was not that nice.

To summarize, if you target 3.5, Visual Studio will make your optional parameters usable from VB and any language that supports optional parameters. But if you are using C# 3.5 the above code is equivalent to:

public Path Copy(
Path destination,
bool overwrite,
bool recursive)

The parameters are not optional (no such thing in C# 3), and no overload gets magically created for you.

If you’re building a library that is going to have both 3.5 and 4.0 versions, and you want 3.5 users to have reasonable overloads of your methods, you’ll have to provide those yourself, which means that providing a version with optional parameters for the benefit of 4.0 users is not going to provide that much value…

Providing all of the following overloads will compile against both 3.5 and 4.0:

public Path Copy(Path destination)
public Path Copy(Path destination, bool overwrite)
public Path Copy(
Path destination,
bool overwrite = false,
bool recursive = false)

UPDATE: as several readers have pointed out, what I wrote was not quite accurate and the compiler does output an optional parameter even when targeting C# 3.5, it's just that C# 3.5 will not be able to take advantage of that extra information. I updated the post to reflect that. Thanks to all who exposed the error.

RSS feeds in Orchard

(c) Bertrand Le Roy When we added RSS to Orchard, we wanted to make it easy for any module to expose any contents as a feed. We also wanted the rendering of the feed to be handled by Orchard in order to minimize the amount of work from the module developer.

A typical example of such feed exposition is of course blog feeds.

We have an IFeedManager interface for which you can get the built-in implementation through dependency injection. Look at the BlogController constructor for an example:

public BlogController(
IOrchardServices services,
IBlogService blogService,
IBlogSlugConstraint blogSlugConstraint,
IFeedManager feedManager,
RouteCollection routeCollection) {

If you look a little further in that same controller, in the Item action, you’ll see a call to the Register method of the feed manager:

_feedManager.Register(blog);

This in reality is a call into an extension method that is specialized for blogs, but we could have made the two calls to the actual generic Register directly in the action instead, that is just an implementation detail:

feedManager.Register(blog.Name, "rss",
new RouteValueDictionary {
{ "containerid", blog.Id } }); feedManager.Register(blog.Name + " - Comments", "rss",
new RouteValueDictionary {
{ "commentedoncontainer", blog.Id } });

What those two effective calls are doing is to register two feeds: one for the blog itself and one for the comments on the blog. For each call, the name of the feed is provided, then we have the type of feed (“rss”) and some values to be injected into the generic RSS route that will be used later to route the feed to the right providers.

This is all you have to do to expose a new feed. If you’re only interested in exposing feeds, you can stop right there. If on the other hand you want to know what happens after that under the hood, carry on.

What happens after that is that the feedmanager will take care of formatting the link tag for the feed (see FeedManager.GetRegisteredLinks). The GetRegisteredLinks method itself will be called from a specialized filter, FeedFilter. FeedFilter is an MVC filter and the event we’re interested in hooking into is OnResultExecuting, which happens after the controller action has returned an ActionResult and just before MVC executes that action result. In other words, our feed registration has already been called but the view is not yet rendered. Here’s the code for OnResultExecuting:

model.Zones.AddAction("head:after", 
html => html.ViewContext.Writer.Write(
_feedManager.GetRegisteredLinks(html)));

This is another piece of code whose execution is differed. It is saying that whenever comes time to render the “head” zone, this code should be called right after. The code itself is rendering the link tags.

As a result of all that, here’s what can be found in an Orchard blog’s head section:

<link rel="alternate" type="application/rss+xml"
    title="Tales from the Evil Empire"
    href="/rss?containerid=5" />
<link rel="alternate" type="application/rss+xml"
    title="Tales from the Evil Empire - Comments"
    href="/rss?commentedoncontainer=5" />

The generic action that these two feeds point to is Index on FeedController. That controller has three important dependencies: an IFeedBuilderProvider, an IFeedQueryProvider and an IFeedItemProvider.

Different implementations of these interfaces can provide different formats of feeds, such as RSS and Atom. The Match method enables each of the competing providers to provide a priority for themselves based on arbitrary criteria that can be found on the FeedContext.

This means that a provider can be selected based not only on the desired format, but also on the nature of the objects being exposed as a feed or on something even more arbitrary such as the destination device (you could imagine for example giving shorter text only excerpts of posts on mobile devices, and full HTML on desktop). The key here is extensibility and dynamic competition and collaboration from unknown and loosely coupled parts. You’ll find this pattern pretty much everywhere in the Orchard architecture.

The RssFeedBuilder implementation of IFeedBuilderProvider is also a regular controller with a Process action that builds a RssResult, which is itself a thin ActionResult wrapper around an XDocument.

Let’s get back to the FeedController’s Index action.

After having called into each known feed builder to get its priority on the currently requested feed, it will select the one with the highest priority.

The next thing it needs to do is to actually fetch the data for the feed. This again is a collaborative effort from a priori unknown providers, the implementations of IFeedQueryProvider. There are several implementations by default in Orchard, the choice of which is again done through a Match method. ContainerFeedQuery for example chimes in when a “containerid” parameter is found in the context (see URL in the link tag above):

public FeedQueryMatch Match(FeedContext context) {
    var containerIdValue = 
context.ValueProvider.GetValue("containerid"); if (containerIdValue == null) return null; return new FeedQueryMatch {
FeedQuery = this, Priority = -5 }; }

The actual work is done in the Execute method, which finds the right container content item in the Orchard database and adds elements for each of them. In other words, the feed query provider knows how to retrieve the list of content items to add to the feed.

The last step is to translate each of the content items into feed entries, which is done by implementations of IFeedItemBuilder. There is no Match method this time. Instead, all providers are called with the collection of items (or more accurately with the FeedContext, but this contains the list of items, which is what’s relevant in most cases). Each provider can then choose to pick those items that it knows how to treat and transform them into the format requested.

This enables the construction of heterogeneous feeds that expose content items of various types into a single feed. That will be extremely important when you’ll want to expose a single feed for all your site.

So here are feeds in Orchard in a nutshell. The main point here is that there is a fair number of components involved, with some complexity in implementation in order to allow for extreme flexibility, but the part that you use to expose a new feed is extremely simple and light: declare that you want your content exposed as a feed and you’re done.

There are cases where you’ll have to dive in and provide new implementations for some or all of the interfaces involved, but that requirement will only arise as needed. For example, you might need to create a new feed item builder to include your custom content type but that effort will be extremely focused on the specialized task at hand. The rest of the system won’t need to change.

So what do you think?

Netbook vs. iPad

(c) Bertrand Le Roy 2010 Troll bait!

Scott Watermasysk posted a piece this morning that to me sounds like another attempt to rationalize the act of buying one more overpriced shiny gadget from Apple: http://scottw.me/post/498411986/ipad-v-netbook.

It also seems like Scott is basing his opinion on the netbooks that were available two years ago. There are now amazingly powerful computers in this format, which makes for a great experience in the exact circumstances that the iPad is designed for. In other words, I think Scott’s post would have made some sense if Apple had shipped its tablet two years ago.

As Scott’s blog for some reason doesn’t have comments on, I thought I’d plagiarize him here :)

Another personal angle on the netbook vs. iPad thing.

The iPad is all about compromise. It is just like a normal iPhone except it’s a lot more expensive, you won’t get 3G unless you fork an additional hundred bucks and it won’t fit in your pocket. Just like its little brother, it doesn’t have a keyboard, it’s riddled with DRM (no app will make it if it isn’t approved by Apple on completely arbitrary criteria), it doesn’t support Flash or multitasking (so no streaming Pandora while reading e-mail), etc. If you were to build a dream laptop, there is absolutely nothing in an iPad you would want today.

The modern multitouch netbooks are about doing things well. They draw a line in the sand on what you should be able to do today. A notebook can talk and it could very well tell you:

There are no tasks I cannot complete. I am not going to force you to complete them in a half ass way. You’ll have a great, unconstrained experience that will leave you happy and satisfied. If this bothers you, please go and buy Apple’s crippled product. You will not be happier (it’s a freaking bunch of electronics, go out and meet people), but you might resent it in the morning when the excitement dies down and the RDF dissipates.

Kidding aside, modern notebooks represent a different take on both casual and temporary business computing. I love the experience and would rather see Apple try to do something bold and different than follow in the drab foot steps of the TabletPC and the iPod Touch.

But I work for Microsoft, so every thing I say is biased :)

Ban HTML comments from your pages and views

Too many people don’t realize that there are other options than <!-- --> comments to annotate HTML. These comments are harmful because they are sent to the client and thus make your page heavier than it needs to be.

Replacing client comments with server comments.When doing ASP.NET, a simple drop-in replacement is server comments, which are delimited by <%-- --%> instead of <!-- -->. Those server comments are visible in your source code, but will never be rendered to the client.

Here’s a simple way to sanitize a web site. From Visual Studio, hit CTRL+H to bring the search and replace dialog.

Choose “Replace in Files” from the second menu on top of the dialog. Open the find options, check “use” and make sure “Regular expressions” are selected. Use “*.aspx;*.ascx;” as the file types to examine. Choose “Entire Solution” under “Look in”.

Here’s the expression to search for comments:

\<!--{[^-]*}--\>

And here’s the replacement string:

<%--\1--%>

I usually use the “Find Next” and “Replace” buttons rather than the more brutal “Replace All” in order to not apply the fix blindingly. Once this is done, I do a second manual pass of finds with the same expression to make sure I didn’t miss anything.

More Posts