views:

570

answers:

3

I've been given the task of content migration from another CMS system to SharePoint 2010.

The data in the old system is fairly easy to capture and the page hierarchy is simple so I'm not worried about that.

However, I am completely flummoxed about how to even create a page in code. I'm using the Microsoft.SharePoint.Client namespace as I do not have sharepoint installed on my system and am wanting to code this up as a console application and so I'm using I'm using ClientContext. (On the other hand, I am willing to go into other solutions if necessary).

My end-game: To get a page uploaded into some folder hierarchy which uses a master page, has the page title in a header web part, and a big ol' content-editable web part in the body so any user can come along and edit the content.

Things I've tried so far:

  • Using FileCollection.Add() to add an aspx file to the folder "Site Pages". This renders the html in the browser but doesn't enable any features for the user to edit the page
  • Using ListItemCollection.Add() to add a page to the site, but I didn't know what fields I needed. Also I remember it came up with a runtime error saying I should use FileCollection.Add()
  • Uploading to 'Site Pages' instead of 'Pages'
  • So many others... ow my head :(

The only plausible thing I can see on the net is to use the PublishingPage type along with PublishingWeb. However, PublishingWeb can only be constructed from an SPWeb object which requires me to be actually hosting the sharepoint application on my workstation.

If anyone can lend a hand that would be greatly appreciated :)

+1  A: 

I don't see a way of creating a publishing page without the actual publishing methods.

When you create a new article page it will only create a few xml parameters inside the page, the layout itself lives in the /_catalogs/masterpage/article-XXXX.aspx file.

You can try downloading a native file created in the Pages document library, understand its structure, fill the XML with your data and then uploading it back to the Pages document library using the FileCollection -- that's my only guess.

Edit: sample Article Page

<%@ Page Inherits="Microsoft.SharePoint.Publishing.TemplateRedirectionPage,Microsoft.SharePoint.Publishing,Version=12.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" %>
<%@ Reference VirtualPath="~TemplatePageUrl" %> 
<%@ Reference VirtualPath="~masterurl/custom.master" %>
<html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"><head>
&nbsp;<!--[if gte mso 9]><xml>
<mso:CustomDocumentProperties>
<mso:PublishingContact msdt:dt="string">1073741823</mso:PublishingContact>
<mso:display_urn_x003a_schemas-microsoft-com_x003a_office_x003a_office_x0023_PublishingContact msdt:dt="string">System Account</mso:display_urn_x003a_schemas-microsoft-com_x003a_office_x003a_office_x0023_PublishingContact>
<mso:PublishingContactPicture msdt:dt="string"></mso:PublishingContactPicture>
<mso:PublishingContactName msdt:dt="string"></mso:PublishingContactName>
<mso:ContentTypeId msdt:dt="string">0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF390078FB5FE740F6714B9595501175ECD8F000727044016EAB3B45B9E104498E366C85</mso:ContentTypeId>
<mso:Comments msdt:dt="string"></mso:Comments>
<mso:PublishingContactEmail msdt:dt="string"></mso:PublishingContactEmail>
<mso:PublishingPageLayout msdt:dt="string">http://dmserver008/_catalogs/masterpage/ArticlePage.aspx, EstudoAndre</mso:PublishingPageLayout>
</mso:CustomDocumentProperties>
</xml><![endif]--><title>New Article</title></head>

To grab one, hit the Pages library => Content Menu => Send To => Download a Copy

F.Aquino
Nice thanks, I've marked this as the accepted solution as it does work for making a new page using the client context. However, I may end up using the server-side API for the final push, as the client API takes a few seconds for it to import each time I ExecuteQuery().
soniiic
A: 

Uploading a page file should work, as long as you get the settings right on the item as well as the document itself. After you upload the file you can set the content type and properties appropriately. If you create a page manually first, you should be able to get an object that has all the right settings.

However, I would strongly recommend getting set up to develop a console app that will run on the sharepoint server rather than relying on the web services. The server side apis (including PublishingPage) tend to be a lot easier to work with.

Tom Clarkson
+1  A: 

Here is a method I use to create pages. It seems a more supported way of creating pages than mr Aquino's. Though this is for MOSS 2007 I'm sure the equivalent exists in 2010. Also, I'd recommend to create console apps using the full object model. You'll have to run it on the server itself but that doesn't seem much of a problem for a migration? This way you won't be limited in any way.

public static void CreatePage(string url, string pageName, string title, string layoutName, Dictionary<string, string> fieldDataCollection)
    {
        var relUrl = new Uri(url);

        using (SPSite site = new SPSite(url))
        using (SPWeb web = site.AllWebs[relUrl.AbsolutePath])
        {
            if (!PublishingWeb.IsPublishingWeb(web))
                throw new ArgumentException("The specified web is not a publishing web.");
            PublishingWeb pubweb = PublishingWeb.GetPublishingWeb(web);
            PageLayout layout = null;
            string availableLayouts = string.Empty;
            foreach (PageLayout lo in pubweb.GetAvailablePageLayouts())
            {
                availableLayouts += "\t" + lo.Name + "\r\n";
                if (lo.Name.ToLowerInvariant() == layoutName.ToLowerInvariant())
                { layout = lo; break; }
            }
            if (layout == null)
                throw new ArgumentException("The layout specified could not be found.  Available layouts are:\r\n" + availableLayouts);

            if (!pageName.ToLowerInvariant().EndsWith(".aspx")) pageName += ".aspx";
            PublishingPage page = pubweb.GetPublishingPages().Add(pageName, layout);
            page.Title = title;
            SPListItem item = page.ListItem;

            foreach (string fieldName in fieldDataCollection.Keys)
            {
                string fieldData = fieldDataCollection[fieldName];
                try
                {
                    SPField field = item.Fields.GetFieldByInternalName(fieldName);

                    if (field.ReadOnlyField)
                    {
                        Console.WriteLine("Field '{0}' is read only and will not be updated.", field.InternalName);
                        continue;

                    }
                    if (field.Type == SPFieldType.Computed)
                    {
                        Console.WriteLine("Field '{0}' is a computed column and will not be updated.", field.InternalName);
                        continue;
                    }
                    if (field.Type == SPFieldType.URL)
                    {
                        item[field.Id] = new SPFieldUrlValue(fieldData);
                    }
                    else if (field.Type == SPFieldType.User)
                    {
                       // AddListItem.SetUserField(web, item, field, fieldData);
                    }
                    else
                    {
                        item[field.Id] = fieldData;
                    }
                }
                catch (ArgumentException)
                {
                    Console.WriteLine("WARNING: Could not set field {0} for item {1}.", fieldName, item.ID);
                }
            } 
            page.Update();
        }
    }
ArjanP
Thanks, I think this is what I'm going to be using in the end. The client queries were taking too long to create and upload each page and the amount of back and forth to create 10k new pages would make it take too long. The code you provided looks great, however where would I put the html content for the page? Within fieldDataCollection in a field called "Content"?
soniiic
That depends on where you want the HTML to go. This is a publishing page; it's content is actually in the list item columns. That is what the fieldDataCollection collection is for. If you add a key "Description" it will populate the item column description, etc.
ArjanP