Serge van den Oever [Macaw]

SharePoint RIP. Azure, Node.js, hybrid mobile apps

  • SharePoint 2007 Navigation - part 3

    Stramit wrote a real good blog post on SharePoint 2007 TreeView navigation. He is used our good friend Reflector to dive into the SPTreeView and SPHierarchyDataSourceControl to find out what you can accomplish with the SharePoint TreeView navigation controls. He explains how to create a custom masterpage where he modifies the properties of the SPHierarchyDataSourceControl to configure what to display in the TreeView, like Lists, Document Libraries, Sub webs. He also explains how to set to root context from where navigation is displayed to the root web of the site collection by using custom server side script in the masterpage. But hé, you can’t use serverside code in your masterpage I hear you think… wrong!! With some tricks you can get it working. Read Stramits blog post if you are into the navigation game. Good work Stramit!

    Some of my earlier SharePoint navigation related posts:

    SharePoint 2007 navigation dissected – part 1
    SharePoint 2007 navigation - part 2

  • SharePoint 2007 navigation - part 2

    I while ago I started with a blog post serie on SharePoint 2007 navigation. I got to part one so far. Time is my enemy! We have been working on some great things with respect to SharePoint navigation lately like completely modified navigation elements and custom SiteMapProviders. I hope I have the time to elaborate on that in some future blog posts. I the mean time I point you to some nice posts on SharePoint navigation I ran into. Kudos to their authors!

    • Modifying the WSS3 tree navigation control explains how to turn on a tree navigation structure to get results like this:
    • On the SharePoint 2007 documentation on MSDN there is a section called How to: Customize the Display of Quick Launch which describes how to replace the Menu Control with the TreeView Control.
    • Another section in the SharePoint 2007 documentation on MSDN  called Using a Custom Data Source for Navigation describes how to use a delegate feature to replace the QuickLaunchDataSource delegate control in the default master page by defining your custom navigation data source that uses a SiteMapProvider. Cool but advanced stuff!

     

  • SharePoint: WSS versus OSS, a blogger from Iran

    Farvashan, a SharePoint Solution provider and blogger from Iran started blogging at http://www.sharepointblogs.com/farvashan. Its first post is about WSS (Windows SharePoint Services) versus OSS (Office SharePoint Server). WSS the free extension of Windows Server 2003 and OSS that needs additional licenses and is built on top of WSS. He argues that you should only use OSS if you use more than 30% of its features, and that WSS is a powerful application platform you can build your applications on. I totally agree with him. Have a look at the about link for some screendumps of his projects and links to live SharePoint based sites in a language I don’t understand but which looks great.

  • SharePoint and printing the contents of a web part

    When you have complex web parts with all kind of navigational structures around then there is often the need with customers to only print the content of that web part, without all surrouding information.Marian Lishman wrote a nice blog post on how to do exactly that. The approach is actually really neat: collect some information on your HTML page by collecting the HTML data from an innerText property of a specified tag, and write the collected content (together with some additional markup if needed) to a new window that you popup, and automatically print the contents of this popup window. This approach would allow you to write headers and footer, and could be extended to print for example everything within your web part zones.

  • Get the url to the virtual root for the current request

    Sometimes you get into the situation that you have to build a Url within the current request to a page that you know the virtual path for, but it has to be on the same server as the current request. The problem is to find the url for the virtual root of the request. So for the request https://server:1234/myfolder/mypage.aspx we need to find https://server:1234.

    Often you see code like:

    Uri requestUri = Context.Request.Url;
    string baseUrl = requestUri.Scheme + Uri.SchemeDelimiter + requestUri.Host + (requestUri.IsDefaultPort ? "" : ":" + requestUri.Port);

    This can be done much easier with the following code:

    string baseUrl = Request.Url.GetLeftPart(UriPartial.Authority);

  • .Net 2.0 smart String Split() functionality

    There is a new version of the String Split() function, a split with the option to remove empty entries is the resulting string array. This new function solves your problems with lazy encoded multi-value strings. I know, this is one of the zillion things that were improved in .Net 2.0, and a lot of people probably know this one for ages. For me it was completely new however, and if it is new for me, there must be someone out there who didn’t know this as well;-)

    The case:

    Often you create a multi-value string separated with a special character at one end of your application, and you retrieve them at the other end of you application by splitting the string on the special character.

    Example: at one side you have list of users that you encode as a string;

    List of users: "serge", "dinah", "scott", "dean". Encode as: "serge;dinah;scott;dean"

    There are two special cases you have to take into account, either on constructing the multi-value string, or on splitting the multi-value string into its values:

    • Empty entries
    • A trailing special character

    Assume you have the following array of strings: "one","", "three","","five". You can either encode it the lazy and simple way, or the complex way. In the simple way you leave it up to the receiving side to skip empty entries and the trailing special character. In the complex way you deliver clean data on the producing side by skipping empty entries and not writing the special character after the last entry.

    Producing Lazy and Simple:

    Resulting string: "one;;three;;five;"

    string result;
    foreach (string s in stringArray)
    {
        result += s + ";";
    }

    UPDATE: As Danny de Haas pointed out to me this can ofcourse be done even lazier:

    string result = String.Join(";", stringArray);


    Producing Complex:

    Resulting string: "one;three;five"

    string result;
    for (int i=0; i<stringArray.Length; i++)
    {
        if (!String.IsNullOrEmpty(stringArray[i]))
        {
            result += stringArray[i];
            if (i != stringArray.Length – 1)
            {
                 result += ";";
            }
        }
    }

    The above code is maybe not the smartest code, but you get the drift.

    Receiving:

    If you receive a string and you want to take into account that the string could be produced in the lazy and simple way you had to do extra processing on the array you get from result.Split(‘;’) to remove empty entries resulting from encoded empty entries or the trailing special character when working with the .Net 1.1 framework. The .Net 2.0 framework now provides an overload of the String Split() function that is smart enough to handle this case:

    string[] resultArray = result.Split(new char[] {';'}, StringSplitOptions.RemoveEmptyEntries);

    This call takes care of the empty entries and the empty entry at the end produced due to a trailing special character.

    See http://msdn.microsoft.com/en-us/library/system.string.split.aspx for more information in the Microsoft documentation on all overloads of the split function, and http://msdn.microsoft.com/en-us/library/system.stringsplitoptions.aspx for more information on the StringSplitOptions.

    Name Description
    String.Split (Char[]) Returns a String array containing the substrings in this instance that are delimited by elements of a specified Char array.

    Supported by the .NET Compact Framework.

    String.Split (Char[], Int32) Returns a String array containing the substrings in this instance that are delimited by elements of a specified Char array. A parameter specifies the maximum number of substrings to return.
    String.Split (Char[], StringSplitOptions) Returns a String array containing the substrings in this string that are delimited by elements of a specified Char array. A parameter specifies whether to return empty array elements.
    String.Split (String[], StringSplitOptions) Returns a String array containing the substrings in this string that are delimited by elements of a specified String array. A parameter specifies whether to return empty array elements.
    String.Split (Char[], Int32, StringSplitOptions) Returns a String array containing the substrings in this string that are delimited by elements of a specified Char array. Parameters specify the maximum number of substrings to return and whether to return empty array elements.
    String.Split (String[], Int32, StringSplitOptions) Returns a String array containing the substrings in this string that are delimited by elements of a specified String array. Parameters specify the maximum number of substrings to return and whether to return empty array elements.

     

  • NAnt task for SharePoint: Save SPWeb as site template to the filesystem

    I love NAnt as a tool to automate deployment processes. Kris Syverstad created a nice set of NAnt tasks for SharePoint that he uploaded to a GotDotNet workspace. My latest task was to save a site as a site template to the filesystem for deployment to another system. I decided to create a task in the same spirit to Kris his tasks. You can add it to the set of tasks that Kris already created. That is what I did.

    The code:

    //

    // NAnt.SharePoint Microsoft Sharepoint Server utility tasks.

    // Copyright (C) 2006 Macaw, Serge van den Oever

    //

    // This library is free software; you can redistribute it and/or

    // modify it under the terms of the GNU Lesser General Public

    // License as published by the Free Software Foundation; either

    // version 2.1 of the License, or (at your option) any later version.

    //

    // This library is distributed in the hope that it will be useful,

    // but WITHOUT ANY WARRANTY; without even the implied warranty of

    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU

    // Lesser General Public License for more details.

    //

    // You should have received a copy of the GNU Lesser General Public

    // License along with this library; if not, write to the Free Software

    // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

    //

    using System;

    using System.IO;

    using System.Globalization;

     

    using Microsoft.SharePoint;

     

    using NAnt.Core;

    using NAnt.Core.Attributes;

    using NAnt.Core.Types;

     

    namespace NAnt.SharePoint.Tasks

    {

        /// <summary>

        /// Save SPWeb as template.

        /// </summary>

        /// <remarks>

        ///   <para>

        ///   Save a template of the SPWebs pecified by a Url on the local machine.

        ///   </para>

        ///   <note>

        ///   If the <see cref="Url" /> specified does not exist, a

        ///   <see cref="BuildException" /> will be raised.

        ///   </note>

        /// </remarks>

        /// <example>

        ///   <para>Delete a SPSite.</para>

        ///   <code>

        ///    <![CDATA[

        /// <deletespsite Url="http://myserver/sites/mysite" />

        ///    ]]>

        ///   </code>

        /// </example>

        /// <example>

        ///   <para>

        ///   Save SPWeb as template. If the SPWeb does not exist, the task does nothing.

        ///   </para>

        ///   <code>

        ///    <![CDATA[

        /// <savespwebastemplate url="${url}" templatename="myTemplate" title="My Template" description="A Template Of My Site" savedata="true" tofile="c:\template.stp" failonerror="false" />

        ///    ]]>

        ///   </code>

        /// </example>

        [TaskName("savespwebastemplate")]

        public class SaveSPWebAsTemplateTask : Task

        {

     

            private string _url = "";

            private string _templatename = "";

            private string _title = "";

            private string _description = "";

            private bool _savedata = false;

            private string _tofile = null;

     

            /// <summary>

            /// The URL for the SPWeb to save as template.

            /// </summary>

            [TaskAttribute("url", Required = true)]

            public string Url

            {

                get { return _url; }

                set { _url = value; }

            }

     

            /// <summary>

            /// The name for the template.

            /// </summary>

            [TaskAttribute("templatename", Required = true)]

            public string TemplateName

            {

                get { return _templatename; }

                set { _templatename = value; }

            }

     

            /// <summary>

            /// The title for the template.

            /// </summary>

            [TaskAttribute("title", Required = false)]

            public string Title

            {

                get { return _title; }

                set { _title = value; }

            }

     

            /// <summary>

            /// The description for the template.

            /// </summary>

            [TaskAttribute("description", Required = false)]

            public string Description

            {

                get { return _description; }

                set { _description = value; }

            }

     

            /// <summary>

            /// Boolean specifying if data of the SPWeb should be included in the template.

            /// Only data up to 10Mb can be included.

            /// </summary>

            [TaskAttribute("savedata", Required = false)]

            public bool SaveData

            {

                get { return _savedata; }

                set { _savedata = value; }

            }

     

            /// <summary>

            /// The file to save the template to.

            /// </summary>

            [TaskAttribute("tofile", Required = false)]

            public string ToFile

            {

                get { return _tofile; }

                set { _tofile = value; }

            }

     

            /// <summary>

            /// Because ExecuteTask is protected added this function to debug the task.

            /// </summary>

            public void DebugTask()

            {

                ExecuteTask();

            }

     

            /// <summary>

            /// Task for saving a SPWeb as template.

            /// </summary>

            protected override void ExecuteTask()

            {

                string templateFilename = TemplateName + ".stp";

                try

                {

                    using (SPSite site = new SPSite(Url))

                    {

                        try

                        {

                            using (SPWeb web = site.OpenWeb(site.ServerRelativeUrl))

                            {

                                // Delete site template with name TemplateName if it exists

                                SPDocumentLibrary webTemplates;

                                try

                                {

                                    webTemplates = site.GetCatalog(SPListTemplateType.WebTemplateCatalog) as SPDocumentLibrary;

                                }

                                catch (Exception ex)

                                {

                                    throw new BuildException(

                                        string.Format("The site collection of the SPWeb '{0}' does not contain a Site Template Gallery.",

                                        Url), Location, ex);

                                }

                                SPFolder folder = web.Folders["_catalogs"];

                                SPFolder subfolder = folder.SubFolders["wt"];

                                subfolder.Files.Delete(templateFilename);

                            }

                        }

                        catch (Exception)

                        {

                            // ignore, no template to delete

                        }

     

                        // Save the SPWeb as template

                        using (SPWeb web = site.OpenWeb())

                        {

                            // If no title is specified, use same as template name

                            if (Title.Length == 0)

                            {

                                Title = TemplateName;

                            }

     

                            web.SaveAsTemplate(templateFilename, Title, Description, SaveData);

                        }

                    }

     

                    Log(Level.Info, LogPrefix + "Save SPWeb '{0}' as template with name '{1}'.", Url, TemplateName);

                }

                catch (Exception ex)

                {

                    // The SPS API will throw an exception when you try and create an

                    // instance of SPSite for a URL that doesn't exist. 

                    throw new BuildException(

                        string.Format("Cannot save SPWeb '{0}' as template. Either the SPWeb does not exist, or savedata is true and the size of the SPWeb > 10MB, or there is already a template by this name.",

                        Url), Location, ex);

                }

     

                if (ToFile != null)

                {

                    try

                    {

                        using (SPSite site = new SPSite(Url))

                        {

                            string templateUrl = site.Url + "/_catalogs/wt/" + templateFilename;

                            System.Net.WebClient objWebClient = new System.Net.WebClient();

                            objWebClient.Credentials = System.Net.CredentialCache.DefaultCredentials;

                            objWebClient.DownloadFile(templateUrl, ToFile);

                        }

                    }

                    catch(Exception ex)

                    {

                        throw new BuildException(

                            string.Format("The SPWeb '{0}' is saved as template '{1}' in the Site Template Gallery, but downloading the template to file '{2}' failed.",

                            Url, Name, ToFile), Location, ex);

                    }

                }

            }

        }

    }

  • SharePoint and objects disposal, the definitive guide!

    One of those difficult things to handle in the construction of SharePoint related code is the cleaning up of used objects. The problem is that if you don't clean up your mess, the garbage collector does its job, and nothing really bad seems to happen. Problems only occur when your site is on heavy load in the production environment, and you have no clue how to solve that problem where your processor hits the 100% and used memory goes sky high.

    Finally there is a great article out there that explains in great detail the best programming practices with SharePoint objects. Go grab it and start reviewing your code!

    Article: Best Practices: Using Disposable Windows SharePoint Services Objects

    Blog post with further discussions: http://blogs.msdn.com/krichie/archive/2006/06/15/632611.aspx

  • SharePoint 2007 - _layouts, pages in site context, help!

    NOTE: See this blogpost for updated information on this topic.

    SharePoint 2003 has a very powerful feature to run pages in the context of a site, this is especially used for the administrative pages. All these administrative pages live in the “/_layouts” folder. If you have two sites, http://server/A and http://server/B, and an administrative page admin.aspx, you can execute this page in site context as follows:

    http://server/A/_layouts/admin.aspx executes in the context of site A

    http://server/B/_layouts/admin.aspx executes in the context of site B

    Within those pages you can directly access the current site with the following line of code:

           SPWeb site = SPControl.GetContextWeb(Context);
     

    With this site object as starting point you can access all information that is in your site.

    This approach is used in all standard pages in /_layouts, with all pages containing inline code.

    All the years I have been working with SharePoint 2003 I had another approach to create web pages to run in the context of a site. I just create a web project, deploy the aspx pages, images, client scripts etc to a directory in /_layouts, and put the "code behind" dll's into /_layouts/bin.

    This approach no longer works, and a new adventure begins...

    THE ADVENTURE

    1. In SharePoint 2007 the _layouts virtual directory no longer contains a "bin" directory, all pages use inline code. First thing I tried was to add a "bin" directory, deploy my "code behind" dll's there and go to my page http://server/_layouts/myapp/default.aspx. Nothing happened, not even an error, just a blank page.
    2. I change the name of of the page to a non-existant name: http://server/_layouts/myapps/blabladefault.aspx. Again nothing happened. All url's requested in _layouts that don't exist just give a blank page!!
    3. After looking at the web.config in SharePoint 2003  I see that the line:

      <trust level="Full" originUrl="" />

      is missing, so I add that line. Still the same result, a blank page. But at the same time strange things start to happen to other parts of SharePoint. The other administrative pages return a blank page as well, and the pages in the SharePoint administration site start to loose their design. After looking at the source of the page it is not so strange: a lot of assets from the /_layouts path are referenced. But it is strange that with trust level "Full", the highest as far as I know, things stop working!

    4. I remove the "bin" directory, the web.config is as prestine as it was, and I try again. Something happens: I get an expected error, the "code behind" dll can't be found! A nice error is displayed in "SharePoint syle", with the message: Could not load type 'myapp._Default'. Ah, almost there I'm thinking, we just need a probing path.

    5. I add the probing path to give .Net direction on where to look for the dll's:

      <runtime>
          <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
              <probing privatePath="myapp\bin"/>
          </assemblyBinding>
      </runtime>

      and I hit the refresh button in great expectation... same error. the "code behind" dll can't be found.

    6. One last thing to try that must work, otherwise I'm getting mad: throw the "code behind" assembly into the GAC. I strong-sign my assembly, drag it to the GAC, do an IISRESET and... shoot! I'm mad! Still the same error!

    7. Back to the model that Microsoft uses in the _layouts pages: all code inline in the aspx pages, and this works... I hate this approach, but it seams the only way.

    QUESTIONS

    And now my questions!!! There must be someone out there who knows how to solve my problem.

    1. Is it possible to have pages with code behind in _layouts, and have the code behind assemblies in a bin directory?
    2. Is it possible to have our own custom"_layouts" like virtual directory that executes "in context" of a page?

    UPDATE: I managed to get a 2005 web project working, where the code is not precompiled. You don’t need to deploy your code-behind code deployed as a DLL. One thing to watch out for however: if you have a web.config file in your project, comment out the following line: <authentication mode="Windows"/>.

  • SharePoint 2007 ends the bucket nightmare.. move those sites!!!

    Do you still remember that good old bucket system in SharePoint Portal Server 2003 where the first 20 portal area's ended up with nice urls, but then the buckets started kicking in and provided you with urls like http:/server/C0/myarea/default.aspx? Those days are over.

    The reason behind the bucket system in Portal Server was understandable; Microsoft expected a huge number of areas, with deep hierarchies that could be moved around at will without breaking links, and probably performance was an issue. But the bucket solution is a really machine oriented solution, users want to be able to understand their urls. If not we could use GUID's instead of urls;-) But I think they calculated wrong, I never saw really deep hierarchies appearing, and in most cases not that many areas, because you don't want to do to many things in areas due to all the limitations imposed compared to the standard WSS sites: no list and document library security, no possibility to backup a single area, no possibility to create a template from an existing area, or create an area based on a template... should I continue?

    In SharePoint 2007 Microsoft got rid of the bucket system. You can move sites around, and the urls of the sites change!! But what happens to urls pointing to those sites? There is a good side to the story, and a bad side. The good side is that all urls in url fields in lists and metadata are rewritten. This is actually quite cool! Move your site and all lists like links lists are updated!! But the bad thing is that all urls NOT managed by SharePoint will NOT be updated (SharePoint has no control over them), and this will break a lot of links.

    I wonder about links within documents within document libraries in SharePoint... would be a nice excercise to update those as well;-)

    Another thing I heard, but not verified yet, is that if you put a url in a url field in a list, and this url points to something within SharePoint it is actually stored as a relative url. You can also store a releative url in a url field now, but if you edit the field again it shows the full url, but still stores the url in a relative format.

  • Web Deployment Projects and deploying web.config settings for multiple machines

    I wrote the following comment on a post http://weblogs.asp.net/dfindley/archive/2006/06/06/Frustrations-with-Web-Deployment-Projects.aspx about having machine dependent configurations in your web.config. DFindley expresses some frustrations with the web deployment projects on configuring per machine settings in the web.config, but he found the fix right away. This approach is powerful, but sometimes not clear where the settings are actually managed. I use another approach that works quite well for me. I posted this as a comment on the mentioned post.

    Scott mentions in his comment to have a web.config per machine, and copy the correct web.config on deployment.
    I prefer to only have replacements for the changing sections per machine. Often these settings are the appSettings, connections and an impersonation account.
    In this approach you can manage the other settings in a generic web.config that is used for all machines.
    So what I do is the following:

    Create appSettings files per machine:

    MACHINE1.appSettings.config
    MACHINE2.appsettings.config

    Create connections files per machine:

    MACHINE1.connections.config
    MACHINE2.connections.config

    On automated deployment check your machine name, and copy:

    MACHINEX.appSettings.config to appSettings.config
    MACHINEX.connections.config to connections.config

    In your web.config you refer to those external files as follows:

    <appSettings configSource="appSettings.Config"/>
    <connectionStrings configSource="connections.config"/>

    Another thing you often want to set is the impersonation account, we manage those in the registry per server in a secure way as follows:

    <!-- Impersonation identity is encrypted in the registry. Identity is set with the following command:
       
    aspnet_setreg.exe -k:SOFTWARE\MyApp\identity -u:"yourdomainname\username" -p:"password"
       
    Tool can be downloaded at:
      
    http://download.microsoft.com/download/2/9/8/29829651-e0f0-412e-92d0-e79da46fd7a5/aspnet_setreg.exe
    -->
    <identity impersonate="true"
              userName="registry:HKLM\SOFTWARE\MyApp\identity\ASPNET_SETREG,userName"
              password="registry:HKLM\SOFTWARE\MyApp\identity\ASPNET_SETREG,password" />

  • SharePoint 2007 navigation dissected – part 1

    One of the areas SharePoint 2003 was suboptimal was site navigation. SPS 2003 has some quite restrictive navigation functionality to navigate through the portal areas. When you end up in a team site you only have your quick links bar at the left side to navigate to lists and libraries within your site, but there is no way to navigate to your sub sites.

    As always the next version will solve all our problems… so let’s have a look at the new and improved, but still beta 2, SharePoint 2007 standard navigation options. I’m working with an out-of-the-box SharePoint installation that includes the portal.

    First thing I did was creating a set of sites and sub sites under the site Sites of type Site Directory with the following structure:

    site1
                    site1sub1
                                    site1sub1subA
                                    site1sub1subB
                    site1sub2
                                    site1sub2subA
                                    site1sub2subB
    site2
                    site2sub1
                                    site2sub1subA
                                    site2sub1subB
                    site2sub2
                                    site2sub2subA
                                    site2sub2subB

     

    This results in the following homepage navigation:

    As you can see, two levels of navigation are displayed.

    Navigation Inheritance

    When a site is created you are prompted with the following option:

    The default setting for this option is Yes. I created site1 and site2 using the Yes setting, and a site3 using the No setting. The results are as follows:

    For site2 (use the top link bar from the parent site):

    For site3 (don’t use the top link bar from the parent site):

    I can see no difference between the two options, both shows their complete path in the breadcrumb bar:

    Home > Sites > site2 > Pages > Home

    Home > Sites > site3 > Pages > Home

    For site3 I actually expected to see:

    Site3 > Pages > Home

    Another strange thing is that I didn’t find an option in the UI with the same phrasing to modify this setting after initial creation of the site. This option can be set in a working way however, keep on reading!

    Site navigation

    If you navigate to Sites you get the following navigation:

    So all sub sites are displayed, with one level of the sub-sub sites.

    If you navigate from here to site2 you get the following navigation:

    This is a different navigation. The current site (site2) is displayed with one level of children (site2sub1, site2sub2), and sites at the same level (site1, site2).

    The question now is: what configures the navigation? If you go to Site Actions >Site Settings >Modify Navigation you get to the Site Navigation Settings.

    The Site Navigation Settings screen looks as follows:

    This screen asks for some experiments!

    Site Navigation Settings

    The Site Navigation Settings screen gives us some configuration options on how navigation works on a site. Lets start with the following options:

    Global Navigation: Use global navigation of the parent site or of this site.

    Current Navigation: Use navigation items of the parent site or of this site. If this site is selected, you can enable to show siblings of this site in the current navigation.

    For the site site1sub1 we go through the different possibilities.

    Global navigation: global navigation of parent

    We see three elements on the above screenshot:

    1.       At the top the path of the root site who’s navigation is used is displayed (empty, the root site)

    2.       The complete parent navigation bar is displayed

    3.       The complete path to the parent sites is displayed

    Global navigation: global navigation of this site

    We see three elements on the above screenshot:

    1.       At the top the path of the root site who’s navigation is used is displayed: site1sub1

    2.       The navigation bar of the current site + it’s sub sites is displayed

    3.       The complete breadcrumb path to the parent sites is displayed

    I created two additional sub sites under site1sub1subA: site1sub1subAsubX and site1sub1subAsubY. Note that these sites become available in a drop down box in the global navigation bar (2):

     

    But what happens if we have set global navigation of the parent site on a site, but a site somewhere up the path has set its global navigation to this site.

    In the above example site site1sub1  has set its global navigation to this site, while site1sub1subA and site1sub1subAsubX have set their global navigation of the parent site. If we now go to the site site1sub1subAsubX we see the following navigation:

    The result is that a site goes up to the hierarchy to the first parent site, and displays its navigation with respect to this parent site!

    Current navigation: use navigation items from the parent site

    We are at site site1sub1. This site is highlighted in the left hand navigation structure. We see the parent site, and all sites at the same level as the parent site. Under the parent site we see the current site (highlighted), and all sites at the same level.

    Current navigation: use navigation items from this site

    We are at site site1sub1. This site is not visible in the left hand navigation structure, the current location can be determined from the site title, the global navigation, and the breadcrumb path as shown in the picture below. We see all sub sites with their sub-sub sites (2 levels).

    Current navigation: use navigation items from this site, show siblings

    We are at site site1sub1. This site is visible in the left hand navigation structure (but not highlighted), We see the sub sites of the current site, and all sibling sites (sites at the same level as the current site), but without their sub sites.

    Showing pages in the navigation

    Besides sub sites a site can contain pages. It is possible to display these pages in the left hand navigation:

    The pages of site1sub1 are displayed in the left hand navigation. Note that the “Home” page is not displayed in this navigation. If we navigate to a page available in the navigation this page gets highlighted in the left hand navigation:

    I did not find a way to make the “Home” page (Pages/default.aspx) part of the left hand navigation.

    Note that the pages are always displayed in the breadcrumb trail.

    Conclusion

    SharePoint 2007 contains a very powerful navigation system that allows you to completely configure the way your site navigation is presented. I did only scratch the surface however. In a upcoming posts I will dive into the following topics:

    Navigation Editing and Sorting – this functionality allows you to add custom additional navigation items and to show or hide sites and pages in the navigation (but not the default page in the Pages library!)

    Navigation under the hood – which navigation controls are used by SharePoint, what are their possibilities and how can you for example change the current depth of 2 that is currently shown in the hierarchy.

    Custom navigation providers – how can you utilize the SharePoint navigation controls with custom navigation information?

    Any feedback is highly appreciated!

  • Microsoft goes Social Networking on SharePoint

    In the last week conference a new part of the ShaerPoint family was announced: Knowledge Network.

    To say it in Microsoft own words:

    Knowledge Network for Microsoft® Office SharePoint® Server 2007
    Knowledge Network for Microsoft® Office SharePoint® Server 2007 is software for enterprise search and social networking that helps users collaborate more effectively by automating the discovery and sharing of previously undocumented information and relationships. Knowledge Network enhances Office SharePoint Server 2007 by adding the ability to search for who knows whom and who knows what in an organization.

    You can use Knowledge Network to do the following:

    • Find people who have expertise in a subject
    • Find people who can help you connect with someone else
    • Find people who have contacts at a specific company or organization
    • Find out who and what you have in common with others

    Knowledge Network is composed of two components, a client-side and a server-side. The client-side component analyzes emails at a local level searching for keywords and contacts and creates automated profiles for each member who joins the network. Each member in the Knowledge Network controls their information at a local level, deciding which information they share with others in the network, so personal information stays private. The server-side component, hosted within Office SharePoint Server 2007, aggregates and indexes profiles across the enterprise. Together, the client and server modules enhance the SharePoint 2007 platform with powerful social networking capabilities.

    De software is now available for download on Microsoft Betaplace.

    There is a blog on Knowledge Network from the development team: http://blogs.msdn.com/kn/.

     

    Other blog entries to have a look at:

    http://www.joiningdots.net/blog/2006/05/ms-knowledge-network.html

    http://craigrandall.net/archives/2006/05/knowledge-network/ 

    I wonder is the client software that analyzes your mail is the Snarf application from Microsoft Research.

  • NAnt, devenv.com and devenv.exe

    In NAnt there is a solution task that works for VS.NET 2003, but not for VS.NET 2005. I needed to build a VS.NET 2005 solution from NAnt, so devenv.exe to the rescue: devenv.exe mysolution.sln /build Debug. Problem was that I did not get any output from the build process, not even if there were errors. A non 0 value was returned in case of errors, but I’m integrating with CruiseControl.Net (ccnet) and want my compilation output from the buildserver in case of errors. After some digging aand Googling I found the solution. Don’t use devenv.exe, but devenv.com and you get your output!!

  • Add item to SharePoint list but returning to another location

    Brad asked me for a solution to the following scenario:

    I have two WSS sites -
    - Site A is a project site for all project team members
    - Site B is an issue capture and resolution site for three project issue trouble shooters.

    Question: How can I call the newitem.aspx, located in Site B - Issues webpart from a link on Site A so that the newitem.aspx form pops up and the Site A users can fill it out. When they click the submit button, they return to Site A?

    In other words, SIte A users only need to fill out the issues form. Site B users collect the issues and work them to resolution. My requirement is that Site B issues should be worked and reviewed on Site B, not on Site A.

    This can be resolved using the Source parameter on the url of newitem.aspx:

    You can add Source=xxx on the url, so:
     
    ../../../AddItem.aspx?Source=http%3A%2F%2Fwww%2Egoogle%2Ecom
     
    Note the encoding!!!
     
    After filling out the item, it will bring you back to the specified URL.
     
    UPDATE: NOTE THE CASING OF THE Source PARAMETER, FIRST ‘S’ MUST BE CAPITAL!!
  • Execute your custom code after instantiating a SharePoint site based on a Site Definition using ExecuteURL

    Sometimes you know you can do something, but are completely forgotten how. This is a kind of post to self, so if I search for it again, I will end up on my own blog again. This actually happens 80% of the time when I search for something on SharePoint;-).

    When you have a Site Definition, but want to execute code after a site is instantited based on the Site Definition (a first time run after creation), you can add a CAML tag ExecuteURL to your Site Definition that points to an ASPX page in the _layouts directory. This tag must be placed in the ONET.XML file for the Site Definition, in the Configuration section.

    In this page you can do things like applying a theme, creation of Site Groups, add users to these groups, or even start an interactive session with the user to request aditional information.

    The documentation can be found here in the SharePoint SDK.

  • Using Office SharePoint Designer 2007 with SharePoint 2003

    Note: the information in this weblog post is based on the Beta version of SharePoint Designer 2007 (version 12.0.3820.1002), the information might not reflect the working and available functionality of newer beta versions or the final product.

    Did you know you can use the new SharePoint Designer 2007 on SharePoint 2003 sites? Well… it works! Still looks a lot like FrontPage, but it has some great new features. It can be installed side-by-side with FrontPage 2003, but switching between SharePoint Designer and FrontPage causes some strange error messages and automatic reinstallation/reconfiguration actions. Don’t try it on a machine where you depend on for real development work, after switching my FrontPage I had some strange behavior.

    NOTE: I’m running WSS 2.0 SP2 under ASP.NET 2.0, I don’t know if everything reported here works the same for ASP.NET 1.1.

    Ok, after all the warnings and disclaimers: let’s get started!

    SharePoint Designer 2007 and WSS 2

    Although FrontPage is renamed to SharePoint Designer, it looks like all the non-SharePoint functionality that was available in FrontPage is still available. I will look at the available fatures in the context of WSS 2, not the new WSS 3 (SharePoint 2007) platform.

    For the Microsoft marketing speech on the full features of SharePoint Designer for SharePoint 2007, have look at http://www.microsoft.com/office/preview/programs/designer/highlights.mspx.

    Master pages

    Earlier I already tried to create a master page for usage with a WSS page, but didn’t get it working. I’m using ASP.NET 2.0 with WSS 2, so I actualy thought that that might work. I think that due to changes to the page the page got unghosted, and the Safe Mode parser prevented the usage of master pages. I didn’t try to add a master page to the site definition, that might work because ghosted pages linking to the pages in the site definition are not interpreted by the Safe Mode parser, but directly by ASP.NET 2.0.

    SharePoint Designer has the capabilities to design a master page through File - New – Page – Master Page.

    SDNewMasterPage

    New content regions can be added through Format – Master Page – Manage Content Regions …, which hows the following dialog:

    SDMasterPageRegions

    I even managed to create a page based on the master page:

    SDAppliedMasterPage

    When I load the test.aspx file in the browser I get the following error however:

    [WebPartPageUserException: Unknown attribute "masterpagefile" found in @Page directive.]

    The page is unghosted and does not seem to support master pages. I think due to the all the restrictions that exists for pages executed by the Safe Mode parser

    Gladly enough good old Dynamic Web Templates, one of the most powerful and overlooked features in FrontPage,  is still suported.. Where master pages combine at runtime, Dynamic Web Templates combine on save or attach of the Dynamic Web Template file I will spend a separate weblog entry on this topic in the near future.

    CSS Styles

    SharePoint Designer has a nice style selector to select a style of one of the connected stylesheets:

    SDCssSelector

    Data View

    One of the renamed menu entries is Data View, which was named just Data in FrontPage 2003. Data Views are one of my favorite parts of WSS, and it is good to see that Data Views will still be there in WSS 3 and the support within SharePoint Designer is better than ever. Some disassembling of the Data View Web Part code and DDWRT XSLT function extension code in WSS 3 reveals that not much changes in the new version of WSS.

    One of the biggest problems with FrontPage 2003 was that when data was retrieved for a Data View, the data querying could become really slow when a lot of items are retrieved. This made the user-interface often really sluggish. Data Views now have a special Data View Preview setting that solves these kind of problems:

    SDCommonDataViewTasks

    Another good improvement in Data View editing is the Data View parameter editor:

    SDDataViewParameters

    This translates in the following parameter bindings in the Data View Web Part:

    <ParameterBinding Name="ParamConnection" Location="Connection" DefaultValue=""/>
      <ParameterBinding Name="ParamControl" Location="Control(L_SearchView)" DefaultValue=""/>
      <ParameterBinding Name="ParamForm" Location="Form(FormField)" DefaultValue=""/>
      <ParameterBinding Name="ParamCookie" Location="Cookie(MyCookie)" DefaultValue=""/>
      <ParameterBinding Name="ParamQueryString" Location="QueryString(queryvar)" DefaultValue=""/>
      <ParameterBinding Name="ParamServerVar" Location="ServerVariable(servervar)" DefaultValue=""/>

    The editing of the Data View properties is a bit extended, but the supported functionality didn’t really change:

    SDDataViewProperties

    The Layout possibilities didn’t change, and there seems to be no way to extend the layouts. Specifying your own XSLT in the XSLT Source tab is new as far as I know.

    The column header sorting bug is NOT solved in XSLT generator of SharePoint Designer.

    The conditional formatting is made even more powerful due to a good style composer and good support for the creation of the xpath rules for conditional formatting. The biggest problem is still there: it is NOT possible to specify a CSS class for styling a conditional format. Microsoft: please change that, you want to be able to maintain style in a centralized place!

    Conclusion

    SharePoint Designer is a cool tool that makes nice improvements on the current SharePoint 2003 version that is already really powerful. It is great that all the already available power in SharePoint 2003 that is now “banned” due to the unghosting issues will be “the way to go” in the next version of SharePoint because the unghosting issues and Safe Mode parser will be something of the past.

    SharePoint Designer is not production ready yet. I had a few crashes in preparing this blog entry. But start learning FrontPage 2003 now, and you will enjoy SharePoint Designer 2007 even more when it hits the market!

    In some future blog entries I will describe the way we use FrontPage 2003 to build really powerful business application on the SharePoint development platform today.

  • Great book on the more advanced configuration capabilities in SharePoint 2003

    I just finished browsing through a new book on advanced SharePoint customizations:

    SharePoint 2003 Advanced Concepts: Site Definitions, Custom Templates, and Global Customizations By Nadrowski, Jason/ Draper, Stacy Published by Addison-Wesley, Microsoft Windows Server System Series ISBN: 0321336615; Published: 3/13/2006; Copyright 2006; Pages: T; Edition: 1

    Check the link for an example chapter.

    It is a small book (247 pages) that has great focus. I hate those 1000 pages books that pretend to cover everything, but only scratch the surface on a zillion topics. This book its focus in on creating site definitions, and it does this well with a lot of valuable tips and good examples. It covers some other topics as the backcover mentions:

    · Construct more powerful site and list templates

    · Control how SharePoint uses ghosted and unghosted pages

    · Use custom site definitions to gain finer control over your site

    · Build list definitions with custom metadata, views, and forms

    · Troubleshoot WEBTEMP, ONET.XML, SCHEMA.XML, SharePoint databases, and their interactions

    · Create custom property types to extend SharePoint's functionality

    · Integrate with other systems and SharePoint sites so that you can use their information more effectively

    · Change themes and edit Help, one step at a time

    · Customize email alerts and system notifications

    · Extend the capabilities of document libraries

    · Control document display and behavior based on extensions

    Most information is also available from other sources like the SharePoint SDK documentation, articles on MSDN and blog entries, but here you get a good written, easy read that gets you into the topic in a matter of hours.

    Highly recommended if you need to get up to speed quickly on the topic, and don’t really care to spend a few bucks. But don’t take only my words for it, always check Amazon for the latest reviews.

  • BUG&FIX: SharePoint Data View column header sorting not working with namespaced XML data

    We (Serge van den Oever and Victor Vogelpoel [Macaw]) found a bug with column header sorting within Data View Web Parts when we use a custom web service as the data provider.


    It seems that column header sorting is not working without removing the namespace prefix for the header field names in the XSLT of the Data View. When trying to sort in the Data View Web Part the header indicates a sorting order, the ascending and descending arrows are showing, but the actual sorting of the data is not executed.

    Let us explain it step-by-step:

    We have a web service that produces a non-dataset diffgram result, it actually just produces data in the following format:

    <?xml version="1.0" encoding="utf-8" ?>
    <ArrayOfAccount xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:my-namespace:webservice:v1">
      <Account>
        <AccountName>Abn Amro</AccountName>
        <AccountCode>ABN</AccountCode>
      </Account>
      <Account>
        <AccountName>Nederlandse Spoorwegen</AccountName>
        <AccountCode>NS</AccountCode>
      </Account>
    </ArrayOfAccount>

    As you can see in the XML all data is within the namespace “urn:my-namespace:webservice:v1”.

     

    In our code we deliver data that comes as an array of the following struct:

    public struct Account
    {
            public string AccountName;
            public string AccountCode;
    }

    The web service code is as follows:

    [WebService(Namespace = "urn:my-namespace:webservice:v1")]
    public class AccountService : WebService
    {
      [WebMethod]
      public Account[] GetAccounts()
      {
        ….
      }
    }

    When we insert a Data View for this web service on a web part page using FrontPage 2003 and enable “Options—>Enable sorting on column headers” on the Data View Web Part, the headers of the columns show up fine in the Data View (AccountName and AccountCode), but the underlying fieldnames for the headers are prefixed with a mapped namespace (ddw1:AccountName and ddw1:AccountCode). This results in the following XSLT code for the header:

    :
    <th class="ms-vh" nowrap="true">
      <xsl:call-template name="dvt.headerfield" ddwrt:atomic="1">
        <xsl:with-param name="fieldname">ddw1:CompanyName</xsl:with-param>
        <xsl:with-param name="fieldtitle">CompanyName</xsl:with-param>
        <xsl:with-param name="sortable">1</xsl:with-param>
        <xsl:with-param name="attachments">0</xsl:with-param>
      </xsl:call-template>
    </th>
    :

    If the namespace prefix (shown in bold) is removed, sorting start working again!

    When a DataSet or DataTable is returned as the result of a web service call this problem does not occur. The reason for this is that the diffgram part of the DataSet or DataTable XML result is not part of the namespace of the web service.

  • SharePoint impersonation the COM+ way

    A lot is written on SharePoint impersonation.One of my collegues Victor Vogelpoel wrote a whole series of blog posts on this topic with a whole bunch of implementations. Using all his described implementation methods one thing was still not possible: check if a user is in a certain role. You need to become admin to do this check, but impersonation by going back to the application pool account (which is also a SharePoint administrator account) as described by Victor is still not good enough for checking roles. Raphael Londner has a blog post on how to achive a kind of impersonation that should be powerful enough in his weblog post SharePoint impersonation using COM+ Components. I did not check it out yet, but it looks promising. Thanks Rui for pointing this out to me!

  • Simultaneous HTTP connections in IE, IE memory leaks (unrelated)... some thoughts and links

    Two things that scares me off a bit with complex client side Javascript programming and AJAX technology are:

    • The number of possible simultaneous connections in a browser
    • IE browser has memory leaks when doing complex operations

    Simultaneous Connections: 

    By default a browser supports only up to 2 simultaneous connections as described by Michael Schwartz in this blog entry. It is possible to increase this amount through a registry setting. Good to increase the amount of simultaneous downloads, but not something you can count on in yor application. This means that you should really watch out in implementing multiple separate XmlHttpRequests from your web page. Although I assume that calls are just blocked when the “request queue” is full, and will be executed when a previous request is finished. I thought that applications in Flash could work around that limitation, but as far as I know Flash utilizes the browser HTTP stack, so will probably suffer from the same restrictions (can someone confirm this?).

    IE memory leaks:

    Something that really “shocked” me a while ago was this weblog post by (again) Michael Schwartz. He describes memory leaks with XmlHttpequests in sites like http://www.start.com. I didn’t hear much about it after that post, until I stumbled over a blog entry by Telerik (the developers of the great WYSIWYG HTML editor). They describe IE memory leaks, and some tips on how to avoid them. They link to this article at http://quirksmode.com with more pointers to information on IE memory leaks.

    Lets hope that implementations like Ajax.Net, MagicAjax and Atlas and all the other Ajax libraries work around these issues so we simple developers don’t have to take care of all the quirks that the different browsers will definitly have. This is one of the reasons why Flash looks so interesting: one vendor, so probably the same bugs on all platforms;-)

     

  • WSS+SP2 + .NET 2.0 + Unghosted Page -> Confirmed problem

    In a previous post I described an issue I had with WSS SP2 running on the .Net 2.0 Framework.

    The issue is that in unghosted pages (pages modified through FrontPage, and therefor having a copy of the modified site definition page ending up in the database) it is not possible to add web parts through the web interface. It is still possible through FrontPage though.

    Sources from within Microsoft confirmed that this is indeed a known issue.

    For now there are the following solutions:

    • Continue running WSS on Everett (funy that Microsoft keeps using the code names for there technologies;-) This means; the .Net 1.1 Framework)
    • Reghost* the page (if this is possible, FrontPage should’t have made changes to the page itself, only to web parts and their connections)
    • Use FrontPage to add web parts for these unghosted pages. One ceveat however: this only works for shared web parts, it is not possible to work with personal web parts through FrontPage.

    Lets hope that Microsoft will come out with a hotfix for this issue, so all out trouble will be over. In the mean time: be careful what you edit with FrontPage and don’t mind about to be only editable through FrontPage, and what must be modifyable through the web interface.

    Happy SharePointing!

    *Reghosting can be done through the GhostHunter web part.

  • WSS+SP2 + .NET 2.0 + Unghosted Page --> Problem!?

    UPDATE: This issue is confirmed by Microsoft. See this weblog entry for more information.

    I have WS SP2 + .Net 2.0 framework, with WSS running on .Net 2.0. Everything works fine. Until I have a unghosted page... when I try to add a web part using the web interface I get the following exception:

    Invalid postback or callback argument.  Event validation is enabled using <pages enableEventValidation="true"/> in configuration or <%@ Page EnableEventValidation="true" %> in a page.  For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them.  If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation.

    I have the enableEventValidation set to false, as configured using the command:

    stsadm.exe –o upgrade –forceupgrade –url http://URLOftheVirtualServer

    I tried to add this setting to other web.config's and to the machine.config, but to no avail.

    Seems like the SharePoint safe mode parser (executed on unghosted apsx pages) is behaving different from the normal ASP.NET page rendere.

    When I modify the pages using FrontPage there is no problem.

    Any ideas? I would hate to go back to the 1.1 FrameWork, because now I can write my web parts using SonOfSmartPart and the full functionality of the ASP.NET 2.0 framework.

    I know I shouldn't unghost pages, but I'm doing a lot of Data View web parts.

    [I'm cross-posting between my weblog (http://weblogs.asp.net/soever) and the sharepointdisussions group @ yahoo]

  • Chm files and 404 Errors

    I must say I was amazed that when I downloaded the latest Windows SharePoint Services 2.0 Administrators Guide I only got 404 errors on every page in the contents. I downloaded the file another time, to no avail. I gave up and thought: well, the file must be corrupted. But no: this is one more step by Microsoft to provide us ultimate security!

    I stumbled across this blog entry by Mark Kruger that provided the solution:

    1. Right-click the CHM file, and then click Properties.
    2. Click Unblock.
    3. Double-click the .chm file to open the file.

     

  • Olaf Conijn from Macaw in the Netherlands: patterns&practices champion!

    One of our youngest collegues becomes a patterns&practices champion!! A smart guy with a bright future!! See his blog at http://bloggingabout.net/blogs/olaf/default.aspx. See the e-mail below!

    Congratulations to this community's newest "patterns & practices Champions!"
    Congratulations to this community's newest "patterns & practices Champions!"(2/3/2006 3:36:58 PM)
    The p&p Champion award is given on a quarterly(ish) basis to members of our community who have gone "above and beyond" the call of duty with regard to helping their fellow community members. These are the people who answer questions, create useful samples or build extensions to the application blocks. In short, these are the people who really make the patterns & practices program work and we couldn't do it without them! 

    The award winners for February 2006 for the Enterprise Library community are: 

    * Olaf Conijn (OlafC). While Olaf worked on the development team for Enterprise Library for .NET 2.0, this award is for his independent contributions to the community, in particular his Environmental Overrides plug-in.

    * Alois Kraus (akraus2): Alois has been one of the most active members of the Enterprise Library Community, and has provided many community members with assistance in using the new January 2006 release on message boards and via his blog.

    * Francois Tanguay (FrancoisTanguay). Francois provided the Enterprise Library team and the community with some great feedback on Preview releases of Enterprise Library for .NET 2.0, and shared his own blocks and extensions with fellow community members.

    Congratulations to the winners and our thanks to everyone (winner or not!) for your contributions to the community. More information about the p&p Champions program, the winners' accomplishments and winners from other communities are published on MSDN.

    Posted By tomhollander

    Go to patterns & practices: Enterprise Library


    GotDotNet CodeGallery | Terms of Use | Privacy Statement | Code of Conduct

  • Usage Event Logging in Windows SharePoint Services - Annotated

    A great article on Event Logging in Windows SharePoint Service appeared in july 2004 on MSDN on how to parse the log files that Windows SharePoint Services produces when logging is enabled. The article describes the format of these log files and provides a sample that demonstrates some of the basics for creating a tool that parses the files to extract information about site usage.

     

    This blog post provides more detailed information on the binary log format. This information is especially useful if you want to provide a managed version in for example C# of the log file parser.

     

    Applies to: Microsoft Windows SharePoint Services 2.0,  Microsoft SharePoint Portal Server 2003

     

    Exact binary format (see also the referenced article for more info on the fields):

      

    Field

    Bytes

    Details

    pPrev

    4 (ABCD)

    Value=A|(B<<8)|(C<<16)|(D<<24)

    bitFlags

    1

    -

    -

    1

    Padding to get to WORD boundary

    cbEntry

    2 (AB)

    Value= A|(B<<8)

    cbSiteUrl

    2 (AB)

    Value= A|(B<<8)

    cbWeb

    2 (AB)

    Value= A|(B<<8)

    cbDoc

    2 (AB)

    Value= A|(B<<8)

    padding2

    2

    Padding to get to DWORD boundary

    cBytes

    4 (ABCD)

    Value=A|(B<<8)|(C<<16)|(D<<24)

    httpStatus

    2 (AB)

    Value= A|(B<<8)

    cbUser

    2 (AB)

    Value= A|(B<<8)

    cbQS

    2 (AB)

    Value= A|(B<<8)

    cbRef

    2 (AB)

    Value= A|(B<<8)

    cbUAS

    2 (AB)

    Value= A|(B<<8)

    padding3

    2

    Padding to get to DWORD boundary

    Reserved

    4

    -

    -

    1

    \r

    -

    1

    \n

    SiteGuid

    36

    ASCII string

    -

    1

    0 (delimits string in C++)

    Time

    8

    ASCII string (HH:MM:SS)

    -

    1

    0 (delimits string in C++)

    SiteUrl

    cbSiteUrl

    ASCII string

    -

    1

    0 (delimits string in C++)

    WebUrl

    cbWebUrl

    ASCII string

    -

    1

    0 (delimits string in C++)

    DocName

    cbDoc

    ASCII string

    -

    1

    0 (delimits string in C++)

    UserName

    cbUser

    ASCII string

    -

    1

    0 (delimits string in C++)

    QueryString

    cbQS

    ASCII string

    -

    1

    0 (delimits string in C++)

    ReferrerUrl

    cbRef

    ASCII string

    -

    1

    0 (delimits string in C++)

    UserAgent

    cbUAS

    ASCII string

    -

    1

    0 (delimits string in C++)