Copying existing files into a server SharePoint - sharepoint

I'm facing of difficulties to change a files into CSV and save it into local environment. How can I achieve this? Try to look around but seem like not what I'm looking for.
I'm running on SharePoint 2010. Before this, this code only grab data from SharePoint and turn it into xlsx and update it into our web.
private static void GenerateSPGroupUsersReport() //
{
Log("Generate Sharepoint Group Users Report");
DataSet dsSecurityReport = new DataSet();
string ConnectedWebURL = ConfigurationManager.AppSettings["SPGroupUsersWebURL"];
//string[] strURL = ConnectedWebURL.Split(';');
DataTable dTblSPGroupUser = new DataTable();
dTblSPGroupUser.Columns.Add("SiteURL", typeof(string));
dTblSPGroupUser.Columns.Add("SharepointGroup", typeof(string));
dTblSPGroupUser.Columns.Add("User", typeof(string));
// Hafees add 10/22/2019
dTblSPGroupUser.Columns.Add("UserLanID", typeof(string));
dTblSPGroupUser.Columns.Add("Email", typeof(string));
SPSite site = new SPSite(ConnectedWebURL);
SPWebApplication webApp = site.WebApplication;
foreach (SPSite s in webApp.Sites)
{
SPGroupCollection groupCol = s.RootWeb.SiteGroups;
foreach (SPGroup group in groupCol)
{
// Hafees include group.Users, user.Email
foreach (SPUser user in group.Users)
{
dTblSPGroupUser.Rows.Add(s.Url, group.Name, user.Name, user.LoginName, user.Email);
}
//bool contains = dTblSPGroupUser.AsEnumerable().Any(rowC => group.Name == rowC.Field<string>("SharepointGroup"));
//if (!contains)
//{
// foreach (SPUser user in group.Users)
// {
// dTblSPGroupUser.Rows.Add(s.Url, group.Name, user.Name);
// }
//}
}
}
DataSet dsSPGroup = new DataSet();
dsSPGroup.Tables.Add(dTblSPGroupUser);
SaveIntoSPLibrary(site, dsSPGroup, "GroupUsers_" + ConnectedWebURL.Replace("http://", "").Replace("https://", "").Replace(":", "-").Trim());
Log("Generate Sharepoint Group Users Report Complete");
}
// This is where I generate the group of user report.
private static void SaveIntoSPLibrary(SPSite site, DataSet ds, string fileName)
{
string UIResourceServerRelativeWebURL = ConfigurationManager.AppSettings["UIResourceServerRelativeWebURL"];
using (SPWeb web = site.OpenWeb(UIResourceServerRelativeWebURL))
{
byte[] byteArray = GenerateExcelFile(ds);
string CustomReportLibrary = ConfigurationManager.AppSettings["CustomReportLibrary"];
string strFileName = String.Format(fileName + ".{0}.xlsx", DateTime.Today.ToString("yyyyMMdd"));
Log("Saving into SP Library. " + CustomReportLibrary + strFileName);
web.AllowUnsafeUpdates = true;
SPFile file = web.Files.Add(CustomReportLibrary + strFileName, byteArray, true);
file.Item["Year"] = DateTime.Now.ToString("yyyy");
file.Item["Month"] = string.Format("{0}. {1}", DateTime.Now.Month, DateTime.Now.ToString("MMMM"));
file.Item.Update();
file.Update();
web.AllowUnsafeUpdates = false;
}
}
// This is where the files save into xlsx and update it into SharePoint Library.
I try to do a copy of SaveIntoLibrary with abit of modification, I change to CSV files and create a new configurationManager which it will point into my local directory. But seem I'm wrong at somewhere. The files still didn't get into my local directory. Please advice.

You should export the DataTable report data to local CSV,
Check the code in this thread, this will output the csv file so you could save to your local.
var dataTable = GetData();
StringBuilder builder = new StringBuilder();
List<string> columnNames = new List<string>();
List<string> rows = new List<string>();
foreach (DataColumn column in dataTable.Columns)
{
columnNames.Add(column.ColumnName);
}
builder.Append(string.Join(",", columnNames.ToArray())).Append("\n");
foreach (DataRow row in dataTable.Rows)
{
List<string> currentRow = new List<string>();
foreach (DataColumn column in dataTable.Columns)
{
object item = row[column];
currentRow.Add(item.ToString());
}
rows.Add(string.Join(",", currentRow.ToArray()));
}
builder.Append(string.Join("\n", rows.ToArray()));
Response.Clear();
Response.ContentType = "text/csv";
Response.AddHeader("Content-Disposition", "attachment;filename=myfilename.csv");
Response.Write(builder.ToString());
Response.End();

Related

How to export SharePoint list data to excel using a timer job with custom coding?

I am new to SharePoint programming.
Can anyone tell me how I can export list data to Excel using a timer job with some custom code?
Please go through the below link for creating timer jobs in sharepoint.
This article is contain the detailed process.
https://www.mssqltips.com/sqlservertip/3801/custom-sharepoint-timer-job/
The below code will help you to export the list data.
public void Export(List<int> ids)
{
DataTable table = new DataTable();
try
{
SPSite site = SPContext.Current.Site;
SPWeb web = SPContext.Current.Web;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite siteE = new SPSite(site.ID))
{
using (SPWeb webE = siteE.OpenWeb(web.ID))
{
webE.AllowUnsafeUpdates = true;
SPList list = webE.Lists["Stationery"];
table.Columns.Add("Product", typeof(string));
table.Columns.Add("Quantity", typeof(Decimal));
DataRow newRow;
GridView gv = new GridView();
foreach (SPListItem item in list.Items)
{
if (ids.Contains(Convert.ToInt32(item["ID"].ToString())) && (item["Status"].ToString() == "New"))
{
newRow = table.Rows.Add();
newRow["Product"] = item["Product"].ToString();
newRow["Quantity"] = Convert.ToDecimal(item["Quantity"].ToString());
item["Status"] = "Exported";
item.Update();
}
}
SPBoundField boundField = new SPBoundField();
boundField.HeaderText = "Product";
boundField.DataField = "Product";
gv.Columns.Add(boundField);
boundField = new SPBoundField();
boundField.HeaderText = "Quantity";
boundField.DataField = "Quantity";
boundField.ControlStyle.Width = new Unit(120);
gv.Columns.Add(boundField);
gv.AutoGenerateColumns = false;
gv.DataSource = table.DefaultView;
gv.DataBind();
gv.AllowSorting = false;
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.ClearHeaders();
string attachment = "attachment; filename=export" + "_" + DateTime.Now.ToShortTimeString() + ".xls";
HttpContext.Current.Response.AddHeader("content-disposition", attachment);
HttpContext.Current.Response.ContentType = "application/Excel";
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
gv.RenderControl(htw);
HttpContext.Current.Response.Write(sw.ToString());
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.Close();
HttpContext.Current.Response.End();
webE.AllowUnsafeUpdates = false;
}
}
});
}
catch (Exception ex)
{
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
HttpContext.Current.Response.Write(ex.ToString());
}

Sharepoint: How to upload files with metadata including Taxonomy fields through web services

Being very new to SharePoint coding I have been assigned the task to create a prototype code to upload a file and setting the field values for that file that will show up when opening the sharepoint page with the file.
This has to be done from a remote machine and not the Sharepoint server itself so using the .Net objects for Sharepoint is out the question.
I quickly found out how to upload a file through the Sharepoint Web Service Copy.asmx:
void UploadTestFile() {
var file = #"C:\Temp\TestFile.doc";
string destinationUrl = "http://mysharepointserver/Documents/"
+ Path.GetFileName(file);
string[] destinationUrls = { destinationUrl };
var CopyWS = new Copy.Copy();
CopyWS.UseDefaultCredentials = true;
CopyWS.Url = "http://mysharepointserver/_vti_bin/copy.asmx";
CopyResult[] result;
byte[] data = File.ReadAllBytes(file);
FieldInformation mf1 = new FieldInformation {
DisplayName = "title",
InternalName = "title",
Type = FieldType.Text,
Value = "Dummy text"
};
FieldInformation mf2 = new FieldInformation {
DisplayName = "MyTermSet",
InternalName = "MyTermSet",
Type = FieldType.Note,
Value = "Test; Unit;"
};
CopyWS.CopyIntoItems(
"+",
destinationUrls,
new FieldInformation[] { mf1, mf2 },
data,
out result);
}
This code easily uploads any file to the target site but only fills the "title" field with info. The field MyTermSet in which I have added 3 terms allready - Test, Unit and Page - will not update with the values "Test;" and "Unit;".
Being very new to Sharepoint and me not grasping all the basics googling has told me that updating "File", "Computed" or "Lookup" fields does not work with the CopyIntoItems method, and MyTermSet being a Taxonomy field is - if I am correct - a Lookup field.
So how do I get MyTermSet updated with the values "Test;" and "Unit;" ?
I would really prefer If someone has a sample code on this. I have followed several hint-links but I am none the wiser. I have found no sample-code on this at all.
Have anyone made one single method that wraps it all? Or another method that takes in the destinationUrl from the file upload and updates the Term Set/Taxonomy field.
Puzzling together what I have found so far, I am now able to do as I wanted. But I would really like to be able to get the Taxonomy field GUIDs dynamically and NOT having to explicitly set them myself:
void UploadTestFile(string FileName, string DocLib, Dictionary<string, string> Fields = null) {
//Upload the file to the target Sharepoint doc lib
string destinationUrl = DocLib + Path.GetFileName(FileName);
string[] destinationUrls = { destinationUrl };
var CopyWS = new Copy.Copy();
CopyWS.UseDefaultCredentials = true;
CopyWS.Url = new Uri(new Uri(DocLib), "/_vti_bin/copy.asmx").ToString();
CopyResult[] result;
var data = File.ReadAllBytes(FileName);
CopyWS.CopyIntoItems(
"+",
destinationUrls,
new FieldInformation[0],
data,
out result);
if (Fields == null) return; //Done uploading
//Get the ID and metadata information of the fields
var list = new ListsWS.Lists();
list.UseDefaultCredentials = true;
var localpath = new Uri(DocLib).LocalPath.TrimEnd('/');
var site = localpath.Substring(0, localpath.LastIndexOf("/")); //Get the site of the URL
list.Url = new Uri(new Uri(DocLib), site + "/_vti_bin/lists.asmx").ToString(); //Lists on the right site
FieldInformation[] fiOut;
byte[] filedata;
var get = CopyWS.GetItem(destinationUrl, out fiOut, out filedata);
if (data.Length != filedata.Length) throw new Exception("Failed on uploading the document.");
//Dictionary on name and display name
var fieldInfos = fiOut.ToDictionary(x => x.InternalName, x => x);
var fieldInfosByName = new Dictionary<string, FieldInformation>();
foreach (var item in fiOut) {
if (!fieldInfosByName.ContainsKey(item.DisplayName)) {
fieldInfosByName.Add(item.DisplayName, item);
}
}
//Update the document with fielddata - this one can be extended for more than Text and Note fields.
if (!fieldInfos.ContainsKey("ID")) throw new Exception("Could not get the ID of the upload.");
var ID = fieldInfos["ID"].Value; //The ID of the document we just uploaded
XDocument doc = new XDocument(); //Creating XML with updates we need
doc.Add(XElement.Parse("<Batch OnError='Continue' ListVersion='1' ViewName=''/>"));
doc.Element("Batch").Add(XElement.Parse("<Method ID='1' Cmd='Update'/>"));
var methNode = doc.Element("Batch").Element("Method");
//Add ID
var fNode = new XElement("Field");
fNode.SetAttributeValue("Name", "ID");
fNode.Value = ID;
methNode.Add(fNode);
//Loop each field and add each Field
foreach (var field in Fields) {
//Get the field object from name or display name
FieldInformation fi = null;
if (fieldInfos.ContainsKey(field.Key)) {
fi = fieldInfos[field.Key];
}
else if (fieldInfosByName.ContainsKey(field.Key)) {
fi = fieldInfosByName[field.Key];
}
if (fi != null) {
//Fix for taxonomy fields - find the correct field to update
if (fi.Type == FieldType.Invalid && fieldInfos.ContainsKey(field.Key + "TaxHTField0")) {
fi = fieldInfos[field.Key + "TaxHTField0"];
}
else if (fi.Type == FieldType.Invalid && fieldInfosByName.ContainsKey(field.Key + "_0")) {
fi = fieldInfosByName[field.Key + "_0"];
}
fNode = new XElement("Field");
fNode.SetAttributeValue("Name", fi.InternalName);
switch (fi.Type) {
case FieldType.Lookup:
fNode.Value = "-1;#" + field.Value;
break;
case FieldType.Choice:
case FieldType.Text:
fNode.Value = field.Value;
break;
case FieldType.Note: //TermSet's
var termsetval = "";
var terms = field.Value.Split(';');
foreach (var term in terms) {
termsetval += "-1;#" + term + ";";
}
fNode.Value = termsetval.TrimEnd(';');
break;
default:
//..Unhandled type. Implement if needed.
break;
}
methNode.Add(fNode); //Adds the field to the XML
}
else {
//Field does not exist. No use in uploading.
}
}
//Gets the listname (not sure if it is the full path or just the folder name)
var listname = new Uri(DocLib).LocalPath;
var listcol = list.GetListCollection(); //Get the lists of the site
listname = (from XmlNode x
in listcol.ChildNodes
where x.Attributes["DefaultViewUrl"].InnerText.StartsWith(listname, StringComparison.InvariantCultureIgnoreCase)
select x.Attributes["ID"].InnerText).DefaultIfEmpty(listname).First();
//Convert the XML to XmlNode and upload the data
var xmldoc = new XmlDocument();
xmldoc.LoadXml(doc.ToString());
list.UpdateListItems(listname, xmldoc.DocumentElement);
}
Then I call it like this:
var fields = new Dictionary<string, string>();
fields.Add("Test", "Dummy Text");
fields.Add("MrTermSet", "Page|a4ba29c1-3ed5-47e9-b43f-36bc59c0ea5c;Unit|4237dfbe-22a2-4d90-bd08-09f4a8dd0ada");
UploadTestFile(#"C:\Temp\TestFile2.doc", #"http://mysharepointserver/Documents/", fields);
I would however prefer to call it like this:
var fields = new Dictionary<string, string>();
fields.Add("Test", "Dummy Text");
fields.Add("MrTermSet", "Page;Unit");
UploadTestFile(#"C:\Temp\TestFile2.doc", #"http://mysharepointserver/Documents/", fields);

Get file/folder size from sharepoint using GetListItems

I am calling Sharepoint web service methond GetListItems, and don't see anything about file/folder size being returned. Am I missing something, or is there another way to get the size of the file/folder. Many thanks in advance.
the field you need is called ows_FileSizeDisplay, this returns an int for the number of bytes.
here is some code to put you on the rigth track
List<File> files = new List<File>(1);
File tempFile;
#region Get SharePointItems
SharePointListService.Lists svc = new SharePointListService.Lists();
XmlNode spItemsNode;
try
{
svc.Credentials = System.Net.CredentialCache.DefaultCredentials;
svc.Url = baseSharePointPath+"/_vti_bin/Lists.asmx";
XmlDocument xmlDoc = new System.Xml.XmlDocument();
XmlNode queryOptions =
xmlDoc.CreateNode(XmlNodeType.Element, "QueryOptions", "");
queryOptions.InnerXml = "<QueryOptions><IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns><DateInUtc>TRUE</DateInUtc><Folder>" +
baseSharePointPath + "/"+ listName + "/"+ folderName + "</Folder></QueryOptions>";
XmlNode query =
xmlDoc.CreateNode(XmlNodeType.Element, "Query", "");
query.InnerXml = "<Where><Eq><FieldRef Name='Usage'/><Value Type='Text'>%%usage%%</Value></Eq></Where>";
query.InnerXml = query.InnerXml.Replace("%%usage%%", ConvertFileUsageToString(usage));
spItemsNode = svc.GetListItems(listName,
null, query, null, null, queryOptions, null);
}
finally
{
svc.Dispose();
}
// load the response into an xml document
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(spItemsNode.OuterXml);
// create a namespace manager
XmlNamespaceManager ns = new XmlNamespaceManager(xDoc.NameTable);
// add all the special SharePoint Namespaces in
ns.AddNamespace("rs", "urn:schemas-microsoft-com:rowset");
ns.AddNamespace("z", "#RowsetSchema");
ns.AddNamespace("sp", "http://schemas.microsoft.com/sharepoint/soap/");
ns.AddNamespace("s", "uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882");
ns.AddNamespace("dt", "uuid:C2F41010-65B3-11d1-A29F-00AA00C14882");
XmlNodeList Items = xDoc.SelectNodes(#"/sp:listitems/rs:data/z:row", ns);
#endregion
foreach (XmlNode currentFile in Items)
{
tempFile = new File();
tempFile.Name = currentFile.Attributes["ows_NameOrTitle"].Value;
tempFile.Type = currentFile.Attributes["ows_DocIcon"].Value;
tempFile.Usage = ConvertToFileUsage(currentFile.Attributes["ows_Usage"].Value);
tempFile.Data = getFileBytes(currentFile.Attributes["ows_RequiredField"].Value, baseSharePointPath);
files
Here is a nice code snippet that will do the job shout if you have any questions
Folder folder = getFolder(serverRelitiveURL);
FileCollection files = folder.Files;
folder.Context.Load(files);
folder.Context.ExecuteQuery();
int folderSize;
foreach(file in files)
{
ListItem li = file.ListItemAllFields;
Console.writeline(li["File_x0020_Size"]);
folderSize = li["File_x0020_Size"]+folderSize;
}
Console.writeline(folderSize);

Adding description to WebPartPage when creating the page

I am following this (http://msdn.microsoft.com/en-us/library/ms450826.aspx) method to add a webpartpage (samplewpp.aspx) and it works. However, I need to add one line description as well. How?
You need to add a Content Editor Web Part (CEWP) to the page and then add your description to this. The CEWP allows you to put text/html onto a page.
To do this programatically then follow something like this code by Razi bin Rais :-
AddAndFillCEWP("http://server","/" ,"/Pages/blank.aspx","this text is adding via code","Header","CEWP WebPart");
private void AddAndFillCEWP(string siteUrl, string webName, string pageUrl, string textCEWP, string zoneId, string title)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite spSiteTest = new SPSite(siteUrl))
{
using (SPWeb web = spSiteTest.OpenWeb(webName))
{
try
{
web.AllowUnsafeUpdates = true;
SPFile file = web.GetFile(pageUrl);
if (null != file)
{
using (SPLimitedWebPartManager mgr = file.GetLimitedWebPartManager(PersonalizationScope.Shared))
{
if (null != mgr)
{
//create new webpart object
ContentEditorWebPart contentEditor = new ContentEditorWebPart();
//set properties of new webpart object
contentEditor.ZoneID = zoneId;
contentEditor.Title = title;
contentEditor.ChromeState = System.Web.UI.WebControls.WebParts.PartChromeState.Normal;
contentEditor.ChromeType = System.Web.UI.WebControls.WebParts.PartChromeType.TitleAndBorder;
//Add content to CEWP
XmlDocument xmlDoc = new XmlDocument();
XmlElement xmlElement = xmlDoc.CreateElement("Root");
xmlElement.InnerText = textCEWP;
contentEditor.Content = xmlElement;
contentEditor.Content.InnerText = xmlElement.InnerText;
//Add it to the zone
mgr.AddWebPart(contentEditor, contentEditor.ZoneID, 0);
web.Update();
}
}
}
}
finally
{
web.AllowUnsafeUpdates = false;
}
}
}
});
}

Copy folders when copying list items from source to destination

This is my code to copy files in a list from source to destination. Using the code below I am only able to copy files but not folders. Any ideas on how can I copy the folders and the files within those folders?
using (SPSite objSite = new SPSite(URL))
{
using (SPWeb objWeb = objSite.OpenWeb())
{
SPList objSourceList = null;
SPList objDestinationList = null;
try
{
objSourceList = objWeb.Lists["Source"];
}
catch(Exception ex)
{
Console.WriteLine("Error opening source list");
Console.WriteLine(ex.Message);
}
try
{
objDestinationList = objWeb.Lists["Destination"];
}
catch (Exception ex)
{
Console.WriteLine("Error opening destination list");
Console.WriteLine(ex.Message);
}
string ItemURL = string.Empty;
if (objSourceList != null && objDestinationList != null)
{
foreach (SPListItem objSourceItem in objSourceList.Items)
{
ItemURL = string.Format(#"{0}/Destination/{1}", objDestinationList.ParentWeb.Url, objSourceItem.Name);
objSourceItem.CopyTo(ItemURL);
objSourceItem.UnlinkFromCopySource();
}
}
}
}
Thanks
This is what worked for me. I had to move folders from spweb to another.
private static void RecursiveCopy(SPList objSourceList, SPFolder objSourceFolder, SPFolder objDestinationFolder)
{
SPListItemCollection objItems = ((SPDocumentLibrary)objSourceList).GetItemsInFolder(objSourceList.DefaultView, objSourceFolder);
foreach (SPListItem objItem in objItems)
{
//If it's a file copy it.
if (objItem.FileSystemObjectType == SPFileSystemObjectType.File)
{
byte[] fileBytes = objItem.File.OpenBinary();
string DestinationURL = string.Format(#"{0}/{1}", objDestinationFolder.Url, objItem.File.Name);
//Copy the file.
SPFile objDestinationFile = objDestinationFolder.Files.Add(DestinationURL, fileBytes, true);
objDestinationFile.Update();
}
else
{
string dirURL = string.Format(#"{0}/{1}", objDestinationFolder.Url, objItem.Folder.Name);
SPFolder objNewFolder = objDestinationFolder.SubFolders.Add(dirURL);
objNewFolder.Update();
//Copy all the files in the sub folder
RecursiveCopy(objSourceList, objItem.Folder, objNewFolder);
}
}
}
public static void CopyListItems(string SourceSiteURL, string DestinationSiteURL, string ListName)
{
string DestinationURL = string.Empty;
using (SPSite SourceSite = new SPSite(SourceSiteURL))
{
using (SPWeb SourceWeb = SourceSite.OpenWeb())
{
using (SPSite DestinationSite = new SPSite(DestinationSiteURL))
{
using (SPWeb DestinationWeb = DestinationSite.OpenWeb())
{
DestinationWeb.AllowUnsafeUpdates = true;
//Get the QA Forms Document libarary from the source web
SPList objSourceList = SourceWeb.Lists[ListName];
SPList objDestinationList = null;
try
{
objDestinationList = DestinationWeb.Lists[ListName];
}
catch
{
//Create a list in the destination web
DestinationWeb.Lists.Add(ListName, string.Empty, SPListTemplateType.DocumentLibrary);
}
objDestinationList = DestinationWeb.Lists[ListName];
//Recursively copy all the files and folders
RecursiveCopy(objSourceList, objSourceList.RootFolder, objDestinationList.RootFolder);
DestinationWeb.Update();
DestinationWeb.AllowUnsafeUpdates = false;
}
}
}
}
}
this copies all the files and folders recursively.
Hope it helps someone.
If you are copying to a destination that is located within the same SPWeb, you can try the following.
using (SPSite site = new SPSite("http://urltosite"))
{
using (SPWeb web = site.OpenWeb())
{
//get the folder from the source library
SPFolder sourceFolder = web.GetFolder("Documents/Folder 1");
//get the folder to the destination
SPFolder destinationFolder = web.GetFolder("New Library");
sourceFolder.CopyTo(destinationFolder.ServerRelativeUrl + "/" + sourceFolder.Name);
}
}
Sadly I don't think this works when copying a folder to a different SPWeb or SPSite.
SPList.Items only returns non-folder items. You can use SPList.Folders to iterate all of the folders in a list. So if you did the same foreach loop, only using:
foreach (SPListItem objSourceFolderItem in objSourceList.Folders)
You would then get all of the folders. To properly move the folder and all of its contents, you would use objSourceFolderItem.Folder.CopyTo(ItemUrl).
I've tried this using a list with only one level of folders (pair it with a foreach loop to get all of the items in the root folder), and it worked for me in SP2007. I believe SPList.Folders gets all of the folders in the entire list, not just the ones in the root folder, so if you end up breaking the list with a multi-level folder system, then an alternative to try might be:
foreach (SPFolder objSourceFolderItem in objSourceList.RootFolder.SubFolders)
Since those are already SPFolder objects, you can just use objSourceFolderItem.CopyTo(ItemUrl).

Resources