Copy sharepoint list items or library files with version history and meta data

SharePoint doesnt support copying files between libraries or lists with version history out of the box. Although when “moving” files it does work.

To get around this you can either code the solution yourself with a custom workflow or much easier just use Sharegate’s Copy SharePoint Content tool: download sharegate trial here which can copy items meta data, version history and permissions. No server install needed and a very easy to use interface. Definitely recommend.

Creating and updating a SharePoint timer job in C#

  1. First of all create a new empty sharepoint project.
  2. Add a new feature.
  3. Right click on the feature and add an event receiver.
  4. Right click on the project name and add a new c# class.

Your structure should look like:

 

In my case the class file i added was called ComplianceData.cs your will obviously be different.

Creating the timer job
Modify the class you created by extending : SPJobDefinition

Next create the constructors like below for your class:

public ComplianceData()

: base()

{

}

 

 

public ComplianceData(string jobName, SPService service, SPServer server, SPJobLockType targetType)

: base(jobName, service, server, targetType)

{

}

 

 

public ComplianceData(string jobName, SPWebApplication webApplication)

: base(jobName, webApplication, null, SPJobLockType.ContentDatabase)

{

this.Title = “MiWorld Compliance Feed Refresh”;

}

 

After this create an execute method:

public override void Execute(Guid contentDbId)

{

// get a reference to the current site collection’s content database

SPWebApplication webApplication = this.Parent as SPWebApplication;

SPContentDatabase contentDb = webApplication.ContentDatabases[contentDbId];

 

//do whatever you need here

 

}

 

Activating the timer job

Next open the feature event receiver class and add the below code:

const string List_JOB_NAME = “MyTimerJob”;

 

public override void FeatureActivated(SPFeatureReceiverProperties properties)

{

SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;

 

// make sure the job isn’t already registered

 

foreach (SPJobDefinition job in webApp.JobDefinitions)

{

 

if (job.Name == List_JOB_NAME)

 

job.Delete();

 

}

 

// install the job

 

ComplianceData listLoggerJob = new ComplianceData(List_JOB_NAME, webApp);

 

SPMinuteSchedule schedule = new SPMinuteSchedule();

 

schedule.BeginSecond = 0;

 

schedule.EndSecond = 59;

 

schedule.Interval = 30;

 

listLoggerJob.Schedule = schedule;

 

listLoggerJob.Update();

}

 

// Uncomment the method below to handle the event raised before a feature is deactivated.

 

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)

{

SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;

 

// delete the job

 

foreach (SPJobDefinition job in webApp.JobDefinitions)

{

if (job.Name == List_JOB_NAME)

{

job.Delete();

}

}

}

 

In the code above we’re creating a new timer job once the feature is activated and settings its frequency to run every thirty minutes. You can also use SPHourlySchedule or SPDailySchedule. We also tell the timer which class to execute when the timer job runs.

The final thing to do is to set the feature scope to WebApplication.

All done.

Updating the timer job
If you decide to make changes after deploying the solution, you may find your timer job doesnt update. This is because you need to change the assembly versions in the AssemblyInfo.cs file.

Force Reinstall of SharePoint 2010 Solution through Visual Studio 2010 – Error occurred in deployment step ‘Add Solution’

If you get the following message in Visual Studio 2010 when deploying a SP2010 webpart:

Error occurred in deployment step ‘Add Solution’ – Use the force attribute to explicitly re-install the feature

Fear not theres a simple fix…. just add AlwaysForceInstall attribute to featurename.Template.xml and set it to True

Update masterpage ReplaceContent on SP2010 Masterpage and Page layouts on deploy

SharePoint 2013 offers a long awaited ability to simply use ReplaceContent=”true” inside a sharepoint module.

SharePoint 2010 doesnt have this ability. In order to achieve the same affect you need to create the following code for the feature activation:

using System;

using System.Collections.Generic;

using System.Xml.Linq;

using System.Text;

using Microsoft.SharePoint;

using Microsoft.SharePoint.Administration;

using System.Globalization;

using System.Xml;

using System.Collections;

using System.Linq;

 

namespace TestSPSolution

{

public class UpdateFiles : SPFeatureReceiver

{

public override void FeatureActivated(SPFeatureReceiverProperties properties)

{

if (properties != null)

{

using (SPSite currentSite = (SPSite)properties.Feature.Parent)

{

using (var web = currentSite.OpenWeb())

{

var ElementDefinitions = properties.Definition.GetElementDefinitions(CultureInfo.CurrentCulture);

 

foreach (SPElementDefinition ElementDefinition in ElementDefinitions)

{

if (ElementDefinition.ElementType == “Module”)

{

Helper.UpdateFilesInModule(ElementDefinition, web);

}

}

}

 

}

}

}

 

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)

{

//// throw new NotImplementedException();

}

 

public override void FeatureInstalled(SPFeatureReceiverProperties properties)

{

////throw new NotImplementedException();

}

 

public override void FeatureUninstalling(SPFeatureReceiverProperties properties)

{

//// throw new NotImplementedException();

}

}

 

internal static class Helper

{

internal static void UpdateFilesInModule(SPElementDefinition elementDefinition, SPWeb web)

{

XElement xml = elementDefinition.XmlDefinition.ToXElement();

XNamespace xmlns = “http://schemas.microsoft.com/sharepoint/”;

string featureDir = elementDefinition.FeatureDefinition.RootDirectory;

Module module = (from m in xml.DescendantsAndSelf()

select new Module

{

ProvisioningUrl = m.Attribute(“Url”).Value,

PhysicalPath = featureDir,

Files = (from f in m.Elements(xmlns.GetName(“File”))

select new Module.File

{

 

FilePath = (m.Attribute(“Path”) == null) ? string.Empty : Path.Combine(featureDir, m.Attribute(“Path”).Value),

Name = f.Attribute(“Url”).Value,

Properties = (from p in f.Elements(xmlns.GetName(“Property”))

select p).ToDictionary(

n => n.Attribute(“Name”).Value,

v => v.Attribute(“Value”).Value)

}).ToArray()

}).First();

 

if (module == null)

{

return;

}

 

foreach (Module.File file in module.Files)

{

 

string physicalPath = string.IsNullOrEmpty(file.FilePath) ? Path.Combine(module.PhysicalPath, file.Name) : Path.Combine(file.FilePath, file.Name);

string virtualPath = string.Concat(web.Url, “/”, module.ProvisioningUrl, “/”, file.Name);

 

if (File.Exists(physicalPath))

{

using (StreamReader sreader = new StreamReader(physicalPath))

{

if (!CheckOutStatus(web.GetFile(virtualPath)))

{

web.GetFile(virtualPath).CheckOut();

}

SPFile spFile = web.Files.Add(virtualPath, sreader.BaseStream, new Hashtable(file.Properties), true);

spFile.CheckIn(“Updated”, SPCheckinType.MajorCheckIn);

if (CheckContentApproval(spFile.Item))

{

spFile.Approve(“Updated”);

}

 

spFile.Update();

}

}

}

 

}

 

private static bool CheckOutStatus(SPFile file)

{

if (file.CheckOutStatus != SPFile.SPCheckOutStatus.None)

{

return true;

}

else

{

return false;

}

}

 

private static bool CheckContentApproval(SPListItem listitem)

{

bool isContentApprovalEnabled = listitem.ParentList.EnableModeration;

 

return isContentApprovalEnabled;

}

 

public static XElement ToXElement(this XmlNode node)

{

XDocument xDoc = new XDocument();

 

using (XmlWriter xmlWriter = xDoc.CreateWriter())

 

node.WriteTo(xmlWriter);

 

return xDoc.Root;

 

}

}

 

public class Module

{

public string ProvisioningUrl { get; set; }

public string PhysicalPath { get; set; }

public Module.File[] Files { get; set; }

 

public class File

{

public string FilePath { get; set; }

public string Name { get; set; }

public Dictionary<string, string> Properties { get; set; }

}

}

}

Bulk deleting sharepoint list items – use SPWeb.ProcessBatchData

For most developers the obvious solution would be to use something like:

foreach (SPListItem item in list.Items)
{
item.Delete();
}

That’s probably fine for small lists.  However when you need to delete anything over say 10 items then it would be better to provide a batch command to SharePoint.  This way with just one batch update you could delete any x number of items based on their item id in the the list or even empty the list completely:

batchString.Append(“”);
foreach (SPListItem item in splic)
{
batchString.Append(“”);
batchString.Append(“” + Convert.ToString(item.theList.ID) + “”);
batchString.Append(“” + Convert.ToString(item.ID) + “”);
batchString.Append(“Delete”);
batchString.Append(“”);
}
batchString.Append(“”);
web.ProcessBatchData(batchString.ToString());

Access content as system user – SPSecurity.RunWithElevatedPrivileges

Any code behind in SharePoint defaults to run as the current logged on user on the site. However this can become an issue if you want to programmatically update/access content that the user does not have permission to. For instance on the code behind of a layout page or workflow.

To get around this you need to run the code under ‘elevated privileges‘ following the example below:

 

SPSecurity.RunWithElevatedPrivileges(delegate()

{

using (SPSite site = new SPSite(web.Site.ID))

{

// write your code here

}

});