Sunday, May 12, 2013

using oData to connect Sitecore to Excell, Lightswitch, Sharepoint...

Sitecore 7 is buzzing!
While unsure about the release data, MVP's around the world are taking the deep dive.
So am I, diving in the new Sitecore version, that Sitecore call a "developer release".

What's good about oData!
oData is the "open data protocol" that microsoft came up with. It's like Rest, but with some additions.
Several products can connect with oData data sources, some examples are  Excell, Lightswitch, Sharepoint...

Why now?
Sitecore 7 brings new API's that make this possible with far less effort than before!
The new search API is responsible: The searchmanager exposes an IQueryable.
Why do we need this? oData converts query arguments to Linq expressions, thus enabling us to automagically, using oData, query Sitecore indexes! how neat.

Show me, Show me!
Was this intro to long for you :-) Time for some code!
I'll explain more, after the code.

  1. [ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.PerSession)]
  2.    public class WcfDataService : DataService<ReturnItemContext>
  3.    {
  4.       public static void InitializeService(DataServiceConfiguration pConfig)
  5.       {
  6.          pConfig.DataServiceBehavior.AcceptAnyAllRequests = true;
  7.          pConfig.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
  8.          pConfig.UseVerboseErrors = true;
  9.          pConfig.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
  10.          pConfig.SetServiceOperationAccessRule("*", ServiceOperationRights.AllRead);
  11.       }
  12.       protected override ReturnItemContext CreateDataSource()
  13.       {
  14.          return new ReturnItemContext();     
  15.       }
  16.    }
  17.    public class ReturnItemContext
  18.    {
  19.       public IQueryable<ContentItem> ContentItems
  20.       {
  21.          [WebGet]
  22.          get
  23.          {
  24.             using (IProviderSearchContext lContext = SearchManager.GetIndex("sitecore_web_index").CreateSearchContext())
  25.             {
  26.                WebOperationContext lOp = WebOperationContext.Current;
  27.                NameValueCollection lParameters =
  28.                   (lOp == null) ? null :
  29.                      (lOp.IncomingRequest.UriTemplateMatch == null) ? null : lOp.IncomingRequest.UriTemplateMatch.QueryParameters;
  30.                var lParser = new ParameterParser<ContentItem>();
  31.                IModelFilter<ContentItem> lParsed = lParser.Parse(lParameters);        
  32.                IQueryable<ContentItem> lSearchQuery = lContext.GetQueryable<ContentItem>();
  33.                IQueryable<object> lFiltered = lParsed.Filter(lSearchQuery);
  34.                return lFiltered.Cast<ContentItem>().ToList().AsQueryable();
  35.             }
  36.          }
  37.       }
  38.    }

What i did, is create a WCF Data Service. These have the possibility to expose oData.
The InitializeService sets things up for this. You can read more on the WCF data service here.
As you can see, the main thing is the ReturnItemContext and it's property called ContentItems.
The ContentItems property provides a IQueryable<ContentItem>.
When an oData consumer accesses this property, the search engine is called (line #34).
The oData query that the client generates, is applied to the Linq query (line #35) by using an open source project called Linq2Rest
When finally the Linq query is executed (line #36), the magic happens and the query is run.

Example oData
The following call to the WCFDataService using the following URL: http://.../WcfDataService.svc/ContentItems?$filter=ParentId eq '11111111111111111111111111111111'
Trigger the query where the oData part [$filter=ParentId eq '11111111111111111111111111111111'] is parsed by Linq2Rest and added to the linq statement. oData clients know to create these URL arguments and will do this.

Using Excell as oData Client
Excell becomes an oData client, when a free business intelligence product from Microsoft called PowerPivot is installed. It adds a new Ribbon that enables you to use a oData datasource.
In the screenshot above, you can see how simple it is to connect to an oData datasource.
1. button to start Table import wizard
2. location for oData service URL.

Using Lightswitch as oData Client
Lightswitch is a tool from microsofts that (so they say) " a simplified, self-service development tool that enables you to build business applications quickly and easily for the desktop and cloud.".
Lightswitch  provides an wizard to connect to an oData service and generates CRUD screens for this.
To test Lightswitch as a client for the service, I followed some simple steps.

1. start a lightswitch (windows) project
2. add a datasource

After this wizard, the tool inspects metadata, and generates a datamodel, in our case with one table.

3. Next, I added a screen

In this screen I configured a filter, "where parentid=111111111111111111":

Pressed F5 and voila, a windows client for sitecore (prototyped):

Of course, you can use oData for self written clients. This makes perfect sense!
And know, with all the new stuff in sitecore 7, you can do this!
The code above is written to get it working, understanding how it works -> Don't use it!

Sharepoint should be able to connect, but I did not test it. For a complete list of oData clients, check


Thursday, April 18, 2013

Sitecore 7, not just for developers!

Sitecore 7 is buzzing!
While unsure about the release data, MVP's around the world are taking the deep dive.
So am I, diving in the new Sitecore version, that Sitecore call a "developer release".

Developer release? No, it's also a content editor release!
Is this release really a developer release?
I don't think so, and this is the reason: While there certainly a lot of developing improvements,
the improvements for the average content editor are far bigger than for example Sitecore 6.5 or 6.6, which had DMS as the most important additions.
What improvements are there for the content editor? Buckets!

Buckets provide many search enhancements!
The integration of buckets is by far the biggest change for content manager. It provides a big step in back-end search functionality.
Buckets started as a marketplace module called "Sitecore Item Buckets" (here) and is the biggest new feature of Sitecore 7.
Buckets provide new searching capabilities with a great user interface (facets, f.e.). Also is allows the content editor to perform operations on all items in a search result.
These functions are called Search Operations (I blogged about these here implementing-search-operations-in-sitecore-7).

1. one search box
2. results can be shown in different ways, this can be altered
3. blazing fast, is said "search has returned 8737 results in 00.0753 seconds "
4. each results has actions you can perform on it
5. facets to narrow down the search

The search box features a dropdrown with additional functions:

1. a list of recent searches for easy access
2. navigate to recently modified content items
3. navigate to recently created content items
4. navigate to recently opened search tabs
5. some predefined search filters, developers can add new ones here
6. search operations, enables performing actions on items in the current search results!

Datasource improvements
The fact that datasource of a layout are stored as id's also provide content editors and page designers with great benefits!
Currently, content bound to a component in the pagedesigner, is lost when this contentitem is moved or renamed. When it's deleted, no warning is shown about the fact it is used as a datasource item.
NO More!!
Due to the fact datasources are stored as id's, links are tracked and moving an item, doesn't mean the connection is lost!

New field types
How many time have you used multilink fields to store related content (if not done by tagging)?
Often these are used for lists of links next to an article, called "also interesting", "more on this subject" or "related articles".
These always required manual updating when new (related) articles were added.
Now, with new field types, these collections of related content can be based on a search query, thus relieving the content editor of keeping the links up to date manually!!

All in all great stuff, not only for developers, but maybe even more so for content editors, hooray!

Thursday, January 27, 2011

Be happy with dynamic objects in Sitecore 6.4

Dynamic objects, a feature in .NET 4.0 is supposed to bring great possibilities. 
Thomas Eldblom and Jens Mikkelsen asked the question earlier: "
Will dynamics in .NET 4 change the way we do Sitecore?"
Personally I believe you should use dynamic objects with care, f.e. for XML, wrapping ActiveX/COM and stuff like that (as seen here). 
Is handling the access to Sitecore item fields, or rendering of Sitecore item content, an example of good usage of Dynamic Objects?

To find out, I first created a simple test class, called DynamicItem. This dynamic class only handles Field of an Item, to keep it simple. It returns the string that the FieldRenderer creates for the field requested. Basically it's a dynamic wrapper for a Sitecore item.
This is the class I created:
public class DynamicItem : DynamicObject
      Item mItem;

      public static implicit operator DynamicItem(Item pItem)
         if (pItem != null)
            return new DynamicItem(pItem);
         return null;

      public DynamicItem(Item pItem)
         mItem = pItem;

      public override bool TryGetMember(GetMemberBinder binder, out object result)
         Field lField = mItem.Fields[binder.Name];
         if (lField != null)
            result = FieldRenderer.Render(mItem, binder.Name);
            result = null;
            Exception lException =new Exception(String.Format("Item {0}, of template {1}, which hasn't a {2} field.", mItem.Paths.ContentPath, mItem.TemplateName, binder.Name));
            throw lException;
         return lField != null;
With this class in place, what can we do in a UserControl or SubLayout?
In the codebehind of an existing SubLayout, I added a simple property:

        public dynamic DynamicItem
              return (IQuality.Common.Sitecore.DynamicItem)Sitecore.Context.Item;

This makes a front end developer -friendly syntax possible, see the following examples:
<%# DynamicItem.Title%> 
<%# DynamicItem.Body%>
<%# DynamicItem.Image%>  

I guess it's clear what the sample does: it renders the same output as the following:
<sc:FieldRenderer ID="frTitle" FieldName="Title" runat="server"/>
<sc:FieldRenderer ID="frBody"  FieldName="Body" runat="server"/>
<sc:FieldRenderer ID="frImage"  FieldName="Image" runat="server"/>

 Before a front end developer will be truly happy, we'd need to do some work on the image (handling the parameters, f.e.) but it shows potential!

Why is this a good idea?
I think it's good, because disadvantages like the absence of compile time checking and the lack of intellisense support do not apply(since these apply to fieldrenderers and the retrieval of field values of items as well.

Would this be a nice shared source module, or an addition to an existing one?
Tell me!

Sunday, January 9, 2011

UML diagramming for Sitecore templates

A while ago, the guys from Hedgehog posted a teaser showing a diagram that supposedly was generated by a coming plugin. Because I do most of my diagramming in Enterprise Architect, which supports importing XMI files, I was wondering: How hard is it to generate a minimal version of XMI, that is constructed based on the template hierarchy in a Sitecore Solution?
If I would make it work, I could generate UML Class diagrams by importing a XMI file into Enterprise Architect!
As show below, this is very easy. What I did:
  1. create a simple class diagram (containing only 2 classes, 2 properties and inheritance)
  2. Exported the class diagram to a simple XMI file
  3. Pasted This XMI into a Layout
  4. Created some logic that supplies repeaters with template information
  5. added repeaters to the aspx, that made the XMI file dynamic
  6. visit a page that 'has' the layout bound to it
  7. voila! a valid XMI file that I can import into Enterprise Architect
Check the images below on the steps I took:

step 1: create a simple class diagram

  1. <packagedElement xmi:type="uml:Class" xmi:id="EAID_B16F5263_B589_479e_8588_CD3EA2BCF8A7" name="Class1" visibility="public">
  2.     <ownedAttribute xmi:type="uml:Property" xmi:id="EAID_49CFB4AF_DF06_48b1_824C_7025907761B1" name="name1" visibility="private" isDerived="false" isOrdered="false"></ownedAttribute>
  3. </packagedElement>
  4. <packagedElement xmi:type="uml:Class" xmi:id="EAID_AD064C48_D2D0_4d00_B739_6E3E8A78005A" name="subclass2" visibility="public">
  5.     <ownedAttribute xmi:type="uml:Property" xmi:id="EAID_AF11B4D8_CD8D_45a0_BC48_9D5E53F06FFB" name="Description2" visibility="private" isDerived="false" isOrdered="false"></ownedAttribute>
  6.     <generalization xmi:type="uml:Generalization" xmi:id="EAID_A05EA125_D602_4d01_B338_31C793A08B12" general="EAID_B16F5263_B589_479e_8588_CD3EA2BCF8A7"/>
  7. </packagedElement>
Step 2: a fragment of the XMI file,it contains the 2 classes, properties and de generalization (=inheritance)

  1.         public List<TemplateItem> Templates
  2.         {
  3.             get
  4.             {
  5.                 List<TemplateItem> lTemplates = new List<TemplateItem>();
  6.                 var lSelected = (from Item lItem in Sitecore.Context.Item.GetSelectedItems("IncludedRoots") select lItem);
  7.                 foreach (Item lItem in lSelected)
  8.                 {
  9.                     if(lItem.TemplateName == "Template")
  10.                     {
  11.                         lTemplates.Add(Factory.GetDatabase("master").GetTemplate(lItem.ID));
  12.                     }
  13.                     else
  14.                     {
  15.                         lTemplates.AddRange(from lTemplateItem
  16.                                             in lItem.GetChildrenDescendantOfTemplate("Template", 10)
  17.                                             where lTemplateItem.TemplateName == "Template"
  18.                                             select Factory.GetDatabase("master").GetTemplate(lTemplateItem.ID));
  19.                     }

  20.                 }
  21.                 return lTemplates.OrderBy(a => a.Name).ToList();
  22.             }
  23.         }
step 4: a collection of templates; I used an item with a "included roots" field, it contains selected template(folders)

  1. <asp:Repeater ID="Repeater1" runat="server" DataSource="<%#Templates%>">
  2.         <ItemTemplate>
  3.             <packagedElement xmi:type="uml:Class" xmi:id="<%#((CustomItemBase)Container.DataItem).ID.ToShortID()%>" name="<%#((CustomItemBase)Container.DataItem).Name%>" visibility="public">
  4.             <asp:Repeater ID="rptSections" runat="server" DataSource='<%#GetFields(((TemplateItem)Container.DataItem))%>'>
  5.                 <ItemTemplate><asp:PlaceHolder runat="server" visible="<%#((TemplateFieldItem)Container.DataItem).Section.Template.Name==((CustomItemBase)Container.GetParentContainerDataItem().DataItem).Name%>">
  6.                 <ownedAttribute xmi:type="uml:Property" xmi:id="<%#((TemplateFieldItem)Container.DataItem).ID.ToShortID()%>" name="<%#((TemplateFieldItem)Container.DataItem).Name%>" visibility="private" isDerived="<%#((TemplateFieldItem)Container.DataItem).Section.Template.Name!=((CustomItemBase)Container.GetParentContainerDataItem().DataItem).Name%>" isOrdered="false">
  7.                 <type xmi:idref="<%#((TemplateFieldItem)Container.DataItem).Type%>"/>
  8.                 <asp:PlaceHolder runat="server" visible="<%#!string.IsNullOrEmpty(((TemplateFieldItem)Container.DataItem).GetStandardValue())%>"><defaultValue xmi:id="<%#((TemplateFieldItem)Container.DataItem).ID.ToShortID()%>" value="<%#((TemplateFieldItem)Container.DataItem).GetStandardValue()%>"/></asp:PlaceHolder>
  9.                 </ownedAttribute>
  10.                 </asp:PlaceHolder></ItemTemplate>
  11.             </asp:Repeater>    
  12.             <asp:Repeater ID="rptBaseTemplates" runat="server" DataSource="<%#((TemplateItem)Container.DataItem).BaseTemplates%>">
  13.                 <ItemTemplate><!-- <%#((CustomItemBase)Container.DataItem).Name%> -->
  14.                 <generalization xmi:type="uml:Generalization" xmi:id="<%=Sitecore.Data.ID.NewID.ToShortID() %>" general="<%#((CustomItemBase)Container.DataItem).ID.ToShortID()%>"/> </ItemTemplate>
  15.             </asp:Repeater>  
  16.             </packagedElement>
  17.         </ItemTemplate>
step 5: the Repeater

Final: A class diagram, created from am imported XMI file!

Really nice, don't you think?
2 things I want do do next:
  1. make the XMI generation work in the Compiled Domain Model shared source module
  2. generate the rest of the documentation, with more info per template/field
That's it, ff you would like some sources, leave a note!
All links in this article are available here.

Tuesday, December 28, 2010

Razor for MVC in Sitecore

Like Peter in his comment to Alex' blog here, I'm also not a big fan of XLST's. I've seen several discussions about (not) using XSLT's in Sitecore with good arguments and even Sitecore has arguments for both. Fact remains, not all the people involved in Sitecore projects know, could the new Razor syntax in MVC be a viable solution here?
Is the following code fragment easier than it's XSLT counterpart?
@foreach (var aChild in Item.Children.Where(Child => Child["ShowInMenu"] != "0"))  

That is a simple sample, but what about "Creating a tree like left menu"? In XSLT Brian Pedersen does it like this, a very good sample. What would that look like in Razor? A simple sample, without reuse/recursion:
@foreach (var aChild in Item.Children.Where(Child => Child["ShowInMenu"] != "0"))  
@foreach (var bChild in aChild.Children.Where(Child => Child["ShowInMenu"] != "0"))  

Is this something people would like in favor of XSLT's? The guys at Sitecore could add some helpers, modelbinders and stuff like that to make MVC even easier (They might be working on it right now), is a LINQ query easier to understand that XPATH?
Would this make Sitecore development even more productive?
I think so, do you? 

Monday, December 27, 2010

Created the blog, now I can share my thoughts.

My thoughts about Sitecore as a product and building solutions in Sitecore.