Skip Ribbon Commands
Skip to main content

Nigels Experiences With SharePoint

:

Quick Launch

Home
February 06
Designing and Developing for Maintainability

I have been involved in SharePoint for about 10 years now and over the years I have come to have issues with certain aspects of SharePoint Solutions and these tend to be in the area of Supportability and maintainability.

 

SharePoint Designer changes should be done in a controlled manner.

The flexibility of SharePoint can actually become an issue once the solution has been deployed and is up and running in a production environment. Changes made with SharePoint Designer can be made without much effort. However, how do you do proper QA of that change and then move the change from say a test to a production environment. It is not straight forward. It's very important to keep this issue in mind when defining the policies for how, when and who makes changes to what using what tools.

The way Microsoft is marketing and selling the SharePoint platform can be a problem in itself. You need to make changes to the look and feel of your intranet? Easy, with SharePoint Designer you can do it! And you do not need to be dependent on expensive consultants and highly paid developers who are the only ones that know how to do even the simplest change in the systems? and they realize that and hold you to hostage ?

You DO NOT want people to make changes to the production system by hand (ie by using SharePoint Designer). The scope for making a mistake is enormous. There is no way you can do a proper QA on that change and there is no change management, no regression path no nothing. This is an unacceptable situation and I hope one of the things that come out in SharePoint 15 is a better way of moving SharePoint Designer changes from one environment to the next, ideally via a wsp.

I accept that what a site administrator does with their own site is up to them and if they want to screw their site up with SharePoint Designer then that's their problem. However, where the change is to a business critical part of the site, then proper change control procedures must be used and SharePoint Designer should not be used. There needs to be very clear guidelines on what can be done by a site administrator and what has to be done under a proper change control procedure. The right way to go depends on many factors, such as how business critical the application is, the amount of custom code that depends on i.e. certain columns and lists being in place, where the responsibility lies if something goes wrong and end user knowledge of the platform and tools.

There must be a governance plan in place that should address these issues.

Take into account supportability when you design a solution.

I recently was involved in a project where there were over 150 sites in it and each site had the same list and that list had a list workflow on it. I was asked to make an amendment to add a column to the list and then to amend the workflow to include that column. Adding the extra column was fairly simple for new instances of the list. The problem comes when you have to add the column to existing lists. You have to write some powershell script to go around all of the sites, find the list, and add the column to the list. Then, you have to update the workflow on the list. But hang on, it's a SharePoint Designer workflow, do you have use SharePoint Designer to update 150 lists ?

A better solution would be to have a single, common event receiver which kicked off a single workflow. This way you only had to update the workflow once. So the moral of this story is to remember the poor person who has to maintain your solution when you design it.

Make it easy to upgrade to the next version of SharePoint

The upgradeability factor is always important to keep in mind, but it's becoming more and more important as the next version of SharePoint (SharePoint 15) is almost upon us.

As a rule, the SharePoint Team puts a lot of efforts to ensure the backwards compatibility of the platform. This means that upgrading an out of the box solution or a site with few customizations to the next version of SharePoint is often a very straightforward process (at least from my experience from upgrading solutions from 2007 to 2010). However, UI customizations and custom developed components will add additional effort though. This is particularly true for CSS "hacks" on top of the out of the box styling. The issue here is that certainly when upgrading 2007 to 2010 Microsoft changed the rendering so that what worked with 2007 did not necessarily work for 2010 as 2010 is Web 2.0 "AA" compliant. So therefore minimize as much as possible these hacks because they will come back and bite you when you upgrade.

February 01
Why You Should Make That First Release Of A Project Out Of The Box Functionality Only

A recent blog posting by Ian Woodgate of PointBeyond set me thinking about how SharePoint projects should be run. I come from the old school of developing solutions and the waterfall way of running projects. In this methodology the project plan consisted of a number of releases, each one building upon the last one. The first release was always the initial release and its objective was to get something out to the users early so they could get used to the new system. Each subsequent release then built on that first release adding new functionality everytime there was a new release.

Unfortunately, SharePoint Projects I have been involved in over the years ( SharePoint Portal Server 2003, MOSS 2007 and SP2010), have involved a long first phase before the first release. This resulted in a "Big Bang" of functionality for the first release. (I was always taught small incremental releases.) It then followed on that there would be a large amount of feedback from the users, some of which demanded changes to the initial release. So now, not only did we have phase 2 to design, write and test, but inevitably the customer wanted their changes incorporated into the next release as well. Yes, I know at this point the Change Request procedure kicks in and all of that entails. The end result of which usually means that the second phase gets delayed and the project itself gets delayed and the total cost of the project has increased from its initial value.

Surely, a better way of running these projects would be to roll out as much of the functionality that is Out of the Box as possible for the first phase Leave the custom code until a later phase. This way the users can get used to SharePoint at an early stage of the project.

In my presentation to #SPSUK "Why do we develop – because we can ?" I suggested that one of the reasons why people dive into Visual Studio right from the "off" is that they do not know what is available "Out Of The Box" so they start coding straight away when all they had to do was look inside SharePoint to find the functionality they want. The other reason, I have found, that people dive for Visual Studio at the first sign of a requirements specification, is that they are unable to give the customer exactly what they want UI wise. If, instead they went back to the customer and said look if you want this exact user interface it will cost £x but if we changed the UI slightly to this then the cost will be considerably less (in terms of development, testing and risk). Most customers would say "yes" we will go with the OOTB UI, because it saves us money and the risk of the project being late is reduced.

I worked on a project for a customer recently where they took just that attitude. They wanted an extranet up and running within a month. So I said that's fine but two things :- 1) The site is going to have to be out of the box with no custom code and 2) There might need to be some compromises on the UI to ensure that item 1) is adhered to. The result was that after the "Look and feel" people did their stuff, we created a CKS:DEV branding project to take the css file, the images, the master page and the page layouts. Modified the Master Page and the Page Layouts to give the user the look and feel they wanted and within a month we had a working extranet. In subsequent releases we added more page layouts and more functionality so that at the end of the project they had a fully functioning extranet which was launched on time and within budget. Not a single line of C# code was written for the project.

So, in summary, when you are talking to the customer about their requirements try and explain the cost (and the risk) of using custom code and explain that with some small changes to the UI they can save a lot of money. Make sure that the first release contains OOTB functionality only and then build the custom stuff in a later release.

January 25
Creating Folders using Microsoft Word in a MOSS 2007 Document Library

I had a problem recently where customers were complaining that they could not create folders within a MOSS 2007 document library and get them approved when the folder was created from Microsoft Word 2003 or Word 2007. However, when I created the folder using the MOSS 2007 document library GUI it created the folder and approved it using the "additem" event handler I had created.

Upon investigation the difference between the two scenarios was that with the MOSS 2007 Document Library GUI method the properties parameter passed into the event hander by MOSS 2007 had the SPItemEventProperties.ListItem object populated. Whereas when the folder was created using Word 2003 or Word 2007 then it was NULL ! (I am told this occurs when MOSS 2007 does not have a context to work with.)

So to fix the problem I changed the event handler to look like this :-

private void ItemHandleEvent(SPItemEventProperties properties)

{

try

{

if((properties.ListItem == null) || (properties.ListItem.ContentType.Name.ToLower() == "folder"))

{

// Its a folder

if (Trace.TraceLevel.TraceInfo)

{

Trace.Write(this, "ItemHandleEvent ContentTypeName = Folder ");

}

DisableEventFiring();

SPSecurity.RunWithElevatedPrivileges(delegate()

{

using (SPSite site = new SPSite(properties.WebUrl.ToString()))

{

using (SPWeb web = site.OpenWeb())

{

SPList doclib = web.Lists[properties.ListTitle];

SPFolder thisfolder = web.GetFolder(properties.AfterUrl.ToString());

SPModerationInformation moderationInformation = thisfolder.Item.ModerationInformation;

if (Trace.TraceLevel.TraceInfo)

{

Trace.Write(this, "ItemHandleEvent modeationinformation = " + moderationInformation.Status.ToString());

}

if (!(moderationInformation.Status == SPModerationStatusType.Approved ))

{

moderationInformation.Comment = string.Format("This folder has been approved on the {0}", DateTime.Now);

moderationInformation.Status = SPModerationStatusType.Approved;

thisfolder.Item.Update();

Trace.Write(this, "ItemHandleEvent " + string.Format("This folder has been approved on the {0}", DateTime.Now));

}

}

}

});

}

}

catch (Exception ex)

{

Trace.Write(this, "We got an exception in Document Event Handler" + ex.Message);

}

finally

{

EnableEventFiring();

if (Trace.TraceLevel.TraceInfo)

{

Trace.Write(this, "ItemHandleEvent Finally");

}

}

}

November 14
Presentation from #SPSUK

​These are the slides from my presentation @#SPSUK titled "Are we developing because we can?" :-

 

 http://blog.njpenterprises.com/Documents/Are%20we%20developing%20just%20because%20we%20can2.pptx

April 14
Out of The Box Claims Based Authentication does not support MembershipProvider.GetUser(username)

I wanted to find a user in my Membership database using their username. I quickly found out that it is not implemented and I get a "NotImplemented Exception". Although if you have the user's Guid (user.ProviderUserKey) then you can find the user. How Bizarre !

 

Then after A LOT of Binging I found a recent response to this question on a Microsoft Forum by a chap called Ryan T Mann. The url of the forum response is (http://social.technet.microsoft.com/Forums/en-US/sharepoint2010programming/thread/5e231fd0-53e1-4ae2-b2d8-702613a7b458).

I repeat his response here :-

 

The Membership class is a static class in System.Web.Security namespace that is based solely off w/e provider is set as the default provider for the current HttpContext. In other words,

Site http://yoursite.com

Membership.GetUser calls the GetUser method of the Membership Provider set as the default MembershipProvider for site http://yoursite.com,

Heres the trick with sharepoint 2010. In sharepoint 2010 every claims based web application has the same default MembershipProvider, and it's set to SPClaimsMembershipProvider.

SPClaimsMembershipProvider acts as a proxy for w/e membership provider you have set in your Sharepoint Web Applications spIISSettings (Central Admin -> Web Applications -> Your Web App -> Authentication).

So when you call Membership.GetUser, it's calling SPClaimMembershipProvider.GetUser which it turns looks up the SPIisSettings for the WebApplication of the SPContext.Current context to get the name of the Membership provider you've configured for the current zone. It then in tern accesses that via the Providers collection in Membership.Providers and call's it's GetUser Method.

 

Long story short, is don't use the Membership class, instantiate your provider like this,

 

private static SPIisSettings _SPIisSettings;

//Store settings IIS Settings about the current Zone this webapp context is in.

internal static SPIisSettings SPIisSettings

{

get

{

 

if (_SPIisSettings == null)

{

SPSecurity.RunWithElevatedPrivileges(delegate()

{

_SPIisSettings = SPContext.Current.Site.WebApplication.GetIisSettingsWithFallback(SPContext.Current.Site.Zone);

});

}

return _SPIisSettings;

}

}

//Stores references to this zones MembershipProvider and RoleProvider (if it's a forms zone)

internal static System.Web.Security.MembershipProvider MembershipProvider

{

get

{

return System.Web.Security.Membership.Providers[SPIisSettings.FormsClaimsAuthenticationProvider.MembershipProvider];

}

}

internal static System.Web.Security.RoleProvider RoleProvider

{

get

{

return System.Web.Security.Roles.Providers[SPIisSettings.FormsClaimsAuthenticationProvider.RoleProvider];

}

}

 

 

Then do this MembershipProvider.GetUser(tbUsername.Text.Trim(), false);

April 03
Getting Claims Based Authentication and User Profiles to work together (Part 2)

So having got the user logged in (http://blog.njpenterprises.com/archive/2011/04/03/getting-claims-based-authentication-and-user-profiles-to-work-together-part-1.aspx) now it was time to time to get the user profile working.

I am indebted to Steve Curran (http://sharepointfieldnotes.blogspot.com/2010/02/creating-sp2010-social-comments.html) for putting me on the right track to fixing my issues. The problem was that when trying to create an user profile I was getting "Access Denied" or Only Administrators can create User Profile for other users. I tried a number of technics to get this to work including RunWithElevatedPrivileges but would never had found it in a million years without Steve's blog. Remember I was still running the application with anonymous access.

What Steve said was "Now most SharePoint developers would expect that by creating a SPSite with the user's SPUserToken and passing in this SPSite to the SPServiceContext.GetContext method that it would create an impersonated SPServiceContext that would generate a comment with that user's name and id. Unfortunately, this is not the case. It seems that the "User Profile Service Application" relies on the HttpContext object to get user profile information to determine who is generating tags and comments." I extrapolated this to most SharePoint developers would expect that by creating a SPSite with the user's SPUserToken and passing in this SPSite to the SPServiceContext.GetContext method that it would create an impersonated SPServiceContext that could be used to create a User Profile with that user's name and id. Unfortunately, this is not the case. It seems that the "User Profile Service Application" relies on the HttpContext object to get user profile information and hence allow Administrators (and as we shall see later) users to create and update User Profiles. So here we go…

string socialDataStatsSite = SPContext.Current.Site.Url;

SPSecurity.RunWithElevatedPrivileges(delegate()

{

using (

SPSite siteColl =

new SPSite(SPContext.Current.Site.ID))

{

using (SPWeb oWeb = siteColl.OpenWeb())

{

try

{

oWeb.AllowUnsafeUpdates = true;

 

// The CreateUser Profile checks the HTTPContext (NOT the SPContext) for some reason best known to itself, so we need to set it up

HttpRequest request = new HttpRequest("", socialDataStatsSite, "");

HttpContext.Current =

new HttpContext(request,

new HttpResponse(new StringWriter(CultureInfo.CurrentCulture)));

HttpContext.Current.Items["HttpHandlerSPWeb"] = oWeb;

WindowsIdentity wi = WindowsIdentity.GetCurrent();

 

typeof(WindowsIdentity).

GetField("m_name", BindingFlags.NonPublic | BindingFlags.Instance)

.SetValue(wi, username);

 

HttpContext.Current.User = new GenericPrincipal(wi , new string[0]);

WindowsIdentity wi2 = WindowsIdentity.GetCurrent();

SPContext adminContext = SPContext.GetContext(HttpContext.Current);

SPServiceContext context = SPServiceContext.GetContext(adminContext.Site);

ProfileSubtypeManager psm = ProfileSubtypeManager.Get(context);

 

// choose default user profile subtype as the subtype

string subtypeName = ProfileSubtypeManager.GetDefaultProfileName(ProfileType.User);

ProfileSubtype subType = psm.GetProfileSubtype(subtypeName);

 

UserProfileManager upm = new UserProfileManager(context);

 

// create a user profile and set properties

UserProfile newProfile = upm.CreateUserProfile(username);

 

As you can see we had to use reflection to change the WindowsIdentity's name property. It is this property that is used to create the user's profile. The username is of the same format as we discussed in the previous post ("i:0#.f|my_membership|email address"). We can no add in our entries thus :-

newProfile[PropertyConstants.FirstName].Add(

FirstName);

newProfile[PropertyConstants.LastName].Add(LastName);

newProfile[PropertyConstants.PreferredName ].Add(FirstName + " "+ LastName);

newProfile[PropertyConstants.WorkEmail].Add(email);

newProfile[PropertyConstants.WorkPhone].Add(

WorkPhone);

newProfile[PropertyConstants.DistinguishedName].Add

(AccountName);

newProfile.Commit();

So we now have our profile created. So you would think that updating that profile would be easy. WRONG ! we had to go through the whole rigmarole again when updating the profile. Reading the profile was easy as you would expect it to be.

So reading a profile (look no RunWithElevatedPrivileges) :-

SPServiceContext context = SPServiceContext.GetContext(site);

UserProfileManager profileManager = new UserProfileManager(context);

string sAccount = SPContext.Current.Web.CurrentUser.LoginName;

UserProfile u = profileManager.GetUserProfile(sAccount);

 

// Get the values from the user's profile

// Being careful to check for null values

 

ddlTitle.SelectedValue = (null == u[PropertyConstants.Title].Value)

? " "

: u[PropertyConstants.Title].Value.ToString();

tbFirstName.Text = (null == u[PropertyConstants.FirstName].Value)

? " "

: u[PropertyConstants.FirstName].ToString();

tbLastName.Text = (null == u[PropertyConstants.LastName].Value)

? " "

: u[PropertyConstants.LastName].ToString();

tbWorkEmail.Text = (null == u[PropertyConstants.WorkEmail].Value)

? " "

: u[PropertyConstants.WorkEmail].ToString();

 

tbJobRole.Text = (null == u[PropertyConstants.JobTitle].Value)

? " "

: u[PropertyConstants.JobTitle].ToString();

tbCity.Text = (null == u[PropertyConstants.Location].Value)

? " "

: u[PropertyConstants.Location].ToString();

 

tbPhone.Text = (null == u[PropertyConstants.WorkPhone].Value)

? " "

: u[PropertyConstants.WorkPhone].ToString();

 

if (null != u[PropertyConstants.WebSite].Value)

{

if ((u[PropertyConstants.WebSite].ToString().ToLower().StartsWith("http://")) ||

(u[PropertyConstants.WebSite].ToString().ToLower().StartsWith("https://")))

{

tbWebsite.Text = u[PropertyConstants.WebSite].ToString();

}

}

 

NB note how I checked for nulls everywhere and how to deal with urls (the other way did not work – I kept getting NullExceptions).

 

So Updating Profiles :-

 

SPSecurity.RunWithElevatedPrivileges(delegate()

{

using (

SPSite siteColl =

new SPSite(SPContext.Current.Site.ID))

{

using (SPWeb oWeb = siteColl.OpenWeb())

{

try

{

oWeb.AllowUnsafeUpdates = true;

 

// The CreateUser Profile checks the HTTPContext (NOT the SPContext) for some reason best known to itself, so we need to set it up

 

HttpRequest request = new HttpRequest("", socialDataStatsSite, "");

HttpContext.Current =

new HttpContext(request,

new HttpResponse(new StringWriter(CultureInfo.CurrentCulture)));

HttpContext.Current.Items["HttpHandlerSPWeb"] = oWeb;

WindowsIdentity wi = WindowsIdentity.GetCurrent();

typeof(WindowsIdentity).

GetField("m_name", BindingFlags.NonPublic | BindingFlags.Instance)

.SetValue(wi, sAccount);

HttpContext.Current.User = new GenericPrincipal(wi, new string[0]);

WindowsIdentity wi2 = WindowsIdentity.GetCurrent();

SPContext adminContext = SPContext.GetContext(HttpContext.Current);

SPServiceContext context = SPServiceContext.GetContext(adminContext.Site);

UserProfileManager upm = new UserProfileManager(context);

UserProfile u = upm.GetUserProfile(sAccount);

 

// Set the values for the user's profile

u[PropertyConstants.FirstName].Value = tbFirstName.Text;

u[PropertyConstants.LastName].Value = tbLastName.Text;

u[PropertyConstants.WorkEmail].Value = tbWorkEmail.Text;

 

u[PropertyConstants.JobTitle].Value = tbJobRole.Text;

u[PropertyConstants.Location].Value = tbCity.Text;

u[PropertyConstants.WorkPhone].Value = tbPhone.Text;

if ((tbWebsite.Text.ToLower().StartsWith("http://")) || (tbWebsite.Text.ToLower().StartsWith("https://")))

{

u[PropertyConstants.WebSite].Value = new Uri(tbWebsite.Text);

}

 

u.Commit();

             }

            }

        }

    }

Again sAccount is in the format described earlier ("i:0#.f|my_membership|email address").

 

I hope this has helped someone solve this particular annoying problem.

 

 

 

 

 

April 03
Getting Claims Based Authentication and User Profiles to work together (Part 1)

Apologies for not blogging recently – I have moved job and things have been a little busy recently.

I am currently working on a project which involves potential users registering for a site before they are allowed onto the site. As is usual for SharePoint 2010 and public facing sites Claims Based Authentication is used for users authenticating with the site. But before they can authenticate they need to register, and this is where my problems started. When a user is registering we do not know who they are and so the registration process runs as the anonymous user so anybody registering cannot do anything untoward whilst they are registering. The potential users enter the usual first name, last name, email address, telephone number and also their company name and their job title.

So I used the out of the box Login page, restyled to the customer's taste. One of the changes to the Login page was a "Register" button which would redirect the user to the Registration page. The first problem was that the "Registration" button was inside of a <LayoutTemplate></LayoutTemplate> so I used an image button which directly re-directed the user to the Register Page :-

<a href= "Register.aspx" ><img src="/_layouts/images/XXXX/system/register.gif" alt="Not a registered user? Register here." /></a>

 

As stated earlier the registration page collects the first name, lastname, the email address, the job title and the company name. The architecture of the site decreed that this information should be stored in a user's user profile within SharePoint 2010. The customer wanted users to login using their email address rather than any other means. So the first thing was we had to create a Claims Based Authentication (CBA) user. You will notice that the username is the same as the email address because this is what the customer wanted :-

 

//1) Create membership user

MembershipCreateStatus status;

// write username and password to membership datbase mark user as inactive

MembershipUser membershipUser = System.Web.Security.Membership.CreateUser(email, password, email, "_Not used_", "_Not used_", EnableUser, out status);

 

if (status == MembershipCreateStatus.Success)

{

//now we have created Membership User

 

Then the fun and games started. The next thing we needed to do was to create an SPUser . Two things were needed here. The first was as we were running as the anonymous user we had to "RunWith ElevatedPrivileges" in order to create a SPUser. The second the format of the username passed into EnsureUser (username) was not your usual DomaonName \ UserName as we were using CBA. So we had to craft the username as "i:0#.f|my_membership|email address" before we could pass it into EnsureUser. Where "i" is the role provider name (straight from the web.config – MS create the default role provider in 2010 as "i"). The ".f" shows it is a FBA (CBA) username. "My_Membership" is the membertship provider name from web.config. But note it is not the default one set up by MS which is "c". Then finally we have the email address we are using to login with.

 

//2) Create sharepoint user

//get the site instance

SPSecurity.RunWithElevatedPrivileges(delegate()

{

using (

SPSite siteColl =

new SPSite(SPContext.Current.Site.ID))

{

try

{

using (SPWeb spWeb = siteColl.RootWeb)

{

spWeb.AllowUnsafeUpdates = true;

// Create SPUser

string roleProvider = System.Web.Security.Roles.Provider.Name;

// need format of username to be i:0#.f|my_membership|fred

username = Membership.Provider.Name + ":0#.f|my_membership|" + email;

SPUser spUser = spWeb.EnsureUser(username );

 

 

}

}

catch (Exception ex)

{

Debug.WriteLine("bRegisterClick: "+ " " +

ex.ToString());

if (_ts.TraceError)

_th.TraceVerbose(

"Error in bRegisterClick {0}",

ex.Message);

}

}

}

);

 

That turned out to be the easier part…….

May 23
Getting FAST ESP 5.3.3 working with SharePoint 2010

I was recently asked to see if I could get FAST ESP 5.3.3 working with SharePoint 2010. So here are the steps (hoops) I went through to get this to work.

First I tried just running the setup.exe that came with the FAST ESP Webparts you can download from codeplex. http://espwebparts.codeplex.com

No such luck it failed saying that WSS 3.0 was not installed. So I downloaded the source code from the above web site.

BTW I was using Visual Studio 2010 to do all of this.

I loaded the source code into VS 2010 so of course it had to update the project from VS2008 (or was it 2005) to VS 2010. No errors.

I watched the video supplied "FAST ESP WebParts" Recording to see how it should be done.

I then compiled the code, first problem the unit tests file pointed to an old "12" hive dll, so as I was not intending doing any unit tests (sorry Woody!) I just excluded the unit tests project from the solution.

 

It then compiled.

 

In the aspx page ESPConnectionConfig.aspx, I changed all of the dll references to 14.0.0.0 just to be safe.

In the folder "WSP" (ESPSearchWebParts\ESPSearchWebParts\WSP) there were three batch files deploywsp, redeploywsp and undeploywsp I modified these to work with the base level hive ("14" hive).

I then ran deploywsp which added the wsp file to the solutions store (no sandboxed solutions here)and then deployed it to my site.

I then activated the FAST ESP Webparts feature in the site collection features and went to sitecollections administration -> ESPQueryServerConnections and my next error message "an unexpected error occurred".

So I turned off customerrors in the web,config and set showstack to true in the web config. Reselected the ESPQueryServerConnections and bang it failed again but this time I got a security exception had occurred. SO off into the SharePoint log I went and found the following :- The SPPersistedObject, ESPConnectionData Name=ESPConnectionData, could not be updated because the current user is not a Farm Administrator – I had got full trust set in the web.config but that did not solve the problem. So I looked at SPPersistedObject in MSDN and by luck there were some community content there saying that the error I was getting had been seen before and that overriding HasAdditionalUpdateAccess and returning "true" will fix the problem so I added :-

/// <summary>

/// Overrides Microsoft.Sharepoint.Administration.SPPersistedObject.HasAdditionalUpdateAccess

/// surposed to fix permissions problem on update

/// </summary>

/// <param></param>

/// <param></param>

 

protected override bool HasAdditionalUpdateAccess()

{

return true;

}

 

To the bottom of public class ESPConnectionData : SPPersistedObject and recompiled.

 

(I know that this is not the most secure way of solving this problem but needs must until someone has a better way of fixing it.)

Undeployed the wsp, deployed it again and tried again and this time it worked. So I entered the url of the FAST Query Server (eg fast.development.lan – no http://).

I then created my FAST ESP site by selecting new site from the site actions menu and then selecting the FAST Search Site (NOT FAST Search centre) and OK.

This created the FAST Search site and a default.aspx. So I then navigated to default.aspx. No search box ! I added one and FAST did not return any results. I debugged the FAST WebParts and found that The search box I added was not passing the search string to the rest of the web parts. So I then looked at the source of the page and found I now had two search boxes ! I deleted the one I had added and looked at the source of the page and found I still had one search box but it was not being displayed on the page. After much head scratching I realised that the Ribbon and the search box were trying to use the same part of the page (even if the ribbon was not displayed !). So I moved         <div style="height:100%; width:100%;padding-left: 2px; padding-top: 16px; padding-bottom: 14px;">

            <div style="width:390px;">

                <WebPartPages:WebPartZone runat="server" AllowPersonalization="false" title="<%$Resources:sps,LayoutPageZone_TopZone%>" id="TopZone" orientation="Vertical" QuickAdd-GroupNames="Search" QuickAdd-ShowListsAndLibraries="false"/>

            </div>

        </div>

 

From under <A name="mainContent"></A> in the placeholder PlaceholdTitleBreadcrumb to just after

<!-- MAINRIGHTBODYAREA_BEG: cell that encompases the main right body area --> <td valign="top" width="100%">

<table border="0" cellpadding="0" cellspacing="0" id="ZoneTable" width="100%" class="ms-tztable">

In default.aspx in the directory ESPSearchWebParts\ESPSearchWebParts\WSP\14\TEMPLATE\SiteTemplates\FASTSearchSite in VS 2010 and recompiled the solution, undeployed it, deployed and tried again. This time I had a search box so I entered some text into it and hit the magnifying glass icon and hey presto ! it worked and brought back some results.

 

Now I know I took some short cuts and the ESP Search page is not the best looking in the world but the object of exercise was to get FAST ESP 5.3.3 and SP 2010 talking to each other. This I have now done and someone else can make it pretty.

 

 

 

 

 

 

 

 

May 04
Upgrading a MOSS 2007 site to SharePoint 2010 (Part 2)

When upgrading a MOSS 2007 site which has been created with features to SharePoint 2010 the question is how do you start ?

Obviously you need to create the web application first, that's the easy bit. The question is what do you do next ?

If you try to deploy the solution (and hence the features) using VS2010 (obviously updating where necessary from VS 2008) then you get a deployment error – it can't find the site.

If you try and deploy the content using Mount-SPContentDatabase there is a string of errors in the 14\Logs log file saying it can't find the webtemp.xml or the site template or any web parts.

So what do you do first ?

In the end I used the following steps :-

  • I create the Content Database using SQL Enterprise Manager
  • Restore the MOSS 2007 Content Database using SQL Enterprise Manager
  • Convert the MOSS 2007 content database to a SharePoint 2010 Content Database using Mount-SPContentDatabase
  • Deploy the solution (and hence the features) using VS2010.
  • Remove the content database using SharePoint 2010 Central Administration
  • Delete the content database using SQL Enterprise Manager
  • Recreate the Content Database using SQL Enterprise Manager
  • Restore the content database using SQL Enterprise Manager
  • Finally use Mount-SPContentDatabase to convert the MOSS 2007 content database to SharePoint 2010.

A bit of a long winded approach but at least it works !

May 03
Upgrading a MOSS 2007 site to SharePoint 2010 (Part 1)

I decided it was time to get my demonstrations moved from MOSS 2007 to SharePoint 2010.

The demo in question used features to set up the site definition, the content types, the site columns, the Master Pages and the Page Layouts.

I was looking forward to using the new SharePoint facilities in Visual Studio 2010 to make things a lot easier.

So off we went, created the web app and the site definition and then used Mount-SPContentDatabase (forever imprinted on my brain after

Andrew Connell's presentation at SPC09) to mount the MOSS 2007 into SP 2010.

So far so good.

I then ran my features to create the Master Pages, the Page Layouts and the content types and the site collections.

I then, for some reason, decided to check the SharePoint Log to see if there were any errors. I found lots of :-

w3wp.exe (0x1518)     0x1468    SharePoint Foundation     General     7fad    Medium     Unable to locate the xml-definition for CType with

 SPContentTypeId '0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF39006D502404FABF4A62B9E470A2F1A9684400 B83444F0B27F479 B8C1124D3C811A25700F473A6A2D8AC46B69840DC07451FECAC', exception: Microsoft.SharePoint.SPException ---> System.Runtime.InteropServices.COMException (0x8000FFFF): <nativehr>0x8000ffff</nativehr><nativestack></nativestack> at Microsoft.SharePoint.Library.SPRequestInternalClass.GetGlobalContentTypeXml(String bstrUrl, Int32 type, UInt32 lcid, Object varIdBytes) at Microsoft.SharePoint.Library.SPRequest.GetGlobalContentTypeXml(String bstrUrl, Int32 type, UInt32 lcid, Object varIdBytes) --- End of inner exception stack trace --- at Microsoft.SharePoint.SPGlobal.HandleComException(COMExceptio...    80ef4d8d-92a1-4325-a711-f82a7e5e5e35

w3wp.exe (0x1518)     0x1468    SharePoint Foundation     General     7fad    Medium     ...n comEx) at Microsoft.SharePoint.Library.SPRequest.GetGlobalContentTypeXml(String bstrUrl, Int32 type, UInt32 lcid, Object varIdBytes) at Microsoft.SharePoint.SPContentTypeCollection.FillCollection(SPRequest req, SqlDataReader rdr, Boolean openWeb)  80ef4d8d-92a1-4325-a711-f82a7e5e5e35

I checked the Content Types Gallery in Site Settings (Site Settings -> Galleries -> Site Content Types) NOTHING of mine !

So I did a simple test took one content type and put it into a feature and deployed it – still NOTHING of mine.

So I created a VS 2010 Content Type project and recreated by Content Type using additem -> Content Type, deployed it – IT WORKS !

OK I thought, easy, take the ID of the Content ID of the content type I was inheriting off and replace what was in my original feature (the ID looked exactly the same) anyway deployed my original content type again and again NOTHING but the same old error message in the SharePoint Log Unable to locate the xml-definition for CType

with SPContentTypeId….

Time to bite the bullet.

I created a new Web Application called Content Hub and a Team Site Collection called Content Hub and used a Visual Studio 2010 Content Type Project to create all of my content types.

Deployed this – all of my content types appeared in my content type hub. I then set up the Metadata service app so that my original site collection could subscribe to and get all of my content types Thanks Wictor for the blog ->

 Plan your SharePoint 2010 Content Type Hub carefully

So I now had my site columns and my content types on my original web apps (looks as if the content type hub also syndicates Site Columns as well.

OK – so we deploy our master page and page layouts feature again, check the Sharepoint log – still the same error messages.

Then I realised that I had not changed the content type IDs in the master page and page layouts feature because of course they are now new !

OK changed all of the content type Ids, redeployed feature again, check SharePoint Log – still the same error messages.

I then checked the site settings -> galleries -> Site Templates and Page Layouts to make sure my content types were OK now.

Wrong

Content Types Associated with Page Layouts

Lots of "Invalid Associated Content Type" entries – so now I had to go through all of my page layouts and master pages inside the master page gallery and change all of my associated content types :-

Checking Content Types of Page layouts

NB although the master page gallery said that everything had the correct associated content type when you edited the properties this is what you get !!

I have now been through all of the master pages and page layouts and sorted out all of the associated content types and IT WORKS !!

BTW before I changed the associated content type I got this message :- error CS0030: Cannot convert type 'Microsoft.SharePoint.WebControls.FieldValue' to 'System.Web.UI.IAttributeAccessor'

Fixing the associated content type fixed the above issue.

Conclusions

The basic problem appeared to be that the content types could not be imported into the SharePoint 2010 site from the MOSS 2007 if created using a feature.

I deliberately created a content type hub so that if I had to trash the SharePoint 2010 site then I would not lose all of the work I had done previously.

Why the content types got disassociated from the master pages and page layouts I don't know and why the feature which was supposed to tie the master pages and page layouts to their content types did not work.

But finally I got my site working. It took a couple of days to sort it out.

 

 

 

 

 About this blog

 
Picture Preview 
Welcome to my new Blog as the old one seems to have disappeared. I will try and retrieve as many of the old posts as I can.  The dates might not be quite right. Anyway I will be blogging about my experiences with SharePoint and everything SharePoint.