Joe's profileJoe Shepherd - Adventure...PhotosBlogListsMore Tools Help

Joe Shepherd - Adventures in MOSS 2007

SharePoint 2007 Information Worker Solutions

Joe Shepherd

Occupation
Location
Interests
Joe is Microsoft Services Manager for an advanced technology consulting firm.

Joe holds an Associate of Applied Science in Aerospace Technology from the Community College of the Air Force, a Bachelor of Science in Management and Information Systems (cum laude) from Park University and an MBA from Thomas More College where he held the position of class president.
October 01

Scheduled to Speak at SharePoint Connections 2009

I just got word that I have been approved to present 3 sessions at the SharePoint Connections Spring 2009 Conference which is being held from March 21-26, 2009 at the Grande Lakes JW Marriott Resort Hotel in Orlando, Florida.

The sessions I will be presenting are entitled:

  • Anatomy of Solution, Using Custom Actions and Application Pages to Manage Issues
  • Driving Information, Information Architecture for Information Workers
  • Creating a Custom Login Form for Forms Based Authentication

I am very excited about these topics and I can't wait to get them out there to you all. Hope to see you all there!

September 12

Class to Read Config Values from Application Settings List

I wanted to provide a follow up to my last article about reading configuration values from a SharePoint list. I wrote a simple C# class that will read configuration values from a list called Application Settings that exists at the web application root. 

Here is a couple of things about the class.

1. It assumes a list called Application Settings lives at the root of the web application.
2. It assume the current user has rights to read from the list
3. The list contains the following fields:

1. Application
2. NameSpace
3. KeyName
4. KeyValue

Once this list is in place you can use this class to retrieve the KeyValue field for any KeyName. Since the fields Application and NameSpace exist we can use the same KeyName across multiple applications. This was something you could not do in the web.config.

Below is the SettingsManager class. As always, the code below works in my environment and is for demonstration purposes only! You can use it and adapt it as you see fit but please test it first. I have not taken the time to ensure that I followed all the best practices so look it over before you drop it into your production environment.

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;

namespace Utilities
{
    class SettingsManager
    {
        #region "Private Variables"
        private string _listName;
        private string _url;
        private string _applicationName;
        private string _className;
        private string _keyName;
        private SPListItem _listItem;
        #endregion

        #region "Properties"
        public string ListName
        {
            get { return _listName; }
            set { _listName = value; }
        }
        public string URL
        {
            get { return _url; }
            set { _url = value; }
        }
        public string ApplicationName
        {
            get { return _applicationName; }
            set { _applicationName = value; }
        }
        public string KeyName
        {
            get { return _keyName; }
            set { _keyName = value; }
        }
        public string GetKeyValue
        {
            get { return _listItem["KeyValue"].ToString(); }
        }
        #endregion

        #region "Constructors"
        public SettingsManager(string listName, string url, string keyName)
        {
            _listName = listName;
            _url = url;
            _keyName = keyName;
            DataBind();
        }
        public SettingsManager(string listName, string url, string applicationName, string keyName)
        {
            _listName = listName;
            _url = url;
            _applicationName = applicationName;
            _keyName = keyName;
            DataBind();
        }
        public SettingsManager(string listName, string url, string applicationName, string className, string keyName)
        {
            _listName = listName;
            _url = url;
            _applicationName = applicationName;
            _className = className;
            _keyName = keyName;
            DataBind();
        }
        #endregion

        #region "Methods"
        public void DataBind()
        {
            SPSite site = null;
            SPWeb web = null;
            try
            {
                site = new SPSite(_url);
                web = site.OpenWeb();
                SPList list;
                list = web.Lists[_listName];

                SPListItemCollection col = list.GetItems(BuildQuery());
                _listItem = col[0];//there should be only one
            }
            catch (Exception e)
            {
                throw new ArgumentNullException("No Application Settings where returned", e);
            }
            finally
            {
                web.Dispose();
                site.Dispose();
            }
        }
        private SPQuery BuildQuery()
        {
            StringBuilder sb = new StringBuilder();
            if (_applicationName != null && _className != null)
            {
                sb.Append(string.Format("<Where><And><And><Eq><FieldRef Name=\"Title\" /><Value Type=\"Text\">{0}</Value></Eq><Eq><FieldRef Name=\"NameSpace\" /><Value Type=\"Text\">{1}</Value></Eq></And><Eq><FieldRef Name=\"KeyName\" /><Value Type=\"Text\">{2}</Value></Eq></And></Where>",_applicationName, _className, _keyName));
            }
            else if (_applicationName != null || _applicationName != string.Empty)
            {
                sb.Append(string.Format("<Where><And><Eq><FieldRef Name=\"Title\" /><Value Type=\"Text\">{0}</Value></Eq><Eq><FieldRef Name=\"KeyName\" /><Value Type=\"Text\">{1}</Value></Eq></And></Where>", _applicationName, _keyName));
            }
            else
            {
                sb.Append(string.Format("<Where><Eq><FieldRef Name=\"KeyName\" /><Value Type=\"Text\">{0}</Value></Eq></Where>", _keyName));
            }
            SPQuery myQuery = new SPQuery();
            myQuery.Query = sb.ToString();
            return myQuery;
        }
        #endregion
    }
}

September 11

Application Settings and Web.Config Options

In the old days of ASP.NET programming we used to place all of our application specific settings under the appsettings section of the web.config. With SharePoint we can still take this approach but we also have a few other options available to us. I want to take a moment and explore what those options are and how I choose to go about this.

Web.config


Obviously SharePoint is just another ASP.NET website under the hood. Therefore we have the traditional method of storing these values in the web.config file at our disposal. The problem with this is that in a server farm environment the settings would have to be placed in each config file on each WFE server. Couple that with an environment where you have extended web applications and you have quite a few changes to keep track of.

It is possible to programmatically update the web.config and even push those changes out to all the WFE servers via a timer. I have some code that does this but there are some drawbacks here as well. Take the following code block from my FeatureActivated method of my Feature Receiver:

SPWebApplication webApp = new SPSite("http://intranet.demo.com").WebApplication;

SPWebConfigModification modification = new SPWebConfigModification(@"section[@Name='appSettings']", "configuration/appSettings");

modification.Owner = "Intranet Portal";
modification.Sequence = 0;
modification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
modification.Value = "<add key='PathToCAMLQueries' value='C:\\CAMLQueries\\'/>";
webApp.WebConfigModifications.Clear();

// Add new modification.
webApp.WebConfigModifications.Add(modification);

// Save changes.
webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();

//Propagate changes.
webApp.Update();

The above code will add the specified key value pair to web.config and propagate the changes out to the WFE servers in the farm. The problem is that it will add it to every web.config for every web application in the farm. I have tried several combinations and approaches to automate the entries in the config file but all of them update all web.config files in the farm. I have seen some mention that if you specify the web app ID in the service call as, webApp.Farm.Services.GetValue<SPWebService>(webApp.Parent.Id).ApplyWebConfigModifications();, then it will work but my testing has shown otherwise. To me this is no longer a viable option.

Update web.config with traditional C# methods.

The web.config is after all just an xml file so then we could conceivably update it with the traditional xmlDocument methods. This however does not propagate our changes out to the remaining WFE servers so the code would have to be run on each WFE manually. This of course if not the best course of action.

Application Settings List

I chose to employ and approach where I build a Application Settings list at the root site collection that is only editable by site collection owners. I then use that list to store all my configuration settings and pull from there I the same manner that I would the config file. See screenshot below for my Application Settings list.

ApplicationSettings

Under this approach instead of the traditional "ConfigurationManager.AppSettings["PathToCAMLQueries"].ToString();" call to get the value you would query the list via CAML. You can of course use a class, and subsequent collection, to represent your application setting or you can just query the list and bring back the SPListItemCollection that contains the results of your query.

I prefer this approach for a couple of reasons.
  1. Changes can be made without interrupting users.
    Updates to the web.config recycle the application pool by design. This can cause issues with users on the site and can result in a loss of cache.
  2. Key Names no longer have to be unique across a web application.
    Given the fact that the settings are contained in a SP List provides us with the ability to query based on multiple fields, therefore our Key Names no longer have to be unique.
  3. Settings exist in a single location
    Since the list lives in the SP database its values are available across all WFEs as well as extended web applications automatically. No need to worry about failed timer jobs that do not push changes out to all entities.
  4. Simplification of Disaster Recovery
    Once again, the settings exist in the database so there is no longer a need for file system backups to capture the web.config.
  5. Easier management via Feature Receivers
    It is much easier to use Feature Receivers to add or remove settings from the list than it is to do the same with the web.config.

As always, I am not saying mine is the only way, or even the best way. My only point here is to provide you with alternatives that may help make your life a little easier and to highlight some of the different ways we can use out-of-box SharePoint capabilities to do extraordinary things. Good luck and happy coding!

September 08

SharePoint Technology Conference

Sorry it has been so long between posts. I have been crazy busy on projects lately and getting my stuff together for the many conferences that are coming up in the new year.

On that note, I just found out that I will be speaking at the SharePoint Technology Conference in San Francisco in January 27-29 2009. I will present two sessions: the first, an overview of the SharePoint Object Model and the second is entitled "Anatomy of Solution, Using Custom Actions and Application Pages to Manage Issues".

I am really looking forward to this. I have done presentations locally but never at a conference. I have also submitted abstracts for some of the other conferences but they are still open at this point so we will just have to wait and see.

Error Importing Site Collection

Recently I ran into a situation where I tried to import a site collection from one farm to another and I got this nice little error telling me that the import failed because it could not find the Feature S2SiteAdmin. Upon further investigation I determined that this feature is part of the Infrastructure Updates to MOSS 2007 that include the updates to Search. This is the update that adds federated search to MOSS 2007. If you run into this make sure that you have these updates applied in the destination environment. Its always a good idea to make sure that your source farm and destination farm are of the same version anyway but hey, this was a test case:)

 
A list of links to friends blogs
Thanks for visiting! Please take a moment to tell me about yourself.
Please wait...
Sorry, the comment you entered is too long. Please shorten it.
You didn't enter anything. Please try again.
Sorry, we can't add your comment right now. Please try again later.
To add a comment, you need permission from your parent. Ask for permission
Your parent has turned off comments.
Sorry, we can't delete your comment right now. Please try again later.
You've exceeded the maximum number of comments that can be left in one day. Please try again in 24 hours.
Your account has had the ability to leave comments disabled because our systems indicate that you may be spamming other users. If you believe that your account has been disabled in error please contact Windows Live support.
Complete the security check below to finish leaving your comment.
The characters you type in the security check must match the characters in the picture or audio.
Marcy Kellarwrote:
Hi Joe, I was googling for some answers about stsadm.exe tonight and you came up 6th in the results.  I thought, could it be?  No!!!  And I was pleased to find out this was indeed the Joe Sheperd that I know.   Kudos on the blog! 
Dec. 2
Jenniferwrote:
I was referred to your blog and am impressed.  Great information!
Jan. 10
Ryan Steenowrote:
Hi Joe,
 
I'll be referencing some of your blog entries!  Good stuff!
Nov. 14
Photo 1 of 31