Tony Tong
Tony Tong

Reputation: 13

Orchard CMS connect external SQL Server

I'm planning to create some pages which display data from an external SQL Server with Orchard CMS. It looks like I need to write a new module to implement this function. Is there any example or idea to implement this requirement?

Upvotes: 1

Views: 699

Answers (1)

Sipke Schoorstra
Sipke Schoorstra

Reputation: 3409

Yes, you will need to write a new module, which provides a new content part and a content part driver. That driver will be responsible for fetching the data from the external SQL Server, which you will set to a property on the shape you will be returning from your driver. The shape's view will then display your data.

This tutorial will walk you through writing a custom content part: http://docs.orchardproject.net/en/latest/Documentation/Writing-a-content-part/

When you do, make sure not to create the content part Record type, since you will not be storing and loading data from the Orchard database - you want to load data from an external database. These are the steps you should follow:

  1. Create a new module
  2. Create a content part class
    1. Have your part inherit from ContentPart, not ContentPart<TRecord> since there won't be any "TRecord".
  3. Create a content part driver
    1. On the Display method, return a shape by calling the ContentShape method. Make sure to add the SQL data access logic within the lambda. If you do it outside of that lambda, that data access code will be invoked every time the content item using your content part is invoked. Although that sounds as if that is exactly what you want, there's a subtlety here that involves Placement.info, which you can use to determine when your shape will actually be rendered or not. If the placement logic determines that your shape should not be rendered, then you don't want to access your external data for nothing.
  4. Create a Placement.info file to configure the shape's placement (within the context of the content item being rendered).
  5. Create the Razor view for the shape that you return in step 3.2.
  6. Create a Migrations class that will define your custom content part, and any content types to which you want to add your part to. See http://docs.orchardproject.net/en/latest/Documentation/Understanding-data-access/ for more information on how to create migrations.

PS. Instead of implementing your data access code directly in the driver, I recommend you implement that in a separate class. Because you know, separation of concerns and such. You can then inject that service into your driver. To have your service class be registered with the service container, make sure that you define an interface for it, that itself derives from IDependency.

Some sample pseudo code:

Service code:

public interface IMyExternalDataStore : IDependency {
   IList<MyExternalDataRecord> GetMyData();
}

public class MyExternalDataStore : IMyExternalDataStore {
   public IList<MyExternalDataRecord> GetMyData() {
      // Connect to your SQL Server database, perhaps using EF, load the data and return it. Could of course also be simply a DataSet.
   }
}

Content Part:

public class MyExternalDataPart : ContentPart {
    // Nothing here, unless you want to include some properties here that influence the data that you want to load. If so, you'll also want to implement the Editor methods in your content part driver, but I'm keeping it simple.
}

Content Part Driver:

public class MyExternalDataPartDriver : ContentPartDriver<MyExternalContentPart> {

   private readonly IMyExternalDataStore _dataStore;

   public MyExternalDataPartDriver(IMyExternalDataStore dataStore) {
      _dataStore = dataStore;
   }

   protected override DriverResult Display(SlideShowProPart part, string displayType, dynamic shapeHelper) {

       return ContentShape("Parts_MyExternalData", () => {
          // Notice that we're performing the data access here within the lambda (the so called "shape factory method").
          var data = _dataStore.GetMyData();

          // Notice that I'm creating a property called "MyData"on the shape (which is a dynamic object).
          return shapeHelper.Parts_MyExternalData(MyData: data));
       }
   }
}

Razor view for the Parts_MyExternalData shape: Filename: Parts.MyExternalData.cshtml

@{
   var records = (IList<MyExternalDataRecord>)Model.MyData;
}
<ul>
@foreach(var record in records) {
   <li>@record.ToString()</li>
}
</ul>

Placement.info:

<Placement>
   <Place Parts_MyExternalData="Content:0"/>
</Placement>

Migrations:

public class Migrations : DataMigrationImpl {
    public int Create() {

       // Define your content part so that you can attach it to any content type from the UI.
       ContentDefinitionManager.AlterPartDefinition("MyExternalDataPart", part => part.Attachable());

       // Optionally, define a new content type here programmatically or attach it to an existing type.

       return 1;
    }
}

Upvotes: 1

Related Questions