Home Development, Queries Dissecting SharePoint content approval

Dissecting SharePoint content approval

Development topicSharePoint lists support content approval. On code level it is called moderation. Querying lists by approval or moderation status needs some explanations. Due to some very bad design decisions there are some dirty tricks that one must use when querying lists by approval status. This posting shows safe way how to query lists by approval status.

SPModerationInformation class

Moderation information is kept in separate class called SPModerationInformation. It has properties Status and Comment. First one of them shows moderation status of list item and the other one contains comment inserted by user who last changed moderation status. List item has property called ModerationInformation that returns this object.

SharePoint: List versioning settings
SharePoint list versioning settings. First setting is for content approval. 
By default content approval is disabled.
 

SPModerationInformation class does nothing special – it is only wrapper for two fields: _ModerationStatus and _ModerationComment (these are internal names of these fields). These fields are added to list when user enables content approval. If content approval is disabled then ModerationInformation property is always null for list items.

Querying list by moderation status

It is possible to query lists by moderation status using CAML queries. As I mentioned before there is field with internal name _ModerationStatus. In database and web services it is integer that keeps values from SPModerationStatusType enumerator. But if you are dealing with list items then this field contains string.

In CAML queries we must use moderation status as string.


var queryString = @"<Where>

                       <Eq>

                         <FieldRef Name=’_ModerationStatus’/>

                         <Value Type=’ModStat’>Approved</Value>

                       </Eq>

                    </Where>";

 

var query = new SPQuery { Query = queryString };

var items = list.GetItems(query);


You can see that we have to use special field type called ModStat. Yes, there is even class called SPFieldModStat for this type.

Awful bug in SharePoint

So far, so good, but this solution works only in english installations of SharePoint. If your SharePoint site uses some other language than english you are in trouble because query shown above doesn’t return items anymore. But it also doesn’t give you any errors.

Names of moderation statuses are not taken from SPModerationStatusType enumerator. There values are read from resource file!

Well, now consider what happens when somebody makes a little typo in one of those translations. I think I don’t have to mention that building code and process logic around translation variables is something we can expect from complete noobs.

Unified solution

To make these queries work in any SharePoint site we have to read correct values from resource file.

  1. From Global Assembly Cache (GAC) copy assembly called Microsoft.SharePoint.intl.dll to some place where you can access it.
  2. Run Reflector and open this assembly.
  3. Under resources section you will find resources in this assembly.
  4. Open Microsoft.SharePoint.resources, sort resources list and find constants that start with word ModerationStatus as shown on the image below.

    reflector-sharepoint-resources
    .NET Reflector showing contents of Microsoft.SharePoint.resources. On the right pane
    moderation status Approved is highlighted.

    Now we want to use these resources in our code. Here is class that provides you with static properties that return correct values for _ModerationStatus fields.


internal class Resources

{

    static Resources()

    {

        var intlAsssembly = Assembly.Load("Microsoft.SharePoint.intl, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c");

 

        IntlResources = new ResourceManager("Microsoft.SharePoint",

                        intlAsssembly);

    }

 

    private static ResourceManager IntlResources { get; set; }

 

    public static string ModerationStatusApproved

    {

        get

        {

            return IntlResources.GetString("ModerationStatusApproved");

        }

    }

 

    public static string ModerationStatusPending

    {

        get

        {

            return IntlResources.GetString("ModerationStatusPending");

        }

    }

}


Now you can write query shown above as follows.


var queryString = @"<Where>

                       <Eq>

                         <FieldRef Name=’_ModerationStatus’/>

                         <Value Type=’ModStat’>{0}</Value>

                       </Eq>

                    </Where>";

queryString = string.Format(queryString, 
                            Resources.ModerationStatusApproved);


This solution is nothing elegant but I don’t think there are completely nice ways to get around hacks without replacing them with correct code.

References

Related posts:

  1. Querying SharePoint lists

  1. No comments yet.
  1. No trackbacks yet.
WordPress SEO fine-tune by Meta SEO Pack from Poradnik Webmastera