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

March 2011 - Posts

What happens when I request a page in Orchard?

(c) Bertrand Le RoyIf you look at a typical request for a page, the route will resolve the URL to the Display method of the ItemController in Orchard.Core/Routable/Controllers. That action will retrieve the content item for that route from the content manager and ask it to build the display. The ShapeResult it will produce is what is returned by the action.

Let's pause for a second here and mention that we'll get back in a moment to what really happened during that BuildDisplay call.

Now starts a second phase where that result gets executed and the shape tree starts getting rendered. One very important shape already exists at this point on the work context, and that is the Layout shape.

When the time comes to render the Layout shape, Orchard will look for the most specific template for it, which is usually found in the current theme. The template contains the rendering calls for the zones, looking like this:

@Zone(Model.Content)

Again, Orchard will look for the most specific way to render a Zone shape, which unless you overrode the template in your theme, is going to be a method on CoreShapes:

[Shape]
public void Zone(dynamic Display, dynamic Shape, TextWriter Output) {
    string id = Shape.Id;
    IEnumerable<string> classes = Shape.Classes;
    IDictionary<string, string> attributes = Shape.Attributes;
    var zoneWrapper = GetTagBuilder("div", id, classes, attributes);
    Output.Write(zoneWrapper.ToString(TagRenderMode.StartTag));
    foreach (var item in ordered_hack(Shape))
        Output.Write(Display(item));
    Output.Write(zoneWrapper.ToString(TagRenderMode.EndTag));
}

This code renders a div around the zone with an id and optionally some classes, and then moves to looping over contained shapes and calling Display on them.

In the case of the Content zone, remember that our controller action described what to inject. We have a Content shape there, which will be rendered by a Content.cshtml template. Part of that template is the definition of new nested local zones (Header, Meta, Content and Footer) defined by calls looking like this:

@Display(Model.Content)

What goes into these local zones was determined by what happened during that call to BuildDisplay that we mentioned earlier. Now is the time to get a closer look at what happened there.

The method (which you can find in DefaultContentDisplay) created the shape for the content item with a reference to the actual content item and some metadata such as the display type (Detail, Summary, etc.).

Then, it determined placement information, which typically comes from placement.info files. That information will help the system dispatch the part and field shapes into the local zones that Content.cshtml created.

Finally, we invoke all handlers in the system to give them a chance to participate in building the shape tree for this request.

This is when drivers can chime in and create a shape for the part they are responsible for. The Display method of the driver of each part in the content item will get called. The resulting shapes can then be added to the local zones under the content item's shape, according to placement information.

If we look into the shape tree using the new Shape Tracing feature from Orchard 1.1, here is what we see:What's in the Content Zone

All that remains to do now is render each of these shapes in order, using the most specific template for each.

And there you have it: a page got rendered by that controller action and then by all these disconnected drivers and templates. The resulting rendering system is both extremely flexible and extensible at will.

Taking over list rendering in Orchard

OooohA task that is likely to pop-up oftentimes when customizing an Orchard theme for a project is list rendering. Two types of shapes will typically be at work when rendering a list in Orchard: the summary shape and the list shape.

The list shape itself will rarely vary as the semantics of a list pretty much mandate the use of a simple UL/LI decorated with CSS classes. It's so simple in fact that it's not even rendered by a template but by a C# shape method in CoreShapes.cs.

The summary shapes can be rendered by templates that are specialized by content type and by display type. That covers most cases of list customization.

In a few rare cases though, you'll want to simply take over the rendering of a specific list completely.

In my LIDNUG demo last Monday, I had changed the item summary template so that my blog post summaries would show a little richer than the default template:A customized summary template

This caused the recent posts widget to also change appearance, and not in a good way, because it's using the same default summary template:The summary template affects recent posts.

All we really want in there is a link to the post. At this point, I could have changed the code of the widget so that it would use a different display type, or I could just take over rendering. I opted for the latter. Let's look at the Parts.Blogs.RecentBlogPosts.cshtml template that I put into my theme's Views folder…

The template is extremely simple once you've got hold of the list of posts. The code for this is a little weird, admittedly:

IEnumerable<object> blogPosts = Model.ContentItems.ContentItems;

Model here is the widget's shape. It has a ContentItems property, which really is a List shape. The list shape itself has a ContentItems property and that last one is the actual list of blog posts. Once we have this, we just need to loop over the posts and display a simple link for each of them:

<ul class="content-items">
@foreach (dynamic post in blogPosts) {
    string title = post.Title;
    ContentItem item = post.ContentItem;
    <li class="content-item-summary">
@Html.ItemDisplayLink(title, item)
</li> } </ul>

Here's the full template code:

@using Orchard.ContentManagement;
@{
    IEnumerable<object> blogPosts =
Model.ContentItems.ContentItems; } @if (blogPosts == null || blogPosts.Count() < 1) { <p>@T("No posts.")</p> } else { <ul class="content-items"> @foreach (dynamic post in blogPosts) { string title = post.Title; ContentItem item = post.ContentItem; <li class="content-item-summary">
@Html.ItemDisplayLink(title, item)
</li> } </ul> }

And here's the result:Neat and clean

I hope this helps.

Dispatching Orchard shapes to arbitrary zones

(c) Bertrand Le Roy 2011In my LIDNUG demo last week, I showed an interesting technique that I know some people will want to apply to their own stuff.

The scenario is that you want the main content being displayed on the page to render parts of itself outside of the Content zone, typically in a sidebar zone.

My own example was a Buy From Amazon part that displays a badge in the sidebar to enable readers to buy the book being reviewed:The Buy From Amazon part gets displayed in the side bar.

Usually, zones contain widgets, but zones are just shapes, and they can contain any nested shape, not just widgets. Here is the shape we are building from our driver:

var shape = shapeHelper.Parts_BuyFromAmazon(
        ProductSku: part.ProductSku,
        AssociateAccount: accountSettings.AssociateAccount,
        BackgroundColor: accountSettings.BackgroundColor,
        TextColor: accountSettings.TextColor,
        LinkColor: accountSettings.Linkcolor,
        Width: accountSettings.Width,
        Height: accountSettings.Height,
        ContentItem: part.ContentItem);

Nothing fancy here. In order to send that shape to the sidebar, all we need is a reference to the current work context in our part driver. This is easily obtained by injecting a dependency to IWorkContextAccessor.

Once this is done, we can just get the layout shape from the work context, and then access its zones. Once we have the right one, we can add our shape to it:

_workContextAccessor.GetContext()
    .Layout.Zones[zone]
    .Add(shape, position);

Finally, we return an empty driver result rather than the shape, so nothing gets rendered in place:

return new DriverResult();

When the zone where we sent the shape is going to render, our shape will get resolved to a template exactly like a widget would. For all practical purposes, this is like a local widget that your content item gets to create and control.

Driving a LED matrix from a Netduino one more time: The Right Way

Driving a LED matrix with a Maxim 7219In previous posts, we've seen two ways one can drive a small LED matrix from a Netduino.

The first time, we just turned the rows and columns of the matrix on and off using digital ports on the Netduino. With this method, we have great control for sure, but it's no good for the following reasons.

It's very slow: the digital ports on the microcontroller don't switch very fast.

What kills it though is that we don't have enough digital ports on the Netduino: for an 8x8 matrix, you would need 16 ports and we only have 14. not to mention the final system we're building will need some ports for other things than display.

With the second and third posts, we used a shift register. The way you talk to a shift register is that you send it data on a serial channel and it will dispatch that data to its output ports. In other words, it trades ports for time, effectively demultiplexing data and multiplying the number of available ports.

The rows in this version were still addressed by individual digital ports on the Netduino. We would scan each line in turn and send the columns to light up for that line to the shift register. Do it fast enough and persistence of vision will make you see a relatively stable image.

This worked well enough, and we wrote some interesting drawing APIs for it, but as we started asking the Netduino to handle more than refreshing the display, we started to see frames drop.

The whole thing was a very useful learning experience, going from the lowest-level way to drive things, to what we're going to do today, which is quite more abstracted than what we started with, but performs admirably.

The solution we settled for, which is clearly The Right Way, is to use a LED driver such as a Maxim 7219 or 7221. Those neat little chips come for ten dollars a piece, which is not cheap, but they are worth every cent.

Those LED drivers do one thing and do it really well: send them data over the serial channel and let them deal with the rest. The driver we picked knows how to drive a 8x8 matrix so all you have to do is send it eight bytes of data every time you want to change what's displayed.

There is a little protocol to deal with as the chip has commands to send data but also commands for setting the display intensity or the display mode but nothing outlandish. In fact, using the driver enabled us to remove most of the low-level display code we were using.

For example, here is the code we need in order to send a screenful of data:

public void Display(byte[] matrix) {
    if (matrix.Length != 8) {
        throw new ArgumentOutOfRangeException("matrix");
    }
    var rowNumber = (byte)RegisterAddressMap.Digit0;
    foreach (var rowData in matrix) {
        Write(rowNumber, rowData);
        rowNumber++;
    }
}

It doesn't get any simpler than that. And it's screaming fast. Almost all of the processing power of the microcontroller can now be used to other tasks than managing the display.

We did hit a few bumps on our way there. The one that got us to scratch our heads in puzzlement the longest was that we noticed that after a while, our driver started to only display parts of the picture.

That was troubling because the driver has a command that does exactly that: crop the display to a fixed number of lines. But here's the thing: we were never calling that command. At all.

This is where hardware requires a lot more experimental method than software: you have to consider every possibility, even unknown failures and random deviations from the spec.

What we did to find what was going wrong is that we looked at the binary codes for the commands we were sending and compared them with the code for the ghost command that was seemingly arriving to the driver. We found that the command to set the intensity of the display was differing by only one bit. Somewhere along the way, that bit was getting lost, one time out of several thousand. But as the cropping command is lasting, the effect of a small error was persisting until the next error. Like a mutation.

Once we determined that and proved that this was effectively what was happening by trying the same demo without the intensity command, we still had to find what was losing the bit. We did that by isolating variables, like one should but we got lucky as the first thing we tried was it.

It happened that we had a small circuit between the Netduino and the Maxim that we added because the Netduino's ports are 3.3V and the Maxim is accepting 5V, with a minimum specified of 3.5V. That circuit is a logic level converter that just takes care of converting digital signals from one voltage to another. Well, it seems like once in a rare while, it loses some bits.

We removed the circuit and tried to see if the Maxim would be OK with 3.3V. Both of those we tried were quite happy with it.

You can follow our progress on our Codeplex project:
http://netduinohelpers.codeplex.com/

Fabien has some more details about using the Maxim driver:
http://fabienroyer.wordpress.com/2011/03/13/using-a-max7219max7221-led-display-driver-with-a-netduino/

My Orchard talk for LIDNUG

The finished site's home pageI just finished speaking at LIDNUG. You can download the recording here:

http://www.lidnug.org/archives.aspx

I hope I can make that available for streaming somewhere in the near future or maybe even reformat the content into shorter screencasts but this will do for now.

I had prepared a metric ton of contents for the presentation and of course I wasn't able to show everything. I'm glad that I went to bed when I did yesterday instead of adding more stuff…

The end result of what I had prepared can be downloaded from my DropBox (under BSD like everything Orchard):

http://dl.dropbox.com/u/10032513/Lidnug.zip

A product review with a buy from Amazon badgeThis contains the site that I showed plus the few things I didn't have time to show. Please don't use this for anything as it is built on an unstable build of Orchard. This is just so that you can play with what I've been showing and dig deeper.

You will need Visual Studio 2010 to compile this as I've remove binaries to make a smaller download.

The admin password is 1234567.

During the course of the demo, I built a module that makes it dead simple to add a badge that enables your readers to buy a product from Amazon. The module can be downloaded from the Orchard module gallery:

http://orchardproject.net/gallery/List/Modules/
Orchard.Module.Vandelay.BuyFromAmazon

And if you want to reproduce the demo, here is my script…

http://dl.dropbox.com/u/10032513/LIDNUG%20Demo.pdf

It's rough notes but I thought it might be useful. The script stops abruptly as I started building a recipe because I hit a few difficulties and realized I had way too much content already.

Anyway, if you have a couple of hours, this might be a good way to get to know Orchard a little better by coding along.

More Posts