Showing posts with label Sharepoint 2007. Show all posts
Showing posts with label Sharepoint 2007. Show all posts

Wednesday, 12 January 2011

SharePoint 2007 and SharePoint 2010 Best Practice - Run SPDisposeCheck as part of your Build process with an Error Condition

One of the most common (and frustrating) sources of memory leak issues in SharePoint 2007 and SharePoint 2010 applications lies in the incorrect disposal of objects with unmanaged components. Memory leak issues typically show themselves in symptoms like:
  1. Excessive paging on the server and low memory issues
  2. The IIS application pools recycling themselves repeatedly
  3. Generally sluggish performance for end users (as the RAM gets eaten up by referenced SharePoint objects)
Why doesn't the .NET garbage collector clean them out of memory? Because the .NET objects are typically small - but it's the unmanaged (invisible to the .NET framework) that ravenously consumes your server's precious memory.

So what objects normally cause these issues? The prime suspects are normally undisposed instances of the SPSite and SPWeb classes - as detailed extensively on MSDN here:
http://msdn.microsoft.com/en-us/library/ee557362.aspx

I'm a firm believer in automated testing and code auditing tools - so to preemptively avoid such issues with disposal of unmanaged objects, I recommend to all of my SharePoint clients that you must have SPDispose check as part of your regular build process in any SharePoint Project. This avoids any existing code or any new code killing your SharePoint Farm with "unmanaged object bloat".

As described by the SPDisposeCheck documentation:
"SPDisposeCheck is a tool to help you to check your assemblies that use the SharePoint API so that you can build better code. It provides assistance in correctly disposing of certain SharePoint objects to help you follow published best practice. This tool may not show all memory leaks in your code. Further investigation is advised if you continue to experience issues.  New features in this release include VS 2008 and 2008 add-in, added “Do Not Dispose Rules”, bug fixes, and updated for WSS 3.0 / MOSS 2007 and SPF / SharePoint Server 2010. "

The great thing about this latest release is that it will even tell you when you are unneccesarily disposing your SharePoint objects.

I didn't have much luck with the Visual Studio Add-in in the latest version of SPDisposeCheck (it would never run a check). As an alternative, I suggest you implement this command as part of your After build in project properties for each of your projects:

"C:\Program Files (x86)\Microsoft\SharePoint Dispose Check\SPDisposeCheck.exe" "$(TargetPath)"


[Alternatively, you can copy the executable to a solution folder and use a relative path]. This commandline will fail the project (returning a non-zero value) if there are any problems - preventing a build from occurring unless the problem is fixed or you use the "SPDisposeCheckIgnoreAttribute" on your method. Unfortunately there are no binaries currently to reference so you can consume this attribute in your code. Instead, you can obtain the source code for the SPDisposeCheckIgnoreAttribute from the following directory once you've installed the SPDisposeCheck msi:

C:\Program Files (x86)\Microsoft\SharePoint Dispose Check\SPDisposeExamplesSource.zip\SPDisposeExamplesSource
DDK

Friday, 19 November 2010

SharePoint - How to get an SPUser Object based on a Person Field in a SharePoint List

I had a question today about how to determine the email address of the user who is mentioned in the "Responsible Field" of a SharePoint list. He was trying to develop an event receiver that would email a particular user if they were mentioned in that field. To this end, here is a tiny method I wrote to get an SPUser based on a Person field in a SharePoint list. The code has to first obtain a reference to the relevant SPField and then use the "GetFieldValue" method of the SPField to get the SPFieldUserValue. The SPFieldUserValue is really just an SPUser:

        /// 
        /// Gets the SP User object from a person field (e.g. the Modified By field) 
        /// so we can determine the email address or other details of that user.
        /// 
        /// e.g. the SPItem with the Person field obtained 
        /// from web.Lists[0].Items[0]         /// e.g. a person field e.g. "Modified By"
        public static SPUser GetSPUserFromPersonField(SPListItem listItem, string fieldName)
        {
            var personField = listItem.Fields[fieldName];
            return ((SPFieldUserValue)personField.GetFieldValue(listItem[fieldName].ToString())).User;
        }

DDK

Monday, 25 October 2010

Fix - "An error occurred during the processing of /_catalogs/masterpage/CompanyNameHomePage.aspx. Code blocks are not allowed in this file." - SharePoint 2007 Exception

Today I had an urgent call from the Support desk at my current client - and had to be pulled out of a meeting to help resurrect a corporate intranet. All pages in the corporate intranet were down and all were giving the same error:

"An error occurred during the processing of /_catalogs/masterpage/CompanyNameHomePage.aspx. Code blocks are not allowed in this file."


Turns out one of the support guys had checked out a page when viewing the master page library and checked it back in. There were no actual changes to the page code at all - but to try and fix the problem, they tried to restore from previous versions in the version history of the library. It made no difference.

When I saw the error, I recognized this immediately that something had been unghosted (ie was now serving the code from the content database and not the filesystem). The SharePoint page parser was now recognizing that there was inline script (as file-system served files are inherently trusted and content database files are inherently untrusted) - and it was failing.

The fix was to just reset the specific page to the site definition to effectively reghost it (so it was the same as the one deployed by the original feature). The steps are:
  1. Start Internet Explorer.
  2. Browse the SharePoint site to locate Site Actions.
  3. Click Site Actions, and then click Site Settings.
  4. On the Site Settings page, click Reset to site definition under the Look and Feel option.
  5. On the Reset Page to Site Definition Version page, type URL for the home page (in the 'Reset specific page to site definition version' textbox (e.g. /_catalogs/masterpage/CompanyNameHomePage.aspx , and then click Reset to reset the page to the site definiton version (and re-ghosting the page)


This resolved the issue immediately and I had a call just 10 seconds later thanking me for fixing it :o).


DDK

Tuesday, 10 August 2010

SharePoint 2007 - Finding Group Membership of Users (Active Directory or SharePoint) through UserProfileService.asmx

By using the SharePoint 2007 (and above) Out-Of-The-Box "User Profile" Web Service found at the following location:
http://ServerName/_vti_bin/UserProfileService.asmx

You can easily obtain information about the group membership (both Active Directory and SharePoint Groups) of a particular user - not just their basic user profile information (e.g. Mobile, Manager). This can be done with the GetCommonMemberships() method.

In this way, without code and without directly accessing Active Directory/LDAP, you can find the group memberships of a user for consumption in an InfoPath form by consuming it as a Web Service-based datasource.

For implementation details of a code-free InfoPath consumption of this web service, see: 
http://claytoncobb.wordpress.com/2009/07/19/infopath-user-roles-in-browser-enabled-forms-using-groups/

DDK

Wednesday, 28 July 2010

Using SharePoint 2007 and SharePoint 2010 with Encrypted Databases

With SQL 2008, a new facility is provided called "TDE" or "Transparent Data Encryption". This is sometimes required by clients whose corporate governance rules require files in a filesystem to be encrypted. What do you have to do to get this working with SharePoint 2007 or SharePoint 2010?

Nothing!

As the name of the feature suggests, you simply have to set it up on the SQL Server side (as per http://technet.microsoft.com/en-us/library/bb934049(SQL.100).aspx), and your underlying database files (and SharePoint Content) and any backups thereof will be encrypted without any extra effort on your part.



DDK

Monday, 21 June 2010

Error when Deploying Solutions in SharePoint using stsadm - "The farm is unavailable" and "Object reference not set to an instance of an object."

If you receive errors when Deploying Solutions in SharePoint using stsadm - such as "The farm is unavailable" and "Object reference not set to an instance of an object.", then you have a permissions issue.

You will typically get errors like this when running stsadm commands such as those found in this PowerShell script snippet below:
if ($isValidConfig -eq "true")
{
 Write-Host "Retracting Solution -  SERVER:$computer, SITE:$siteUrl" -Fore DarkGreen
 stsadm -o retractsolution -name SolutionName.wsp -immediate -url $siteUrl
 stsadm -o execadmsvcjobs
 Write-Host "Deleting Solution -  SERVER:$computer, SITE:$siteUrl" -Fore DarkGreen
 stsadm -o deletesolution -name SolutionName.wsp -override
 stsadm -o execadmsvcjobs
 Write-Host "Adding Solution -  SERVER:$computer, SITE:$siteUrl" -Fore DarkGreen
 stsadm -o addsolution -filename SolutionName.wsp 
 stsadm -o execadmsvcjobs
 Write-Host "Deploying Solution -  SERVER:$computer, SITE:$siteUrl" -Fore DarkGreen
 stsadm -o deploysolution -name SolutionName.wsp -url $siteUrl -immediate -allowgacdeployment -force
 stsadm -o execadmsvcjobs
 Write-Host "Activating Feature - SERVER:$computer, SITE:$siteUrl" -Fore DarkGreen
 stsadm -o activatefeature -name FeatureName -url $siteUrl -force
 stsadm -o execadmsvcjobs
 Write-Host "OPERATION COMPLETE - SERVER:$computer, SITE:$siteUrl" -Fore DarkGreen
 stsadm -o execadmsvcjobs
 Write-Host "Resetting IIS so we avoid 'Unknown Error' or 'File Not Found' errors - SERVER:$computer, SITE:$siteUrl" -Fore DarkGreen
 iisreset
 stsadm -o execadmsvcjobs
}

Errors that occur with the script if you don't have correct permissons on the SharePoint configuration database:



You should have dbo permissions to the Configuration database for your farm. See my related article for details on the permissions you need for solution deployment - http://ddkonline.blogspot.com/2010/03/list-of-permissions-required-for.html

DDK

Monday, 31 May 2010

Fix - SharePoint Very slow to start after an IISRESET or Recycle of App Pool (30-130 seconds)

I was asked by another team at my current client to look at a performance issue that they'd been having major issues with. There were no obvious errors in the Windows Event Log or SharePoint logs related to the issue. The problem was that:
  1. If the application pool is recycled, it would take around 90-120 seconds for the first page to be served. This would be unacceptable to the client in case the App pool was recycled in the middle of the day - it would mean 2 minutes of downtime for all employees.
  2. A similar issue with after an IIS reset was performed - it also happened with ALL sites, not just one or two.
To diagnose the issue, I did the following:
  1. ANY performance improvement should be measurable. So I used the Fiddler Web Debugger (http://www.fiddler2.com/fiddler2/)  to measure the total request time. Time was 84 seconds on this particular test server.
  2. Used Sysinternals Process Explorer to see what the threads were doing. This revealed little - but it was clear that the process wasn't 100% the whole time so it wasn't a problem related to intensive CPU processing.
  3. I enabled ASP.NET tracing at the application level as per http://msdn.microsoft.com/en-us/library/1y89ed7z(VS.71).aspx and viewed the trace log through http://servername/Pages/Trace.axd. However, looking at the load of the control tree - nothing was taking a particularly long time. Even when the trace.axd was loading up, it would take an inordinately long time to start up and server the first requested page. This ruled out the possibility of it being a slow control being rendered.
  4. I created a completely new web application in SharePoint and it exhibited the same problem. I began to suspect machine-level config settings.
  5. I found and fixed several errors in the Windows Event Log and Sharepoint Log but they made no difference.
  6. I began to look at the Fiddler trace while testing again and by chance noticed that requests were also being made to an external address at Microsoft for code signing certificates. I thought this was unusual - so did a bit of research and found that it was checking for a revoked certificates list on a Microsoft web server. This is done when any of the cryptography calls are performed. Some details about this can be found here - but the article is related to Exchange specifically:
    http://msexchangeteam.com/archive/2010/05/14/454877.aspx  
  7. To work around the issue, I tried the registry entries suggested by http://msexchangeteam.com/archive/2010/05/14/454877.aspx, but it didn't seem to work. What DID work was pointing the hosts file so that crl.microsoft.com would resolve to the local host (127.0.0.1).  This meant that the call would much more quickly fail when it tries to access the certificate revoke list at http://crl.microsoft.com/pki/crl/products/CSPCA.crl and http://crl.microsoft.com/pki/crl/products/CodeSignPCA2.crl, and not hold up the loading of Applications on the SharePoint server.
  8. After the HOSTs file change, recycle time (and reset time) went from 84 seconds to 20 seconds.
Hopefully this blog entry helps someone else with diagnosing this slowdown problem. Note that this fix only applies if your server doesn't have access to the internet - it is a problem specific to offline or intranet servers.

[UPDATE] - Found that someone else encountered this same issue as per
http://blogs.technet.com/b/markrussinovich/archive/2009/05/26/3244913.aspx and
http://www.muhimbi.com/blog/2009/04/new-approach-to-solve-sharepoints.html


The first article suggests the use of an XML file in each config - but I've not tested this out:

<?xml version="1.0" encoding="utf-8"?> 
<configuration> 
      <runtime> 
              <generatePublisherEvidence enabled="false"/> 
      </runtime> 
</configuration>

[UPDATE - 11 October 2010]
One of my colleagues from Oakton had a similar issue and the above fix (using the hosts file) didn't work for them.

One of the fixes that did work was to do the following:
"Disable the CRL check by modifying the registry for all user accounts that use STSADM and all service accounts used by SharePoint. Find yourself a group policy wizard or run the vbscript at the end of this posting to help you out. Alternatively you can manually modify the registry for each account:


[HKEY_USERS\\Software\Microsoft\Windows\CurrentVersion\WinTrust\Trust Providers\Software Publishing]
"State"=dword:00023e00 "

The following script applies the registry change to all users on a server. This will solve the spin-up time for the service accounts, interactive users and new users.


const HKEY_USERS = &H80000003
strComputer = "."
Set objReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" _
& strComputer & "\root\default:StdRegProv")
strKeyPath = ""
objReg.EnumKey HKEY_USERS, strKeyPath, arrSubKeys
strKeyPath = "\Software\Microsoft\Windows\CurrentVersion\WinTrust\Trust Providers\Software Publishing"
For Each subkey In arrSubKeys
  objReg.SetDWORDValue HKEY_USERS, subkey & strKeyPath, "State", 146944
Next



DDK

Tuesday, 25 May 2010

SharePoint Installation/Deployment Best Practice - Using SQL Server Aliases to avoid issues if the SQL Database Server is Renamed, a SQL Instance is added or the SQL Port is changed

One of the problems SharePoint 2007 is that the database name and server name is held in several tables within the configuration database. When you need to change the name of the database server from Central Administration, several references in the configuration tables need to change. There is the hard way and the easy way of doing this as below:
Changing SharePoint Database Server Name - the HARD/WRONG way
Here is the typical process to change the database Server that SharePoint is using:
  1. Move or attach all the sharepoint databases to the new server.
  2. Change the location of the config database with
    stsadm.exe -o setconfigdb -databaseserver ServerName -farmuser MyUserName – farmpassword MyPassword
  3. Delete the Central Administration Site in IIS
  4. Re-run the the SharePoint Products and Technologies Configuration Wizard.
  5. DONE
Changing SharePoint Database Server Name - the EASY/RIGHT way
The above process is a bit painful - and I never like deleting a core component of SharePoint like Central Admin. 
To greatly simplify migraton if you should need to change the port or the server name of your SharePoint database server, you should instead use SQL Server Aliases for your connection from SharePoint to SQL. To do this, go to a command prompt on all servers (as they all connect to the database) and enter the following to open the SQL Client Configuration Tool (note that it doesn't have an i between the n and the f):

cliconfg

Once this is open, you can add a TCP/IP alias as neccessary, which points to your physical Server name, port or instance. Use this alias name when entering the database server in SharePoint - and you wont' look back! The server name change process is then as follows:
  1. Move or attach all the sharepoint databases to the new server.
  2. Change the Alias
  3. DONE!
DDK

Friday, 21 May 2010

Fix for SharePoint 2007 Deployment Issue - Solutions in Permanent state of "Deploying", Application Server Administration Service Timer Job in permanent State of 'Initialized'

If you encounter the following issues when attempting to deploy a SharePoint solution (wsp):

  1. It is permanently/constantly in a status of "Deploying" (as seen in Central Administration - Operations - Solution Management)
  2. You cannot cancel the Deployment (no matter how many times you click on 'Cancel')
  3. The SharePoint Timer job definitions are permanently in a status of "Initialized" (as seen in Central Administration - Operations - Timer Job Status).
  4. Your SharePoint Log files are being flooded with the following 5uuf error and growing extremely large (one of ours got to 3GB!):

    05/21/2010 11:41:44.87 OWSTIMER.EXE (0x08E0) 0x08E8 Windows SharePoint Services Timer 5uuf Monitorable The previous instance of the timer job 'Config Refresh', id '{604B2E6E-5850-4C95-8015-D49A61449456}' for service '{681C12E2-4C2C-4BB5-9C9C-BCCF5B4FF5BE}' is still running, so the current instance will be skipped. Consider increasing the interval between jobs.
This is due to an invalid configuration cache on one or or all of the servers. What was happening in my situation was that:
  1. The SharePoint Configuration databasse went down.
  2. The XML configuration files on SERVER02 were updated by SharePoint but not on SERVER01
  3. In fact, there were 500 XML files on one server and 520 on the other whereas they should always be in sync.
However, is is not sufficient to JUST do it on the central admin server. You have to follow this blog entry (http://blogs.msdn.com/josrod/archive/2007/12/12/clear-the-sharepoint-configuration-cache-for-timer-job-and-psconfig-errors.aspx) or (http://support.microsoft.com/kb/939308)  and perform a similar process (as desribed above on each server.)

You must do the following:

  1. Stop the OWSTIMER service on the Index Server and then ALL of the MOSS servers in the farm (for me it was the 2 servers mentioned above e.g. SERVER01 and SERVER02. Just use the following at a command prompt to do this on EVERY WFE and INDEX SERVER
    net stop "Windows SharePoint Services Timer"
  2. [DO FOR ALL SERVERS BEFORE RESTARTING THE TIMER SERVICE]
    Go to C:\Documents and Settings\All Users\Application Data\Microsoft\SharePoint\Config\
    Move (not just copy) all the xml config files (don't delete the config file or the folder itself, just all the xml files) to another location (e.g. a "zz" folder") in a temporary directory as a backup.
  3. [DO FOR ALL SERVERS BEFORE RESTARTING THE TIMER SERVICE]
    Open the cache.ini with Notepad and reset the number to 1. Save and close the file.
  4. Once all XML files are removed and the cache.ini files reset to 1 for ALL SERVERS, run
    net stop "Windows SharePoint Services Timer"on the Index Server first.
  5. Once all the Xml files are generated, run
    net stop "Windows SharePoint Services Timer" on Query Servers and Web Front End Servers in turn.
DDK


Additional Blog Note - how to remove unwanted solutions that are stuck in a "Deploying"State (without fixing the underlying Config problems as detailed above)

  1. Reboot Server (in line with my "If in doubt, restart it!" motto). This in effect will restart all the services anyway.
  2. Use the following command to get a list of all solutions that are being deployed.
    stsadm -o enumdeployments
  3. Use the JobId GUID that comes back from this e.g. Deployment JobId="e99b7304-cfc0-419a-a3f2-18ca5193c838"
  4. Cancel the "stuck" deployment (in "Deploying" status" with the following command
    stsadm -o canceldeployment -id e99b7304-cfc0-419a-a3f2-18ca5193c838
  5. Delete the stuck solution once and for all with
    stsdm -o deletesolution -name mysolution.wsp -override
  6. Redeploy your solution.

Thursday, 18 March 2010

List of Permissions Required for Deployment and Activation of Solutions/Features on a SharePoint Site

Today I had some issues today with deployment of SharePoint Solutions/Features to one of the development servers. I knew you need both database and site permissions - but wasn't clear on exactly what databases I needed permissions to. Here are the permissions that you need to deploy a solution/feature to SharePoint:
  1. Farm Administrator (add this through Central Admin)
  2. Site Collection Administrator (Done through the Individual Site Collection itself)
  3. db_owner and db_securityadmin permissions on the Central Admin Content database (note that this is normally generated with a Guid in the name e.g. SharePoint_AdminContent_XXXX-XXX-XXX-XXXX.
  4. db_owner permissions on the Content database for your site e.g. DEV_MachineName_WSS_Content_Portal_5000_0
  5. Local admin rights on the server itself.

Wednesday, 3 February 2010

SharePoint 2007 - "The trial period for this product has expired." Error message when Editing Page Content or viewing InfoPath Forms

If you get exception when Editing SharePoint objects or opening up Infopath Forms like the one shown below:

The trial period for this product has expired.


It was not caused by the other 101 things detailed on the web that can also cause the issue (e.g. Antivirus, Permissions problems with DCOM - such as detailed here http://msmvps.com/blogs/shane/archive/2008/02/05/the-trial-period-for-this-product-has-expired.aspx).

I'm so used to spurious and misleading errors in SharePoint that the most obvious answer was the last I considered - it may be that the original installer didn't enter an Enterprise Product key during the install process (unbeknownst to you). Before you go trying all the other options, you should check your current license status by going to:

Central Administration -> Operations -> Convert License Type

This will tell you your current license status and allow you to enter your relevant license key (Enterprise or Standard).


In addition to what is mentioned here(http://technet.microsoft.com/en-us/library/cc263204.aspx), you also have to do an iisreset to get the error to disappear.

DDK

Wednesday, 20 January 2010

Problem and Fix: Microsoft.SharePoint.WebControls.SPDatePickerControl doesn't render Dates based on Regional Settings

I had a problem today that a SharePoint Application Page (ie an ASP.NET page hosted in the SharePoint _layouts directory under the 12 hive) I use wasn’t rendering the SharePoint Date Time Control date format according to SharePoint regional settings.  No matter what setting I tried, it would not change the format that was rendered - instead it was using the default US date format. This is disconcerting for users because all the other pages in the site render the dates correctly. Even the InfoPath forms hosted via Forms Services (which make use of the Application pages as lookup forms) render the date format as per Australian regional settings.

 Some of the things I tried to resolve/check the issue:

  1. Regional Settings under Site Settings -> Regional Settings did not make any difference.

  2. Checked Internet Explorer 7.0 browser settings in Tools->Options->Language – which is already English [AU]

  3. I tried to override the InitializeCulture() handler and set the Thread.Culture (ie date format etc) and UICulture (which resource files that ASP.NET uses) – but it made no difference.

    /// 
            /// Force application page to render in Australian format as SP Date Control
            /// support standard SharePoint regional Settings
            /// 
            protected override void InitializeCulture()
            {
                Thread.CurrentThread.CurrentCulture =
                    CultureInfo.CreateSpecificCulture("en-AU");
    
                Thread.CurrentThread.CurrentUICulture = new
                            CultureInfo("en-AU");
                base.InitializeCulture();
            }
    


However none of the solutions above did a thing. By luck I noticed through debugging that there is a property called “LocaleId” on the Microsoft.SharePoint.WebControls.SPDatePickerControl ( as per http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.webcontrols.spdatepickercontrol.aspx). When I set this to the LocaleId=3081 (for English(Australian)), then the SharePoint Date control renders the date format correctly (ie in dd/MM/yyyy format for Australian users rather than the default US date format of MM/dd/yyyy).

This LocaleId could also be set programatically based on a config file if you don't want to hardcode the locale into your SharePoint Application Page.


Monday, 18 January 2010

How to Create Subfolders within Subfolders in SharePoint 2007 via the Lists.asmx Web Service

I did an entry on the deletion of folders via the Lists.asmx web service back in July 2008 which can be found here (http://ddkonline.blogspot.com/2008/07/deleting-folders-in-moss-via-web.html) - but I failed to include how to create folders using the same UpdateListItems() mechanism.

A sample of creating a folder and subfolders within SharePoint 2007 lists can be found below:

/// <summary>
        /// As checked in U2U CAML query builder, this is valid in 
        /// <Batch PreCalc='TRUE' OnError='Continue' RootFolder='/Purchase Order Forms V2'>
        ///<Method ID='1' Cmd='New'><Field Name='ID'>New</Field><Field Name='FSObjType'>1</Field><Field Name='BaseName'>DDkTest2</Field></Method></Batch>
        /// THIS Works for Subfolders
        /// <Batch PreCalc='TRUE' OnError='Continue' RootFolder='/Purchase Order Forms V2/2010_01_January'>
        /// <Method ID='1' Cmd='New'><Field Name='ID'>New</Field><Field Name='FSObjType'>1</Field><Field Name='BaseName'>DDkTest2</Field></Method></Batch>
        /// </summary>
        private void CreateFolder(string listName, string rootSubFolderName, string newFolderName)
        {
            ListsSoapClient client = new ListsSoapClient(); //TODO: Change to use WCF Client Factory

            //Correct invalid characters
            newFolderName = newFolderName.Replace(":", "_");
            string rootFolder = rootSubFolderName.Length > 0 ? string.Format("/{0}/{1}", listName, rootSubFolderName) : listName;
            string xmlCommand = string.Format("<Method ID='1' Cmd='New'><Field Name='ID'>New</Field><Field Name='FSObjType'>1</Field><Field Name='BaseName'>{1}</Field></Method>", rootFolder, newFolderName);
            client.ClientCredentials.UserName.UserName = ConfigHelper.SharePointServiceUserName;
            client.ClientCredentials.UserName.Password = ConfigHelper.SharePointServicePassword;
            XmlDocument doc = new XmlDocument();
            System.Xml.XmlElement batchNode = doc.CreateElement("Batch");
            batchNode.SetAttribute("OnError", "Continue");
            //Insert / to front as it is required by web service.
            if  (!rootFolder.StartsWith("/"))
                rootFolder = string.Format("/{0}",rootFolder);

            batchNode.SetAttribute("RootFolder", rootFolder);
            batchNode.InnerXml = xmlCommand;
            XmlNode resultNode = client.UpdateListItems(listName, batchNode;
        }

Friday, 15 January 2010

Dynamically Modifying the Submit Location of InfoPath Forms using SharePoint Forms Services using Code Behind

It is a well known fact (e.g. http://blogs.msdn.com/sharepoint/archive/2007/07/25/scaling-large-lists.aspx) that SharePoint performance can decline significantly when there are more than 2000 items in a SharePoint "container"  (e.g. the root folder of a Document Library). To avoid this, you can store your documents in separate lists or you can store them in separate subfolders within your list.

On issue is that InfoPath 2007 doesn't support dynamic saving to subfolders out of the box (it only supports dynamic file names). You need to perform a code-based workaround to get it happening. In the code sample below, I dynamically submit to a folder location (ie a subfolder within a Document Library or List) based on the current date. All form submissions in this way are grouped by Year and Month (the client is not likely to have more than 2000 forms submitted in one month).

public void submitButton_Clicked(object sender, ClickedEventArgs e)
        {
            ////Need to submit the form to a programatically determined subfolder location (based on the date)
            //Folder format is 2010_01_January (YYYY_MM_MMMMM)
            FileSubmitConnection submitConnection = (FileSubmitConnection)DataConnections["SharePoint Library Submit"];
            submitConnection.FolderUrl = string.Format("{0}/{1}_{2}_{3}",submitConnection.FolderUrl ,
                DateTime.Today.Year, DateTime.Today.Month.ToString("00"), 
                System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat.GetMonthName(DateTime.Today.Month)); 
            submitConnection.Execute();
            ////TODO: Need to create folder with SP Object Model to hold attachments as well before saving them there.
        }

Thursday, 17 December 2009

CX_ST_MATCH_ELEMENT:XSLT exception.System expected element 'MyTableName' SOAP Fault when calling a SAP BAPI remotely via Web Service

If you receive the following error when calling a BAPI in SAP (e.g. from a .NET WCF client or using SOAPUI):

CX_ST_MATCH_ELEMENT:XSLT exception.System expected element 'MyTableName'

Then you have not initialized your variables correctly. In SOAPUI (http://www.soapui.org/), you cannot remove the elements even though instances are marked as "Zero or many". Instead, you have to pad it with empty elements. You cannot have zero elements in the table (even though the XSD seemingly permits it) otherwise the SAP Web service will spit the dummy.





By the same token, you must initialize all your arrays/lists in .NET:
e.g.

try
{
CostObjectSearchService.Z_Bapi_Cost_Object_FindClient client = new CostObjectSearchService.Z_Bapi_Cost_Object_FindClient();
CostObjectSearchService.ZBapiCostObjectFind request = new CostObjectSearchService.ZBapiCostObjectFind();

request.ICompanyCode = "2000";
request.ISpendType = "P";
request.ICostObject = costObjectMatchString;

//Return Object initialization (for Asset, Cost Centre or Work Breakdown Structure (WBS)
// - otherwise returns error from SAP Web Service
// XSLT CX_ST_MATCH_ELEMENT:XSLT exception.System expected element 'MyTableName'
request.TTypeAAsset = new CostObjectSearchService.Zfanla[0];
request.TTypeOkhCostCentre = new CostObjectSearchService.Zfcsks[0];
request.TTypePWbs = new CostObjectSearchService.Zfprps[0];
CostObjectSearchService.ZBapiCostObjectFindResponse response = client.ZBapiCostObjectFind(request);

Thursday, 10 December 2009

InfoPath 2007 - Conditional values in InfoPath using XPath

I had a question today regarding Infopath and making conditional statements in Xpath:

Question

Hi Guys,
I was wondering if any of you have tried doing an if then else using xpath.
What I am trying to do is use a formula on an infopath form control.
This is what I want
If(field1 = “x”)
Then “1”
Else “2”
Ive had a look at some forums and you can do this with xpath2.0 but im using infopath2007 which I think uses xpath1.0
The work around seems to be something like this which I cant seem to get working either.
Concat(substring("1", 1, field1=”x” * string-length("1")), substring("2", 1, not(field1=”x”) * string-length("2")))
Any ideas would be great.
thanks


Answer

There are 2 options for this:
  1. You can use Conditional Statements within Rules e.g. on a text box to set the value conditionally in another field (much simpler than Xpath workarounds)
  2. You can use Xpath to give conditional results (effectively an "if" or "iif"). To implement the example in the question above, you could put this into an expression box (make sure "Xpath(Advanced)" is checked on):

    concat(substring("1", 1, (my:FieldA = "x") * string-length("1")), substring("2", 1, (not(my:FieldA = "x")) * string-length("2")))

The problem with the Xpath in the original question was that the parentheses were not in the correct positions. For more info on option 2, you can see http://blogs.msdn.com/infopath/archive/2006/11/27/conditional-default-values.aspx

Thursday, 26 November 2009

Exposing the SAP Netweaver CE 7.1 BPM Universal Worklist (UWL) through an iView and the Object Tag Viewer Web Part in SharePoint 2007

SAP iViews are one of many mechanisms by which you can surface SAP content into a SharePoint site. This post describes how you can show the SAP Universal Worklist (UWL) in SharePoint through a custom web part called the Object Tag Page Viewer.

As desribed in an MS white paper ( http://download.microsoft.com/download/B/F/2/BF2C3AAD-BC64-496C-B3BC-72ADD9617E2C/iView%20Integration%20with%20Microsoft%20Office%20SharePoint%20Server.pdf):

"There are scenarios where an end user would require logging in to SAP GUI or SAP Portal to perform some of their commonly performed operations. It would be convenient if these operations were performed from a portal like Microsoft Office SharePoint Server Portal (MOSS) which an end user might be using more frequently. In such scenarios the best point of integration is to display SAP iViews or Web Dynpro iViews in MOSS. MOSS out of the box provides two web parts that can be used for displaying pages from portals/web sites outside MOSS. These are Page Viewer Web Part and iView Web Part. When configuring SAP iView or Web Dynpro iViews, these web parts can go in to an infinite refresh loop with some iViews. In order to overcome this issue, there is a need to develop a custom web part that would display the SAP iView. The Object Tag Page Viewer Web Part is an approach that allows MOSS portals to display these iViews. "

While the document above covers the creation of the custom web part, there are a few issues with it:

  • a) It doesn't cover how you set up or consume something like the SAP UWL (The UWL is basically the same thing as the Task list in SharePoint)
  • b) The code in the whitepaper is not complete.

The Object Tag Page Viewer Web Part (Code)

using System;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Serialization;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.ComponentModel;

namespace Microsoft
{
///
/// Created as per pdf Document "SAP iView Integration with Microsoft Office SharePoint 2007"
///

[Guid("a9c26185-1970-4f29-b45c-edad343938c1")]
public class ObjectTagPageViewer : System.Web.UI.WebControls.WebParts.WebPart
{
const int heightWidth = 150;

#region Properties
/// /// The URL to display in the Object Tag ///
private string pageUrl = "http://";

[Personalizable(), WebBrowsable(true), Browsable(true), Category("Custom Property"), DefaultValue("http://"), WebPartStorage(Storage.Personal),
FriendlyName("Page Url"), Description("Default page URL such as http://www.live.com")]
public string PageUrl { get { return pageUrl; } set { pageUrl = value; } }

#endregion

///
///
///

///
protected override void OnPreRender(EventArgs e)
{
if (base.Height.IsEmpty)
{
base.Height = heightWidth;
}
base.OnPreRender(e);
}

protected override void Render(HtmlTextWriter output)
{
if (String.Compare(pageUrl, "http://") == 0 String.IsNullOrEmpty(pageUrl))
{
output.WriteBreak();
output.WriteLine(@"To link to content, <a id="'ObjectTagPageViewer_" href="javascript:MSOTlPn_ShowToolPane2Wrapper("> output.WriteBreak();
}
else
{
if (Uri.IsWellFormedUriString(pageUrl, UriKind.Absolute))
{
string objectTagID = "outputObject_" + base.UniqueID;
output.AddAttribute(HtmlTextWriterAttribute.Id, objectTagID, false);
output.AddAttribute(HtmlTextWriterAttribute.Name, objectTagID, false);
output.AddAttribute(HtmlTextWriterAttribute.Width, "100%", false);
output.AddAttribute(HtmlTextWriterAttribute.Height, "100%", false);
output.AddAttribute(HtmlTextWriterAttribute.Type, "text/html", false);
output.AddAttribute("data", pageUrl, false);
output.RenderBeginTag(HtmlTextWriterTag.Object);
output.RenderEndTag();
}
else
{
output.WriteBreak();
output.WriteLine("Please enter a valid Absolute Page Url ");
output.WriteBreak();

}

}
}

public ObjectTagPageViewer()
{
}

}
}

Setup of iView Web Part to show the SAP UWL

  1. Go to http://insert_ce_server_name_here/irj/portal and log in.
  2. Go to Content Administration -> Portal Content -> Content Provided by SAP -> End User Content -> Standard Portal Users -> iViews -> com.sap.netweaver.bc.uwl.iviews -> Universal Worklist
  3. Right Click - > Preview
  4. Use the url that shows in the new preview window and put it into an Object Tag Page Viewer Web Part that you’ve added to a SharePoint Web Part page (as per the Microsoft Whitepaper)
  5. Et voila! SAP UWL now shows in SharePoint. Clicking on tasks opens them up into another window - from where the user can action the task.
  6. Tasks now open up in a new window for actioning:

Thursday, 19 November 2009

Deploying SharePoint 2007 Custom Content Types using Inheritance with a SharePoint Feature

I had the following question sent to me this morning regarding the creation of custom content types:

"I need to create custom content types in MOSS 2007 and want to know the best way to do it. I want to achive the inheritance such as: My Core Content Type --- > Generic Content Type -- > News Content Type"

You will find that Microsoft themselves use a feature as the mechanism to deploy all of the out of the box (OOB) content types. You can see this file at:
"C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\FEATURES\ctypes\ctypeswss.xml".

In fact, the feature.xml file that Microsoft uses is in the same directory. This uses a standard schema, which can be found on MSDN here http://msdn.microsoft.com/en-us/library/ms463449.aspx

Which brings me to the content type inheritance part of the question.

The critical part to understand when creating the feature is that inheritance in content types is defined by the Ctype ID. If you go to the Content Type Gallery (for your site/site collection) and create a new content type, you can see this ctype in the URL when you hover over the name of your new content type in the gallery list. For example, when I click on the content type I just created, the link was to this location:
http://servername/_layouts/ManageContentType.aspx?ctype=0x0100E00AAE6F9A33274BBC67EACB89D61FFA&Source=%2F%5Flayouts%2Fmngctype%2Easpx

When I create a new content type that inherits from the other content type, then I just append a 01 to it and it inherits from the parent type. i.e. the Content Type Id is
ctype=0x0100E00AAE6F9A33274BBC67EACB89D61FFA01
A "grandchild" of the parent type would be
ctype=0x0100E00AAE6F9A33274BBC67EACB89D61FFA0101
and so on.



In summary, to answer the question:

  1. Create a feature to deploy your content types (using WSPBuilder or your preferred tool).
  2. In the elements file, specify your content type id (ctype) and fields which should be displayed.
  3. Give the wsp file to SharePoint administrators to Deploy the file.
  4. Done!
Additional Notes/References
  1. Another option which allows more control and full programmatic flexibility would be to create a feature receiver which then allows you to run code against the SharePoint object model to perform additional checks in the OnFeatureActivated/OnFeatureInstalled event
  2. As a best practice, Content types should not be modified by a feature once they have been installed - as manual changes to the content type may be overwritten.
  3. One of the most illuminating articles on this topic can be found here:
    http://blogs.msdn.com/eigilm/archive/2007/09/04/inherit-content-types.aspx

Thursday, 12 November 2009

WCF Fix-The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'NTLM'.

I thought I'd done a post on this error previously, but I double checked google and I obviously hadn't.

The Problem
When calling WSS / SharePoint web services (such as Lists.asmx) via WCF, you will normally get this error if you leave the settings as configured by the “Add Service Reference Wizard” :

“The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'NTLM'.”

The Solution

You must specify a non-anonymous impersonation level for your ClientCredentials. Just specifying a username and password for your WCF Service reference's ClientCredentials.UserName.UserName and ClientCredentials.UserName.Password is not sufficient to resolve the problem.

In particular (When SharePoint server is on different domain):

ServiceReference1.ListsSoapClient client = new ServiceReference1.ListsSoapClient();
client.ClientCredentials.Windows.ClientCredential = new System.Net.NetworkCredential("username", "password", "domain");
client.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Identification;
client.GetListCollection();


Of course, when on same domain, don’t have to pass in the Windows.ClientCredential information. You can also set the above values in app.config configuration elements rather than code, but I won't cover that here.

You can use (with descending levels of security):
System.Security.Principal.TokenImpersonationLevel.Identification
System.Security.Principal.TokenImpersonationLevel.Impersonation
System.Security.Principal.TokenImpersonationLevel.Delegation

Details on these impersonation levels can be found at: http://msdn.microsoft.com/en-us/library/system.security.principal.tokenimpersonationlevel.aspx

Config Changes


<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ListsSoap">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
<client>
<endpoint address="http://servername/_vti_bin/Lists.asmx"
binding="basicHttpBinding" bindingConfiguration="ListsSoap"
contract="ServiceReference1.ListsSoap" name="ListsSoap1" />
</client>
</system.serviceModel>
</configuration>

Friday, 30 October 2009

SharePoint 2007 vs SAP DMS vs SAP KM vs OpenText for Document Management

Differences between SAP DMS and SharePoint 2007


With SharePoint 2007 having such an incredible level of growth and popularity in the CMS, Portals and Collaboration space, questions arise as to whether the document management system (DMS) that comes with SAP should be used at all if both co-exist in the same enterprise environment. Here are some of the advantages as I see them when comparing the 2 systems:

SharePoint 2007 Advantages
  1. Familiarity to MS Office users and reduced training
  2. MS Office Integration e.g. Check in, check out and update document metadata from within Word/Excel/etc itself - without Install of SAP Easy DMS
  3. Offline capabilities i.e. checkout to "SharePoint Drafts" folder so you can work from home without a connection - without SAP Easy DMS
  4. Licensing - Licensing models are different - no SAP licenses required - esp if most users are not using SAP.

SAP DMS Advantages

  1. No Additional Licenses required if all users are using SAP
  2. Direct link of document to Business Entities directly without specifying additional metadata (e.g. supporting documentation for invoice) - this is sometimes a more natural linkage.

As desribed in this Cap Gemini blog on the subject - "Will we get to the point where companies just have their SAP system as a backend database and have SharePoint vNext (SharePoint 2014) as the integration platform? "
(From http://www.capgemini.com/technology-blog/2009/02/will_sharepoint_14_become_sap.php)

[UPDATE 2nd November 2009 - 1]
It has been pointed out to me that a comparison between SAP KM and SharePoint 2007 would be a more relevant comparison.

SAP KM Advantages

  1. Doesn't have requirement for client (like SAP Document Management System (DMS) does)
  2. Can preview CAD and other documents within the Web UI directly, unlike SharePoint
  3. Closer integration with SAP Business Data versus SharePoint

[UPDATE 2nd November 2009 - 2]
SAP Document Management offering with OpenText

One of my Oakton colleagues brought this to my attention - SAP now has a partnership deal with OpenText.

"The last option (out of SharePoint/DMS & KM/OpenText) is really powerful but comes at a price as OpenText is a leader in Document Management and integrates into SharePoint seamlessly. For large organisation with strong records management requirements with industrial class DM requirements option 3 would be a good choice, hoping that OpenText has done all the heavy lifting in terms of SAP Integration."