SharePoint 2010 Document Library Replicator: Part 3

Today I added the following changes to the solution:

1 – Added a ReplicatorLogger Class to the solution.

2 – Updated the Feature Receiver code to create a Replicator logger list in the Web.

3 – Updated the ItemUpdated method in the Event Receiver to write to the Replicator Logger list when an item is added or updated.

The following code is the new ReplicatorLogger Class:

internal class ReplicatorLogger

 {

publicvoid writeToLog(string title, string logDate, string modifiedBy, string action, string copySource, string fileName, SPWeb web)

{

 // Get the current httpcontext

 System.Web.HttpContext currentContext = System.Web.HttpContext.Current;

 // Set the httpcontext to null;

 HttpContext.Current = null;

 using (web)

{

 try

 {

 // Create an item the Replicator Logger list to record the event

 SPList spList = web.Lists[“Replicator Logger”];

 SPListItem logItem = spList.Items.Add();

logItem[“Title”] = title;

logItem[“Log Date”] = logDate;

logItem[“Modified By”] = modifiedBy;

logItem[“Action”] = action;

logItem[“Copy Source”] = copySource;

logItem[“File Name”] = fileName;

logItem.Update();

 }

 catch (SPException spEx)

{

 }

 finally

 {

 // Set the httpcontext back to the original

 System.Web.HttpContext.Current = currentContext;

}

}

}

}

The following code was added to the Feature Receiver to create the Replicator logger list:

 // Create the replicator logging list

 spWeb.Lists.Add(“Replicator Logger”, “Document Library Replicator Logging List”, spWeb.ListTemplates[“Custom List”]);

 SPList replicatorLoggingList = spWeb.Lists[“Replicator Logger”];

replicatorLoggingList.NoCrawl = true;

replicatorLoggingList.Fields.Add(“Log Date”, SPFieldType.Text, true);

replicatorLoggingList.Fields.Add(“Modified By”, SPFieldType.Text, true);

replicatorLoggingList.Fields.Add(“Action”, SPFieldType.Text, true);

replicatorLoggingList.Fields.Add(“Copy Source”, SPFieldType.Text, true);

replicatorLoggingList.Fields.Add(“File Name”, SPFieldType.Text, true);

replicatorLoggingList.Update();

 // Update the default view to show the new fields

SPView spLogView = replicatorLoggingList.DefaultView;

spLogView.ViewFields.Add(“Log Date”);

spLogView.ViewFields.Add(“Modified By”);

spLogView.ViewFields.Add(“Action”);

spLogView.ViewFields.Add(“Copy Source”);

spLogView.ViewFields.Add(“File Name”);

spLogView.Update();

The code below updates the Event Receiver to also write the properties to the Replicator Logger list:

public overridevoid ItemUpdated(SPItemEventProperties properties)

{

 base.ItemUpdated(properties);

 using (SPSite spsite = newSPSite(properties.WebUrl))

 try

 {

EventFiringEnabled = false;

 if (properties.ListItem.ParentList.Title != “Replicator Logger”)

{

 SPWeb siteForLogger = spsite.OpenWeb();

 // determine target filename – the same as the source

 string targetfilename = properties.ListItem.Name.ToString();

 string SourceLib = properties.WebUrl + “/” + properties.ListItem.ParentList.ToString();

  // Copy the file to the destination library (targetlibrary)

 properties.ListItem.File.CopyTo(properties.WebUrl + “/” + “targetlibrary” + “/” + targetfilename, true

);

 // Write to the Replicator Log – in test mode…

 ReplicatorLogger replogger = newReplicatorLogger();

 // Get the current Date and Time

 DateTime dtime = DateTime.Now;

 // Create the title for the logger list item

 string title = (dtime.Date.ToString() + “_” + dtime.Hour.ToString() + “_” + dtime.Minute.ToString() + “_” + dtime.Second.ToString() + “_” + targetfilename.ToString());

 // Write the information to the logger list

 EventFiringEnabled = false;

replogger.writeToLog(title, dtime.ToShortDateString(), properties.UserDisplayName.ToString(),“New/Updated Document”, SourceLib, targetfilename, siteForLogger);

}

}

catch (SPException spEx) { }

 finally

 {

  // Enable Event Firing

 EventFiringEnabled = true;

}

}

Here is an example of the item created in the Replicator Logger list when an item is uploaded or updated:

SharePoint 2010 Document Library Replicator: Part 2

In my previous post I demonstrated how easy it was to have a document copied, on upload, to another document library with very few lines of code. This involved utilizing an Event Receiver which performed an override using the ItemUpdated method. This would also support document updates as the code utilized the ItemUpated method.

 Since then I have been working on a feature receiver which that creates a SharePoint list that defines the source and target document libraries for the copy operation.

The ideal approach is to code this so that when the Document Library Replicator feature is activated (the event receiver), we would like the replication configuration list to be created at the same time in the current Web. This has been achieved by created a Feature Receiver within the project that does the following:

1 – Create the “Replicator Configuration” list.

2 – Sets the crawl attribute for the list to none.

3 – Create two text fields for the source and target path and name

4 – Adds the two new text fields to the default view.

The feature receiver only overrides the FeatureActivated method, and does not remove the list when the Document Library Replicator feature is de-activated.

The code for the feature receiver is below:

public class Document_Library_ReplicatorEventReceiver: SPFeatureReceiver

{

.public override void FeatureActivated(SPFeatureReceiverProperties properties)

{

try

{

using (SPWeb spWeb = (SPWeb)properties.Feature.Parent)

{

// Create the replicator configuration list

SPSite spSite = spWeb.Site;

spWeb.Lists.Add(“Replicator Configuration”, “Document Library Replicator Configuration”, spWeb.ListTemplates[“Custom List”]);

SPList replicatorConfigList = spWeb.Lists[“Replicator Configuration”];

replicatorConfigList.NoCrawl = true;

replicatorConfigList.Fields.Add(“Source Library Path and Name”, SPFieldType.Text, true);

replicatorConfigList.Fields.Add(“Target Library Path and Name”, SPFieldType.Text, true);

replicatorConfigList.Update();

// Update the default view to show the new fields

SPView spView = replicatorConfigList.DefaultView;

spView.ViewFields.Add(“Source Library Path and Name”);

spView.ViewFields.Add(“Target Library Path and Name”);

spView.Update();

}

}

catch (SPException spEx)

{

}

finally

{

}

}

}

SharePoint 2010 Document Library Replicator: Part 1

I have been recently working on coding a SharePoint document library replicator. Everytime an item is updated in one library, I wanted to ensure a copy of the updated document is written to another library within the same Web.

Even though I am still working in the final solution, I wanted to share a small code snippet which is a SharePoint 2010 Event Receiver that copies a file from one library to a specified target document library named “targetlibrary”. To perform this basic function the code was very straight forward, and any libraries that get updated would get the file copied to the target library within the Web.

The properties are hard-coded in this sample, but in my final solution I may have a list which manages source and destination library urls. It could also handle and manage SPFolders from the source to the target libraries. I’m also adding a log writer to show the copied files with a timestamp that shows properties such as the last user who edited the file. The log writer will write the information to a SharePoint list.

*** You may want to add some code to skip the block if an update is made to the target library ***

using System;

using System.Security.Permissions;

using Microsoft.SharePoint;

using Microsoft.SharePoint.Security;

using Microsoft.SharePoint.Utilities;

using Microsoft.SharePoint.Workflow;

using System.IO;

namespace DocLibraryReplicator.Document_Library_Receiver

{

///<summary>

/// List Item Events///</summary>

publicclass Document_Library_Receiver : SPItemEventReceiver

{

///<summary>/// An item was added.///</summary>

publicoverridevoid ItemAdded(SPItemEventProperties properties)

{

base.ItemAdded(properties);

}

///<summary>/// An item was updated.///</summary>

publicoverridevoid ItemUpdated(SPItemEventProperties properties)

{

base.ItemUpdated(properties);

using (SPSite spsite = newSPSite(properties.WebUrl))

try

{

// determine target filename – the same as the source

string targefilename = properties.ListItem.Name.ToString();

// Disable Event Firing as the target will try to copy to itself

EventFiringEnabled = false;

 // Copy the file to the destination library (targetlibrary) ** BEWARE ** Target file overwritten with true directive

properties.ListItem.File.CopyTo(properties.WebUrl + “/” + “targetlibrary” + “/” + targefilename, true);

 // Enable Event Firing

EventFiringEnabled = true;

}

catch (SPException spEx) { }

finally { }

}

}

}

SharePoint 2010 – Profiles missing from import

Today I came across a very odd issue where I had seen a number of missing SharePoint User Profiles missing from the Active Directory synchronization.

The problem was, the deleted Active Directory users were left in the User Profile database marked as deleted, but never deleted by the “My Site Cleanup Job”. You can query the UserProfile_Full table to determine which profiles have the bdeleted column set to 1.

A description of the timer job is displayed below:

It turned out that the solution was to ensure a My Site host had been configured as part of the farm setup, so that the missing profiles from import are correctly removed. The My Site Cleanup Job runs every hour,  by default, and even though the job looked as though it ran successfully it wasn’t actually performing the specified function.

You can follow this Microsoft TechNet Article to configure a My Site Host in your farm.

Microsoft Hyper-V R2 SP1: Application Workload Performance

Recently, I came across this white paper where the Enterprise Strategy Group Lab provided an excellent summary on virtualizing Microsoft SQL Server 2008 R2, Microsoft SharePoint Server 2010 and Microsoft Exchange Server 2010. The white paper covers the technical architecture utilized within the lab, with detailed performance tests and workload scalability graphs. Each section provides an excellent summary and a set of highlights.

I recommend reading this white paper for some insight into the scale that Hyper-V R2 SP1 provides to these applications.

The white paper can be downloaded here.

Microsoft SQL Azure Training: Creating a Microsoft SQL Azure Server and Database

I’ve created a video to demonstrate how to create SQL Azure Server and database.

This SQL Azure demonstration covers the following training:

1) Creating a SQL Azure Database Server
2) Reviewing Firewall settings
3) Creating a SQL Azure Database
4) Connecting and manage SQL Azure

SharePoint Server 2010: Service Application Error

I recently came across an issue where I was unable to manage the SharePoint Service Applications within Central Administration. The error I received was as follows:

“The specified user or domain group was not found”

This symptom was caused by a user account which was removed from Active Directory, that was assigned to a Managed Metadata Service Application. The account in question was assigned administrator rights in the service application. I worked woth Microsoft to remedy the issue in my case after performing some initial steps to determine which service application was causing the problem.

To determine the problem, I first had to find out which service application was causing the message to appear. I followed these steps:

1 – Opened IIS Manager

2 – Navigated to Sites -> SharePoint Web Services

3 – Each Service application has a guid and in the basic properties, you can review the path of the web service to identify the service.

4 – The SharePoint diagnostic logs should correlate to the application ID with the error in question, and so should the application event logs.

5 – When you determine which service application is causing the issue, you can run the following SQL statement against your SharePoint configuration database (I used %Metadata%, as I was aware it was the Metadata Service application):

SELECT [Name], [Version], CAST([Properties] as xml)

From [SharePoint_Config].[dbo].[Objects] with (nolock)

Where [Name] LIKE ‘%Metadata%’

6) Click the properties column XML result and review the following sections:

<sFld type=”Stringname=m_SerializedAcl>

7 – There should be some identities associated with the service application.

8 – Check each Identity Name in Active Directory to determine which one was removed.

8 – In some cases you should be able to re-create the account in Active Directory, since the service application is looking for a principle name, and not a SID. Ensure you synchronize your Active Directory Domain.

9) You should now be able to navigate to the service applications (providing the particular service application is looking for a principle name in Active Directory), and then remove the account from the service application permissions.

10) If the above solution does not work, you can create a new account, with a different name, and try the following stsadm command:

stsadm -o migrateuser -oldlogin {the domain\old users login name that was removed} -newlogin {the domain\new AD account} -ignoresidhistory

e.g. stsadm -o migrateuser -oldlogin corp\deleteduser -newlogin corp\newuser -ignoresidhistory

You can also use the SharePoint Management Shell if you prefer and use the Move-SPUser command.

Should the above remedy not work in your situation, I highly recommend logging your particular case with Microsoft Premier Support to resolve your issue.

I also highly recommend not to make any direct changes to the SharePoint configuration database via custom code or SQL statements, in order to keep a  supported SharePoint environment.

Creating and deploying your first Windows Azure Project

I’ve created a video which demonstrates how to create your first Microsoft Windows Azure project in Visual Studio 2010. The demonstration covers the folowing training content.

A walk through creating a Microsoft Windows Azure project in Microsoft Visual Studio 2010. A review of the Web Role settings is demonstrated, with some changes to the page markup for the project home page. The final part of this demo walks you through creating a Hosted Service through the Windows Azure Management Portal, creating  and finally uploading your Windows Azure package.

Visual Studio 2010 Training – Creating your first Visual WebPart

I’ve created a video to demonstrate how to create a SharePoint 2010 solution with a Visual WebPart in Visual Studio 2010.

The video covers the following training:

1) Creating a SharePoint 2010 Project
2) Creating a Visual Web Part
3) Adding WebPart Controls
4) Adding the WebPart to a Page
5) Enabling some Basic Ajax Extensions in the Web Part

I welcome your feedback, and if you would like to see additional training videos on SharePoint Development I’ll do my best to accommodate your requirements.

SharePoint 2010 Training – Creating a Custom Content Type

I have recently created a training video which I would like to share, on how to create a custom content type in Microsoft SharePoint Server 2010. The video covers the following training:

1) Creating a SharePoint Site
2) Creating a Car Manufacturers List
3) Creating a Car List
4) Creating a Content Type
5) Assigning the Content type to the Car List

I welcome your feedback and I will start to add more training videos to this blog in the future.