What a Good SharePoint Consultant Should Know!

August 23, 2008

Everyone who can spell SharePoint

o            What is Sharepoint?

 

Sharepoint is the portal. It is developed by Microsoft. This is used to create Content Management System web sites. We can develop individual sites, team sites and enterprise portals.

 

o            What is the difference between Sharepoint Portal Server and Windows Sharepoint Services?

 

Sharepoint Portal Server features are very high. Search portal and navigations are most important features of the Sharepoint Portal Server.

 

Windows Sharepoint Services are used to create CMS Web sites and blogs, Forums and document sharing Libraries.

 

o            What is a document library?

 

To share a document that referenced in news, articles published site.

 

o            What is a meeting workspace?

 

Meeting workspace is used to store information about particular organization employees work related tasks meetings (related information). And also place the minutes of the meeting and each person task details.

 

o            What is a document workspace?

 

To share a document with others, we create a document workspace site. We can easily share documents and some other files. We can give each and every file permissions.

 

o            What is a web part?

WSS 3.0 has a new infrastructure called Web Part. The WSS Web part classes are derived from ASP.Net Web Part Class. It is supported by Widows Sharepoint Services 3.0. We can also create connectable web parts. The connectable web part is connected to any other related web part. These two connected web parts are has some programs.

 

Mid-level SharePoint Consultant

o            What is the difference between a document library and a form library?

 

Document Library has documents and content, which gets stored in the Sharepoint content database.

Form Library has an Info path XML forms. When submitting with InfoPath Form Services, the submitted data is generated as XML which refers the original form template .XSN. The XML files are stored in Document Library.

 

o            What is a web part zone?

 

Web Parts are displayed by using Web Part Zone. The WebPartZone class derived from WebZone and WebPartZoneBase classes. A Web Part zone is a WebPart container that can be configured to control the organization and format of the Web Parts contained in it.

 

o            How is security managed in SharePoint?

 

Sharepoint using three types of user authentications. There are Windows, Form and Single Sign On.

Security Socket Layer (SSL) is also used for authentication in Sharepoint. Authorization, Authentication and Impersonation these are configured by config file.

 

o            How are web parts developed?

 

WebParts developed by using Visual Studio .Net 2005. It offers many Sharepoint templates like Site Definition, Web Part etc. And also using Widows Class Library.

 

o            What is a site definition?

 

A Site Definition is a group of files that used to define a unique type of Sharepoint Site. Example, one site definition defines the Team Site, Blank Site, and Document Workspace templates, and another site definition defines the Basic Meeting Workspace, Blank Meeting Workspace, Decision Meeting Workspace, Social Meeting Workspace, and Multipage Meeting Workspace templates.

 

o            What is a template?

 

Templates are built-in solutions for applications, business portals, Design and Look & Feel. Sharepoint has a some pre-build templates. The templates are customizing and deploying in to the server.

 

o            How do you install web parts?

 

  1. Open the Command prompt in Visual studio .Net.
  2. Find the path for you developed web part dll file path.
  3. Type the command gacutil /I  dll name, then press enter.
  4. Reset the IIS using iisreset command.
  5. Open the Folder “C:\Inetpub\wwwroot\” Open the web.config file. Copy the SafeControl for your installed web Part. And Open your web site config file, paste here the SafeControl tag.
  6. Open your web site. Go to Site Actions > Site Settings > Site collection Features. Now find and activate your installed web Part.
  7. Next, go to site settings> Web Parts here click the “New” link. Here find your installed Web Part and select. Then press “Pop up Gallery” button.
  8. Now you can add web part any page in this site.

  

o            What is the difference between a site and a web?

 

Site is defined as Website. It has many subsites.

Web is a single subsite of the Site.

 

o            What are the differences between web part page gallery, site gallery, virtual server gallery and online gallery?

 

1. Web Part Gallery has a many WebParts.

2. Site Gallery has a many site galleries. For example. Shared Document, Calendar, Announcement, Lists, Tasks, Team Discussion.

3. Virtual Server Gallery has developer developed web parts are stored in a particular server.

 

o            What is the GAC?

 

GAC is Global Assembly Cache. Each computer where the CLR installed has a machine code is called GAC. It stores assemblies. We can use GAC to install the web parts in Sharepoint application.

 

o            What is a DWP?

 

DWP means Dashboard Web Part. The DWP files are importing to the Sharepoint Site after we used.

 

o            What is CAML?

 

CAML is Collaborative Application Markup Language. It is the XML based language. That is used to build a customize web site based on Sharepoint services. It is used to get a list values, particular data in a list.

 

o            What are themes?

 

A theme is a collection of CSS and Graphics. That are modifying / customizing how a web site looks you want.

A Basic web site needs a graphical look and feel. Sharepoint has a some built-in themes. We can create new themes is possible for Sharepoint site.

 

o            What is presence?

Groove features include presence information, chat, application sharing, file sharing, contacts, messaging, project management, data sharing, and content synchronization.

  

o            Can web parts be connected? If so, how?

Yes. Two web parts has sharing information in a runtime. We use the Connection Interfaces to create Connectable Web parts.

 

o            What is a personal view and what is a shared view?

 

A Web Part page view has two views. There are Personal view and Shared View.

 

Personal View: This view is set by each user. For example, one user has changed the list in some format. The changes will not see the other users.

 

Shared View: This view web part designs and any thing is not changed by users. Users will not be changed these types of web parts. The site admin can change the web part view and anything

 

o            What is an STP file?

 

STP means Site Template. We can create new site definition. This definition has webparts and list (there are derived from default Sharepoint components). We can save the file for .stp format.

 

o            What is an FWP file?

 

FWP file is nothing a backup file for Sharepoint site. We can restore and backup the Sharepoint site.

 

o            Can you upload MP3’s to SharePoint?

 

Yes. (http://manish-sharepoint.blogspot.com/2008/06/playing-audiovideo-files-within.html)

 

o            how does SharePoint support MS Outlook integration?

 

We can use some features from OutLook in Sharepoint, ex. Calendar and contacts

 

o            How can you extend lists in SharePoint?

 

We expand the size of the lists. Click Start, point to All Programs, point to Administrative Tools, and then click SharePoint Central Administration.

 

 

o            Explain the document versioning in SharePoint document libraries

 

We can maintain version in all Sharepoint libraries and lists.  When we upload or update any document, while Sharepoint creates version.

Senior SharePoint Consultant

o            Where is web part resources contained?

 

The WebPart resources can not part of the DLL, because there are used in url based. Like images, jscript files. The WebPart is installed in GAC and Bin directory.

 

o            What are the different installation methods for deploying web parts? And what are the pros/cons?

 

  • We use GAC
  • We develop web part in Windows Class Library. While the web part once runs, it will install automatically in GAC.

 

o            What is a ghosted/unghosted page?

 

A Ghosted Page is modified by Sharepoint Designer. Example, Master page.

An Unghosted Page is not modified by Sharepoint Designer. Example, forum pages, calendar lists etc

 

It has another one page there is “Reghosted” it means by Reset to Site Definition

 

o            How is site data stored?

 

In Database.

 

o            Where is metadata for a web stored?

 

Meta Data is stored inside XML files on the server or SQL Server database.

 

o            What is an audience and describe the use?

 

http://www.microsoft.com/learning/en/us/syllabi/3370bfinal.mspx#EJB

 

The primary audience for this clinic is the IT Professional who generally works with both Windows and Office technologies. The types of duties that are typical of this IT Professional are administrative and support duties such as planning and deployment of Office server products in a Microsoft Windows environment, configuration and security administration, and updates of Office upgrades and patches. The target audience for this clinic is IT Professionals that want an overview of what Microsoft Office SharePoint Server 2007 is, and how to deploy it.

 

o            What are the trust levels and what is the default trust associated with Sharepoint?

 

The Sharepoint Trust Levels has Security and user interaction with the site. 3 types. There are WSS_FULL, WSS_MEDIUM, WSS_MINIMUM.

 

 

o            What are the two logging mechanisms for usage statistics?

  • All default log files are stored in \%windir%\system32\LogFiles\STS this path.
  • Virtual server Folder. It’s like a cache.

 

o            What functionality does owssup.dll provide for client side activities?

 

The owssup.dll is used to create Single Sign On in Sharepoint Portal Server.

 

o            What is the difference between a site owner and a site administrator?

 

Site Owner has only individual site and sub sites access only.

Site Administrator access all site and Central Administration

 

o            What is STSAdm and what can it be used for?

 

It is used to create/manage sites, lists, web parts etc..

 

o            Can WSS search subsites?

 

The Subsite has a unique permission of the parent site, we can search subsite content. Until we can’t search Subsite Content.

 

o            Can you register alerts for users?

 

No, the admin can give some permission.

 

o            Are PDFs searchable?

 

Yes, but default is now. We can use IFILTER type functionality do this moment.

 

SharePoint Architect

o            What is a SharePoint farm?

 

It is a deployment scenario, we have two are more server to host Sharepoint. It is 3 types.

1. Small Server, 2. Medium Server, 3. Large Farm.

 

o            Describe a large deployment

 

2 Sharepoint servers 2 SQL Server 1 Search Server 1 Clustering Server. It is called large deployment.

 

o            How can you synchronize custom Active Directory attributes to SharePoint?

 

Profile Importer from Shared Services Provider.

o            If it is anticipated that our organization would need to store 1 terabyte of documents, what is the recommended configuration and storage requirement?

 

It is based on your users count.

 

o            Describe the implementation of SharePoint and Project Server

 

We can use Project server web parts inside Sharepoint portal server and also create dashboards on Sharepoint pages and can also create custom WebParts using PDC and .Net.

 

o            What are the BKMs for workflow and SharePoint?

                                                   

o            Explain how you would deploy SharePoint on an extranet

 

Usually servers that are accessible from external sources are housed in DMZ’s. Depending on the requirements and the workflow for publishing content you could go with Multiple Servers hosting the same information. One server would reside inside with the SQL Cluster while the external server resides in the DMZ simply calling data. Security would be handled by the same or different active directory domain clusters as well increasing security.

 

o            What is the BKM for maximum number of virtual servers configured for SharePoint on a single box?

 

15 Virtual servers.

 

o            What are the migration strategies for moving sites around?

 

You could use the Sharepoint Portal Server backup and restore tool as well as the STSADMIN and GUI STSAMIN tools. We have migrated database from the SQL Level and have simply reconnected the front end.

 

o            What are the archiving strategies?

 

o            Describe the search strategies?

 

o            Can you implement forms-based authentication with SharePoint?

 

Yes. We can implement forms-based authentication with SharePoint.

 

o            Describe how single sign-on works

1. Easily maintain Role and group users’ information in one place.

 

 

 


A base SharePoint web part for AJAX in ASP.NET 3.5

August 8, 2008

Introduction

This article describe an abstract web part class developed for the SharePoint 2007 (WSS 3.0 or MOSS 2007) platform. The web part contains the logic to address some known conflicts between SharePoint and ASP.NET AJAX and is designed as the base class for all AJAX enabled SharePoint web parts.

Background

With SharePoint (WSS 3.0 or MOSS 2007) SP1, AJAX is officially supported. However, there are still lots of manual configuration needs to be performed for AJAX to work in the SharePoint environment. Basically you can create an ASP.NET web application targeting .NET framework 3.5 and merge the AJAX related entries into the web.config of your SharePoint application. However, this is not enough. In the MSDN article titled Walkthrough: Creating a Basic ASP.NET AJAX-enabled Web Part, a technique is introduced to fix the conflict between SharePoint and the ASP.NET AJAX UpdatePanel. This article provides a good starting point for developing AJAX enabled SharePoint web part. However, the technique described in the article had its limitations as well. I will go over these limitations below and explained how they can be addressed.

Using the code

ASP.NET AJAX requires one instance, and only one instance of the ScriptManager on any page. There are several ways to include the ScriptManager in a SharePoint web part page. One thing you can do is to modify the master page. Another common technique is to detect if an instance of the ScriptManager already exist, and create one on demand if it does not exist. I like the later approach as it is more flexible than modifying the master page, which affects all pages regardless if AJAX is used in the page. After all, there are 3rd party AJAX libraries that are not currently compatible with ASP.NET AJAX, and you may not have full control on all the contents that appears on a portal.

After reviewing the life cycles of an ASP.NET page one more time, I decided to place the logic that creates an instance of the ScriptManager inside the OnInit event, and that seems to work pretty well.

Another issue comes with the “EnsurePanelFix” logic, as it too, should not be registered more than once. By creating a common base class for AJAX enabled web part, and register the script using the type of the base web part, the problem can be solved. This is especially good as not only the base web part promotes code reuse, it also fixes problems!

The full code for the web part is included below:

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.Services;
using System.Web.UI;
using System.ComponentModel;
using System.Xml.Serialization;
using System.Web.UI.WebControls;
    public abstract class AjaxBaseWebPart : System.Web.UI.WebControls.WebParts.WebPart
    {
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            // Register the ScriptManager
            ScriptManager scriptManager = ScriptManager.GetCurrent(this.Page);
            if (scriptManager == null)
            {
                scriptManager = new ScriptManager();
                scriptManager.ID = ScriptManager1″;
                scriptManager.EnablePartialRendering = true;
                Controls.AddAt(0, scriptManager);
            }
        }

        protected override void CreateChildControls()
        {
            // Add fix according to http://msdn2.microsoft.com/en-us/library/bb861877.aspx
            EnsurePanelFix();
        }

        private void EnsurePanelFix()
        {
            if (this.Page.Form != null)
            {
                String fixupScript = @”
     _spBodyOnLoadFunctionNames.push(“
_initFormActionAjax”);
     function _initFormActionAjax()
     {
       if (_spEscapedFormAction == document.forms[0].action)
       {
         document.forms[0]._initialAction =
         document.forms[0].action;
       }
     }
     var RestoreToOriginalFormActionCore =
       RestoreToOriginalFormAction;
     RestoreToOriginalFormAction = function()
     {
       if (_spOriginalFormAction != null)
       {
         RestoreToOriginalFormActionCore();
         document.forms[0]._initialAction =
         document.forms[0].action;
       }
     }”
;
                ScriptManager.RegisterStartupScript(this,
                  typeof(AjaxBaseWebPart), UpdatePanelFixup”,
                  fixupScript, true);
            }
        }
    }

Points of Interest

Despite the official support of AJAX in SP1 of SharePoint 2007, it still take lots of effort to start using AJAX in the SharePoint environment. Maybe the next service patch for Visual Studio 2008 will provide the same support for SharePoint development as the support we get for ASP.NET 3.5 AJAX? Let’s keep our fingers crossed.


ASP.NET AJAX and Web Parts in Windows SharePoint Services 3.0

August 8, 2008

You can now extend Microsoft ASP.NET 2.0 by using Microsoft ASP.NET 2.0 AJAX Extensions 1.0, which is a new Microsoft Web development technology that integrates cross-browser script libraries with the ASP.NET 2.0 Web application framework. ASP.NET AJAX allows you to quickly create pages with sophisticated, responsive user interfaces and more efficient client-server communication, simply by adding a few server controls to your Web pages.

This topic introduces Microsoft ASP.NET AJAX Extensions 1.0 technology in the context of Windows SharePoint Services 3.0. It also provides an overview of the server controls provided with ASP.NET AJAX. For a comprehensive look at the technology behind ASP.NET AJAX, see About ASP.NET AJAX.

Microsoft ASP.NET AJAX

ASP.NET AJAX enables you to create Web pages that use partial-page updates to create a dynamic user experience. ASP.NET AJAX includes AJAX Extensions 1.0, which is the server-side control framework, and the Microsoft AJAX Library, which is the set of client-side browser scripts.

The Microsoft AJAX Library can be installed without the .NET Framework. It can also be used in environments that are not Windows-based, to create Web applications for browsers that support JavaScript. See ASP.NET AJAX Downloads to download the ASP.NET 2.0 AJAX Extensions 1.0, the Microsoft AJAX Library, and other ASP.NET AJAX components.

Server Controls in Microsoft ASP.NET AJAX

ASP.NET 2.0 AJAX Extensions include server-side controls that are used for partial-page updates, as well as progress bars, timers, and script management components. A brief overview of the server-side controls is included here.

ScriptManager

The ScriptManager control manages all client script for ASP.NET AJAX. The ScriptManger automatically registers the script for ASP.NET AJAX when you add it to the Web page. You must add this as the first item in the page controls collection. The ScriptManager controls partial-page rendering in a browser when a page contains one or more UpdatePanel controls.

UpdatePanel

The UpdatePanel control stores other controls and allows partial-page updates. The UpdatePanel control allows you to request partial-page updates without writing any client script. You can, however, add custom client-side script if you want to enhance the client user experience. The UpdatePanel and associated triggers are tracked by the ScriptManager control.

UpdateProgress

The UpdateProgress control provides status information on partial-page updates in UpdatePanel controls. By default, a div element is created and displayed while an update is in progress. You can customize the default display of the div control by using the ProgressTemplate property.

Timer

The Timer control fires a postback at defined intervals. You can also use the Timer control to post the whole page rather than partial-page updates. Timer controls can be used inside or outside of an UpdatePanel control. If you want the Timer control to trigger an update, you must add a trigger attribute to the UpdatePanel control declaration.


Build web parts with AJAX

August 8, 2008

In this post I’m going to explain how to start using ajax in your web parts.  The goal of this article is to reproduce functionality similar to the KPI and BDC web parts in MOSS 2007.  If you don’t know what ajax is or the basics of how it works this article is probably not for you.

ASP.net 2.0 has a cool new feature called client script call backs.  Script call backs basically allow you to use javascript to execute a server side method in your assembly and then do something with the result. This allows you to dynamically update parts of the page, or in this case the webpart, without refreshing the entire page.  This article (http://msdn.microsoft.com/msdnmag/issues/04/08/CuttingEdge/) has a nice explanation of how script call backs work in .net 2.0 but the details of how to actually use it in your code are outdated, so follow the instructions in this post, not the msdn one.  The fact that the script call back feature is built into .net makes it really easy to implement and use.

For this example we will pretend that we have a web part that takes a long time to generate its display. To solve this problem we are going to have the render method output a blank div tag when the web part is initially loaded and then replace the contents of the div, via ajax, with the actual content for the webpart. This will allow the page to load and let the user look at everything else on the page while our web part is loading. Lets get started….

Go ahead and create a new web part project. Add the following directive at the top of your web part class…

using System.Web.UI;

 

 

To let .net know that your class is using script call backs you have to implement the System.Web.UI.ICallbackEventHandler interface….

public class TreeViewRollUp : System.Web.UI.ICallbackEventHandler

 

 

The ICallBackEventHandler interface has two methods,  public string GetCallbackResult() and public void RaiseCallbackEvent(string eventArgs). We will cover these alittle later on.

Now go ahead and add two class variables..

private string datadiv; //This will hold the name of your div tag
private string ajaxdata; //This will hold the data that is returned via ajax…

 

 

The datadiv variable contains the html id of the div tag we are using to render our contents in. The name of this div tag should be unique per instance of the web part. If it was the same name all the time and you had two instances of the web part on the same page they would replace each others contents.

Now add the following to your render method…

this.datadiv = this.ClientID + “content”;  //Uses the client side id of the web part instance + a name we give it

 

writer.Write(“<div id=\”” + this.datadiv + “\”><img src=\”_layouts/images/kpiprogressbar.GIF\” width\”150\”></div>”);

 

 

You can see in the last line we write the div tag with an image in it. This is just the little progress gif animation that the kpi web parts use. You can replace this with whatever you want and it won’t really affect anything.

Now in your OnLoad handler paste the following code…

protected override void OnLoad(EventArgs e)

        {

            this.datadiv = this.ClientID + “content”;

           

string js = Page.ClientScript.GetCallbackEventReference(this, “‘blah'”, “filldiv”, “‘” + this.datadiv + “‘”, true);

           

string contentloader = “var ajaxcommands=”;  window.onload = ajaxloader; function ajaxloader () { eval(ajaxcommands); } function filldiv(arg, ctx) { var mydiv = document.getElementById(ctx); mydiv.innerHTML = arg; }”;    

            if (Page.ClientScript.IsClientScriptBlockRegistered(“contentloader “) == false)

                Page.ClientScript.RegisterClientScriptBlock(Page.ClientScript.GetType(), “contentloader”, contentloader, true);

            Page.ClientScript.RegisterStartupScript(this.GetType(), “myloader”, ” ajaxcommands = ajaxcommands + \”” + js + “;\”;”, true);

            base.OnLoad(e);

        }

 

 

In this method there are two different blocks of javascript that we are registering. The first string, js, is being set by the GetCallbackEventReference. The GetCallbackEventReference method basically returns the javascript that executes the call back to the server to retrieve the data.  We are passing it a reference to our control (the webpart), “Blah” as some initial data that will get passed back to our assembly when the call back is initiated,  the name of the javascript method to execute once the callback is complete, the name of our div tag as the context, and setting asynchronous to true. The javascript code generated by this will look similar to the following…

WebForm_DoCallback(‘ctl00$m$g_a010b3bd_1a68_40f9_b46b_f87050cf516f’,’blah’,filldiv,’ctl00_m_g_a010b3bd_1a68_40f9_b46b_f87050cf516fcontents’,null,true);

Now we could stop here and just use this javascript in the OnClick event of a button to initiate the callback to populate the div tag. For this example we don’t want the user to have to click anything to continue loading the web part so we are going to call the WebForm_DoCallback method when the browser loads. That’s what the contentloader string is all about.  The contentloader  string declares a javascript variable, ajaxcommands,  that holds the command(s) we would like to execute. It also sets the window.onload event to execute the ajaxloader method.  When the ajaxloader  method runs it will use the eval function to execute all the commands stored in the ajaxcommands variable.  The reason you have to do it this way is because if you have more than once instance of your ajax web part on page both of them will try to use the window.onload event to load their data, which creates a problem because only the last set event handler will execute, not both.  So we set a common method to window.onload event and then each web part just appends its WebForm_DoCallback code to the ajaxcommands variable.  This is kind of funky, and I’m sure there is a better way to do it, but it seems to work for me. Finally the contentloader string also includes the filldiv function that gets executed when the call back is completed. The filldiv method simply sets the innerhtml of the div to the contents returned from the callback.

The final step in the OnLoad method of our class is to register the scripts with the page.  Since we only want the contentloader javascript to be rendered once on each page we need to check to see if it has already been registered with the script manager by another webpart on the page.

Now all we have left to do is implement the two methods required by the ICallbackEventHandler interface…

       public string GetCallbackResult()

        {

            return this.ajaxdata;

        }

        public void RaiseCallbackEvent(string eventArgs)

        {

            this.ajaxdata = “Some crazy message here!”;

        }

 

 

 

RaiseCallbackEvent is invoked when the client call back is started.  It is a void method so it doesn’t actually return anything, just sort of gets the data ready for the GetCallbackResult method to return it.   The RaiseCallbackEvent method is where you would put all the code that typically goes in your web parts Render method. In this example we are just going to be sending a simple message back to the client. Go ahead and compile and test it out.

Well hopefully this will help you get started using script call backs. Please post comments or suggestions if you have any.


“Microsoft.SharePoint.SPException: One or more field types are not installed properly.” Using SPQuery

August 6, 2008

Have you run into this error? “Microsoft.SharePoint.SPException: One or more field types are not installed properly.” ? Well I did, I was banging my head into the wall, until I realized that the fields had been renamed at some point, and when referencing splistItem[”FieldName”] in my code, it was not recognizing the updated name. So make sure you reference either the GUID or the name it was before renaming.


Programmatically uploading multiple files to Custom sharepoint list in 2007

August 6, 2008

Introduction:

 

A custom SharePoint list can be configured to collect any type of data and SharePoint automatically generates the forms for adding new items, editing items and viewing items.

 

Team Web site comes with a built-in List Calendar, Task, which is listed on the Quick Launch bar. A new custom list has to be created for storing the files.

Steps creating custom list:

 

 

 

Custom list created

 

 

Custom Column Creation

  1. While creating custom list Named as FileList default column will create Title.
  2. Modify column name Title as Filename.
  3. Create one more column as Filedate.
  4. Create one more column as FileSize.

Implementation of Web part

The files are added to the custom GridView (list) in web part level using browse file upload button. You can add and delete multiple files in this list. Finally all the files are uploaded in custom share point list Filelist using submit button in webpart.

 

The steps to create a web part

  • Make sure installed VS.net 2005.
  • Make sure installed Web part Project Library in your system.
  • Start VS.Net 2005 and create a new project.
  • Select Project Type as Visual C#–>SharePoint.
  • Visual Studio Installed templates as Web Part.
  • Change Name as MultipleUploadWebpart.
  • Change Location as e:\ MultipleUploadWebpart.
  • Change Solution name as FileUploadWebPart.

 

Using the Render method

 

The Web part base class seals the Render method of System.Web.UI.Control because the Web Part infrastructure needs to control rendering the contents of a Web Part. For this reason, custom Web Parts must override the Render method of the Web part base class.


The Complete Web part Code

 

#region File Information

///<summary>

/// ——————————————————————————————————

/// Namespace : MultipleFileUploadWebPart

///

/// Purpose   : To Create Webpart to programmatically upload MultipleFiles to Custom SharePoint List

///        

/// Change History

/// ——————————————————————————————————-

/// Date            Edit            Author            Comment             

/// ————-+——–+——————————————————————————-

/// 12-July-2007    [100]          Saravanan_Gajendran     Create Webpart

/// ————-+——–+——————————————————————————-

///</summary>

using System;

using System.Runtime.InteropServices;

using System.Web.UI;

using System.Web;

using System.Web.UI.WebControls;

using System.Web.UI.HtmlControls;

using System.Web.UI.WebControls.WebParts;

using System.Xml.Serialization;

using System.Data;

using System.IO;

using System.Text;

using System.Web.SessionState;

using Microsoft.SharePoint;

using Microsoft.SharePoint.WebControls;

using Microsoft.SharePoint.WebPartPages;

 

namespace MultipleUploadWebpart

{

     [Guid(“2115a405-ff46-4040-8370-6e4fcb7b9194”)]

     public class MultipleUploadWebpart : System.Web.UI.WebControls.WebParts.WebPart

     {

          #region Variables

          private HtmlInputFile inputFile;

          private Button btnUpload;

          private Label lblMessage;

          private GridView dgdUpload;

          private string fileName = “”;

          private Button btnSubmit;

          private HyperLinkField hlnkFileName;        

          private BoundField bndFileSize;

          private BoundField bndFileKb;

          private ButtonColumn btnclmDelete;

          private CommandField cmdDelete;

          private double length;

          byte[] contents;

          DataTable dt;//datatable use for multiple file upload

          DataRow dr;//datarow use for multiple file upload

          DataColumn dc;//datacolumn use for multiple file upload

          double count = 0;//count of file size

          #endregion

          #region Create Child Control

          protected override void CreateChildControls()

          {

               #region inputfile

               this.inputFile = new HtmlInputFile();

               this.inputFile.ID = “_fileUpload”;

               #endregion           

               #region message label

               this.lblMessage = new Label();

               this.lblMessage.ID = “_lblMessage”;

               this.lblMessage.Text = “”;
               #endregion
  
               #region
  Button

               this.btnUpload = new Button();

               this.btnUpload.ID = “_btnUploadUpload”;

               this.btnUpload.Text = “Upload”;

               this.btnUpload.Click += new EventHandler(btnUploadUploadClick);

               this.btnSubmit = new Button();

               this.btnSubmit.ID = “_btnSubmit”;

               this.btnSubmit.Text = “Submit”;

               this.btnSubmit.Click += new EventHandler(btnSubmit_Click);

               #endregion

               #region GridView

               this.dgdUpload = new GridView();

               this.hlnkFileName = new HyperLinkField();

               this.hlnkFileName.DataTextField = “FileName”;

               this.hlnkFileName.DataNavigateUrlFormatString = “FilePath”;

               this.hlnkFileName.HeaderText = “FileName”;

               this.bndFileSize = new BoundField();

               this.bndFileSize.HeaderText = “FileSize”;

               this.bndFileSize.DataField = “FileSize”;

               this.bndFileKb = new BoundField();

               this.bndFileKb.HeaderText = “”;

               this.bndFileKb.DataField = “KB”;

               this.cmdDelete = new CommandField();

               this.cmdDelete.HeaderText = “Delete”;

               this.cmdDelete.ButtonType = ButtonType.Link;

               this.cmdDelete.InsertImageUrl = “delete.gif”;

               this.cmdDelete.DeleteText = “Delete”;

               this.cmdDelete.ShowDeleteButton = true;

               this.dgdUpload.ID = “_dgdFileUpload”;

               this.dgdUpload.Columns.Add(hlnkFileName);

               this.dgdUpload.Columns.Add(bndFileSize);

               this.dgdUpload.Columns.Add(bndFileKb);

               this.dgdUpload.Columns.Add(cmdDelete);

               this.dgdUpload.AutoGenerateColumns = false;          

               this.dgdUpload.RowDeleting += new GridViewDeleteEventHandler
              
(dgdUpload_RowDeleting);

               #endregion

               #region Add Controls

               this.Controls.Add(dgdUpload);

               this.Controls.Add(inputFile);
               this.Controls.Add(lblMessage);

               this.Controls.Add(btnUpload);

               this.Controls.Add(btnSubmit);

               base.CreateChildControls();

               #endregion

          }

          #endregion

          #region RowDeleting

          private void dgdUpload_RowDeleting(object sender, GridViewDeleteEventArgs e)

          {

               int recordToDelete= e.RowIndex;

               dt = (DataTable)Page.Session[“Files”];

               int cn = dt.Rows.Count;

               dt.Rows.RemoveAt(recordToDelete);

               dt.AcceptChanges();
               Page.Session[“Files”] = dt;
               this.dgdUpload.DataSource = dt
               this.dgdUpload.DataBind();

           }

           #endregion

           #region OnLoad

           protected override void OnLoad(EventArgs e)

           {

                base.OnLoad(e);

           }

           #endregion

           #region File in SharePoint List

           private void btnSubmit_Click(object sender, EventArgs e)

           {

                SPWeb site = SPContext.Current.Web;

                SPList list = site.Lists[“FileList”];

                SPListItem myNewItem ;          

                dt = (DataTable)Page.Session[“Files”];

                int _dtcnt = dt.Rows.Count;

                string strDate=“”;

                foreach (DataRow dr in dt.Rows)

            {

                 strDate = System.DateTime.Now.Date.TimeOfDay.ToString();

                 myNewItem = list.Items.Add();

                 fileName = dr[“Filename”].ToString();              

                 string strFilepath= dr[“FilePath”].ToString()

                 StreamReader sr = new StreamReader(strFilepath);

                 Stream fStream=sr.BaseStream ;               

                 contents = new byte[fStream.Length];

                 fStream.Read(contents, 0, (int)fStream.Length);

                 fStream.Close();

                 myNewItem[“Filename”] = dr[“Filename”].ToString();

                 myNewItem[“FileSize”] = dr[“FileSize”].ToString();

                 myNewItem[“Filedate”] = strDate;

                 myNewItem.Attachments.Add(fileName, contents);

                 myNewItem.Update();

                 System.IO.File.Delete(strFilepath);

             }

             lblMessage.Text = “Sucessfully Submited”;

             }

             #endregion

             #region Upload File Add in List

             protected void btnUploadUploadClick(object sender, EventArgs e)

             {

                  fileName = System.IO.Path.GetFileName(inputFile.PostedFile.FileName);

                  if (fileName != “”)

             {

                  string _fileTime = DateTime.Now.ToFileTime().ToString();

                  string _fileorgPath =  System.IO.Path.GetFullPath
                  (inputFile.PostedFile.FileName);

                  string _newfilePath = _fileTime + “~” + fileName;

                  length = (inputFile.PostedFile.InputStream.Length) / 1024;

                  string tempFolder = Environment.GetEnvironmentVariable(“TEMP”);

                  string _filepath = tempFolder + _newfilePath;               

                  inputFile.PostedFile.SaveAs(_filepath);

                  AddRow(fileName, _filepath, length);

                  lblMessage.Text = “Successfully Added in List”;

             }

             else
 
           {

                  lblMessage.Text=“Select a File”;

                  return;

             }

        }

        #endregion

        #region Render

        protected override void Render(HtmlTextWriter writer)

        {

             // TODO: add custom rendering code here.

             EnsureChildControls();

             this.inputFile.RenderControl(writer);

             this.btnUpload.RenderControl(writer);

             this.lblMessage.RenderControl(writer);

             this.dgdUpload.RenderControl(writer);

             this.btnSubmit.RenderControl(writer);

        }

        #endregion

        #region AddMoreRows for file upload

        private void AddMoreColumns()

        {

             dt = new DataTable(“Files”);

             dc = new DataColumn(“FileName”, Type.GetType(“System.String”));

             dt.Columns.Add(dc);

             dc = new DataColumn(“FilePath”, Type.GetType(“System.String”));

             dt.Columns.Add(dc);

             dc = new DataColumn(“FileSize”, Type.GetType(“System.String”));

             dt.Columns.Add(dc);

             dc = new DataColumn(“KB”, Type.GetType(“System.String”));

             dt.Columns.Add(dc);

             Page.Session[“Files”] = dt;

        }

        #endregion

        #region AddRow for file upload

        private void AddRow(string file, string path, double length)

        {

             dt = (DataTable)Page.Session[“Files”];

             if (dt == null)

            {

                 AddMoreColumns();

            }

            dr = dt.NewRow();

            dr[“FileName”] = file;

            dr[“FilePath”] = path;          

            dr[“FileSize”] = Convert.ToString(length);

            dr[“KB”] = “KB”;         

            dt.Rows.Add(dr);

            Page.Session[“Files”] = dt;

            this.dgdUpload.DataSource = dt;

            this.dgdUpload.DataBind();//bind in grid

       }

       #endregion

   }
}

 

 

Deploy File Upload Web part in the share point server

  1. Right click solution file then select properties. 

  1. Select Debug Start browser with URL selects your respective SharePoint Site.


  2. Select Signing option.


  3. Ensure the strong name key and sign the assembly check box.
  4. Right Click properties select Deploy.


  5. It is automatically deployed the web part in respective site.
  6. Deploy will take care of .Stop IIS, Buliding solution, Restarting Solution, Creating GAC, Restarting IIS like that.


  7. Multiple Upload Webpart is new one.
  8. New MultipleUploadWebpart Web Part.

Events

1. Browse Button

It is used to browse and select the particular file.

2. Upload Button

It is used to upload file to the windows temp folder then list the files.

3. Submit Button

It is used to store all files in share point custom list.

All the files are listed

Delete

using this option you need to delete the file in this list.Whenever you give the submit only it will go to SharePoint list.

All the files are uploading in respective share point custom list.

 


The Long Path to Content Deployment

August 6, 2008

Recently I’ve had the pleasure to use the content deployment feature of MOSS between some of our SharePoint environments.

It was not a smooth ride and I believe that I have now met every single obstacle and bug in that feature. This posting is the result of several months’ worth of frustration.

We got three environments Dev, Test and Prod and we want to use content deployment to move content from the production servers to the development and test servers, simply to ensure current test data.

As a side node, you might want to read the Microsoft brief “Team-based Development in Microsoft Office SharePoint Server 2007” for another good reason to make content deployment one of your skills.

Well, without beating around the bush anymore the following are the steps needed to do a content deployment (with some minor obvious exceptions) in order of appearance.

Setup path

Content deployment requires you to first setup a path and then one or more jobs for that path. Simply put the path is the server to server connection configuration, the job is a specification of what to do and when.

I try to use security best practices so all my both service users are just standard domain users, any special rights they might need are assigned by MOSS during the configuration wizard. In the same vein my farm administrator accounts are standard domain users that are assigned extra permissions only through SharePoint.

 

The first problem with creating a path is an access denied problem during the path setup page (/_admin/DeploymentPath.aspx), when you select the source web application and site collection. For the destination site collection you are required to provide an explicit user with sufficient rights.

Figure 1: The “Access denied” message

It seems that your logged in user needs to be able to read the IIS metabase when you select a web application. There are many ways to grant access, I choose to add my farm administrator to the IIS_WPG local security group on the server. In my opinion the SharePoint team forgot to impersonate the call to read the IIS metadata. Will hopefully be fixed in some future service pack.

The second problem (on the very same page) occurs if you connect to another farm using SSL (which you should!) – You get the exception “Requested registry access not allowed” when you submit the page.

After some tracing I’ve learned that the problem is that the server tries to store the SSL key for your destination server in the registry hive for the system user, which is the correct one, but apparently the SharePoint configuration wizard tightened the security on the keys in question.

To get around this: Grant your user (farm admin) membership to the local WSS_RESTRICTED_WPG security group and grant that group “full control” to HKEY_USERS\.DEFAULT\Software\Microsoft\SystemCertificates. You could also opt for granting your user direct access to the key.

To sum it up:

  1. Your logged in user should be a farm administrator
  2. Should be a member of either the local IIS_WPG or WSS_WPG groups
  3. Grant access to HKEY_USERS\.DEFAULT\Software\Microsoft\SystemCertificates
    1. Add user to WSS_RESTRICTED_WPG group
    2. Grant that group “full control” access to the key

That’s it! You should now be able to setup a path.

Setup Job

Next setup the job to your liking, choose whatever options you desire.

Run the job. If it succeeds then stop reading now and save a few minutes of your time. No? Carry on then…

Hotfix deployment

At this point I got the following exception:

User cannot be found. at Microsoft.SharePoint.SPUserCollection.GetByID(Int32 id) at Microsoft.SharePoint.SPWeb.get_Author() at Microsoft.SharePoint.Deployment.WebSerializer.GetDataFromObjectModel(Object obj, SerializationInfo info, StreamingContext context) at Microsoft.SharePoint.Deployment.DeploymentSerializationSurrogate.GetObjectData(Object obj, SerializationInfo info, StreamingContext context) at Microsoft.SharePoint.Deployment.XmlFormatter.SerializeObject(Object obj, ISerializationSurrogate surrogate, String elementName, Boolean bNeedEnvelope) at Microsoft.SharePoint.Deployment.XmlFormatter.Serialize(Stream serializationStream, Object topLevelObject) at Microsoft.SharePoint.Deployment.ObjectSerializer.Serialize(DeploymentObject deployObject, Stream serializationStream) at Microsoft.SharePoint.Deployment.SPExport.SerializeObjects() at Microsoft.SharePoint.Deployment.SPExport.Run()

Looking like this:

Figure 2: Deployment error – no creator/owner of site

The exception occurs fairly quickly during the preparation phase. It obviously indicates that a creator of a (sub) site it not to be found in the SharePoint user database.

In my case it happened because the farm was originally deployed using a site collection backup/restore from another AD domain, the creators of various sites would then be users in the original SharePoint farm which would be unknown in the new (which is now my source). I suppose you might see this error if you deleted some users as well.

There is nothing you can do about this error; Microsoft however, has a hotfix for this (which also solves a few other bugs). Hotfix number is 313183 and the knowledge base article you are trying to address is kb936867. At the moment of writing this is private hotfix that can only be obtained by contacting MS support. Sucks but there is a way at least.

The hotfix solves a total of 11 bugs including one more in relation to Content Deployment entitled “Violation of PRIMARY KEY” – it seems I avoided one snag after all.

Feature problems

Next error in line occurred right after the last during the export phase. I received the very informative exception:

Failed to compare two elements in the array.
at System.Collections.Generic.ArraySortHelper`1.QuickSort[TValue](T[] keys, TValue[] values, Int32 left, Int32 right, IComparer`1 comparer)
at System.Collections.Generic.ArraySortHelper`1.QuickSort[TValue](T[] keys, TValue[] values, Int32 left, Int32 right, IComparer`1 comparer)
at System.Collections.Generic.ArraySortHelper`1.QuickSort[TValue](T[] keys, TValue[] values, Int32 left, Int32 right, IComparer`1 comparer)
at System.Collections.Generic.ArraySortHelper`1.Sort[TValue](T[] keys, TValue[] values, Int32 index, Int32 length, IComparer`1 comparer)
at System.Collections.Generic.ArraySortHelper`1.Sort(T[] items, Int32 index, Int32 length, IComparer`1 comparer)
at System.Array.Sort[T](T[] array, Int32 index, Int32 length, IComparer`1 comparer)
at System.Collections.Generic.List`1.Sort(Int32 index, Int32 count, IComparer`1 comparer)
at System.Collections.Generic.List`1.Sort(IComparer`1 comparer)
at Microsoft.SharePoint.Deployment.WebSerializer.GetDataFromObjectModel(Object obj, SerializationInfo info, StreamingContext context)
at Microsoft.SharePoint.Deployment.DeploymentSerializationSurrogate.GetObjectData(Object obj, SerializationInfo info, StreamingContext context)
at Microsoft.SharePoint.Deployment.XmlFormatter.SerializeObject(Object obj, ISerializationSurrogate surrogate, String elementName, Boolean bNeedEnvelope)
at Microsoft.SharePoint.Deployment.XmlFormatter.Serialize(Stream serializationStream, Object topLevelObject)
at Microsoft.SharePoint.Deployment.ObjectSerializer.Serialize(DeploymentObject deployObject, Stream serializationStream)
at Microsoft.SharePoint.Deployment.SPExport.SerializeObjects()
at Microsoft.SharePoint.Deployment.SPExport.Run()
*** Inner exception:
Object reference not set to an instance of an object.
at Microsoft.SharePoint.SPFeature.EnsureProperties()
at Microsoft.SharePoint.SPFeature.get_TimeActivated()
at Microsoft.SharePoint.Deployment.WebSerializer.ExportFeatureComparer.System.Collections.Generic.IComparer .Compare(ExportObject exportObject1, ExportObject exportObject2)
at System.Collections.Generic.ArraySortHelper`1.QuickSort[TValue](T[] keys, TValue[] values, Int32 left, Int32 right, IComparer`1 comparer)

Going to the source server I tried to pinpoint the error by running “stsadm –o export …” on the base site collection url (same error) and then the first level of sub sites (all exported fine).

That command is exactly the same as a content deployment just without the transfer and import part on the destination end (you are responsible for transfer and then use the import command).

The exception basically means that some of the features activated at the site collection level no longer exist on disk. Their feature definition files have probably been deleted. This can easily occur if you delete some features from your solution packs without deactivating/reactivating all features on deployment (and who cares to do that?).

If you know exactly what features are the problem (might be more than you know) I suppose you might be able to reinstall, deactivate and then uninstall to fix the problem. You might also be able to create dummy features with the correct ids and then try to install, deactivate and uninstall.

I did neither; code had to be written ;-)

What you need to do is:

  1. Go recursively through your web application / site collection / root web / web
  2. Each of these “parent” objects have a Feature collection
  3. Each of these features in the feature collection should be examined
    1. If there is no feature.Definition (== null) then this is one of the faulty features.Simple remove it by executing parent.Features.Remove( id, true ). The force parameter is needed since the feature is not properly installed anymore, so you just remove it without any knowledge of deactivation event handlers etc.

I wrote an aspx page for this that is installed as a feature in the Central Administration site:

Figure 3: My page to list and possibly remove features from web app / site / web

Pretty cool -)

In due time, I will clean up the code and publish another article about this administration feature along with a few others that I’ve developed and since found indispensable.

Server Name Problem

Finally the export phase can be completed. Next problem is the transfer phase, which simply moves the exported files from the server assigned the task of performing the content deployment job to the destination server. In the path specification the location of the Central Administration site on the destination server is specified along with the destination web application and site collection.

The source server tries to export the file directly to the destination server handling content deployment jobs, which might or might not be the same server that’s running the Central Administration site. It does so by resolving the FQDN (Fully Qualified Domain Name) of the server, which might very likely be a problem to you.

If you deploy content between servers in separate network segments this won’t work out of the box, e.g. the source server can probably not find your destination server by the name “my_dest_server.my_domain”, which is only known within the immediate local AD domain of that server.

There’s no reason to think too deeply about these names – just try to do a content deployment and if it fails during the transport phase it’ll report “The remote upload Web request failed” along with the name it’s trying to resolve. A similar event log entry is also created:


Event Type: Error
Event Source: Windows SharePoint Services 3
Event Category: Timer
Event ID: 6398
Date: 6/12/2007
Time: 9:48:07 PM
User: N/A
Computer:
Description:

The Execute method of job definition Microsoft.SharePoint.Publishing.Administration.ContentDeploymentJobDefinition (ID 2f94ff2b-2aa1-498b-96ba-649c2e75ada7) threw an exception. More information is included below.

The remote name could not be resolved: ‘servername.dev.local’

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.

The fix is simple:

  1. Open your host file, usually located at c:\windows\system32\drivers\etc\hosts
  2. Add a new line (don’t delete existing lines): “qqq.xxx.yyy.zzz servername.dev.local“. Be sure to use the correct ip address and name for your destination server. Remember that it should be an ip address that works from the source server (in some cases internal other external ip). You can probably get away with specifying the same ip address you used for the Central Administration site in that path definition – if you used a dns name then just ping the dns and grab the ip address.
  3. Save the file
  4. Retry your content deployment. No need to restart any services the fix is immediate.

Feature problems – part II

We’re now in the import phase and almost through. During the import SharePoint will check whether all the activated features at the source site collection (and sub sites) are also available at the destination site collection.

If not you’ll get an informative error, similar to: “Content deployment job ‘Remote import job for job with sourceID = 71bb6ada-762c-4e78-8bc3-2a105bbe5988′ failed.The exception thrown was ‘Microsoft.SharePoint.SPException’ : ‘Could not find Feature xxxxxx.’

The solution is obvious – install the same solutions/features at the destination web application as on the source.

Specified Name is already in use

If you get an error similar to “Content deployment job ‘Remote import job for job with sourceID = 71bb6ada-762c-4e78-8bc3-2a105bbe5988′ failed.The exception thrown was ‘Microsoft.SharePoint.SPException’ : ‘The specified name is already in use. A list, survey, discussion board, or document library cannot have the same name as another list, survey, discussion board, or document library in this Web site. Use your browser’s Back button, and type a new name.’

You forgot to read the manual (ok, blogs) that specifies that the destination site collection should be a brand new blank site collection – in my case I tried to export to a newly created publishing site collection.

The Small Print

Finally your content deployment ought to be complete -)

If your site looks a bit strange it’s probably because the master page settings wasn’t copied, so you’ll have to assign the correct master page through the site settings. Might also be the case for the welcome page, though I haven’t confirmed it.

During the export every file of your site will be copied to the deployment package so if any files have gone missing you’ll get appropriate warnings during the export, but it’ll still complete.

This is actually a great way to detect if any aspx files have been deleted by accident, e.g. an AllItems.aspx page for a custom list might have gone missing if somebody changed the list definition (probably deployed within a feature).

Phew! At least it works for me now…

(Updated) Other bugs

This is a small list of other bugs I’ve heard/read about

1. (Thanks Harry!) The Cab-files are not always deleted and remain in the folder C:\WINDOWS\Temp\ContentDeployment. Regardless of the content deployment setting of the number of jobs to keep, they will not be deleted. Roll your own workaround and delete the files. You could schedule a job to delete everything older than 1 day (as I’m sure your job can complete in less time than that)

And of course: Move the directory location to a non-system drive

2. (Thanks Harry!) Specific sites within the site collection: I select only the language-variations but not the root. After Test Job or Run Now the root has been always added to the Scope (Fix 937208 apparently solves the problem)

3. Some characters are mangled after deployment, specifically “nbsp;” in html fields (probably a lot of others too). Update: This has been fixed with hotfix 938536 (private hotfix for now – sorry) -)

4. Missing disk space on destination server will be reported (on the source server) as
Failed to read package file. at Microsoft.SharePoint.Deployment.ImportDataFileManager.Uncompress(SPRequest request) at Microsoft.SharePoint.Deployment.SPImport.Run() *** Inner exception: Failure writing to target file at Microsoft.SharePoint.Library.SPRequest.ExtractFilesFromCabinet(String bstrTempDirectory, String bstrCabFileLocation) at Microsoft.SharePoint.Deployment.ImportDataFileManager.<>c__DisplayClass2.<Uncompress>b__0() at Microsoft.SharePoint.SPSecurity.CodeToRunElevatedWrapper(Object state) at Microsoft.SharePoint.SPSecurity.<>c__DisplayClass4.<RunWithElevatedPrivileges>b__2() at Microsoft.SharePoint.Utilities.SecurityContext.RunAsProcess(CodeToRunElevated secureCode) at Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(WaitCallback secureCode, Object param) at Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(CodeToRunElevated secureCode) at Microsoft.SharePoint.Deployment.ImportDataFileManager.Uncompress(SPRequest request)

5. If you choose to copy “all” security information between servers not in the same domain you might get the following error (copying role definitions only works fine)
A duplicate name “62c4fcbb-7ff7-4cc3-842e-17476b2e6219″ was found. at Microsoft.SharePoint.SPFieldCollection.AddFieldAsXmlInternal(String schemaXml, Boolean addToDefaultView, SPAddFieldOptions op) at Microsoft.SharePoint.Deployment.ListSerializer.CreateOrUpdateField(SPList list, String fieldName, XmlNode fieldNode) at Microsoft.SharePoint.Deployment.ListSerializer.UpdateListFields(SPList list, Dictionary`2 listMetaData) at Microsoft.SharePoint.Deployment.ListSerializer.SetObjectData(Object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) at Microsoft.SharePoint.Deployment.XmlFormatter.ParseObject(Type objectType, Boolean isChildObject) at Microsoft.SharePoint.Deployment.XmlFormatter.DeserializeObject(Type objectType, Boolean isChildObject, DeploymentObject envelope) at Microsoft.SharePoint.Deployment.XmlFormatter.Deserialize(Stream serializationStream) at Microsoft.SharePoint.Deployment.ObjectSerializer.Deserialize(Stream serializationStream) at Microsoft.SharePoint.Deployment.ImportObjectManager.ProcessObject(XmlReader xmlReader) at Microsoft.SharePoint.Deployment.SPImport.DeserializeObjects() at Microsoft.SharePoint.Deployment.SPImport.Run()

On hotfixes: Please note that hotfixes are cumulative and later numbers super seeds earlier ones – so the game is to get the highest number of all 😉 

(Updated) Conclusion (sort of)

Some of you have asked (in the comments) whether or not it all worked in the end. It actually did work! -) All of the above steps where enough to solve our immediate problems with the content deployment between our three environments.

Great! So do we use it? No.

We really really wanted to use this feature and all looked so well after our the latest hotfix deployment that we planned to use it for the existing publishing site as well as for a some additional upcoming site collections we’re developing.

One particular annoying feature (sorry for the pun) is breaking the content deployment which I have yet to find a solution for. The new sites are based on custom site definitions and a number of features that creates custom content types and site columns from a number of xml files. Some of these site columns are lookup columns that which cannot be created with xml files the same way as every other site column, because they need to refer to an existing list by list id (in the xml file) but the list will be assigned a dynamic id by the system when it’s created (by another feature that the site columns is dependent on).

To get around that problem a feature activation handled is executed that creates the lookup site columns using custom code that find the dynamic list id from the name. That code is roughly based on code found on codeplex (here). Some minor differences: I fixed some bugs with internal/display name mixup, reactivation problems and a missing “webid” (had to be dynamic as well) in the constructed field. The missing “webid” did cause content deployment to fail immediatly. For some reason I have yet to track down it now fails if the content type using one of the lookup site columns is in use, i.e. a list item of that type exists anywhere in the site collection. For lookup site columns created through the web interface there are no problems. Bummer.

The choice we’re facing (barring that I manage to solve the problem before long) is

1. Either: We can define the content type through xml files

2. Or: we can use content deployment and create content types manually through the web interface – they will be copied as part of the content deployment)

We chose the first option as content deployment at the current level of maturity seems too unstable. Furthermore we also decided to use only one strategy and therefore not use the content deployment for the first site collection that this article originally targetted (one where all content types where created through the web interface).  

How do we do it now? We use “stsadm -o backup/restore” to deploy new versions of the site. It’s essentially a database backup with all the benefits and drawbacks of such. It’s very stable. Specifically history of all items are maintained, you get a messed up user database where you’ll (eventually) find users from all environments, you need to explicitly set new ownership (to a valid user that can be found in the relevant environments AD), you get the luxury of copied security permissions sets and groups (which I might still build a tool to import/export).