Sunday, March 27, 2011

Upload files to SharePoint 2007 from Network Share


To upload files to SharePoint document library from a network share we need to create a SharePoint timer job. I was written a SharePoint timer job which iterates through all the folders of the network share and uploads all the files present in the folders to a SharePoint document library. For your convenience of debugging I will be posting a console application code below. Once you feel everything is working as expected please convert it to a SharePoint timer Job.
namespace CopyDocumentsFromSharedFolderToSharePoint {
class Program
{
const string NetworkPath = "\\\\ServerName\\Reports";
const string SharePointPath = "http://SiteAddress/sites/Reports/Staging Reports/TEST/";
const double maxFileSize = 52428800;//50MB in Bytes 50*1024*1024
static void Main(string[] args)
{
ProcessFolder(NetworkPath);
Console.ReadKey();
}
private static void ProcessFolder(string startingPath)
{
int iterator = 0;
List<string> dirList = new List<string>();
dirList.Add(startingPath);
string parentFolder = startingPath;
// Every new folder found is added to the list to be searched. Continue until we have
// found, and reported on, every folder
while (iterator < dirList.Count)
{
parentFolder = dirList[iterator]; // Each FileTreeEntry wants to know who its parent is
try
{
foreach (string dir in Directory.GetDirectories(dirList[iterator]))
{
dirList.Add(dir);
}
foreach (string filename in Directory.GetFiles(dirList[iterator]))
{
FileInfo file = new FileInfo(filename);
int returnCode = validateFileUploadToSharePoint(file);
if (returnCode == 0)
{
UploadFileToSharePoint(filename, (SharePointPath + file.Name));
}
Console.WriteLine(file.Name);
}
}
// There are two *acceptable* exceptions that we may see, but should not consider fatal
catch (UnauthorizedAccessException ex1)
{
}
catch (PathTooLongException ex2)
{
}
catch (DirectoryNotFoundException ex3)
{
}
catch (Exception ex4)
{
}
iterator++;
}
}
private static int validateFileUploadToSharePoint(FileInfo file)
{
//ensure folder path exists
//Check if file size exceeds 50MB
if (file.Length > maxFileSize)
{
//file length is greater then 50MB
return 2;
}
return 0;
}
protected static void UploadFileToSharePoint(string UploadedFilePath,string SharePointPath)
{
WebResponse response = null;
try
{
// Create a PUT Web request to upload the file.
WebRequest request = WebRequest.Create(SharePointPath);
request.Credentials = CredentialCache.DefaultCredentials;
request.Method = "PUT";
// Allocate a 1 KB buffer to transfer the file contents.
// You can adjust the buffer size as needed, depending on
// the number and size of files being uploaded.
byte[] buffer = new byte[1024];
// Write the contents of the local file to the
// request stream.
using (Stream stream = request.GetRequestStream())
using (FileStream fsWorkbook = File.Open(UploadedFilePath,FileMode.Open, FileAccess.Read))
{
int i = fsWorkbook.Read(buffer, 0, buffer.Length);
while (i > 0)
{
stream.Write(buffer, 0, i);
i = fsWorkbook.Read(buffer, 0, buffer.Length);
}
}
// Make the PUT request.
response = request.GetResponse();
File.Delete(UploadedFilePath);
}
catch (Exception ex)
{
throw ex;
}
finally
{
response.Close();
}
}
}
}
References:
http://www.scottleckie.com/2009/07/iterating-through-a-bunch-of-folders-and-files/
http://blogs.msdn.com/b/erikaehrli/archive/2009/06/30/how-to-upload-files-to-sharepoint-server-2007-from-asp-net-web-applications.aspx
http://msdn.microsoft.com/en-us/library/dd902097.aspx

Best Object Model Coding Practices for SharePoint 2007


I was working on performance tuning a SharePoint 2007 application and these are the common bad coding practices which developers make unintentionally.
Never Use SPList.Items.GetItemById(ID):
Refer this link for further details
http://www.3guysonsharepoint.com/?p=197
SPWeb.EnsureUser Vs. SpWeb.AllUsers:
The best way to check if the user exists / have access to the site / web is this way.
SPWeb.AllowUnsafeUpdates = true;
SPUser user = webInUserContext.EnsureUser("ad\\C001234");
SPWeb.AllowUnsafeUpdates = false;
Don't forget to use AllowUnsafeUpdates if the logged in user only has read/contribute permissions, otherwise you will get "Access Denied". It is not necessary to use AllowUnsafeUpdates if you are running code with elevated privileges or impersonation.
http://blog.qumsieh.ca/2008/06/26/spweb-siteusers-vs-spweb-users/
This is not a good way.
SPUser user = webInUserContext.AllUsers["ad\\C001234"];
Windows SharePoint Services 3.0 SDK
SPWeb.AllUsers – Gets the collection of user objects that represents all users who are either members of the site or who have browsed to the site as authenticated members of a domain group in the site.
SPWeb.SiteUsers – Gets the collection of all users that belong to the site collection.
SPWeb.Users – Gets the collection of user objects that are explicitly assigned permissions on the Web site.
SPWeb.EnsureUser - Checks whether the specified login name belongs to a valid user of the website, and if the login name does not already exist, adds it to the website.
Best way of Accessing SharePoint Groups:
I think this is the best way of accessing SharePoint groups if we know the name of the group.
SPGroupCollection groupColl = newWeb.SiteGroups.GetCollection(new String[] { "Readers", "Contributers" });
This one gets SharePoint groups only which you want where as below one gets all the SharePoint Groups
SPGroupCollection groupColl = newWeb.SiteGroups;
Efficient way of adding list item to SharePoint list:
Refer the link below
http://msdn.microsoft.com/en-us/library/bb687949(office.12).aspx
public static class Extensions
{ /*efficient way of adding list item to SharePoint list
* http://msdn.microsoft.com/en-us/library/bb687949(office.12).aspx */
public static SPListItem AddItem(this SPList list)
{
const string EmptyQuery = "0";
SPQuery q = new SPQuery { Query = EmptyQuery };
return list.GetItems(q).Add();
}
}
Usage…
SPListItem item = list.AddItem();
List item query elapsed time:
I got this message in the SharePoint ULS log.
01/21/2011 10:30:02.00 w3wp.exe (0x1320) 0x1944 Windows SharePoint Services Database 8sli Monitorable List item query elapsed time: 4508 milliseconds, Additional data (if available): Query HRESULT: 0 List internal name, flags, and URL: {A134D627-5580-49FD-883C-9D1325CE6CD3}, flags=0x0000000020801088, URL="http://SiteURL/Lists/Tickets/AllItems.aspx" Query XML: "<Query><OrderBy><FieldRef Name="Modified" Ascending="FALSE"/></OrderBy></Query>" SQL Query: " SELECT TOP 101 t1.[Type] AS …….
I was wondering what this message in the SharePoint ULS log means, finally figured out that this message is logged whenever we try to load a SharePoint List View which has large number of rows and which does not use default view sorting order (List Item ID)
I our case our SharePoint List had 1,000,00 rows in it and the AllItems View is being sorted by Last modified descending.
Select Distinct or Unique values from SharePoint List column:
Refer the link below
http://blog.visualstudioteamsystem.com/post.aspx?item=33
if (web.ServerRelativeUrl == "/")
{
ticketsList = (SPList)web.GetList(ticketsListURL);
}
else
{

ticketsList = (SPList)web.GetList(string.Concat(web.ServerRelativeUrl, ticketsListURL));
}
SPField field = ticketsList.Fields.GetFieldByInternalName("CreatedByHistorical");
object[,] values;
uint numberValues = ticketsList.GetDistinctFieldValues(field, out values);
for (int i = 0; i < numberValues; i++)
dropDownListEnterers.Items.Add(values.GetValue(0, i).ToString());

Wednesday, January 12, 2011

Locks / Critical Sections in Multi – WFE Environment

While we are dealing Deadlocks in SharePoint 2007 case which I have blogged here
http://bharatreddybasani.blogspot.com/2010/10/deadlocks-in-sharepoint-2007_29.html
with Microsoft, One of the Microsoft representative made this statement regarding placing Locks / Critical sections in multi-WFE environments.
In multi-WFE env, this lock may not work properly, because the objLock is different instance on each WFE.
I was surprised to learn about it. I do not have a solid proof to prove the above statement. To eliminate transactions being deadlocked in multi - Web front end environments, this was the workaround given by Microsoft representative. Below statement is in the context of SharePoint.

Another portion of the workaround that you may not be familiar with is to add a property key/value pair in the SPWeb object so that the values can be queried from all servers. It is actually quite easy to use it and you can see it from here. http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spweb.allproperties.aspx. On another note, you do not have to use the SPWeb property bag to store the value. You can also use a SharePoint list at the root site level to contain both the flag and URLs mentioned in the steps below. Or you can also use a custom DB to store those. All in all, there are several options for storing these values, you can choose the one that fits your need the best.