Sharepoint Document Library for Document Management

Document Management could get painful, especially when you are saving documents in your server. Even though storage is cheap, managing documents via Sharepoint could be a neat solution if you are using Sharepoint as some kind of a back end CMS. I did some document management using Sharepoint for one of my projects that I’d like to share. So let’s jump right in.

In order to manage documents, you will have to do these:

  • Have a DTO (a Data Transfer Object –  if necessary) to send the document information (if you are doing AJAX using jQuery or whatever)
  • Document Upload – In order to upload documents, you will need the following methods
    • Check if the folder exists – A method to check if the folder exists
    • Create Folder – Create a folder in the document library (to store documents by an Entity ID)
    • Upload File – Upload documents to a specific folder
  • Document Download – Download the specified document
  • Delete documents

DTO Definition

This is how my DTO looks –

public class MyDTO
{
public string Id { get; set; }            // ID of the document
public string Index { get; set; }         // Index of the document
public string FileName { get; set; }      // File Name
public string FileTypeIcon { get; set; }  // File Type Icon
public string CreatedOn { get; set; }     // Created On
public string FileRef { get; set; }       // Sharepoint File Reference
}

Document Upload

To upload documents, the first method we’ll look at is the CheckIfFileExists method –


/// <summary></pre>
 /// Check if a file / folder exists
 /// </summary>
 /// <param name="FilePath">File Path</param>
 /// <returns></returns>
 public bool CheckFileExists(string FilePath)
 {
 Lists lists = new Lists();
 lists.Url = ConstructServiceUrl("Lists.asmx");  // A custom method to construct Sharepoint URL eg. https://yoursharepointsite.com/_vti_bin/lists.asmx
 lists.Credentials = new System.Net.NetworkCredential("Username", "Password"); // Your Sharepoint credentials

XmlNode nodes;

 // Instantiate an XmlDocument object
 System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
 System.Xml.XmlElement query = xmlDoc.CreateElement("Query");
 System.Xml.XmlElement viewFields = xmlDoc.CreateElement("ViewFields");
 System.Xml.XmlElement queryOptions = xmlDoc.CreateElement("QueryOptions");

query.InnerXml = "<Where><Gt><FieldRef Name=\"ID\" />" +
 "<Value Type=\"Counter\">0</Value></Gt></Where>";
 viewFields.InnerXml = "<FieldRef Name=\"Title\" /><FieldRef Name=\"Description\" />";
 queryOptions.InnerXml = "<ViewAttributes Scope=\"RecursiveAll\"/>";

nodes = lists.GetListItems("UploadList", null, query, viewFields, "5", queryOptions, null); // Get List Items from the Sharepoint List Library "UploadList"

foreach (System.Xml.XmlNode node in nodes)
 {
 if (node.Name == "rs:data")
 {
 int index = 1;
 for (int i = 0; i < node.ChildNodes.Count; i++)
 {
 if (node.ChildNodes[i].Name == "z:row")
 {
 if (node.ChildNodes[i].Attributes["ows_FileRef"].Value.Split('#')[1] == FilePath)
 {
 return true;
 }
 }
 }
 }
 }
 return false;
 }
<pre>

Next, we want to create a folder to save all the documents.

</pre>
/// <summary>
 /// Creates Folder
 /// </summary>
 /// <param name="FolderPath">Folder Path</param>
 /// <returns></returns>
 public bool CreateFolder(string FolderPath)
 {
 Dws dws = new Dws();
 dws.Url = ConstructServiceUrl("Dws.asmx");  // Custom method to construct the web service URL eg: https://yoursharepointsite.com/_vti_bin/dws.asmx
 dws.Credentials = new System.Net.NetworkCredential("Username", "Password");

if (!CheckFileExists(FolderPath))
 {
 dws.CreateFolder(FolderPath);
 return true;
 }
 else
 {
 return false;
 }
 }
<pre>

Simple Isolated Storage Exploitation

Isolated Storage is nothing but a storage location in a user’s local filesystem where an application can store data. The Isolated Storage is generally exploited by web applications to store information of any kind (say application data, user data, session state etc) . The initial quota for an application is 1MB, which could be modified later by the application. The maximum limit depends on the operating system and the hard disk space.

The Isolated Storage data in Windows 7 is located in:

C:\Users\<User Profile>\AppData\Local\IsolatedStorage

 In order to use Isolated Storage in a simple Silverlight Application, consider the following steps.

  • Add the Isolated Storage library,

using System.IO.IsolatedStorage;

  • Now, we need to create a file in the Isolated Storage for storing the data, so we need to instantiate IsolatedStorageFile class and inform the application to store data in the next available memory compartment.
  • Having done that, we will need to write data into that file, so we need to instantiate IsolatedStorageFileStream class with the filename, file mode and and the IsolatedStorageFile instantiation.

Consider the following code as an example:

using System.IO.IsolatedStorage;                    // Step 1

private void SaveUserData(string UserName, string Pwd, int UserNumber)

{

var file = new XDocument(

new XElement("UserNum", UserNumber,

new XElement("UserName", UserName),

new XElement("Password", Pwd))

);

using(IsolatedStorageFile isf = new IsolatedStorageFile.GetUSerStoreForApplication())            // Step2

{

IsolatedStorageFileStream isfs=new IsolatedStorageFileStream("File1", FileMode.Append, isf);          // Step 3

file.Save(isfs);

}

}

In the above code, the GetUserStoreForApplication() method gets the next available storage location available for the application. In order to store data for the entire site, the GetUserStoreForSite() method can be used.  

The above code stores the following as a file in the isolated storage.

<UserNum>1</UserNum>

<UserName>Sample User</UserName>

<Pwd>Sample Pwd</Pwd>

Though the quota is fixed for an application initailly, it can be changed by the developer. To do that the following method is used.


long a = 2048000;

isf.IncreaseQuotaTo(a);

This increases the quota for the application to 2MB.

In order to view the quotas of different silverlight applications do the following:

  • Right click the Silverlight Application and select “Silverlight”.
  • Go to “Application Storage” and you would see somthing like this.

Advantage

  • By using the isolated storage, the application can store more data and have a better control of the stored data.
  • The data stored in localized to the user’s system.
  • 

Disadvantage

  • It gets difficult to use in applications which needs to run with lower privileges.

Nested Data Binding – Silverlight

One of the major features of Silverlight, which saves the developer a lot of coding time is DataBinding, where you can bind a UserControl to data or a collection of data. If you are still wondering how DataBinding saves time, here is an example. Consider a tree of depth say 1000. Instead of adding 1000 TreeViewItems manually, you can write few lines of code to bind your TreeView to a Collection.
I would like to add this basic example for binding a TreeView to a data source. I will also be using nested binding, wherein a DataTemplate uses another DataTemplate as ItemTemplate.
Its a best practice to add the Template (DataTemplate or HierarchicalDataTemplate) to any UserControl’s Resource which is at a higher level and at a scope of visibility to the desired control. This facilitates code re-usability by the child controls.
As an example I created this sample application, where a HierarchicalDataTemplate uses another HierarchicalDataTemplate as ItemTemplate. The simplest example I could think of was a collection of Files and Folders.

Though the idea was something like an Folder Explorer. I used a simple File and Folder collection just to show the nested binding. To make the application look like a Folder Explorer, I created a Grid with two columns containing a TreeView on the left pane and a ListBox on the right pane.

Having created controls which can contain Items, I create two HierarchicalDataTemplates; one for files and the other for the folders. To keep it simple, I use a StackPanel which holds an Image and a TextBlock which has the File / Folder’s name as its Text.

Something like this.


<common:HierarchicalDataTemplate x:Name="template2">
<StackPanel Orientation="Horizontal">
<Image x:Name="imgTemplate2" Source="Images/file-icon.png" Height="15" Width="15"></Image>
<TextBlock x:Name="txtTemplate2" Text="{Binding FileName}"></TextBlock>
</StackPanel>
</common:HierarchicalDataTemplate>
<common:HierarchicalDataTemplate x:Name="template1" ItemTemplate="{StaticResource template2}"
ItemsSource="{Binding Files}">
<StackPanel Orientation="Horizontal">
<Image x:Name="imgTemplate1" Source="Images/Open-Folder-icon.png" Height="15" Width="15">
</Image>
<TextBlock x:Name="txtTemplate1" Text="{Binding FolderName}"></TextBlock>
</StackPanel>
</common:HierarchicalDataTemplate>

Having created the HierarchicalDataTemplates for the Files and Folders which can be used as ItemsSource for TreeView, we create a HierarchicalDataTemplate for the ListBox.


<common:HierarchicalDataTemplate x:Name="template3">
<StackPanel Orientation="Horizontal">
<Image x:Name="imgTemplate3" Source="Images/file-icon.png" Height="25" Width="25"></Image>
<Text
Block x:Name="txtTemplate3" Text="{Binding FileName}"></TextBlock>
</StackPanel>
</common:HierarchicalDataTemplate>

After creating all the HierarchicalDataTemplates, we can now createthe  TreeView and ListBox and ItemsSource them to their respective HierarchicalDataTemplates

<controls:TreeView x:Name="TreeBind" ItemTemplate="{StaticResource template1}"
ItemsSource="{Binding Folders}"
SelectedItemChanged="TreeBind_SelectedItemChanged">
</controls:TreeView>
<ListBox x:Name="lstRight" Grid.Column="1" ItemTemplate="{StaticResource template3}"
ItemsSource="{Binding Folders}"
SelectionChanged="lstRight_SelectionChanged"></ListBox>

One which holds the File information and the other which holds Folder information.

public class FileInfo
{
/// <summary>
/// File Name
/// </summary>
private string _fileName;

public string FileName
{
get { return _fileName; }
set
{
if (_fileName != value)
_fileName = value;
}
}
}
public class FolderInfo
{
/// <summary>
/// FolderName
/// </summary>
private string _folderName;

public string FolderName
{
get { return _folderName; }
set
{
if (_folderName != value)
_folderName = value;
}
}

/// <summary>
/// Collection of Files inside a Folder
/// </summary>
public ObservableCollection<FileInfo> Files { get; set; }

}  After this, I create a simple method to populate the TreeView on the left pane.
/// <summary>
/// A method to populate the TreeView
/// </summary>
private void PopulateTreeView()
{
for (int i = 0; i < 10; i++)
files.Add(new FileInfo() { FileName = "File" + i });

for (int i = 0; i < 10; i++)
{
Folders.Add(new FolderInfo()
{
FolderName = "Folder" + i,
Files = files
});
}

TreeBind.ItemsSource = Folders;
}

I also create the SelectedItemChanged event for the TreeView and ListBox to make the application look like a simple Folder Explorer.


/// <summary>
/// LstRight SelectionChanged Event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void lstRight_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
FileInfo file = (FileInfo)lstRight.SelectedItem;
MessageBox.Show("You selected " + file.FileName, "Sample MessageBox", MessageBoxButton.OK);
}

/// <summary>
/// TreeBind SelectedItemChanged Event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TreeBind_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
Type tSelectedItem = TreeBind.SelectedItem.GetType();
Type tFolders = typeof(FolderInfo);
Type tFiles = typeof(FileInfo);

if (tSelectedItem == tFolders)
{
FolderInfo folder = (FolderInfo)TreeBind.SelectedItem;

lstRight.ItemsSource = folder.Files;
}

if (tSelectedItem == tFiles)
{
FileInfo file = (FileInfo) TreeBind.SelectedItem;
MessageBox.Show("You selected " + file.FileName,"Sample MessageBox",MessageBoxButton.OK);
}
}

Hope this application gives a flavor of Folder Explorer which can be used in different scenarios.   Here are few screenshots of the application.

– Aswin Ramakrishnan

A Simple WCF with Silverlight

I would like to add this basic introduction to WCF where I create a Silverlight Application hosted in a ASP.NET Web Application and a WCF Service to it.

I explain it here using Visual Studio 2008, but you may also use Visual Studio 2010.

If you don’t have Silverlight development toolkit, I would recommend the following download:

Silverlight 3 tools for Visual Studio 2008 SP1

http://www.microsoft.com/downloads/details.aspx?familyid=9442b0f2-7465-417a-88f3-5e7b5409e9dd&displaylang=en

Also, Silverlight Web Platform installer in case you haven’t done this previously.

http://www.microsoft.com/web/gallery/install.aspx?appid=silverlight4tools;silverlight4toolkit;riaservicestoolkit

Don’t forget to install the Silverlight Toolkit. You can find it here.

http://silverlight.codeplex.com/

I installed Silverlight 3 November 2009 tools for VS 2008 and think its pretty stable.

In case you find debugging errors saying you will need Silverlight Managed debugging package (I mean after installing the toolkit and the web platform installer).

Something like this.

Silverlight Managed Debugging Package Error

Try reinstalling the Silverlight Package (Visual Studio tools, SDK and Web Platform Installer or Silverlight Developer Runtime ).

Though reinstalling the Silverlight 3 stuff will provide a straight forward solution, if you find the errors coming up again. Do the following:

Download the chainer package. Go to command line and then to the directory where you downloaded the chainer.

Execute this command: silverlight_chainer.exe /x:SLChainer \Folder

The package gets extracted in the <currentDirectory>\SLChainer\Folder location.

Run the Silverlight 2.0 executable in case you have Silverlight 2.0 or less or the Silverlight SDK if you have Silverlight 2.0 installed.

Try giving a restart to the system. You should be fine.

Alright now. After the above steps, you should be good to start a Silverlight Application hosted in ASP.NET website.

Open a new project as usual.

Select Silverlight and choose Silverlight Application in the right pane

Note: If you have Silverlight 2.0, you will be able to create Silverlight Navigation Application only.

Select Host the project in a new web site. (You can also uncheck the checkbox, but you will need to run your Silverlight (SL)  Application out-of-browser in order to make the WCF service run and to avoid any Communication Exceptions.

So to keep it simple, lets start by hosting the SL Applicatoin in a new website.

Alright now. We are all set to rock and roll. :)

Now open the MainPage.xaml and create a textblock and a button inside a StackPanel.

Note: though VS2010 shows us the designer view of the SL Page, as a best practice we will write the MainPage.xaml without looking at the Designer view.

Now. This is my MainPage.xaml

<UserControl x:Class="WCFIntroduction.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<Grid x:Name="LayoutRoot">
<Grid.Background>
<LinearGradientBrush>
<GradientStop Color="Azure" Offset="0.5" />
<GradientStop Color="White" Offset="0.2" />
</LinearGradientBrush>
</Grid.Background>
<StackPanel x:Name="StackPanel">
<TextBlock x:Name="txtblock"  Text="Text" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Button Content="Click Me!" Click="btn1_Click"></Button>
</StackPanel>
</Grid>
</UserControl>

I just created a textblock control and a button control giving them appropriate names and declaring an event handler for the button’s Click event.

Now, add the WCF service to the ASP.NET Web Site by right-clicking the project and Add-> Add New Item-> Silverlight Enabled WCF Service

You can also add the regular WCF Service. It works too.

Having added the Service, I add the following code.


using System;

using System.Linq;

using System.Runtime.Serialization;

using System.ServiceModel;

using System.ServiceModel.Activation;

using System.Collections.Generic;

using System.Text;

namespace WCFIntroduction.Web

{

[ServiceContract]

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

public class WCFService

{

[OperationContract]

public string PrintTime(string txt)

{

return string.Format("The Time now is: {0}", DateTime.Now);

}

// Add more operations here and mark them with [OperationContract]

}

}

This code returns a string with a Time Stamp on it. Having created the Service, Build the solution and check for errors. When the service is error-free,  right click the service and select View in Browser. This is essential because, if you miss this step, the port for the service will not be opened and you will encounter errors while adding the service to the Silverlight Application.

If your service is good, it should look something like this when you view it in a browser.

You can click the link, and view the WSDL code for the service you added.

Now its time to add the service to the Silverlight Application. In order to do that, right-click the SL Project or the Service Reference folder and select Add Service Reference.

You should see the following dialog box.

Now click the Discover button to discover the services inside the Solution.

Note: The address in the address combo-box will be detected automatically if you view the Service in a web browser. If you find errors while discovering the solution, it means the port has not been opened for the web service. It will be resolved if you view the web service in the browser.

Having added the service, add a reference to your MainPage.xaml.cs code, and write the code to wire up the Service to the SL Application.

The basic steps to add a service to any project is :

– To instantiate the Service client you just created.

– Declare Event Handler(s) to the methods (or) Operational Contracts you created in the Service.

– Call the Async method for the event you just added.

– Define the event handler you declared previously.

The following code shows how you can wire up a service to an application (the SL Application in our case).


using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

using WCFIntroduction.ServiceReference1;

namespace WCFIntroduction

{

public partial class MainPage : UserControl

{

public MainPage()

{

InitializeComponent();

}

private void btn1_Click(object sender, EventArgs e)

{

WCFServiceClient client = new WCFServiceClient();

client.PrintTimeCompleted+=new EventHandler<PrintTimeCompletedEventArgs>(client_PrintTimeCompleted);

client.PrintTimeAsync(txtblock.Text);

}

private void client_PrintTimeCompleted(object sender, PrintTimeCompletedEventArgs e)

{

txtblock.Text = e.Result;

}

}

}

Having done this, we are all set to debug our project. After building and knowing that the code is error-free, its F5 time.
Debug and you should see something like this.
When you click the button, you should see this
You might encounter Communication Exception while debugging if you have your Silverlight Application as your Start-up project and not having it to Out-of-Browser.
In order to resolve this, set the ASP.NET Application as the Startup Project or set the Silverlight Application to work out-of-browser.
To make the SL Application work out-of-browser, right click the project, Select Properties and in the Silverlight tab, check the Enable running application out of browser.
This is the introduction to create a basic WCF Service and adding it to a Silverlight Project. Hope this post was useful.