Technical


My friend asked me that he has a document repository site in sharepoint and wants to edit the documents online.

 Much like the “edit in Microsoft Word” option of sharepoint, but he needed to do that programmatically.

Such features are available in MS Office 2007 version.So, my friend first needed to check the MS Office version of the client machine. As you know, it is very difficult to get software information of the client machine through web applications.

My friend tried various options,he checked the registry but it only returned the servers information not the clients.

After searching the net for long, the sharepoint upload page gave him a good idea.

He noticed that the “Upload multiple files” is shown in some versions and not in others. Digging deep he found the “Upload Multiple Documents” feature is an ActiveX control that installs with Office 2003/2007 so if you aren’t running either Office versions then the option won’t show up in SharePoint. This ActiveX control is called STSUpld.UploadCtl.

Now that we know which activeX control to call to check the version of office, now we need to edit the document online as it can be done through “Edit in Microsoft office word”.

After seraching the net, I found an ActiveX control that allows users to edit documents with their associated applications in the context of Microsoft Windows SharePoint Services called OpenDocuments Control.

So, in the final code, first we check whether STSUpld.UploadCtl exists or not and then we call OpenDocuments axtiveX to edit the document on the fly.

The javascript for this is shown below:

function EditDoconFly(strDocument){var objEditor;var objactivex; try{if(objactivex = new ActiveXObject(‘STSUpld.UploadCtl’)){objEditor = new ActiveXObject(‘SharePoint.OpenDocuments.1’);if(objEditor){ objEditor.EditDocument(strDocument, ”); }else{ alert(‘Cannot edit documents on fly below Microsoft Office 2007’);  }objactivex = ”;objEditor=”;}else{alert(‘Cannot edit documents on fly below Microsoft Office 2007’);}}catch(e){alert(‘Cannot edit documents on fly below Microsoft Office 2007’);} return false;} 

Advertisements

To view users in Sharepoint we have to ge to http://servername/_layouts/people.aspx. There we can see all user groups and users added to each group. Remembering this path might be easy for sharepoint developers but what about common users who want to view a report displaying all users, their email id and usergroups?

To do this, we need to do some amount of custom coding…. which is shown below.

protected void Page_Load(object sender, EventArgs e)
{
string siteUrl = SPControl.GetContextSite(Context).Url;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
string Globaltbl = string.Empty;
using (SPSite ospSite = new SPSite(siteUrl))
{
using (SPWeb site = ospSite.OpenWeb())
{
try
{
SPGroupCollection groups = site.SiteGroups;
dtUserTable.Columns.Add(new DataColumn(“Name”, typeof(string)));
dtUserTable.Columns.Add(new DataColumn(“Email”, typeof(string)));
dtUserTable.Columns.Add(new DataColumn(“Group”, typeof(string)));
Globaltbl += “<table width=’100%’ border=’0′ cellpadding=’6′ cellspacing=’4′ >”;
Globaltbl += “<tr><th align=’left’ style=’width:33%; font-family:verdana, Arial ;font-size:11px; color:#000000;’>Name</th><th align=’left’ style=’width:34%; font-family:verdana, Arial ;font-size:11px; color:#000000;’>Email</th><th align=’left’ style=’width:33%; font-family:verdana, Arial ;font-size:11px; color:#000000;’>Group Name</th></tr>”;
foreach (SPGroup grp in groups)
{

if (grp != null)
{
SPUserCollection users = grp.Users;
if (users != null)
{
if (users.Count > 0)
{
foreach (SPUser user in users)
{
Globaltbl += “<tr width=’100%’><td style=’width:33%; font-family:verdana, Arial ;font-size:11px; color:#000000;’>” + user.Name.ToString() + “</td><td style=’width:34%; font-family:verdana, Arial ;font-size:11px; color:#000000;’>” + user.Email.ToString() + “</td><td style=’width:33%; font-family:verdana, Arial ;font-size:11px; color:#000000;’>” + grp.Name.ToString() + “</td></tr>”;
DataRow temprow = dtUserTable.NewRow();
temprow[“Name”] = user.Name.ToString();
temprow[“Email”] = user.Email.ToString();
temprow[“Group”] = grp.Name.ToString();
dtUserTable.Rows.Add(temprow);
temprow = null;
}
}
}
}
}
Globaltbl += “</table>”;
Page.Controls.Add(new LiteralControl(Globaltbl.Trim()));
}
catch (Exception ex)
{
SPUtility.HandleAccessDenied(ex);
}
finally
{
site.Dispose();
ospSite.Dispose();
}
}
}
});
}

This will display the user records on the web page as:

 

 

Name Email Group Name
Gitolekha Ray gitolekha.ray@someplace.com Admin
Charles Dickens charles.dickens@someplace.com Visitor

 

  This will open a web page displaying all users in the system, their name, email address and user group. In case the user profile only contains the user id and not the name, you can write code to fetch it from the LDAP. You can also export the data to excel so that the user finds it easy to view the records.

The below code is only to show, how to export this data to excel, so that the user can view the user details exactly as shown above in excel, so the code to export to excel is shown below:

This will export the user details to excel in exactly the same format as shown above, so that the user finds it easy to search for a user and see which group he belongs to rather than remembering the complicated sharepoint url.

 
 protected void btnExport_Click(object sender, EventArgse)
{

 string defaultFileName = “UsersReport.xls”;
 Response.ClearContent();
 Response.AddHeader(“content-disposition”, “attachment;filename=”+ defaultFileName);
 Response.ContentType = “application/excel”;
 this.EnableViewState = false;
 Response.Charset = “”;
 StringWriter sw = new StringWriter();
 HtmlTextWriter hw = new HtmlTextWriter(sw);
}

 
public string CreateExcelFile(DataTable dt)
{
 SPSite site = SPContext.Current.Site;
 SPWeb web = site.OpenWeb();
 string sTableStart = “<HTML><BODY><TABLE Border=1>”;
 string sTableEnd = “</TABLE></BODY></HTML>”;
 string sTHead = “<TR>”;
 StringBuilder sTableData = new StringBuilder();
  try
  {

  sTHead += “<th scope=’col’>Name</th><th scope=’col’>Email</th><th scope=’col’>Group   Name</th></tr>”;
    foreach (DataRow row in dt.Rows)
    {
 sTableData.Append(“<TR>”);
 sTableData.Append(“<TD>” + row[“Name”] + “</TD>”);
 sTableData.Append(“<TD>” + row[“Email”] + “</TD>”);
 sTableData.Append(“<TD>” + row[“Group”] + “</TD>”);
  sTableData.Append(“</TR>”);
    }
  }
  catch (Exception ex)
  {
 throw ex;
  }
  finally
  {
 site.Close();
 site.Dispose();
 web.Close();
 web.Dispose();
  }
  string sTable = sTableStart + sTHead + sTableData.ToString() + sTableEnd;
  return sTable;
}

This will open the excel file in exactly the same format as the web page appears.

I was getting the Access Denied page when I tried to access the UsersCollection of a SPGroup Instance or SiteGroups of SPWeb object.
I used RunWithElevatedPrivileges to be able to access the users collection but all in vein.
After searching through the net, I found that all code should be inside elevated priviledge, because if we access SiteGroups from a SPWeb object that was created prior to using elevated priviledge, the problem would still sustain.

So, I changed my code to define the objects inside elevated priviledges like:

SPSecurity.SPWeb (delegate()
{       SPSite ospSite = SPContext.Current.Site;
        SPWeb site = ospSite.OpenWeb();
……code to access users
}

The code was still giving errors because Context, SPContext or SPControl.GetWebContext, etc. cannot be used inside elevated privileges. The reason is that Context object is created before the code with elevated privileges is executed.

So, the change will be:

 string siteUrl = SPControl.GetContextSite(Context).Url;
        SPSecurity.RunWithElevatedPrivileges(delegate()
  {
        string Globaltbl = string.Empty;
        using (SPSite ospSite = new SPSite(siteUrl))
        {
            using (SPWeb oWeb = ospSite.OpenWeb())
            {
                    SPGroupCollection groups = oWeb.SiteGroups;  
                    foreach (SPGroup grp in groups)
                    {
                        SPUserCollection users = grp.Users;
                        if (users != null)
                        {
                            foreach (SPUser user in users)
                            {
                                //MyCode//
                            }
                        }
                    }
}
}
});

And Voila! everything works just fine.

One of my friends asked me how to sort a xml file which is deserialized and put into a treeview.
The xml lookes something like the one shown below:

  <?xml version=”1.0″ encoding=”us-ascii” ?>
– <TreeView>
– <node text=”Topics”>
  <node text=”Animal Health” /> 
– <node text=”Tools”>
– <node text=”Corporate”>
   <node text=”knowledge management” />
   <node text=”Media relations” />
   <node text=”Agency management” />
   <node text=”Messaging” />
   <node text=”Communications planning” />
   <node text=”Newsflow” />
  </node>
  </node>
  </node>
  </node>
  </TreeView>

As you can see the xml dosen’t look sorted, So in order to sort it alphabetically, xsl may be the
easiest route. Here’s the transform to sort alphabetically:

<?xml version=”1.0″ encoding=”us-ascii” ?>
<xsl:stylesheet version=”1.0″ xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” xmlns:fo=”http://www.w3.org/1999/XSL/Format“>
<xsl:template match=”node”>
            <xsl:copy>
                  <xsl:copy-of select=”@*”/>
<xsl:apply-templates select=”node”>
      <xsl:sort select=”@text”/>
</xsl:apply-templates>
 </xsl:copy>
      </xsl:template>
</xsl:stylesheet>

Now, we can use XSL Transform to Transform the XML data using the loaded XSLT stylesheet. See the Code Below

string strSortFile = @”C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\sort.xsl”;
string filename = @”C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\BizFocus.xml”;
XmlDocument doc = new XmlDocument();
doc.Load(fileName);
MemoryStream sstream = new MemoryStream();
// Modify the XML file.
XmlElement root = doc.DocumentElement;
// Create an XPathNavigator to use for the transform.
XPathNavigator nav = root.CreateNavigator();
// Transform the file.
System.Xml.Xsl.XslTransform xtr = new System.Xml.Xsl.XslTransform();
xtr.Load(strSortFile);
//XmlTextWriter writer = new XmlTextWriter(fileName, null);
XmlTextWriter writer1 = new XmlTextWriter(sstream, null);
xtr.Transform(nav, null, writer1, null);
XmlTextReader reader = null;
sstream.Position = 0;

/*Insert Logic to add node to treeview from XMLTextReader*/
You might get the error ‘Root element is Missing’, but do not worry, it isn’t a problem with the input file or the transform script. The problem is that the XslTransform.Transform function leaves the stream position set to the end of the stream. There’s no root element because the XmlDocument.Load function thinks the stream has a 0 byte length. The fix is to simply set the position to 0.

Ever thought of creating files on the fly (say by typing contents  in a textbox) and saving them to the document library? refer to my previous post https://techolyvia.wordpress.com/2009/01/13/how-to-create-files-dynamically-and-save-that-in-document-library/ which talks about this.

Now, if we want to edit the uploaded data, we need to read the content from the document library and show the content in the textbox. So, how do we do that? See the code below:

SPSite ospSite = SPContext.Current.Site;
SPWeb ospWeb = ospSite.OpenWeb();
/*docPath returns the url of the file as sharepoint url/document library/filename*/
string docPath = Request.QueryString[“Path”];
SPFile tempFile = ospWeb.GetFile(docPath);
/*OpenBinaryStream() opens the file as a stream*/
StreamReader reader = new StreamReader(tempFile.OpenBinaryStream());
/*txtUpload is the textbox control where we insert the value of the text file*/
txtUploadText.Text = reader.ReadToEnd();
reader.Close();

So, we use StreamReader to read the content of the text file in document library and display the content in a Multiline Textbox, so that the user can  edit the content of the textfile.

For details refer to http://www.dotnetspider.com/forum/189095-Read-file-content-from-document-library-write-textbox.aspx

The other day, I was working on how to create files on the fly(dynamically create any file of any extension like .doc, .txt etc.). To do this, we will first have to provide an editor like rich text box where the user can type in something and when he saves,a dynamic file is created which is saved in the document library.
I used a FCK editor in this case.

I intended to save other meta data along with the file in the document library(will talk about it later in this article).

string strRTFFileName = string.Empty;
SPList ospList = null;
Hashtable metadataTable = new Hashtable();
MemoryStream mstream = new MemoryStream();
Stream stream = null;
SPWeb ospWeb = ospSite.OpenWeb();
string strReader = string.Empty;
SPWeb sourceWeb = SPContext.Current.Web;
string sourceList = “Brochure”; //Name of Document library to save file.
SPList sourceListObj = sourceWeb.Lists[sourceList];

//Declare a streamwriter and output it’s value to memory stream
StreamWriter sw = new StreamWriter(mstream);
//FCKeditor1 is name of the FCK Editor.
sw.Write(FCKeditor1.Value);
// Creating file name dynamically based on datetime value

strRTFFileName = string.Format(“text-{0:yyyy-MM-dd_hh-mm-ss-tt}.rtf”, DateTime.Now);
string pattern = “[^a-z0-9A-Z. ]”;
Regex objRegex = new Regex(pattern);
strRTFFileName = objRegex.Replace(strRTFFileName, “”);

// End of dynamic file name creation

// On flushing StreamWriter, value is copied to memorystream.
sw.Flush();
byte[] contents = new byte[mstream.Length];
mstream.Read(contents, 0, (int)mstream.Length);

ospWeb.AllowUnsafeUpdates = true;
sourceItem = sourceWeb.Files.Add(sourceWeb.Url + “/” + sourceListObj.RootFolder.ToString() + “/” + strRTFFileName, mstream, true);
mstream.Close();
ospWeb.AllowUnsafeUpdates

Once my colleague was getting an error “The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again” while trying to move documents from one document library to another document library.

His piece of code was,

public void MoveDocument(string filePath,string destinationList)
{
try
{
SPWeb ospWeb = SPContext.Current.Web;
SPList destList = ospWeb.Lists[destinationList];
SPFile ospFile = ospWeb.GetFile(filePath);
ospFile.MoveTo(ospWeb.Url + "/" + destList.RootFolder + "/" + ospFile.Name);
}
catch (Exception ex)
{
throw ex;
}
}

After some amount of searching in the net, it was found that the error is caused due the security validation in sharepoint. So, there should be a method we turn  off the security validation:

One method to turn off security validation is,
Central Administration—>application management—->web application general settings–>”turn security validation off”

but,it is dangerous to do….as it could potentially leave your site open to malicious code.

Ideally, the security validation should be turned off only long enough for your own code to execute and should be turned back on again as soon as the code finishes execution.

So, the code needs to be recoded as,
public void MoveDocument(string filePath,string destinationList)
{
try
{
SPWeb ospWeb = SPContext.Current.Web;
Microsoft.SharePoint.Administration.SPWebApplication webApp = ospWeb.Site.WebApplication;
webApp.FormDigestSettings.Enabled = false;
SPList destList = ospWeb.Lists[destinationList];
SPFile ospFile = ospWeb.GetFile(filePath);
ospFile.MoveTo(ospWeb.Url + “/” + destList.RootFolder + “/” + ospFile.Name);
webApp.FormDigestSettings.Enabled = true;
}
catch (Exception ex)
{
throw ex;
}
}

« Previous PageNext Page »