Take the 2-minute tour ×
SharePoint Stack Exchange is a question and answer site for SharePoint enthusiasts. It's 100% free, no registration required.

I Made an application to download a folder from a given sharepoint site, but its consuming memory above 600,000K once i click on Connect button, anyone can give suggestion to improve my code ?

I Tried to debug my form and problem is coming at method " private void MapWebs(SPWebCollection webList, TreeNode webparentNode)" where its calling itself again and again to go through each single web and its sub web, however I checked in the start when i click on connect and it goes through code line

using (SPSite CurrentSite = new SPSite(tbSite.Text)) The memory usage goes from 20,000 K to 40,000 K (approx)

In order to run this application you must have sharepoint installed on yur PC, an example of this type of app is on this link ,

enter link description here

    using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.SharePoint;
using System.IO;

namespace WindowsFormsApplication3
{
    public partial class MainWindow : Form
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    //Connects to Sharepoint site provided and populates Webs and Subwebs and subwebs....
    private void bConnect_Click(object sender, EventArgs e)
    {
            //Getting current site
            using (SPSite CurrentSite = new SPSite(tbSite.Text))
            {
                //Opening TopLevel Web for Site given
                using (SPWeb TopLevelWeb = CurrentSite.OpenWeb())
                {
                    //Clearing all the nodes in TreeWeb
                    TreeWeb.Nodes.Clear();
                    //Creating a root (First Node for webtree) which will be Top Level web's title
                    TreeNode rootWebNode = new TreeNode(TopLevelWeb.Title);
                    //Giving node a tag, which will be used later on in order to get value of node
                    rootWebNode.Tag = TopLevelWeb;
                    //Check if Top Level Web got any Sub webs if it does, it will create a new node for them
                    //Calls Map Webs to check for more sub webs + mapping them on webtree as nodes
                    foreach (SPWeb CurrentWeb in TopLevelWeb.Webs)
                    {
                        try
                        {
                            TreeNode webNode = new TreeNode(CurrentWeb.Title);
                            webNode.Tag = CurrentWeb;
                            MapWebs(CurrentWeb.Webs, webNode);
                            TreeWeb.Nodes.Add(webNode);
                        }
                        finally 
                        {
                            if (CurrentWeb != null)
                                CurrentWeb.Dispose();
                        }
                    }
                }
            }
        }

    // Maps Webs and there sub webs on webtree
    private void MapWebs(SPWebCollection webList, TreeNode webparentNode)
    {
            for (var i = 0; i < webList.Count; i++)
            {
                TreeNode node = new TreeNode(webList[i].Name);

                using (SPWeb web = webList[i])
                {
                node.Tag = webList[i];
                    webparentNode.Nodes.Add(node);
                    if (webList[i].Webs.Count > 0)
                        MapWebs(webList[i].Webs, node);
                }
            }
            GC.Collect();
    }

    //when the form loads it clears the list and create new cloumns to be used
    private void MainWindow_Load(object sender, EventArgs e)
    {
        bFolder.Enabled = false;
        bConnect.Enabled = false;
        lvFiles.GridLines = true;
        lvFiles.View = View.Details;
        lvFiles.Columns.Add("Name", lvFiles.Width/4, HorizontalAlignment.Left);
        lvFiles.Columns.Add("Date Created", lvFiles.Width/3, HorizontalAlignment.Left);
        lvFiles.Columns.Add("Size", lvFiles.Width / 5, HorizontalAlignment.Left);
        lvFiles.Columns.Add("Time Last Modified", lvFiles.Width / 5, HorizontalAlignment.Left);
        if (lvFiles.View == View.Details && lvFiles.Columns.Count > 0)
            this.Width = lvFiles.Columns.Count * (lvFiles.Width / 2);
        lvFiles.Columns[lvFiles.Columns.Count - 1].Width = -2;
    }

    //creates directory for downloading folder
    private bool CreateDirectoryStructure(string baseFolder, string filepath)
    {
        if (!Directory.Exists(baseFolder)) return false;

        var paths = filepath.Split('/');

        for (var i = 0; i < paths.Length - 1; i++)
        {
            baseFolder = System.IO.Path.Combine(baseFolder, paths[i]);
            Directory.CreateDirectory(baseFolder);
        }
        return true;
    }

    //opens an dialog box for selecting path where selected folder will be downloaded
    private void bBrowse_Click(object sender, EventArgs e)
    {
        if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
        {
            this.tbDirectory.Text = folderBrowserDialog1.SelectedPath;
        }
    }

    //when a node is selected in webtree it checks for folders in it , + sub folders + folders......
    private void TreeWeb_AfterSelect(object sender, TreeViewEventArgs e)
    {
        TreeFolder.Nodes.Clear();
        TreeNode currentNode = TreeWeb.SelectedNode;
        using (SPWeb oWeb = (SPWeb)currentNode.Tag)
        {
            foreach (SPList list in oWeb.Lists)
            {
                if (list is SPDocumentLibrary && !list.Hidden)
                {
                    TreeNode folderNode = new TreeNode(list.Title);
                    folderNode.Text = string.Format("{0} ({1})", list.Title, list.ItemCount);
                    folderNode.Tag = list.RootFolder;

                    foreach (SPListItem listItem in list.Folders)
                    {
                        if (listItem.Folder != null)
                        {
                            TreeNode node = new TreeNode(listItem.Folder.Name);
                            node.Tag = listItem.Folder;
                            node.Text = string.Format("{0} ({1})", listItem.Folder.Name,
                                                 GetFilesCount(listItem.Folder));

                            MapFolders(listItem.Folder.SubFolders, node);
                            folderNode.Nodes.Add(node);
                        }
                    }

                    TreeFolder.Nodes.Add(folderNode);
                }
            }
        }
    }

//Maps folder on foldertree
private void MapFolders(SPFolderCollection folderList, TreeNode parentNode)
{
    for (var i = 0; i < folderList.Count; i++)
    {
            TreeNode node = new TreeNode(folderList[i].Name);
            node.Text = string.Format("{0} ({1})", folderList[i].Name,
                                         GetFilesCount(folderList[i]));
            node.Tag = folderList[i];
            parentNode.Nodes.Add(node);

            if (folderList[i].SubFolders.Count > 0)
                MapFolders(folderList[i].SubFolders, node);
    }
}

//Maps files in a folder to listview
private void TreeFolder_AfterSelect(object sender, TreeViewEventArgs e)
{
    lvFiles.Items.Clear();
    TreeNode currentNode = TreeFolder.SelectedNode;
    //if (currentNode != rotnode)
    //{
    double TotalSize = 0;
    SPFolder oFolder = (SPFolder)currentNode.Tag;
    foreach (SPFile oFile in oFolder.Files)
        {
            TotalSize += (oFile.Length)/1024/1024;

            ListViewItem LTI = new ListViewItem(oFile.Name.ToString());
            LTI.SubItems.Add(oFile.TimeCreated.ToString());
            LTI.SubItems.Add(oFile.Length.ToString());
            LTI.SubItems.Add(oFile.TimeLastModified.ToString());
            lvFiles.Items.Add(LTI);
        }
        label4.Text = TotalSize.ToString();
    //}
}

//download selected folder + validation
private void bFolder_Click(object sender, EventArgs e)
{
        TreeNode currentNode = TreeFolder.SelectedNode;
            SPFolder oFolder = (SPFolder)currentNode.Tag;
            foreach (SPFile file in oFolder.Files)
            {
                if (CreateDirectoryStructure(tbDirectory.Text, file.Url))
                {
                    var filepath = System.IO.Path.Combine(tbDirectory.Text, file.Url);
                    byte[] binFile = file.OpenBinary();
                    System.IO.FileStream fstream = System.IO.File.Create(filepath);
                    fstream.Write(binFile, 0, binFile.Length);
                    fstream.Close();
                }
            }
}

//calculates files in selected folder
private int GetFilesCount(SPFolder folder)
{
    int fileCount = folder.Files.Count;
    foreach (SPFolder subfolder in folder.SubFolders)
    {
        fileCount += GetFilesCount(subfolder);
    }
    return fileCount;
}

//validation
private void tbSite_TextChanged(object sender, EventArgs e)
{
    if (tbSite.Text != "")
        bConnect.Enabled = true;
    else
        bConnect.Enabled = false;
}

//validation
private void tbDirectory_TextChanged(object sender, EventArgs e)
{
    if (tbDirectory.Text != "" && TreeFolder.Nodes.Count != 0)
        bFolder.Enabled = true;
    else
        bFolder.Enabled = false;
    }
}

Already checked with SP Dispose checker but it says this (at MapWebs method line "node.tag = weblist[i]... and if statement")

Notes: Call to Microsoft.SharePoint.SPWebCollection.get_Item and no variable to catch return value More Information: http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss-3-0-dispose-patterns-by-example.aspx#SPDisposeCheckID_130

share|improve this question
add comment

3 Answers

You're using the SharePoint Object Model. To use that, it has to load those DLLs - like Microsoft.SharePoint.dll - and some of the other assemblies that relate to them. That's quite big, and that's why you're seeing so much memory usage.

Options would be:

  1. live with it,
  2. change your code to use the client object model (which is smaller, and would mean your program could be run on machines other than the server - though the API is more limited)
  3. put all of your code in other assembly, and load and execute that in it's own AppDomain. Once you're done, you can unload your AppDomain, and that will return your memory.

Otherwise, yes, using the SharePoint server API does load around 60Mb of stuff, even if you're just loading an SPSite.

share|improve this answer
    
if you can provide me any links or tutorial for putting all code in an other assembly would be great as i couldn't find any tutorial. cheers –  sds Dec 26 '11 at 10:16
add comment

Honestly, I would say that the entire approach is wrong from the ground up. Almost nobody has SharePoint installed on their machine so having that as a requirement is oppressive to start with. It is also very limiting because you can then only access data in the SharePoint installed locally. If you wanted data from a dev or qa site you would be out of luck.

Rather than using this, why don't you just leverage the SharePoint Web Services and pull down the data you need on demand? That is what they are there for.

However, if you are set on this implementation then I would recommend only storing your own objects on the .Tag property. The SharePoint objects are enormous and storing those will take a huge amount of memory depending on the size of your site collection. And, as Ashish rightly points out, it also can cause issues with object disposal.

share|improve this answer
    
Can you provide of any link to tutorial or something as i couldn;t find anything related to what i want to do using webservices, as most examples i find are webservices being used in an ASP.Net page not win forms. CHeers –  sds Dec 26 '11 at 10:14
    
The mechanics of calling a web service in .Net are the same in ASP.Net as they are in WinForms. The only difference would be in how the resulting content is presented. This might help: blogs.msdn.com/b/steve_fox/archive/2009/02/08/… –  Dave Wise Dec 27 '11 at 15:12
add comment

I think you need to avoid code that prevents sharepoint objects from disposing. For example, storing entire SPWeb as tag of the tree node. now tree node has same life as your application so I think it might keep reference of SPWeb objects. Instead, you could define a data structure that contains important and only desired properties of SPWeb objects like id, url, title etc. and assign that data structure to tag property. You may want to apply this guideline elsewhere.

Let me know the results after the change.

share|improve this answer
1  
I would agree with other users above that you should probably look for alternatives like client side object model or web services (they are used internally by client side object model) –  Ashish Patel Dec 23 '11 at 18:29
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.