Handy Regular Expressions

While working on a Sharepoint css file, I was able to use a nift regex instead of copying and pasting all over the place.

The tag I had looked like this:

#MSOZoneCell_WebPartWPQ4 td h3 a

I wanted to add a tag on the end so that it looked like this:

#MSOZoneCell_WebPartWPQ4 td h3 a, #MSOZoneCell_WebPartWPQ5 td h3 a

I used this Regex in Sharepoint Designer to do so:

Find

#MSOZoneCell_WebPartWPQ4 {.*$}

Replace

#MSOZoneCell_WebPartWPQ4 1, #MSOZoneCell_WebPartWPQ5 1

The “1” is called a “Tagged Expression”.  It refers to the part of the value that is tagged in the “Find” syntax.  You tag something using brackets, so in this case “.*$” was tagged, which corresponded to this part of the result ” td h3 a”.  I had about 10 of these, so this saved me a lot of time.

.Net Logging Framework

Found a fantastic logging framework for .Net:

http://www.theobjectguy.com/dotnetlog/

It’s very lightweight, has a ton of loggers already defined, and is easily extensibile.  The feature that drew me to it was the ability to log to multiple places at once and to filter what type of entry gets logged to each location.  For instance, I wanted to log everything to a text file but only log exceptions to the Windows Event Log.  With this framework, it was no problem.

SharePoint Webpart Styling

I always wondered how to style a single webpart on the page.

http://www.heathersolomon.com/blog/articles/Controlling-Single-Web-Parts-with-CSS.aspx

Been dealing with CSS for a long time and never knew about attribute selectors.  Only issue is you can’t be in Quirks mode, which does mess up the rendering of some elements in SharePoint.

CSS Framework

Just came across this today: http://www.blueprintcss.org

Looks like a good starting point for anyone developing a new website.  I know from past experience that fighting with page layouts consumed a good chunk of time when I developed a website.  So, anything that could save me time would be very useful.

Looks like it even works for Sharepoint!

Outlook 2007 Free/Busy Issues

Came across an interesting issue that I thought I would pass along.  For the longest time I couldn’t see any Free/Busy information when I used the Outlook client to connect to Exchange.  When I used webmail, the information was there.

I finally figured out why: http://www.networkworld.com/community/node/17227.

After I added the key, the info is available.  Unbelievable.

Sharepoint 2003 to 2007 Upgrade thoughts

I just completed a medium sized upgrade (83GB) for a client from Sharepoint 2003 to 2007 and thought I’d share a few things I took away from it:

  • You’re probably going to need to create a new Site Definition to map to the old one if the old one is customized at all
  • Set expectations with users upfront that while most of the things on the site will work correctly, there will be some issues (hopefully minor) that will have to be resolved post-upgrade.  For some reason, on the site I upgraded parts of the site were upgraded flawlessly while other parts had issues.
  • Perform the migration at least once in a dev environment and let users perform UAT.  Make sure you document their issues and how you fixed them.  This document proved invaluable once we did the production migration.
  • The database upgrade option is by far the safest and is recommended.

Some helpful links:

http://blogs.msdn.com/michael_yeager/archive/2007/08.aspx <– This was, by far, the most useful

http://blogs.msdn.com/sharepoint/archive/2007/03/06/how-to-upgrade-an-area-based-on-a-custom-site-definition.aspx

New Sharepoint Book

Here’s a new Sharepoint book that my manager Sean McDonough and John Ferringer co-wrote:

SharePoint 2007 Disaster Recovery Guide

Book Description:

Microsoft’s SharePoint technology gives organizations access to a wide range of tools and functionality designed to encourage collaboration, manage documents, discover shared knowledge, and much more. As the use of these resources through SharePoint grows, so does an organization’s dependency upon the availability and reliability of its SharePoint infrastructure. Disaster recovery is not a new concept in the realm of information technology nor is it unique to SharePoint, but as with any specialized technical platform, disaster recovery planning for SharePoint presents unique challenges and approaches. The problem is that SharePoint disaster recovery is not as simple as backing up your discs or load balancing your servers. It requires specialized activities to save data for recovery and to subsequently properly recover that same data. SharePoint professionals need a cohesive and comprehensive resource that guides them through the steps of planning, implementing, and testing the right disaster recovery plan for their situation. The “SharePoint 2007 Disaster Recovery Guide” provides such a resource. It provides a unique guidebook to all the necessary best practices, procedures, and tools for disaster recovery in SharePoint, such as how to plan for disaster recovery in SharePoint, and how to setup SharePoint, SQL Server, operating system, and file system backups step-by-step through SQL Server or STSADM.exe. The negative and positive aspects of every solution are detailed so that users can pick the disaster recovery plan that’s right for them. This is an essential guide for any IT professional tasked with protecting their organization’s valuable SharePoint data.

Amazon Link

Welcome Page Updater

During a recent uprade from Sharepoint 2003 to 2007, I noticed that some of the sites’ welcome pages weren’t getting set correctly. For some reason, they were set to UpgLandingPgRedir.aspx, which redirected to nowhere. Very convenient; must be a feature.

Here’s a piece of code I wrote that looks at every weclome page in your site collection and changes it if necessary. The Pause() isn’t necessary; I found it helpful to verify the changes that were being made.

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

namespace SPWelcomePageUpdater
{
    class SPWelcomePageUpdater
    {
        static void Main(string[] args)
        {
            Console.Write("Please enter the URL of the Sharepoint site: ");
            string url = Console.ReadLine();
            using (SPSite siteCollection = new SPSite(url))
            {
                SPWebCollection coll = siteCollection.AllWebs;

                for (int i = 0; i < coll.Count; i++)
                {
                    using (SPWeb targetWeb = coll[i])
                    {
                        SPList pagesLib = targetWeb.Lists["Pages"];
                        SPFile newWelcomePage = null;
                        foreach (SPListItem li in pagesLib.Items)
                        {
                            if (li.Name == "default.aspx")
                            {
                                newWelcomePage = li.File;
                            }
                        }

                        if (newWelcomePage != null)
                        {
                            if (PublishingWeb.IsPublishingWeb(targetWeb))
                            {
                                PublishingWeb publishingWeb = 
                                     PublishingWeb.GetPublishingWeb(targetWeb);
                                Console.WriteLine(publishingWeb.DefaultPage.Name);
                                if (publishingWeb.DefaultPage.Name=="UpgLandingPgRedir.aspx")
                                {
                                    // this sets the new welcome page
                                    publishingWeb.DefaultPage = newWelcomePage;    
                                    publishingWeb.Update();
                                    Console.WriteLine(publishingWeb.Name 
                                         + " welcome page updated.");
                                    Pause();
                                }
                                else if (!publishingWeb.DefaultPage.Url.ToUpper()
                                                .Contains("PAGES"))
                                {
                                    // this sets the new welcome page
                                    publishingWeb.DefaultPage = newWelcomePage;    
                                    publishingWeb.Update();
                                    Console.WriteLine(publishingWeb.Name 
                                         + " welcome page re-updated.");
                                    Pause();
                                }
                            }
                        }
                    }
                }
            }
        }
        static void Pause()
        {
            Console.WriteLine("Press any key to continue...");

            Console.ReadKey(true);
        }
    }
}

Infopath Item Level Security

Man it’s been awhile since I posted last.  Since nobody reads this, I guess it doesn’t matter.

Item level security on Infopath forms has been bugging me awhile.  It should be easy to set permissions for a form in the form library by using Rules or some other method.  However, that’s not the case.

You can do it using EventReceivers, though.  And I’m happy to say that it works pretty well.  Here’s the code:

public override void ItemAdded(SPItemEventProperties properties)
{
        Guid siteID, webID, listID;
        int itemID;
        SPUser curr;
        listID = properties.ListId;

        itemID = properties.ListItem.ID;
        using (SPWeb web = properties.OpenWeb())
        {
            siteID = web.Site.ID;
            webID = web.ID;
            curr = web.CurrentUser;
        }
        SPSecurity.RunWithElevatedPrivileges(delegate()
        {
            using (SPSite site = new SPSite(siteID))
            {
                using (SPWeb web = site.OpenWeb(webID))
                {
                    SPList list = web.Lists[listID];

                    SPRoleAssignmentCollection roles = list.RoleAssignments;
                    SPListItem addedItem = list.GetItemById(itemID);
                    addedItem.BreakRoleInheritance(false);

                    SPRoleDefinition roleDefinition =
                    web.RoleDefinitions.GetByType(SPRoleType.Reader);

                    SPRoleAssignment roleAssignment =
                    new SPRoleAssignment(curr.LoginName.ToString(),
                    curr.Email.ToString(), curr.Name, "");

                    roleAssignment.RoleDefinitionBindings.Add(roleDefinition);

                    addedItem.RoleAssignments.Add(roleAssignment);

                    this.DisableEventFiring();

                    web.AllowUnsafeUpdates = true;
                    addedItem.Update();

                    this.EnableEventFiring();
                }
            }
        });

}

Sharepoint web services + autocompleteextender

Oh boy that was fun.  I’m not even going to get into what I had to do and how long it took to get this working.  However, some code below will be helpful for those of you that want to try this yourselves (it’s not mine; I pulled it from the Smarttools source).  This solves the issue that Sharepoint has with Ajax postbacks/callbacks.

Also, you’re going to want to make sure that your “servicepath” attribute of the autocompleteextender is setup like this: “~/_vti_bin/nameofyourwebservice.asmx” or else you’ll get prompted to log in every time you call the service (which, incidentally, should be deployed to the ISAPI directory in your “12” hive).

If you need additional details, let me know.


ScriptManager sm = ScriptManager.GetCurrent(this.Page);

if (sm == null)
{
    //create new ScriptManager and EnablePartialRendering

    sm = new ScriptManager();
    sm.EnablePartialRendering = true;
    sm.EnableScriptLocalization = true;

    // Fix problem with postbacks and form actions (DevDiv 55525)
    Page.ClientScript.RegisterStartupScript(typeof(AgencyCodePicker),
    this.ID, "_spOriginalFormAction = document.forms[0].action;", true);

    //tag:"form" att:"onsubmit" val:"return _spFormOnSubmitWrapper()"
    //blocks async postbacks after the first one
    //not calling "_spFormOnSubmitWrapper()" breaks all postbacks
    //returning true all the time, somewhat defeats the purpose of
    //the _spFormOnSubmitWrapper() which is to block repetitive postbacks,
    //but it allows MS AJAX Extensions to work properly
    //its a hack that hopefully has minimal effect

    if (this.Page.Form != null)
    {
        string formOnSubmitAtt = this.Page.Form.Attributes["onsubmit"];
        if (!string.IsNullOrEmpty(formOnSubmitAtt)
        && formOnSubmitAtt == "return _spFormOnSubmitWrapper();")
        {
            this.Page.Form.Attributes["onsubmit"] = "_spFormOnSubmitWrapper();";
        }
        //add the ScriptManager as the first control in the Page.Form
        //I don't think this actually matters, but I did it to be consistent
        //with how you are supposed to place the ScriptManager when used declaritevly
        this.Controls.AddAt(0, sm);
    }
}

Switch to our mobile site