jQuery to SharePoint Web Services

Recently I have been working on a Google Maps integration for SharePoint and one of the desired capabilities was to include items from SharePoint lists on the map.  The solution was not going to leverage the AJAX .NET capabilites and would instead be built using standard .NET and jQuery.  This presented the major challenge, while we could convert the lists into RSS, GeoRSS, and KML feeds they all required authentication to access these feeds, something that Google Maps does not support in the GGeoXml object.  Google Maps are heavily javascript focused so we couldn’t use the SharePoint API to access the items directly especially since we wanted to avoid post backs to the server, and javascript arrays would likely run out of space give the number of possible items.  This really left us with one possible solution, javascript calls to the SharePoint Web Services.  Fortunately, talking with one of my co-workers he pointed me to a nice, somewhat limited, jQuery plugin for the SharePoint web services available here:

http://www.sympraxisconsulting.com/Demos/Demo%20Pages/SPjQueryWebServices.aspx

Using this service I have been able to access the current web’s lists and items from those lists.  Here is an example of how I have used this plugin to retrieve the lists and populate a selection box, their code for the button clicks are also available.

My Code

$(“.list_select_cell”).html(“<img src=\”/_layouts/images/ewr133.gif\” alt=\”Loading lists\” />”).SPServices({
operation: “GetListCollection”,
completefunc: function(data, status) {
var mySelectBox = “<select size=’5’ id=’list_select’>”;
$(data.responseXML).find(“List”).each(function() {
mySelectBox += “<option value=’” + $(this).attr(“Title”) + “’>” + $(this).attr(“Title”) + “</option>”;
});
mySelectBox += “</select>”;
$(“.list_select_cell”).html(mySelectBox);
}
});

So what is really happening here?

$(“.list_select_cell”).html(“<img src=\”/_layouts/images/ewr133.gif\” alt=\”Loading lists\” />”).SPServices({…

In the above code we have selected a location that currently exists in our page’s DOM and have added the ewr133.gif, the same gif SharePoint uses when processing Site creations.  So basically you specify the DOM object you want to effect while making the asynchronous calls to the SharePoint web service.  You do not have to add or remove text from a DOM object, you could also choose to show or hide an object, that is based on your needs.

operation: “GetListCollection”

Here you are specifying the service you are calling.  These match the name of the asmx file provided by SharePoint, in this case the call is actually going to the GetListCollection.asmx service.  Only certain service calls are supported as the jQuery library is not an all inclusive library.

completefunc: function(data, status) { …

This specifies the action to take when the asynchronous call completes.  The first argument provided to this function is the XmlHttpRequest object, thus in order to gather any information from the response you must parse the responseXML.  At the end of this function I recommend, if you changed the DOM object’s html as part of the “while processing” action that you now set the value to something useful to the user.

So now you can access your lists, and your list items from Javascript and you don’t even need to perform a standard PostBack.

Some limitations

One of the biggest limitations I experienced with this tool is that the plugin assumes you want to use the “current” SharePoint web when retrieveing lists, and also assumes that any list you are accessing is stored in the current web.

Conclusion

This plugin while limited is EXTREMELY stable for an 0.X version, and saved me a number of hours of custom coding WCF services, or building my own version of this plugin.

Read more...

To Workflow or to Item Event Receive

I was recently asked about how to determine when a List Item should be transferred from one list to another.  Immediately two possible solutions came to mind, use a Workflow or use an Item Event Receiver.  I offered both as “capable” of handling such a need, which of course lead to the next “well which should I use for this…” question and this blog.

Background

SPItemEventReceiver “Provides methods for trapping events that occur to items.” – MSDN.  This class generally provides two functions for each action that can occur to an item in a list, eg. ItemAdded and ItemAdding, one that is Synchronous and the other that is Asynchronous.  Custom receivers can be added to lists either programmatically or by ContentType ID.

SPWorkflow “A workflow instance that has run or is currently running on an item.” – MSDN. This class is not used like the SPItemEventReceiver because with a workflow we are usually looking at Sequential or State Machine Workflow instances, but I want to remain as generic about the workflows in this article as possible.  This statement does highlight a significant and important difference between the Item Event Receiver and the Workflow, workflows run ON an item but are not necessarily driven BY the item itself.

Before going any further I want to make sure the reader understand that I’m not saying one solution is right and the other is wrong, or that you should only use this solution for this issue.  I also want to be clear in that this is not an either-or approach to solving a problem, in fact the more complex the issue the more you may find the need for both in a “little of this-little of that” solution.  Instead what I have found is that developers often learn one of these two skills and then apply that to everything because it is what they are comfortable with or because it is a new skill and we all like to use our new skills!  Which ever of these cases you fall into I hope this blog will help you understand the benefits of another capability, and save you some time.

SPItemEventReceiver

A SPItemEventReceiver is intended to deal directly with a List Item, either during or immediately after an that item has been involved in an event.  The statement “defining” the SPItemEventReceiver above shows that the SPItemEventReceiver is used to “react to” changes to the item itself.  The Event Receiver is aware of all information stored by an item in the list, and in the ‘ing’ (sychronous) events even exposes the original and new values.

Since the SPItemEventReceiver is designed to interact directly with a list item when a change occurs, actions that are driven by the information it represents are standard candidates for being implemented in the SPItemEventReceiver.  The most common example of this is dealing with records that could be associated with an item that has been deleted from a list.  In this case removing the record association link from all items in the list would be implemented in the asynchronous ItemDeleted event.

My rule of thumb:   Use SPItemEventReceiver when the information in this list item the driver for the event (when you must react).  This may be part or all of the entire information stored by the list item, but in all cases the information in the list item is the MOST IMPORTANT aspect to consider.

SPWorkflow

A SPWorkflow comes in different flavors, but workflows all have one thing in common and that is a “process” by which the workflow will move from beginning to end.  The statements “defining” the SPWorkflow above show that the SPWorkflow is running ON an item.  Therefore the workflow process is typically generic and not oriented to the specific information contained in the actual List Item it is associated with.  This is not to say that the list item’s data is irrelevant, the information may be displayed or modified in one or many of the workflow steps, but the workflow is more oriented toward processing the steps an item must go through to reach a “final” state.

Since the SPWorkflow is designed to progess an item through a series of steps it is mostly concerned with its own state (active/complete), how to move to the next state, and so forth.  Due to this orientation toward step processing of an item, series of actions that will repeat consistently and predictably are candidates for being implemented as Workflows.  The most common example of this is of course the approval process where one or many users/groups must “sign off” on the item before is is approved.

My rule of thumb: Use SPWorkflow when there are a series of steps and actions an item must go through to get from a beginning state to an ending state (when you must cause action).

So what did I recommend for moving the item from one list to another?  First, my question was “How do you determine when to move the item?”.  Based on the answer, “User checks a box on the Edit Item screen” I recommended the SPItemEventReceiver because there was no process for “approving” or determining when to move the item, just a reaction to a List Item’s field.

Read more...

SharePoint SP2 Bug – 180 Day Countdown

Microsoft recently released the latest service pack for SharePoint 2007 (SP2) which does provide a number of enhancements.  However, in their process of developing this Service Pack they happened to overlook the fact that SP2 resets your SharePoint Installation into a Trial Mode.  What does this mean, basically you have 180 days after installing SP2 to reactivate your SharePoint install as a non-trial version or your SharePoint instance will stop working.  Currently there are no automatic hot fixes for this, but you can re-enter your Product ID on the Convert License Type page which will resolve this issue.

Here is the official statement on the SharePoint blog.

Read more...

Bamboo List Aggregator Web Part

A customer I support has the Bamboo List Aggregator web part which allows you to consolidate multiple lists into a single view and display on a site, very helpful in SharePoint!  The customer had added one to a page and wanted to be able to set a default “Sort By” and default “Group By” value.  He assumed, as did I went I first looked at this issue, that there would be some very simple option to select a default “Sort By” and “Group By” value, but there wasn’t.  So looking at the web part on the page understanding that Bamboo has simple provided a nice GUI to the Content Query Web Part I knew there was some way to make this work.  So here is how:

Set the Default Sort By Value

  1. Select the “Sort By” value you want to be your default.
  2. Once the page refreshes open the source and search for the value you selected, in this case “Site Path”.  This value will appear multiple times so make sure you find the location in the HTML with the correct Sort By <select> tag and the <option selected> tag.  From there copy the Value of the option tag.
  3. Open the Parameters Editor for the Content Query Web Part and find:
    <ParameterBinding Name=”dvt_sortfield” Location=”Postback;Connection;CAMLVariable” />
    this should be near the top of the parameter edit text box
  4. Add DefaultValue=”<value from option tag in step 2>” (in my example it was DefaultValue=”bsc_SiteProperties”) and then save your changes.
  5. Apply your changes to the web part and verify the field is now defaulted to your desired value.

Set the Default Group By Value

  1. Follow the first two steps in the section above.  Make sure to copy the value from the Group By <select> tag and the<option selected> tag’s Value.
  2. Open the Parameters Editor for the Content Query Web Part and find:
    <ParameterBinding Name=”dvt_groupfield” Location=”Postback;Connection” />
    this should be near the bottom of the parameter edit text box
  3. Add DefaultValue=”<value from option tag>” (in case this was “DefaultValue=”bscListName”) and then save your changes.
  4. Apply your changes to the web part and verify the field is now defaulted to your desired value.

Read more...

Did You Know - SPQuery DateTime default comparison

After hours of wondering why my code kept reporting scheduling conflicts when I could see events did not overlap I discovered a VERY important note in MSDN on the SPQuery page.
…DID YOU KNOW…

When SPQuery is used to check values against a DateTime field it only checks the Date portion by default? In order to make SPQuery include a time check you must include IncludeTimeValue=’TRUE’ in the Value tag.
Example:

<Value Type=’DateTime’ IncludeTimeValue=’TRUE’><Today/></Value>

Reference:

http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spquery.aspx

Read more...

Visual Web Part Development

So I readily admit that I am often a code junkie, if I can do it in code then I will. However, I have started to look for tools and solutions that let me code less, drag and drop more, and generate solutions that look better faster.
I have always wanted to experiment with building WebParts using the Visual Studio GUI, but have often found time lacking, until recently. I have a very complex solution that leverages ‘n’ Membership Providers to handle provisioning user information into several different systems (MOSS, AD, OCS, Exchange, Adobe Connect, etc). Working with another developer we initially laid out the solution that would tie all these together, however we quickly realized that we had cut our ability to use the standard .NET Membership Controls. Fortunately, we are able to revisit our designs as we use an iterative approach to our solution development and we have moved back toward the .NET Membership Control support. As such we decided to use the CreateUserWizard control to handle our user creation, however we needed to customize this control…A LOT! Enter visual development of web parts.
We are using the Visual Studio 2008 for development and I initially created a web site project and added a user control to the project. My reason for this is I do not want a code behind page in a SharePoint solution so I will do the initial development and layout in the web project. Because I was using the web project I could use my membership providers to test the compatibility, perform debugging, and just work in a generally scaled down environment.
When I was done with the ascx development, including customization of the look, feel, and actions I copied the ascx into my SharePoint solution. Visual Studio attempted to be helpful by also copying the code behind file, which I deleted. I created a class file in the SharePoint solution and had it inherit from System.Web.UI.UserControl. I copied the functions I had in the code behind page into this class file and saved it. I then changed the <%@ Control … line so that rather than referencing a code behind file I inherited from the class I had just added to the SharePoint solution. Finally, for the code where I referenced controls on the ascx I included protected controls in the class file (if you forget this step the compiler will remind you).
Once I had the ascx and the class file included in my SharePoint solution I added a WebPart class that simply called the Page.LoadControl(…) and passed the relative path to my ascx user control. The Page.LoadControl returns a Control object which I then added to the Controls of my WebPart.
That was it, I loaded the solution and added the web part to the page. As soon as it was added the part displayed exactly as expected and functioned just like it had in the web site project. Total time for this was about 30 minutes, which if I had tried to create the wizard in code and customize the template would probably have taken most of a day, if not multiple days.

Read more...

Meeting Workspace Template Using Current Site Navigation

Recently I was asked to provide the same kind of “Current Site Navigation” on a Meeting Workspace template that appears on the site’s master page. Amazingly, given the right tools this is actually a VERY simple task. However, in order to accomplish this in the easiest method you will need SharePoint designer.

 
 

Steps:

  1. Open the Site using SharePoint Designer
  2. Open the Page with SharePoint Designer
  3. On the Custom Content object in the Content Place Holder PlaceHolderLeftNavBar click on the > button and choose to revert to the master page content.

  4. If you want you can simple delete everything in the <asp:Content ContentPlaceHolderId=”PlaceHolderLeftNavBar” …>…</asp:Content> section from the page
  5. Save the page back to SharePoint
  6. Go to the Site Navigation Settings page

  7. Site Actions->Site Settings
  8. Navigation (under the Look and Feel heading)
  9. Choose the Display only the navigation items below the current site radio button in the Current Navigation page section.
  10. Customize the Current Navigation items in the Navigation Editing and Sorting page section.

Read more...

Using List Item Events

Being one of the Sr. Developers on a project, and being responsible for Code Review and a part of the Configuration Management team I recommended we use some versioning of our assemblies. I stand by this decision on the versioning as I do believe it is very important, but when had to start modifying code in the Account Registration process I realized a flaw. I was using a SPItemEventReceiver and had not accounted for the assembly numbers changing which would affect SharePoint’s ability to call the correct event receiver. The key issue was I HAD to update the event receiver and without the ability to remove the old event handlers and replace them with the new assembly event receivers I couldn’t comply with the Code Review standards for Assembly Versioning.

 
 

After a little thinking and research the code below allowed me to resolve the issue.

 
 

Step 1. Finding and remove the old event receiver

list = spWeb.GetListFromUrl(listUrl);

bool allItemsChecked = false;

while (!allItemsChecked)

{

allItemsChecked = true;

foreach (SPEventReceiverDefinition receiver in list.EventReceivers)

{

if (

(receiver.Type == SPEventReceiverType.ItemAdded  

receiver.Type == SPEventReceiverType.ItemUpdated)

&& receiver.Class == typeof(MyRequestItemEventReceiver).ToString()

)

{

receiver.Delete();

allItemsChecked = false;

break;

}

}

 
 

You will notice that I loop through the event receivers and each time I removed/delete a receiver I start looping again. This restart ensures that when you delete the object the foreach loop continues to work properly and does not reference deleted items. I chose to compare just the Receiver.Class because, as I mentioned above the version numbers change but the list is maintained.

 
 

I initially assumed that receiver.Type would return to me the Object.Type information. This was not an accurate assumption and I do think it is a BAD thing that Microsoft allowed in this case. Given that Type is a specific object in .NET I really think this attribute should have been named EventType, but I wasn’t asked…so… Anyway, I check the Type to ensure that I only remove the events that I added custom actions for.

 
 

 
 

Step 2. Add new event receivers

list.EventReceivers.Add(SPEventReceiverType.ItemUpdated,

this.GetType().Assembly.ToString(),

typeof(MyRequestItemEventReceiver).ToString());

 
 

list.EventReceivers.Add(SPEventReceiverType.ItemAdded,

this.GetType().Assembly.ToString(),

typeof(MyRequestItemEventReceiver).ToString());

 
 

 
 

I implemented this code as part of my SPFeatureReceiver in the FeatureActivated function, because during that event I also update some other critical items the SPItemEventReceiver uses. You may find that removing and adding your custom event receivers to the list during the FeatureActivated event is more appropriate.

Read more...

Maps grab attention, and IDV's Visual Fusion Suite Helps

A partner company, IDVSolutions, is preparing a webcast to demonstrate their Geospatial SharePoint ready web parts.  I have been working with IDV for almost 1 year now, and I have had a lot of success extending their suite of tools to meet customer capabilities.  If you have the time make sure you sign up and join the webcast, if you don’t have time at least take a look at their Wonders of the World demo site.

Read more...

Activating Features in a SharePoint Farm

I have been pounding my head against a wall for the last few days trying to get a couple of features to activate in my projects new High Availability Environment (HA).  The environment consists of two MOSS Web Front Ends (WFE) named web1 and web2.  Our env. also includes web3 which runs the Central Admin site, but does not have any of the externally accessible sites (the ones that run on port 80 and 443).  This has lead to the following issues.

  1. Attempt to activate the feature fails when executed from the web app.  This issue was easily resolved when I read The Kid’s blog, basically the permissions proposed by Microsoft for the MOSS configuration does not allow this.
  2. Actual values never appear in the web.config for web1 or web2
  3. I have a theory about this issue.  In our development environment we have two WFEs, but one of them is also running Central Admin.  I believe that I need to have the web applications running on the server that is also running Central Admin in order for this to work.  As I work through this issue with our system admins I will update my findings.
Per the results here is my recommendation about configuring a SharePoint environment.  When you are running within a SharePoint farm ensure that the Central Admin server is also running the Web Application Service.  You do not necessarily have to allow it to be one of the Network Load Balanced WFE's but having it running the Web Applications seems to be important to allow configuration changes through out the farm. Since I have now gotten this to work consistently I feel comfortable with my code implementation, so here it is.  This IS how you can get a SharePoint Solution Feature Listener to actually modify the web.config file in a single server or multi-server SharePoint installation. First we create the class that is going to be our feature listener.  To do this using Visual Studio create a new class file and add inheritance from SPFeatureReceiver.  After adding this inheritance add the appropriate "using" statement, this can be done using the Intelli-Sense menu.  Next, using the Intelli-Sense menu add the four abstract methods FeatureActivated, FeatureDeactivating, FeatureInstalled, FeatureUninstalling.  For the Installing, and Uninstalling functions we will just leave those blank.  My personal preference is to now create a function that will return a list of SPWebConfigModifications, however I have seen other concepts on the web as to how best create the SPWebConfigModifications so it is up to you.  For this blog I am simply going to assume we have a function that returns a list of SPWebConfigModificaitons, the method you choose is up to you. FeatureActivated

        public override void FeatureActivated(SPFeatureReceiverProperties properties)

        {

            List<SPWebConfigModification> modifications = CreateConfigModification();

            SPWebApplication webApp = null;

 

            if (properties.Feature.Parent is SPSite)

            {

                SPSite spSite = properties.Feature.Parent as SPSite;

                webApp = spSite.WebApplication;

            }

            else if (properties.Feature.Parent is SPWebApplication)

            {

                webApp = properties.Feature.Parent as SPWebApplication;

            }

 

            foreach (SPWebConfigModification mod in modifications)

            {

                webApp.WebConfigModifications.Add(mod);

            }

 

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

            webApp.Update();

        }

  1. To allow a more generic approach to the activation getting the SPWebApplication object is done so we can handle Web Application, Site, etc. feature activation scopes.
  2. Once we have created the list of SPWebConfigModifications we simply loop through it and apply them to the SPWebApplication object.
  3. Finally, call the SPWebApplication's Farm Service to Apply the web.config modifications.  This causes the changes to setup across the farm.  ALWAYS follow this with the SPWebApplication's update function, which essentially causes the modifications to "stick".
FeatureDeacting

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)

        {

            List<SPWebConfigModification> modifications = CreateConfigModification();

            SPWebApplication webApp = null;

 

            if (properties.Feature.Parent is SPSite)

            {

                SPSite spSite = properties.Feature.Parent as SPSite;

                webApp = spSite.WebApplication;

            }

            else if (properties.Feature.Parent is SPWebApplication)

            {

                webApp = properties.Feature.Parent as SPWebApplication;

            }

 

            foreach (SPWebConfigModification mod in modifications)

            {

                webApp.WebConfigModifications.Remove(mod);

            }

 

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

            webApp.Update();

        }

  1. To remove the modifications simply cycle through the same list of modifications we used orignally during activation.  I like this method because it is very clean and a bit more efficient.  However there is a problem with this approach!  If you do not name your modification correctly the modification will not be removed.  Therefore you may wish to cycle through the SPWebApplication's WebConfigModification list first matching the owner name to this feature's owner name and then cycle though that list removing the modifications as shown below

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)

        {

            List<SPWebConfigModification> modifications = new List<SPWebConfigModification>();

            SPWebApplication webApp = null;

 

            if (properties.Feature.Parent is SPSite)

            {

                SPSite spSite = properties.Feature.Parent as SPSite;

                webApp = spSite.WebApplication;

            }

            else if (properties.Feature.Parent is SPWebApplication)

            {

                webApp = properties.Feature.Parent as SPWebApplication;

            }

 

            foreach (SPWebConfigModification mod in webApp.WebConfigModifications)

            {

                if (mod.Owner.Equals(this.GetType().ToString()))

                    modifications.Add(mod);

            }

 

            foreach (SPWebConfigModification mod in modifications)

            {

                webApp.WebConfigModifications.Remove(mod);

            }

 

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

            webApp.Update();

        }

  1. I usually use the typename as the owner, since the typename's must all be unique this ensures that all of my owners are unique.  I have also seen other developers use the Feature ID for the Owner property, that is up to you but make sure your's is always going to be unique if you use this method.
Now you can activate and deactivate the feature for the farm.  I want to recommend adding The Kid's Web Modification Manager page to your central admin site as well.  This will help you see if and when the modifications have been added, and will also allow you to remove ones that get orphaned.  If you are doing activation and deactivation especially in the development process, this will be a life (or sanity) saver.

Read more...

A web configuration modification operation is already running.

I have been using the SPWebConfigModification class for a while, and every now and then I hit the issue that when I attempt to activate a feature that modifies the web.config file I get the following error:

A web configuration modification operation is already running. at Microsoft.SharePoint.Administration.SPWebService.ApplyWebConfigModifications()
  at ...

The biggest issue here is that I can no longer activate any other features that are going to edit the web.config, BIG PROBLEM!  So with some investigation here is what I have found that will allow you to overcome this issue.  Open your SharePoint Central Admin site, click on the Operations tab and click on the Job Definitions link under the Global Configuration heading.  Here you will see a number of Timer Jobs that execute Daily, Disabled, Hourly, Mintues, etc.  Here we are looking for a timer job titled Windows SharePoint Services Web.Config Update which executes One Time and will have an N/A listed for the Web Application.  If you click on the title you will be directed to the Edit Timer Job page.  This page provides you with three options, Delete, OK, Cancel.  You can probably guess the next step, but before I confirm let me provide a warning.  BY DELETING THE TIMER JOB BAD THINGS COULD HAPPEN!  Now, go ahead and delete the timer job.  You should now be able to activate your feature.

Here are a few blogs about how to properly deploy and activate features that should help you avoid this issue.

Read more...

Modifying the web.config with SPWebConfigModifications

A confusing aspect of using the SPWebConfigModifications is what should you use as the Name of your modification?

Here are my recommendations, I do not claim to have a complete or exact list, but this should help get you started.

  1. If you are adding items that will have repeating xml node names , like section or add, then your name should be something like the following to prevent overwriting any previously added modifications.
  2. add[@name=’name’] for <add name=”name” …/>
  3. section[@name=’name’] for <section name=”name” …/>
  4. etc.
  5. If you are adding custom xml nodes that will have child nodes then you should use the name of that node, this includes standard nodes located in the web.config file.
  6. membership for <membership>…</membership>
  7. etc.

If you need help, have haning web.config modifications etc, here is a link I found that provides a nice .aspx page that will allow you to remove those changes.  Also available at the link is more information about doing the web.config changes using SPWebConfigModification objects.

http://blog.thekid.me.uk/archive/2007/03/24/web-config-modification-manager-for-sharepoint.aspx

If you fail to name your modification properly then you might find that the next modification actually overwrites what you just added.


Another question I run across often is how to change the attribute of a tag that already exists.  It actually turns out that this is very simple.  Using the membership section of a web.config I will show you.

<system.web>
  <membership defaultProvider=”AspNetActiveDirectoryMembershipProvider”>
      <providers>
        <clear />
        <add name=”AspNetActiveDirectoryMembershipProvider” type=”…” connectionStringName=”…” … />
      </providers>
  </membership>
</system.web>

Lets say we have our own membership provider and you plan on referencing it using the name “MyCustomMembershipProvider” your SPWebConfigModification would look like the following.  Rember you would have to also add a membership provider using a SPWebConfigModification and the naming described above.

SPWebConfigModification membershipProviderPrimary = new SPWebConfigModification(“defaultProvider”, “configuration/system.web/membership”);
                membershipProviderPrimary.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureAttribute;
                membershipProviderPrimary.Sequence = 0;
                membershipProviderPrimary.Owner = GetType().ToString();
                membershipProviderPrimary.Value = “MyCustomMembershipProvider”;

Notice here set the name to the name of the xml attribute who’s value we want to set.  The XPath provided does not include the xml attribute, only the xml node which contains that attribute.  Finally, we set the SPWebConfigModification’s value to the desired value (“MyCustomMembershipProvider”). Once this change is commited you will see that the defaultProvider has been changed to “MyCustomMembershipProvider”.

Read more...

SharePoint Web Application Extension

The urls below are ficticious so if you attempt to navigate to them.  I have no idea what will happen nor do I claim responsibility or support for any content on the www.devsite.org if it even exits.  I have used this name in an attempt to provide a complete example of what occoured and how to correct the problem.

 

A team member recently deployed a web application capability to our development environment (web application name: devsite80) which caused an error in the web.config.  When I went to central admin to deactivate the feature I tested using our internal url (http://devsite) which is the default zone’s url for devsite80 in SharePoint alternate access mappings.  The site was back up, then I attempted to reconnect to our dev site from my local machine, again using the public address.  The site was down, with the same web.config issue.  What happened?

 

Background

When we created the public development site, we extended the internal development site (http://devsite) site.  This allowed the public development site to be configured in the same mannor as the internal development site, but also added the proper host headers, etc for us.

 

When features were deployed and activated everything worked fine.  When feature were deactivated, only the http://devsite site was effected.  (Quick Note:  In Central Admin only http://devsite was avaible for deploy/activate/deactivation, http://www.devsite.org __was not.)  After inspecting the file system we noted that there were two independent folders, devsite80 and www.devsite.org80.  The other thing I found was that devsite80’s web.config had the feature’s xml changes removed, but www.devsite.org80’s web.config did not.  We, a system admin and myself, decided that managing one folder would be much easier than trying to manage two (kinda obvious).  So here is what we did.

 

Steps
  1. Central Admin->Application Management->Remove SharePoint from IIS Web Site
  2. Selected http://devsite as the Web Application
  3. Selected http://www.devsite.org from the Select IIS Web site and zone to remove
  4. Selected the Yes radio button for Delete IIS Web sites
  5. OK
  6. Central Admin->Operations->Alternate access mappings
  7. Select Add Internal Urls 1. Selected Devsite80 from the Alternate Access Mapping Collection 2. Entered http://www.devsite.org for the URL protocol, host and port 3. Selected Internet from the Zone dropdown 4. Save
    • Opened IIS management console (Right Click My Computer->Manage)
  8. Navigated to the Web Sites folder (IIS Manager->local computer->Web Sites)
  9. Right clicked on Harmonieweb80 site and selected Properties
  10. Selected Advanced… on the Web Site tab (next to the IP Address drop down list)
  11. Selected Add… in the Multiple identities for this Web site. 1. Selected (All Unassigned) from the dropdown list for the IP Address (This site did not have any specific IP address assigned so this was appropriate, you might have to select an appropriate IP address) 2. Entered 80 for the TCP port 3. Entered www.devsite.org  for the Host Header value 4. OK
  12. OK
  13. Apply
  14. OK
    • Restart IIS

Following this we ended up with one web application, one web application folder, and the ability to activate and deactivate successfully.  We were also able to now access the site from both the http://devsite and the http://www.devsite.org urls.

Recommendation

If you ever need to add additional urls for a site use alternate access mapping with host headers.  This may take you a few extra steps, but for management it will save you a lot of time.  DO NOT use web application extension to create a new zone entry for an already existing application unless you want them to function and act independently.

Read more...

Spell Check Your Code (Funy Storie)

Before I tell this story I must admit that without Spell Check I never would have graduated college.  It is not because I mistyped words, I am a horrible speller!

 

I recently developed a solution allowing SharePoint KPIs to be associated with GeoRSS polygons.  The solution also leveraged IDV Solutions (www.idvsolutions.com) Visual Fusion Suite as the map display and region creation tool.  The KPI would be used to determine the color of the region when it was activated on the map.  This required me to perform the KPI calculations for the dynamic KPIs, could not find any method of getting the dynamic value.  One of the dynamic calculations is to find the Minimum value of the items in the list…simple enough.  I developed the code and tested, fixed a few bugs and then set it on to our tester.  While our tester was looking at the tool another developer performed a code review and remarked that I had misspelled “Minimun” in the code.  So I went back and fixed the issues from the code review and redeployed for our tester.  Next day I spoke with the tester and several tests had all of a sudden begun to fail!  This was very strange because most of the code review comments had been violations of our variable and method naming schema, code compiled so all of that should have been working…

 

After using U2U’s CAML viewer I discoverd I hadn’t misspelled Minimun, SharePoint actually uses Minimun!  Of course the value in the User Interface is spelled Minimum.

 

Moral of the story, spell check your code.  I have been told this before in software development classes and seminars, and never really understood, cared, or ever did it.  I understand now, that simple spelling mistake can really cause issues for others using your code.  Worse it can cause you problems later in your code when you actually spell that variable name correctly.

Read more...

JavaScript your WebControls

I recently ran into an issue recently where I needed to get javascript access to controls that were created programatically to my WebControl/WebPart.  I passed the control’s ID to the javascript function, which was rendered as the page was rendered, but was still not able to get access to the control.  When I looked at the HTML rendering of the page I found that the ID of the control, when I requested it from within my C# code was not the same as what the webpart rendered in the HTML. 

 

Because the webpart class implents the INamingContainer interface all of its controls are added to the page with IDs that include namespacing from the INamingContainer interface.  This can be a major pain to get around, but there is a very simple resolution. 

 

By adding:

 

myControl.Attributes.Add("ID", myControl.ClientID);

 

I was able to override the INamingContainer’s ID attribute and use the ClientID I was expecting.

Read more...