in

SharePoint Blogs

The Best Place for SharePoint-related Blogs

This Blog

Syndication

News

Mar 17 2008   Commuting this AM I independently ran into 3 ex-colleagues from the same small firm. Now I know Perth isn't big, but that is just too weird & 'paranoidal'. So Chris, Dan and Sean - stop dabbling in Occult over IpEspFi V6 - it's freaking me out!

Feb 20 2008   Aussie day has been and gone and things have been hectic, but I'm now on a course with the irrepressible Clayton James - with many ideas to blog about!

Jan 21 2008   Back again, with the promised info on moving those web pages in code.

Jan 16 2008   I'm away for a few days for a Geraldton funeral (sniff), but back in Perth I'll have something to say about moving pages between webs...

Jan 14 2008   Happy New Year and a Happy New Blog to all - especially MOSS masters Mr P.CleverWorkarounds and Sezai "Yoda"!

Archives


G'Day MOSSuMS

 
View Mike Stringfellow's profile on LinkedIn  
 
 
Join me, Mike Stringfellow, in the upside down world of the baggy green MOSS. I hope you find my rantings useful, as I search out my own path through the challenges and opportunities that "the other MS" throws out.
 

January 2008 - Posts

  • Page Movers R Us


    Moving a page interactively is easy using Copy, but in code...

    ...you have to figure out and match the MS process, and hope they don't change it!

    So, having tested out calling CopyTo (works but you have to also copy over the history) and MoveTo (only had limited success), I settled on the popular export/import method. I tried out a large number of options, and an example of my final approach is given below.

    Notes: I had issues with this until applying the full suite of SP1s for SP/Office.

    With thanks to the following for their invaluable information:
    http://k2distillery.blogspot.com/2007/10/copy-version-history-with_5.html
    http://blogs.technet.com/stefan_gossner/archive/2007/10/12/deep-dive-into-the-sharepoint-content-deployment-and-migration-api-part-5.aspx

     

    MyCopy(@"http://mikedev", @"http://mikedev/Web1/Web2/Pages/testPage.aspx", @"http://mikedev/Web1/Web2/testWeb/", @"C:\TEMP\");

    using System;
    using System.Globalization;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Deployment;

    static void MyCopy(String commonSiteUrl, String sourceUrl, String targetUrl, String importExportFileLoc)
    {
        string destinationUrl = targetUrl;
        string relativeSoruceUrl = sourceUrl.Replace(commonSiteUrl, "");
        string relativeDestinationUrl = targetUrl.Replace(commonSiteUrl, "");

       
    SPSite commonSite = new SPSite(commonSiteUrl);
        SPWeb sourceWeb = commonSite.OpenWeb(relativeSoruceUrl, false);
        SPWeb destWeb = commonSite.OpenWeb(relativeDestinationUrl, false);

        object sourceObj = sourceWeb.GetObject(sourceUrl);
        object destObj = destWeb.GetObject(targetUrl);

        if (sourceObj == null)
            throw new Exception("No object found at " + sourceUrl + " for this copy.");

        Guid sourceId = Guid.Empty;
        SPDeploymentObjectType deployType = SPDeploymentObjectType.Invalid;

       
    if (sourceObj is SPListItem)
        {
            sourceId = (sourceObj as SPListItem).UniqueId;
            deployType = SPDeploymentObjectType.ListItem;
        }
        else if (sourceObj is SPFile)
        {
            sourceId = (sourceObj as SPFile).UniqueId;
            deployType = SPDeploymentObjectType.File;
        }
        else if (sourceObj is SPFolder)
        {
            sourceId = (sourceObj as SPFolder).UniqueId;
            deployType = SPDeploymentObjectType.Folder;
        }
        else if (sourceObj is SPList)
        {
            sourceId = (sourceObj as SPList).ID;
            deployType = SPDeploymentObjectType.List;
        }
        else if (sourceObj is SPWeb)
        {
            sourceId = (sourceObj as SPWeb).ID;
            deployType = SPDeploymentObjectType.Web;
        }
        else if (sourceObj is SPSite)
        {
            sourceId = (sourceObj as SPSite).ID;
            deployType = SPDeploymentObjectType.Site;
        }
        else
            throw new Exception("Unknown object type of " + sourceObj.GetType().FullName + " for this copy.");

        // Export

        SPExportObject exportObject = new SPExportObject();

        if (sourceId != Guid.Empty) 
          
    exportObject.Id = sourceId;
         

        exportObject.Type = deployType;
        exportObject.ExcludeChildren = false;
        exportObject.IncludeDescendants = SPIncludeDescendants.All;

        SPExportSettings expSettings = new SPExportSettings();
        expSettings.ExportObjects.Add(exportObject);
        expSettings.ExportMethod = SPExportMethodType.ExportAll;
        expSettings.SiteUrl = commonSiteUrl;
        expSettings.BaseFileName = "export.cab";
        expSettings.FileLocation = importExportFileLoc;
        expSettings.LogFilePath = importExportFileLoc + "export.log";
        expSettings.LogExportObjectsTable = true;
        expSettings.FileCompression = true;
        expSettings.CommandLineVerbose = true;
        expSettings.IncludeSecurity = SPIncludeSecurity.All;
        expSettings.IncludeVersions = SPIncludeVersions.All;
        expSettings.OverwriteExistingDataFile = true;
        expSettings.LogExportObjectsTable = true;
        expSettings.ExcludeDependencies = true;
        expSettings.Validate();

        SPExport export = new SPExport(expSettings);
        export.Run();

        // Now Import

       
    SPImportSettings impSettings = new SPImportSettings();
        impSettings.SiteUrl = commonSiteUrl;
        impSettings.WebUrl = targetUrl;  // Also can be done in 'OnImportStarted' event
        impSettings.BaseFileName = "export.cab";
        impSettings.FileLocation = importExportFileLoc;
        impSettings.LogFilePath = importExportFileLoc + "import.log";
        impSettings.FileCompression = true;
        impSettings.CommandLineVerbose = true;
        impSettings.IncludeSecurity = SPIncludeSecurity.All;
        impSettings.HaltOnWarning = true;
        impSettings.UpdateVersions = SPUpdateVersions.Append;
        impSettings.UserInfoDateTime = SPImportUserInfoDateTimeOption.ImportAll;
        impSettings.IgnoreWebParts = false;
        impSettings.RetainObjectIdentity = false;
        impSettings.Validate();

        SPImport import = new SPImport(impSettings);

       
    EventHandler<SPObjectImportedEventArgs> importedEventHandler = new EventHandler<SPObjectImportedEventArgs>(OnImported);
        import.ObjectImported += importedEventHandler;

        import.Run();
    }

    staic void OnImported(object sender, SPObjectImportedEventArgs eventArgs)
    {
        // Update the links, (currently pages only)
        SPImport import = sender as SPImport;
        string url = eventArgs.SourceUrl;
        SPSite destSite = new SPSite(import.Settings.SiteUrl);
        SPWeb destWeb = destSite.OpenWeb(url, false);
        object obj = destWeb.GetObject(url);

        if (obj is SPListItem)
        {
            SPListItem listItem = obj as SPListItem;
            int count = listItem.BackwardLinks.Count;
            for (int i = count - 1; i >= 0; i--)
            {
                SPLink link = listItem.BackwardLinksIdea;
                using (SPWeb linkWeb = destSite.OpenWeb(link.ServerRelativeUrl, false))
                {
                    object o = linkWeb.GetObject(link.ServerRelativeUrl);
                    ReplaceLinks(o, eventArgs.SourceUrl, eventArgs.TargetUrl);
                }
            }
        }
    }
  • Developer Build Events


    We all have a collection of these, but I use just one Post Build Event while developing:

    $(ProjectDir)postBuildDebug.bat "$(ProjectDir)" "$(TargetDir)" "$(DevEnvDir)" "$(TargetName)" "$(TargetFileName)"

    Yes, I know that's a cheat! But I find it much easier to manage in a separate file...

    So what's in the box?

    I don't have a file area yet, so I've placed postBuildDebug.bat at the end of this post if you want a look (apologies for the length).

    Notes: This has a number of unused sections, depending on what I am doing at that moment. It also places the dll in the gac, but leaves the pdb and dll file locally as well. That way you can hit debug break points without copying extra files into the gac, but you will see some duplicate reference warnings.

    ===========================================================================================================================


    REM Example of Use: IF $(ConfigurationName)==Debug $(ProjectDir)postBuildDebug.bat "$(ProjectDir)" "$(TargetDir)" "$(DevEnvDir)" "$(TargetName)" "$(TargetFileName)"
    ECHO postBuildDebug.bat received call with parameters %1, %2, %3, %4 and %5

    SET PROJECTdir=%1
    ECHO ...PROJECTdir set to %PROJECTdir%

    SET TARGETdir=%2
    ECHO ...TARGETdir set to %TARGETdir%

    SET DEVENVdir=%3
    ECHO ...DEVENVdir set to %DEVENVdir%

    SET TARGETname=%4
    ECHO ...TARGETname set to %TARGETname%

    SET TARGETfilename=%5
    ECHO ...TARGETfilename set to %TARGETfilename%

    ECHO Changing directory to %PROJECTdir%
    CD %PROJECTdir%

    SET TWELVEdir=%CommonProgramFiles%\Microsoft Shared\web server extensions\12
    SET TEMPLATEdir=%TWELVEdir%\TEMPLATE
    SET CONTROLTEMPLATESdir=%TEMPLATEdir%\CONTROLTEMPLATES
    SET FEATURESdir=%TEMPLATEdir%\FEATURES
    SET IMAGESdir=%TEMPLATEdir%\IMAGES
    SET STSADM=%TWELVEdir%\bin\stsadm.exe
    SET GACUTIL=%DEVENVdir%..\..\SDK\v2.0\Bin\gacutil.exe
    SET MAKECAB=C:\makecab\BIN\MAKECAB.EXE
    SET IISAPP=%SystemRoot%\system32\iisapp.vbs
    SET GAC=%SystemRoot%\assembly\GAC_MSIL

    ECHO Copying source files from "TEMPLATE\CONTROLTEMPLATES\%TARGETname%\*.ascx" to WSS directory "%CONTROLTEMPLATESdir%\%TARGETname%" with switch /y
    COPY "TEMPLATE\CONTROLTEMPLATES\%TARGETname%\*.ascx" "%CONTROLTEMPLATESdir%\%TARGETname%" /y

    ECHO Copying source files from "TEMPLATE\FEATURES\%TARGETname%\*.xml" to WSS directory "%FEATURESdir%\%TARGETname%" with switch /y
    COPY "TEMPLATE\FEATURES\%TARGETname%\*.xml" "%FEATURESdir%\%TARGETname%" /y

    ECHO Copying source files from "TEMPLATE\IMAGES\%TARGETname%\*.gif" to WSS directory "%IMAGESdir%\%TARGETname%" with switch /y
    COPY "TEMPLATE\IMAGES\%TARGETname%\*.gif" "%IMAGESdir%\%TARGETname%" /y

    REM ECHO Copying source files to WSS \TEMPLATE directory
    REM CALL XCOPY /e /y TEMPLATE\* "%TEMPLATEdir%"

    ECHO Removing assembly %TARGETname% from the GAC at %GAC% using %GACUTIL% /u %TARGETname% /nologo
    %GACUTIL% /u %TARGETname% /nologo

    ECHO Removing the directory containing the assembly using: RMDIR %GAC%\%TARGETname%, as GacUtil doesn't always do this
    RMDIR %GAC%\%TARGETname%

    ECHO Checking that %GAC%\%TARGETname% directory no longer exists
    IF EXIST %GAC%\%TARGETname% GOTO ERROR1

    ECHO Changing Directory to %TARGETdir%
    CD %TARGETdir%

    ECHO Registering %TARGETfilename% in the GAC at %GAC% using %GACUTIL% /i %TARGETfilename% /nologo
    %GACUTIL% /i %TARGETfilename% /nologo

    ECHO Checking that %GAC%\%TARGETname% now exists again
    IF NOT EXIST %GAC%\%TARGETname% GOTO ERROR2

    REM ECHO Installing feature with STSADM
    REM %STSADM% -o installfeature -filename %TARGETname%\feature.xml -force

    REM ECHO Activating feature with STSADM
    REM %STSADM% -o activatefeature -name %TARGETname% -url http://Server/Site/Subsite

    ECHO Recycling app pool for this app only - use iisreset for a full recycle
    %IISAPP% /a "Sharepoint - 81" /r
    REM IISRESET

    GOTO End

    :Error1
    ECHO Error1: GAC uninstall of %GAC%\%TARGETname% using %GACUTIL% failed - please review details Build output
    EXIT 1

    :Error2
    ECHO Error2: GAC install of %TARGETdir%\%TARGETfilename% to %GAC%\%TARGETname% using %GACUTIL% failed - please review details Build output
    EXIT 2

    :End
    ECHO Completed OK
  • Binding to lists in ye olde ascx user control


    Welcome

    This blog starts at the technical coal face, but I'm also going to let loose on:

    • .Net 
    • Build Events
    • Web Config Modifications
    • Features
    • Visual Studio
    • Workflow
    • and anything else I come across in fact!

    So let's dive in with a nice quick and easy one.

    When Two Worlds Collide 

    I was integrating existing user controls into sharepoint, and wanted to replace xml data bindings with lists (but no other changes - I'm lazy like that).

    But blow me if there wasn't much info beyond webparts and GUID references!

    So this is the simplest solution I could come up with - no CAML or nesting yet, but I'll revisit that...

     <%@ Register Tagprefix="SPwebControls" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
    <asp:DropDownList ID="selCountry" runat="server" DataSourceID="dataSourceCountries" DataTextField="Title" DataValueField="CountryCode2Digit"></asp:DropDownList>
    <SPwebControls:SPDataSource id="dataSourceCountries" runat="server" UseInternalName="True" DataSourceMode="List" SelectCommand="<View></View>" >
        <SelectParameters>
            <asp:Parameter Name="WebUrl" DefaultValue="{sitecollectionroot}"/>
            <asp:Parameter Name="ListName" DefaultValue="Countries"/>
           
    <%-- <asp:Parameter Name="WebUrl" DefaultValue="someSubWeb"/> --%>
        </SelectParameters>
    </SPwebControls:SPDataSource>

    I hope this helps someone else - let me know if you improve this or test out dynamic filtering.

    NB: For the non.netters, note that <%--  --%> can be used to prevent instantiation and rendering to the page.


Need SharePoint Training? Attend a SharePoint Bootcamp!

Posts (c) their respective authors. Everything else (c) 2007 SharePoint Experts