I was trying to create a table and add rows and cells in it using c#.

And tried to hyperlink in a tablecell, tried to add styles in the hyperlink without touching the css class and open the hyperlink popup via navigateurl in a new window.

putting hyperlink on tablecell:

TableRow tr = new TableRow();
TableCell td = new TableCell();
HyperLink hyper1 = new HyperLink();
hyper1.NavigateUrl = “http://techolyvia.wordpress.com/category/technical/sharepoint/spgroup/”;
hyper1.Text = “SPGroup”;
td.Controls.Add(hyper1);
tr.Cells.Add(td);
tableOuterCtrl.Rows.Add(tr);

Using navigateurl to open in a new window:

hyper1.Target = “_blank”;

Add styles in hyperlink without modifying css classes.

hyper1.Style.Add(”font”, “normal 8pt Verdana;”);
hyper1.Style.Add(”color”, “black”);

full code goes like this:
tableOuterCtrl = new Table();
tableOuterCtrl.CellPadding = 0;
tableOuterCtrl.CellSpacing = 0;
Controls.Add(tableOuterCtrl);
TableRow tr;
TableCell td;
tr = new TableRow();
tr.Width = Unit.Percentage(100);
tableOuterCtrl.Rows.Add(tr);
td = new TableCell();
HyperLink hyper1 = new HyperLink();
td.Wrap = false;
td.Width = Unit.Percentage(100);
hyper1.Style.Add(”font”, “normal 8pt Verdana;”);
hyper1.Style.Add(”color”, “black”);
hyper1.NavigateUrl = “http://techolyvia.wordpress.com/2009/03/31/report-to-show-all-users-and-user-groups-in-sharepoint-site/”;
hyper1.Target = “_blank”;
hyper1.Text = “Displaying all users and groups through coding”;
td.Controls.Add(hyper1);
tr.Cells.Add(td);
tableOuterCtrl.Rows.Add(tr);
this.Controls.Add(tableOuterCtrl);

An user might want to email an url like the one given below:
http://gitolekha:82/default.aspx?ConnectSearch=good sharepoint blog

We need to do url encoding to send such links because often url’s contain characters outside the ASCII set, so URL encoding converts the url to valid ASCII sets.URL encoding replaces unsafe ASCII characters with “%” followed by two hexadecimal digits corresponding to the character values in the ISO-8859-1 character-set.

URLs cannot contain spaces. URL encoding normally replaces a space with a + sign or as %20.

To do url encoding with .NET,one usually uses System.WebHttpUtility.UrlEncode to encode the querystring.

I had to do this through javascript.There are methods like
escape(string) to do encoding, but it did not work for me.
So, what I chose is the replace mothod to replace all unsafe characters.
what I used is regular expression to replace all occurences of space in  string “good sharepoint blog” as encodestring.replace(/\\s+/g ,’$-*’);

A detailed explaination of the above is as follows,
/ = start pattern
, = pattern to look for in the string badtext
/ = end pattern
g = global (anywhere the pattern match occurs in the string)
“$-*” = what to replace the pattern with if found

So, the full code to send the encoded url in email is given below.

parent.location = ‘mailto:?body=” + HttpUtility.UrlEncode(SPContext.Current.Web.Url + “/default.aspx?ConnectSearch=”) + “‘+txtSearch.value.replace(/\\s+/g ,’$-*’)+’~-~User=’+txtTopicsSearch.value.replace(/\\s+/g ,’$-*’)+’~-~Place=’+txtDocTypeSearch.value.replace(/\\s+/g ,’$-*’)+’~-~Country=’+txtCountrySearch.value.replace(/\\s+/g ,’$-*’)+’&subject=site search link’

The mail has a subject line of ’site search link’ as seen above.

This emails the encoded url as,
http://gitolekha:82/default.aspx?ConnectSearch=good$-*sharepoint$-*blog~-~User=gitolekha~-~Place=any$-*where/$-*in$-*India~-~Country=All$-*geographic$-*scopes

Now when the user types/paste the above url in the browser, we can use httphandler to make the application decode the above url in the desired format.
Now, we know that an ASP.NET HTTP handler is the process that runs in response to a request that is made to an ASP.NET Web application. When users request an .aspx file, the request is processed by the page handler.An IHttpModule is registered in the Web.Config file and it is notified of every HTTP request.
IHttpModule is an interface defined in System.Web.dll. The interface contains only two method signatures: Init and Dispose. On the Init method wire up, the behavior—for example application events—that you want the IHttpModule to support and perform any clean up in the Dispose method.

using System.Web;
namespace Gitolekha.Sample.KnowledgeManagement
{
class CustomHandler : IHttpModule
{
public void Dispose()
{
//throw new Exception(”The method or operation is not implemented.”);
}
public void Init(HttpApplication context)
{
context.BeginRequest+=new EventHandler(context_BeginRequest);
}
public void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
string requestedPage = app.Request.RawUrl;
if (requestedPage.Contains(”?ConnectSearch=”))
{
string strurl = app.Request.Url.AbsoluteUri;
if (strurl .Contains(”$-*”))
{
strurl = strurl.Replace(”$-*”, ” “);
}
if (strurl.Contains(”~-~”))
{
strurl = strurl.Replace(”~-~”, “&”);
}
string strencode = HttpUtility.UrlEncode(strurl );
HttpContext.Current.Response.Redirect(strurl, true);
}}

This will do the required decoding for this url.
Possible scenarios/reasons for users wanting to send url might be Sometimes it is easy for users to email interesting links of a site to another user.To elaborate, suppose you have a document management system where the users like to share interesting and important links of documents to other users through emails.

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 http://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

One of my colleague was using a treeview. He was not able to get the value of the node selected in a checkbox,the nodes were rendering in a td,say the name of the node is Apple and name of the treeview is tview :-

<td><div style=”width:20px;height:1px”></div></td><td><a id=”tviewn1″ href=”javascript:TreeView_ToggleNode(tview_Data,1,tviewn1,’ ‘,tviewn1Nodes)”><img  alt=”Expand Apple” style=”border-width:0;” /></a></td><td style=”white-space:nowrap;”><input type=”checkbox” name=”tviewn1CheckBox” id=”tviewn1CheckBox” /><span class=”tview_0″ id=”tviewt1″>Apple</span></td>

The javascript to get the node name in this case will be :-

function getSelectedNodeValue()
{
var storeTemp = ”;
var x=document.getElementsByTagName(”td”);
for(var i=0;i
{
var srch=x[i].innerHTML;
if(srch.search(’CHECKED’)>=0)
{/storeTemp += x[i].innerText + ‘,’; }
}
storeTemp = storeTemp.substring(0,storeTemp.lastIndexOf(’,'));
}

Refer to http://www.dotnetspider.com/resources/24242-how-get-value-selected-node-treeview.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;
}
}

We often see sites which has a text box with some default value, mostly in grey and when we click inside the textbox, the default value disappears and we can type in, similarly if we click elsewhere in the page the default value again re-appears.

This can be achieved very simply using javascript where we display the default data on onblur event and it disappears on onfocus event, see the illustration below:

Suppose I have a html textbox as follows,

<input id=”txtBizFocus” runat=”server” name=”txtBizFocus” autocomplete=”off” type=”text”  enableviewstate=”true”/>

 Now, I have to check whether txtBizFocus is empty or not, if it is empty include the default value in grey color. Now, if the user clicks inside the textbox txtBizFocus, the default value should disappear and the user should be able to type inside in font-color black.

 if (txtBizFocus.Value == “”)

txtBizFocus.Value = “<type here or select>”;

if (txtBizFocus.Value == “<type here or select>”)

{

    txtBizFocus.Style.Add(“color”, “#808080″);

 

}

else

{

    txtBizFocus.Style.Add(“color”, “black”);

}

 txtBizFocus.Attributes.Add(“onfocus”,   var txtBizFocus = document.getElementById(’” + txtBizFocus.ClientID + “‘); if(txtBizFocus.value==’<type here or select>’){txtBizFocus.value=”; txtBizFocus.style.color=’black’;};”);

 

txtBizFocus.Attributes.Add(“onblur”,   var txtBizFocus = document.getElementById(’” + txtBizFocus.ClientID + “‘); if(txtBizFocus.value==”){txtBizFocus.value=’<type here or select>’; txtBizFocus.style.color=’#808080′;};”);

 

 So, when the page loads, txtBizFocus comes with a default value “<Type here or select>” in grey color, the moment user clicks inside the textbox(onfocus) the writing disappears and becomes blank so that the user can type in black(this is checked in the above code, where we check if the value inside txtBizFocus is not the default value, change color to black).

Next Page »