29 czerwca 2011

Test-SPContentDatabase and how to locate MissingWebPart

MissingWebPart error


During preparation phase for SharePoint 2010 upgrade from WSS/MOSS 2007, often Test-SPContentDatabase command is being executed against existing SharePoint 2007 content databases.

Test-SPContentDatabase -Name ContenDatabaseName -WebApp WebApplicationUrl > TestPreUpgradeLog.txt

One of the error types (not blocking the upgrade though) that could be found in Test-SPContentDatabase execution log (TestPreUpgradeLog.txt in the sample above) is called MissingWebPart. Error description from the pre-upgrade log is shown below:

Category        : MissingWebPart
Error           : True
UpgradeBlocking : False
Message         : WebPart class [WebPartTypeId here] is referenced [x] times in the database [ContentDatabase name here], but is not installed on the current farm. Please install any feature/solution which contains this web part. Remedy : One or more web parts are referenced in the database [ContentDatabase name here], but are not installed on the current farm. Please install any feature or solution which contains these web parts.

WebPartTypeId cannot be reverse-engineered


If there is a large number of site collections in the content database that could contain MissingWebPart references, it's not easy to locate pages that are hosting webpart instance with WebPartTypeId provided in the pre-upgrade log. The reason for MissingWebPart is missing assembly in the GAC that defines the webpart type or missing SafeControl entry in  theWeb.config for particular webpart.

WebPartTypeId is calculated from the full qualified assembly name and the full webpart type name. On codeplex.com there is a tool called  easywebparttypeidgen that can calculate WebPartTypeId.

SPLimitedWebPartManager and ErrorWebPart on and off relationship

ErrorWebPart in WebParts collection 


There are times when we would like to manipulate (add/remove) or iterate over (export/import) WebParts collection associated with the SharePoint page. The task in itself is quite easy, as SharePoint API provides SPLimitedWebPartManager class. However in the console application scenario, when accessing WebParts property, all or some webpart instances can be returned as ErrorWebPart's. This behaviour can be caused by several factors, the ones I was able to discover were:

  1. Invalid SafeControl entries in Web.config (missing Assemblies) 
  2. WebParts on the page referencing assemblies that are not deployed on the farm
First step in troubleshooting this kind of problem will be checking the EvetLog and looking for the following errors:

Error: Failure in loading assembly: [AssemblyNameHere], Version=1.1.0.0, 
Culture=neutral, PublicKeyToken=[PublicKeyTokenHere]

See source code below that could be triggering  error messages  entries in the EventLog.

using (SPSite site = new SPSite(...))
{
  using (SPWeb web = site.OpenWeb(...))
  {
     using (SPLimitedWebPartManager limitedWebPartManager = web.GetLimitedWebPartManager(pageUrl, PersonalizationScope.Shared))
     {
        foreach (WebPart webPart in limitedWebPartManager.WebParts)
        {
            Type webPartType = spWebPart.GetType();
        }
     }
  }

}

The easiest way to resolve the problem, will be adding missing assembly to the GAC. And, if required add SafeControl entry in Web.config to register it correctly.

22 czerwca 2011

SharePoint 2010 upgrade failed - Feature upgrade failed for Feature

Test-SPContentDatabase went fine


Upgrading content database from MOSS/WSS 2007 to SharePoint 2010 is a challanging task in itself. It gets even tricker when overtime number of customizations has been deployed (custom features, event receivers etc) to SharePoint 2007 installation. Microsoft has provided really helpfull Powershell command Test-SPContentDatabase that performs analysis of SharePoint 2007 content database against configured SharePoint 2010 installation. If there are any references to custom components in content database that are not installed on the SharePoint 2010 farm warning and errors will appear in the log.

It was Mount-SPContentDatabase that failed


On the other side Test-SPContentDatabase command cannot discover all inconsistencies that may exist in the content database and may fail the upgrade. After resolving all the problems uncovered by the Test-SPContentDatabase, I run Mount-SPContentDatabase to attach SharePoint 2007 content database.

Mount-SPContentDatabase -Name [ContentDBName] -DatabaseServer [SqlInstance] -WebApplication [WebAppUrl] 

I wasn't expecting flawless upgrade during attach process, but I was really suprised when I finished with 56 errors. All errors where listed in the upgrade log and one of them was Feature upgrade failed.

[powershell] [SPSiteWssSequence2] [INFO] [6/17/2011 9:41:22 AM]: SPSite Url='http://sitecollectionadress here
[powershell] [SPSiteWssSequence2] [ERROR] [6/17/2011 9:41:22 AM]: Feature upgrade failed for Feature 'Mulawa.FailedFeature1' (Id: 'FeatureId here') in Web 'http://sitecollectionadress here'.
[powershell] [SPSiteWssSequence2] [INFO] [6/17/2011 9:41:22 AM]: SPSite Url=http://sitecollectionadress here
[powershell] [SPSiteWssSequence2] [ERROR] [6/17/2011 9:41:22 AM]: Exception: Object reference not set to an instance of an object.
[powershell] [SPSiteWssSequence2] [INFO] [6/17/2011 9:41:22 AM]: SPSite Url=http://sitecollectionadress here
[powershell] [SPSiteWssSequence2] [ERROR] [6/17/2011 9:41:22 AM]:    at Microsoft.SharePoint.SPFeature.HandleUpgradeException(Exception e, Boolean continueUpgrade, Boolean markAsUpgraded, Boolean force)
   at Microsoft.SharePoint.Administration.SPFeatureDefinition.Upgrade(SPFeature feature, SPWebService webService, SPWebApplication webApp, SPSite site, SPWeb web, Boolean fForce)
   at Microsoft.SharePoint.SPFeature.Upgrade(SPSite site, SPWeb web, Boolean fForce)
   at Microsoft.SharePoint.Upgrade.SPSiteWssSequence2.DoUpgrade()


Feature upgrade failed  error caused the whole upgrade to be marked as failed, which made me somehow unhappy. As the error message didn't ring the bell, actually I didn't know where to start. So, I looked into SharePoint log, it was Verify upgrade and review upgraded sites (SharePoint Foundation 2010) article that encouraged me to check if there are any hints hidden there (dump from SharePoint 2010 log).

PowerShell.exe (0x21DC)  0x0860 SharePoint Foundation          Feature Infrastructure         9fnu High     Feature Upgrade: Exception thrown updating content database with new version number for Feature 'Mulawa.FailedFeature1' (Id: 'FeatureId here') in Web 'http://sitecollectionadress here': Object reference not set to an instance of an object. 
PowerShell.exe (0x21DC)  0x0860 SharePoint Foundation          Feature Infrastructure         g0gz High     Feature Upgrade: Error exception thrown upgrading Feature 'Mulawa.FailedFeature1' (Id: 'FeatureId here') in Web 'http://sitecollectionadress here': System.NullReferenceException: Object reference not set to an instance of an object.     at Microsoft.SharePoint.SPFeature.UpdateFeatureVersion(Boolean fForce)     at Microsoft.SharePoint.Administration.SPFeatureDefinition.UpgradeCore(SPFeature feature, SPWebApplication webApp, SPSite site, SPWeb web, Boolean fForce)     at Microsoft.SharePoint.Administration.SPFeatureDefinition.Upgrade(SPFeature feature, SPWebService webService, SPWebApplication webApp, SPSite site, SPWeb web, Boolean fForce) 
...........................
Microsoft.SharePoint.Upgrade.SPUpgradeSession.Upgrade(Object o, Boolean bRecurse)     at Microsoft.SharePoint.Upgrade.SPUpgradeSession.ReflexiveUpgrade(Object o, Boolean bRecurse)     at Microsoft.SharePoint.Upgrade.SPUpgradeSession.Upgrade(Object o, Boolean bRecurse... 
PowerShell.exe (0x21DC)  0x0860 SharePoint Foundation          Topology                       8xqz Medium   ...)     at Object state)     at System.Threading.ThreadHelper.ThreadStart()   ff2e5232-6422-4b57-bab9-588bb64e4cc6


17 czerwca 2011

SQL Server Replication Explorer 0.1 - debiut

Jak przeglądać topologię replikacji - czyli Replication Explorer w akcji?


W wolnym czasie popełniłem aplikację o nazwie SQL Server Replication Explorer, która umożliwia przeglądanie komponentów składowych replikacji (oczywiście na platformie Microsoft SQL Server). W wersji 0.1 Replication Explorer (RE) umożliwia przeglądanie informacji o następujących elementach architektury replikacji:

  • Dystrybutor 
  • Baza dystrybucyjna
  • Serwer publikacji
  • Publikacja
  • Subskrybent 

RE jest też pewną alternatywą dla uruchamiania kilku procedur składowanych oraz zapytań na bazie dystrybucyjnej. Do uruchomienia RE potrzebny jest tylko zainstalowany .NET Framework 3.5 SP1.



Więcej informacji o aplikacji (np. kod zródłowy) można znaleźć na stronie projektu http://replicationexplorer.codeplex.com/.

16 czerwca 2011

Jak określić wersję instacji SQL Servera z poziomu aplikacji?

Wersja instancji SQL Servera


Ostatnio musiałem zaimplementować w Replication Explorer ograniczenie z jakimi wersjami SQL Server będzie mógł współpracować. Informacja o wersji instancji SQL Servera do której się łączymy znajduje się we właściwości ServerVersion obiektu SqlConnection. ServerVersion jest zwracana w następującym formacie major.minor.build (##.##.####), gdzie liczba cyfr dla major i build może być różna w zależności od wersji.

Pełną listę znaczących wersji Micrsoft SQL Server dla wersji 2000, 2005, 2008, 2008 R2 można znaleźć tutaj.

Oczywiście dokładne informacje o wersji instancji SQL Server przy pomocy T-SQL można uzyskać przy użyciu funkcji @@VERSION.

SELECT @@VERSION

Aczkolwiek, jeżeli chcemy dokonać tego z poziomu aplikacji możemy użyć  SqlConnection. ServerVersion.

Parsowanie SqlConnection.ServerVersion

Do pobrania trzech składowych wersji użyłem wyrażenia regularnego. Definiując wyrażenie (dostępne poniżej) użyłem grup do wyciągnięcia trzech elementów wersji.

(?<majorversion>\d{1,2})\.(?<minorversion>\d{1,2})\.(?<buildnumber>\d{1,4})

Do testowania i projektowania wyrażeń regularnych polecam edytor Expresso , pomaga on okiełznać trochę niekiedy skomplikowaną składnię RegEx'ów. Poniżej jest dostępna klasa pobierająca wartość pola SqlConnection.ServerVersion w konstruktorze i udostępniająca Major, Minor i Build Number jako swoje właściwości.

01 czerwca 2011

MARSianie atakują SqlDataReader

Otwarty SqlDataReader


Może się zdarzyć, że kolejność przetwarzania danych będzie wymagała wywoływania różnych procedur/zapytań naprzemiennie.

Załóżmy, że chcemy wyciągnąć listę tabel systemowych z bazy master z tabeli sys.objects. Dla każdej tabeli chcemy pobrać oddzielnym zapytaniem nazwę pierwszej kolumny dla danej tabeli. Oczywiście przykład jest tylko hipotetyczny, gdyż tę informację można wybrać jednym zapytaniem z prostym JOIN'em.

using(var connection = new SqlConnection(
    "Data Source=.;Initial Catalog=master;Integrated Security=true;"))
{
    connection.Open();
    var sysObjectsCmd = new SqlCommand(
        "SELECT object_id, name FROM sys.objects WHERE type = 'S'", 
        connection);
    using(SqlDataReader userTableReader = sysObjectsCmd.ExecuteReader())
    {
        while (userTableReader.Read())
        {
            string select = @"SELECT name 
                FROM sys.columns WHERE Object_id = @objectId";
            var nestedCmd = new SqlCommand(select, connection);
            nestedCmd.Parameters.AddWithValue("objectId", 
                userTableReader["object_id"]);

            object firstColumName = nestedCmd.ExecuteScalar();
            Console.ForegroundColor = ConsoleColor.White;
            var table = string.Format("Tabel {0}",userTableReader["name"]);
            Console.WriteLine(table);
            Console.ForegroundColor = ConsoleColor.Green;
            var column = string.Format("First table column {0}", firstColumName);
            Console.WriteLine(column);
        }
    }
}


Przy wykonaniu tego kodu otrzymamy następujący wyjątek:

System.InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.

WPF i pewna czwórka (Grid, DockPanel, TreeView i GridSplitter)

Daily WPF


Rozpoczynając pracę nad moją pierwszą Non-HelloWorld aplikacją w WPF zderzyłem się z prostym problemem. Chciałem uzyskać następujący layout:
  • Po lewej drzewko (TreeView) wypełnia całą wolną przestrzeń
  • Po prawej jakiś panel (StackPanel), który wypełnia całą wolną przestrzeń
  • Splitter pomiędzy drzewkiem i panelem (GridSplitter)
  • Na górze menu
  • Na dole Status bar
I niestety chwilę mi to zajeło zanim uzyskałem zadowalający efekt.