0
votes

In Orchard CMS I have a service that pulls data from an external data source, and loads the data into an Orchard Content Part. The Part has a migration that welds it with a title part, and I have a route so that my controller is being hit via a URL:

I am using a controller to access the item via a URL, much like the Blog Part controller. However I can't render my part... The Blog Controller does similar to the following:

    var asset = _assetService.Get(1234);
    if (asset == null) return HttpNotFound();

    var model = _services.ContentManager.BuildDisplay(asset); 

    return new ShapeResult(this, model);

But if I do this, the 'BuildDisplay' method looks for asset.ContentItem but this is null, despite deriving my part from 'ContentPart'.

What do I need to do to get my data to display?

2
What does your _assetService.Get() do? Is your asset a content type?devqon
The Asset is Derived from ContentPart. (In theory I can then create a ContentItem that uses this part and others welded together). The first stage is getting a ContentPart - populated from an external source - to show on a page....then add other parts (in code) to it so that it is an Orchard Content Item, with all teh bells and whistles that go with it.GadgetGeekUK
I'm not sure if you can use BuildDisplay on a single partdevqon
That's the question - what is the correct way to get from a Content Part - to ??? - to a Shape? - to be displayed?GadgetGeekUK
Why do you insist on it being a part? A part should never be used outside of a content item. You don't need a part to use shapes. It looks like you;'d make your life a lot less difficult by just building a shape from your controller action.Bertrand Le Roy

2 Answers

0
votes

If I understand correctly, you are trying to display only one part, and not a whole content item.

To display a single shape, you can do the following:

private readonly IAssetService _assetService;

public MyController(IShapeFactory shapeFactory, IAssetService assetService) {
    _assetService = assetService;
    Shape = shapeFactory;
}

public dynamic Shape { get; set; }

public ActionResult MyAction(int assetId) {
    var asset = _assetService.Get(1234);
    if (asset == null) return HttpNotFound();

    // the shape factory can call any shape (.cshtml) that is defined
    // this method assumes you have a view called SomeShapeName.cshtml
    var model = Shape.SomeShapeName(asset);

    return new ShapeResult(this, model);
}

!!Note: This does not kick of the (display)driver of the part, it only returns the .cshtml with the given model

0
votes

By having my part deriving from ContentPart, I can use the following Controller method:

private readonly IAssetService _assetService;
private readonly IOrchardServices _services;

public MyController(IShapeFactory shapeFactory, IAssetService assetService, IOrchardServices services) {
    _assetService = assetService;
    _services = services;
    Shape = shapeFactory;
}

public dynamic Shape { get; set; }

public ActionResult MyAction(int assetId) {
    var asset = _assetService.Get(1234);
    if (asset == null) return HttpNotFound();

    // this method assumes you have a view called Parts.Asset.cshtml (see the AssetPartDriver)
    var model = _services.ContentManager.New("Asset");
    var item = contentItem.As<AssetPart>();
    item.Populate(asset) // Method that just populates the service loaded object into the ContentPart

    return new ShapeResult(this, _services.ContentManager.BuildDisplay(item));
}

This will use the 'AssetPartDriver':

public class AssetPartDriver : ContentPartDriver<AssetPart>
    {
        protected override DriverResult Display(AssetPart part, string displayType, dynamic shapeHelper)
        {
            return ContentShape("Parts_Asset", () => shapeHelper.Parts_Asset()); // Uses Parts.Asset.cshtml
        }
    }

And in conjunction with the 'Placement.info' file renders on the screen:

<Placement>
  <Match ContentType="Asset">
    <Match DisplayType="Detail">
      <Place Parts_Asset="Content"/>
    </Match>
  </Match>
</Placement>

The migration file combines my web service part with other Orchard parts:

public class Migrations : DataMigrationImpl
    {
        public int Create()
        {
            ContentDefinitionManager.AlterTypeDefinition("Asset", cfg => cfg
                .WithPart("AssetPart")
                .WithPart("AutoroutePart", builder => builder
                    .WithSetting("AutorouteSettings.AllowCustomPattern", "True"))
                .Listable()
                .Securable()
                .Creatable(false));

            ContentDefinitionManager.AlterPartDefinition("AssetPart", part => part
                .WithDescription("A part that contains details of an individual Web Service loaded asset."));
            return 1;
        }
    }

These additional parts are not yet used, but can be populated during creation and displayed individually using the placement file. This is the first step of what I was trying to achieve!!