Creating a shape with a dynamic name from a controller

Topics: Writing modules
Dec 13, 2011 at 3:27 PM

Is it possible to create a shape whose name will not be known until run time from a controller (i.e from a string)? 

I have tried using IShapeFactory.Create, but it gives me a null reference exception @ shapeMetadata.BindingSources, so clearly there is something about shape creation I don't know.

In case what I am trying to do matters in some way, I am trying to build feeds from shape templates, so from the route "/feeds/{format}/{path}" I'd like to yield a shape named Feeds_{format} with templates located at views/Feeds_{format}.cshtml or views/feeds/{format}.cshtml. And if your wondering why on earth I'd want to do that the answer is simple: The more I read over the Feeds module code the more I see it isn't gonna work for what I am trying to do, and the formats I'd like to produce, heck even RSS, would be more easily done in templates. 

Coordinator
Dec 13, 2011 at 5:17 PM

Why don't you use a DisplayType?

Dec 13, 2011 at 6:02 PM

You know, that's a good question.

I hadn't considered it. But now that you have me thinking about it that does make a lot of sense. 

Dec 13, 2011 at 9:22 PM
Edited Dec 13, 2011 at 9:22 PM

Bertrand: DisplayType is only relevant when building content item displays - IContentManager.BuildDisplay(item,displayType) runs the whole handler/driver/placement pipeline and that's the only situation when you have a display type (out of the box).

reverand: The way to approach this is use shape table events (IShapeTableEvents) to set an Alternate for your Feed shape that includes the differentiator.

If you want to build more complex shape compositions from models, you could investigate my Origami module (latest version at http://scienceproject.codeplex.com) which gives you a new driver pipeline for arbitrary models (i.e. non-content) and that way lets you apply display types and placement to any shape building. But simple alternates should suit you fine unless you want to make your feeds highly compositional and extensible! Sounds like an interesting concept anyway.

Dec 14, 2011 at 12:21 AM

Actually I think Bertrand has It.

If you eliminate the last step of creating a wrapper shape around the container type to be turned into a feed and simple supply a DisplayType when building the display shape of the container you end up with the same result.  

Dec 14, 2011 at 12:38 AM
reverand wrote:

Actually I think Bertrand has It.

If you eliminate the last step of creating a wrapper shape around the container type to be turned into a feed and simple supply a DisplayType when building the display shape of the container you end up with the same result.  

Ah well, if you're able to build from a content item then of course you can do that.

By the way for future reference, I just had a look and the reason your original IShapeFactory call didn't work is because you need to call it like this:

_shapeFactory.Create("ShapeType", Arguments.Empty())

You can search in the Orchard source for various examples of where this is used successfully.

Dec 14, 2011 at 1:09 PM
randompete wrote:
reverand wrote:

Actually I think Bertrand has It.

If you eliminate the last step of creating a wrapper shape around the container type to be turned into a feed and simple supply a DisplayType when building the display shape of the container you end up with the same result.  

Ah well, if you're able to build from a content item then of course you can do that.

By the way for future reference, I just had a look and the reason your original IShapeFactory call didn't work is because you need to call it like this:

_shapeFactory.Create("ShapeType", Arguments.Empty())

You can search in the Orchard source for various examples of where this is used successfully.

Well interestingly enough this actually isn't working as I had hoped. I am returning a List shape from my controller and using a template List-{format} where in the case of my first attempt is List-rss but I get nothing back, except if I enable ShapeTracing, then I get a ShapeTracing wrapper for my List shape. Curious.

That's almost how I called Create, except I supplied a set of named arguments:

public static dynamic CreateShape(this IShapeFactory shape, string name, object arguments) {
    Type argType = arguments.GetType();
    List<string> names = new List<string>();
    List<object> values = new List<object>();
            
    foreach (var prop in argType.GetProperties())
    {
       names.Add(prop.Name);
       values.Add(prop.GetValue(arguments, null));
    }
            
    return shape.Create(name, Arguments.From(values, names));
}

This is operating on the assumption that the named arguments are the named parameters provided when creating shapes in the normal way:

Shape.List(
    Parameter: Value
);
But I don't have the Clay source handy at the moment to figure out how it's implementation of IDynamicMetaObjectProvider works.