Creating a custom IShapeTableProvider for Parts

Jan 26, 2011 at 4:23 PM
Edited Jan 26, 2011 at 4:26 PM

I want to be able to identify parts based on specific content types and provide an alternative lookup schema. I tried following the instructions here: http://weblogs.asp.net/bleroy/archive/2011/01/10/orchard-shapeshifting.aspx but was successful. I have also not been able to find any ShapeTableProvider that actually describes Parts within the system so I am at a loss here.

I added the following class and put breakpoints, hoping to catch one so I know what I need to describe and expand on the code from there. Regardless of where I break in the Discover method  I'm not hitting anything.

 

namespace CyberStride {
    using Orchard;
    using Orchard.ContentManagement;
    using Orchard.DisplayManagement.Descriptors;

    public class PartsShapeProvider : IShapeTableProvider 
    {
        private readonly IWorkContextAccessor _workContextAccessor;
        public PartsShapeProvider(IWorkContextAccessor workContextAccessor) 
        {
          _workContextAccessor = workContextAccessor;
        }
        public void Discover(ShapeTableBuilder builder) 
        {
            builder.Describe("Part")
           .OnDisplaying(displaying =>
           {
               var type = displaying.ShapeMetadata.DisplayType;
           });
            builder.Describe("Parts")
           .OnDisplaying(displaying =>
           {
               var type = displaying.ShapeMetadata.DisplayType;
           });
            builder.Describe("Shape")
           .OnDisplaying(displaying =>
           {
               var type = displaying.ShapeMetadata.DisplayType;
           });
        }        
    }
}

 

 

Any help would be appreciated, thanks!

Coordinator
Jan 26, 2011 at 4:30 PM

There is no shape called "Part", "Parts" or "Shape". You need to be more specific than that. What exactly are you trying to do?

Jan 26, 2011 at 4:38 PM

I was under the assumption that being Describe actually pertained to the suffix ("Content-[....]" or in my case "Parts.[...]")

I am trying to create a means of overwriting parts for specific ContentTypes. For example, if I wanted to override the common "Parts.Common.Body.Summary" for various content types, then I would like to be able to say something like "Parts.Staff.Body.Summary" or "Parts-Staff.Body.Summary"

 

 

Coordinator
Jan 26, 2011 at 4:44 PM

I'm not sure but I think you're trying to add alternates for specific types, so that the theme can override the shapes in specific situations. If so, my article does show you the way except that you should catch "Parts.Common.Body" and add new alternates to it. If you want to do that for *any* part, maybe you'll need to handle that from some event on a handler rather than on a shape descriptor, so that you can widen the net.

Jan 26, 2011 at 5:05 PM

Thanks for the help. I was afraid that were the case, but was hoping otherwise. I'll do it bitwise for now and come up with a more permanent solution later. 

 

Quick question - would the Content Type be stored in the shape's metadata? 

Jan 26, 2011 at 5:15 PM

Actually, I'm not hitting a breakpoint with:

 

        public void Discover(ShapeTableBuilder builder) 
        {
            builder.Describe("Parts.Common.Body.Summary")
           .OnDisplaying(displaying => {
               var wrappers = displaying.ShapeMetadata.Wrappers;
               var type = displaying.ShapeMetadata.DisplayType;
               
           });
        }     
either

Coordinator
Jan 26, 2011 at 5:17 PM

No you don't because that's not the name of the shape, it's the name of one of its alternates. Remove the summary substring.

Jan 27, 2011 at 3:33 PM

bertrand:

Even with the following code with breakpoints set at each of the actual lines of code (eg var breakpoint = displayed), it still isn't hitting any of them.

        public void Discover(ShapeTableBuilder builder) 
        {
           builder.Describe("Parts.Common.Body")
           .OnDisplayed(displayed =>
           {
               var breakpoint = displayed;
           })
           .OnCreating(creating =>
            {
               var breakpoint = creating;
            })
           .OnDisplaying(displaying => {
               var wrappers = displaying.ShapeMetadata.Wrappers;
               var type = displaying.ShapeMetadata.DisplayType;
               
           });
        } 

I do however seem to be catching more exceptions in ShellRoute.cs on the following block of code

            public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) {
                _scope = _workContextAccessor.CreateWorkContextScope(new HttpContextWrapper(context));
                try {
                    return _httpAsyncHandler.BeginProcessRequest(context, cb, extraData);
                }
                catch {
                    _scope.Dispose();
                    throw;
                }
            }

 

Feb 4, 2011 at 10:24 PM

Hi chanceusc,

Did you solve this in the end. I am wanting to do exactly as you describe but for the Parts.Common.Metadata shape. I tried catching

builder.Describe("Parts_Common_Metadata")

But it doesn't hit the breakpoint, even though i proved it was that shape being rendered by navigating to /Core/Common/View/Parts.Common.Metadata.cshtml and editing it there directly.

Glad to see it isn't just me baffled by this system. I think it's probably very powerful but too concept heavy and involved to be practical.

Hope things improve.

 

Cheers,

 

Ian

Coordinator
Feb 4, 2011 at 11:32 PM

Random question, but I have to ask: is your feature enabled?

Feb 4, 2011 at 11:43 PM

No, I ended up mutilating the Summary view of what I needed it for, destroying the parts.

 

bertrand - which feature?

Coordinator
Feb 4, 2011 at 11:44 PM

The feature that code you wrote is part of.

Feb 7, 2011 at 4:01 PM

Yes, of course. Have you been able to set a breakpoint on a Parts rendering?  If so, could you please show me the code that produced it? Maybe I'm missing something.

 

Thanks,

Chance

Coordinator
Feb 7, 2011 at 5:36 PM

Another random thing to check: make sure you put the breakpoint inside the Lambda, not on the OnXXX call.

Feb 7, 2011 at 5:39 PM
Right, I know and did. :/

Sent from my iPhone

On Feb 7, 2011, at 1:36 PM, "bertrandleroy"<notifications@codeplex.com> wrote:

From: bertrandleroy

Another random thing to check: make sure you put the breakpoint inside the Lambda, not on the OnXXX call.

Coordinator
Feb 7, 2011 at 5:44 PM

Well, if the code you're testing really is what's written a few posts above, maybe the code is getting optimized away because it really doesn't do anything. Did you check that you had optimizations off?

Feb 7, 2011 at 5:49 PM
Yea, optimization is turned off.
Feb 7, 2011 at 5:51 PM

Btw, I do not believe the increase in shell exceptions was related. Forgot to mention that earlier.

Feb 7, 2011 at 6:33 PM

Based on your code above isn't the problem that there are dots instead of dashes, shouldn't it be:

builder.Describe("Parts_Common_Body")

This hits a breakpoint for me. I don't see how to then target the alternate to a specific page (eg the homepage) in the same way as bertrands post does, he uses contentItem but what do we use for Parts_Common_Body.

Bertrand - Any suggestions?

Coordinator
Feb 7, 2011 at 6:41 PM

Yes I can confirm that: the breakpoint is hit with _, not with dots.

Feb 7, 2011 at 6:47 PM
Ah - that would explain a great deal. Thanks guys!

Coordinator
Feb 7, 2011 at 7:05 PM

I don't really see why you couldn't target the alternate to a specific page. Can you explain?

Feb 7, 2011 at 9:00 PM

Sure. It's probably just my understanding isn't correct. If I do.

 

builder
     .Describe("Parts_Common_Body")
      .OnDisplaying(displaying =>
                                {
                                    displaying.ShapeMetadata.Alternates.Add("MyAlternate");
                                });

 

This creates an alternate for all pages. On your blog post you use:

ContentItem contentItem =
              displaying.Shape.ContentItem;

To get the current item and match the Id on the conditional. Maybe my question should be how do I do the same for the Parts_Common_Body part. The contentItem is null when I do the same in the Body part. I poked around the IWorkContextAccessor and couldn't find anything that distinguished what page I was on.

I could access the httpContext and match the url slug although Id matching or some sort of type matching etc would be more robust to changes.

Coordinator
Feb 7, 2011 at 9:06 PM

Try to access the ContentPart property of the shape and then you can get the content item from there.