Monday 28 May 2012

Binding SharePoint list columns with distinct values to a dropdownlist using LINQ and DataTable


Using DataTable
Using the DataTable and DataView we can sort the items, but we can not take the distinct values from the columns. We should explicitly remove the duplicates again by writing a separate method .
SPWeb web = SPContext.Current.Web;
SPList list = web.Lists["DocumentLibraryName"];
SPListItemCollection listItems = list.GetItems();
DataTable dtTable = list.Items.GetDataTable().DefaultView.ToTable(true, “ColumnName”);
DataView dvName = new DataView(dtTable);
dvName.Sort = “ColumnName”;
ddl.DataSource = dvName;
ddl.DataTextField = “ColumnName”;
ddl.DataValueField = “ColumnName”;
ddl.DataBind();
RemoveDuplicateItems(ref ddlBusinessUnits)
private void RemoveDuplicateItems(ref DropDownList ddl)
{
            try
           {
               for (int i = 0; i < ddl.Items.Count; i++)
                {
                    ddl.SelectedIndex = i;
                    string str = ddl.SelectedItem.ToString();
                    for (int counter = i + 1; counter < ddl.Items.Count; counter++)
                    {
                        ddl.SelectedIndex = counter;
                        string compareStr = ddl.SelectedItem.ToString();
                        if (str == compareStr)
                        {
                            ddl.Items.RemoveAt(counter);
                            counter = counter – 1;
                        }
                    }
                }
                for (int i = 0; i < ddl.Items.Count; i++)
                {
                    if ((ddl.Items[i].Text.Length == 0) || (ddl.Items[i].Value.Length == 0))
                    {
                        ListItem item = ddl.Items[i];
                        ddl.Items.Remove(item);
                        i = i – 1;
                    }
                }
                ddl.Items.Insert(0, new ListItem(“Select”, “”));
                ddl.SelectedIndex = 0;
            }
            catch { }
}
The above method using the data table will decrease the performance. It will take a lot of time when there are ‘n’ no. of items to be bind to the dropdown list.
Using LINQ
SPWeb web = SPContext.Current.Web;
SPList list = web.Lists[DocumentLibrary];
var objItems = (from item in (from listitem in list.GetItems().Cast()
                                       where
                                       listitem["ColumnName"] != null
                                       select new { value = listitem["ColumnName"].ToString() }).ToList().Distinct()
                      orderby item.value ascending
                      select item); 
ddl.DataSource = objItems ;
ddl.DataTextField = “value”;
ddl.DataValueField = “value”;
ddl.DataBind();
ddl.Items.Insert(0,new ListItem(“Select”,string.Empty));
That’s it. it will bind the distinct values of the column in the drop down in ascending order of the items. It reduces the lot of loading time when ‘n’ no. of items has to be loaded in the drop down.

SPSecurity.RunWithElevatedPrivileges - while using it with SPContext.Current.Web in sharepoint

http://stackoverflow.com/questions/8052190/spsite-site-new-spsitespcontext-current-web-url-vs-spcontext-current-web-sit

http://sahanganepola.blogspot.in/2009/08/spsecurityrunwithelevatedprivileges.html


SPSecurity.RunWithElevatedPrivileges - while using it with SPContext.Current.Web in sharepoint

Normally we will use SPSecurity.RunWithElevatedPrivileges() to execute some code that has to be run under some higher privileges.



Whenever we use SPSecurity.RunWithElevatedPrivileges(), it will execute the code under the context of Application Pool identity. Now we can see a scenario where we will get the “Access denied” exception from the code block even if you use SPSecurity.RunWithElevatedPrivileges.



This was the code snippet that I have used initially inside a custom webpart to read XML content from of an InfoPath form which was uploaded in a document library. This code will throw an “Access denied” exception while calling the OpenBinaryStream() method whenever I execute it through an Anonymous user account.



SPSecurity.RunWithElevatedPrivileges(delegate()

{

SPWeb oWeb = SPContext.Current.Web;

SPList oList = oWeb.Lists["InfoPathLib"];

SPListItem oListItem = oList.Items[0];

Stream oStream = oListItem.File.OpenBinaryStream();

StreamReader oReader = new StreamReader(oStream);

string strLine = "";



strLine = oReader.ReadLine();



oReader.Close();

oStream.Close();



oReader.Dispose();

oStream.Dispose();



lblFileContent.Text = strLine;



this.Controls.Add(lblFileContent);

});





Here the problem was, whenever we take the SPWeb instance using

SPWeb oWeb = SPContext.Current.Web;, then SPWeb instance still running under anonymous account only , because we are taking it through the current web context in which the current user is running under anonymous account (IUSR_MachineName). That was the reason that we got that “Access Denied” exception. We need to remember this point all time whenever we use RunWithElevatedPrivileges under the web context.



So what we need to that, we have to take the current context outside the SPSecurity.RunWithElevatedPrivileges block and then create a new instance of SPSite and SPWeb inside the that block which will run under application pool identity.



SPWeb oWeb1 = SPContext.Current.Web; // taking the current SPWeb context running under the anonymous account

SPSecurity.RunWithElevatedPrivileges(delegate()

{

using (SPSite oSite = new SPSite(oWeb1.Site.Url))

{

// creating a new SPSite running under Application pool idenity

using (SPWeb oWeb = oSite.OpenWeb())

{



SPList oList = oWeb.Lists["InfoPathLib"];



SPListItem oListItem = oList.Items[0];



Stream oStream = oListItem.File.OpenBinaryStream();



StreamReader oReader = new StreamReader(oStream);



string strLine = "";



strLine = oReader.ReadLine();



oReader.Close();



oStream.Close();



oReader.Dispose();



oStream.Dispose();



lblFileContent.Text = strLine;



this.Controls.Add(lblFileContent);

}

}



});

The above code will work fine and we can read the InfoPath document. So, please do not forget to create a new instance of SPSite and SPWeb inside SPSecurity.RunWithElevatedPrivileges,while using it in a web context.



Another work-around to this paritcular requirement (read the file content) is - use GetFileAsString() method of the SPWeb directly. And here there is no need to use the SPSecurity.RunWithElevatedPrivileges. Since, I have enabled anonymous authentication on this SharePoint web application it will allow to read the file using the below method under the context of anonymous account.

string strXML = SPContext.Current.Web.GetFileAsString("/FannyDocLib/Form1.xml");

Friday 18 May 2012

Difference between Server.Transfer() and Server.Execute()

The HttpServerUtility.Execute method executes a request to another page using the specified URL path to the page. The Execute method continues execution of the original page after execution of the new page is completed.
e.g.
Server.Execute(“ProcessTestAnswers.aspx”) ;

Server.transfer : 
Terminates execution of the current page and begins execution of a new page for the current request.
The page transferred to should be another Web Forms page (.aspx page) in the same application. You cannot use Server.Transfer to redirect to an .asp or .asmx page. Make sure that the target page exists. Because Server.Transfer is executed on the server, the browser does not have a record of the page change. Therefore, if the user refreshes the page, unexpected results can occur.
e.g.
Server.Transfer("Logon.aspx");




server.transfer method will transfers the execution from current ASPX page to specified ASPX page in the same webserver whereas 
server.execute method allows the current ASPX page to execute specified ASPX page in the same webserver, when it finishes the execution of the specified page, control will return back to same point where server.execute method is called and continues the further process.

SharePoint 2010 and web templates

Getting the Changed DataTable


Introduction

Consider a situation in which you have a datagrid with all or most of its rows in editable mode. You change a single item in the datagrid and press the save button. Most probably you will be sending all the data into the database for the update. This can be very bad for performance if you are sending thousands of rows as we only changed one row and thus only this row should be sent to the DAL layer to perform the update. In this article, we will see how we can only get the changed rows from the datatable object.

Background

Setting the User Interface

The User Interface is pretty simple.
I have three columns which are UserIDUserName and the Score. These columns are created using the "Property Builder" (Right click on DataGrid control in design view and select property builder). If you want to create your columns dynamically than check out my article, Creating bound and template columns dynamically in a datagrid.
As you can see, score is a "TextBox" column which will allow us to make changes. When we press the "Get Changed Rows" button, we will only get the rows that have been changed.

BindGrid Method

BindGrid method is called whenever there is no postback.
private void BindData() 
{
Database db = DatabaseFactory.CreateDatabase(); 
DBCommandWrapper selectCommandWrapper = db.GetStoredProcCommandWrapper("GetGrades");
oldDataSet = db.ExecuteDataSet(selectCommandWrapper); 
DataGrid1.DataSource = oldDataSet; 
DataGrid1.DataBind(); 
// Put the DataSet in the session object 
Session["DataSet"] = oldDataSet;
}
The most important line is the bold one where I have assigned the oldDataSet into a Session object so I can have a copy of the DataSet.

Using the Code

Button Click Code (Getting the Changes)

The main idea behind getting only the changed values from the datagrid is simple. We get the old DataSet. We make a DataTable object from the oldDataSet. We loop through the Datagrid and retrieve values of each row. We assign the oldDataTable with a primary key, which in this case is UserID (It will be a good idea to not display the UserID as it is a primary key). Later we check the old score with the new score using DataRow object. And finally we use the "GetChanges" method of the DataTable to only get the changes into a new DataTable.
DataSet also has a "GetChanges" method which you can use to perform the same actions.
private void Button1_Click(object sender, System.EventArgs e)
{
// Gets the DataSet from the Session
oldDataSet = (DataSet) Session["DataSet"];
// Gets the DataTable out of the DataSet
DataTable oldDataTable = oldDataSet.Tables[0];
DataTable newDataTable = new DataTable();
DataRow dataRow;
int oldScore = 0;
foreach(DataGridItem dgi in DataGrid1.Items)
{
// Gets the text out of the Score column and convert it to Int32
int score = Convert.ToInt32(((TextBox) dgi.FindControl("TextBox1")).Text);
// Get the UserID out of the first column
int userID = Convert.ToInt32(dgi.Cells[0].Text);
// Make a DataColumn object which is used to set the primary key
DataColumn[] userIDColumn = new DataColumn[1];
userIDColumn[0] = (DataColumn) oldDataTable.Columns["UserID"];
// Set the primary key to the oldDataTable
oldDataTable.PrimaryKey = userIDColumn;
dataRow = oldDataTable.Rows.Find(userID);
if(DBNull.Value == dataRow["Test1"])
{ dataRow["Test1"] = score; }
else
{
oldScore = Convert.ToInt32(dataRow["Test1"]);
// Check to see if the score has changed or not
if(score != oldScore)
{ dataRow["Test1"] = score; }
}
}
// Get only the changes from the oldDataTable to the newDataTable
newDataTable = oldDataTable.GetChanges();
// Bind the newDataTable to the DataGrid
DataGrid2.DataSource = newDataTable;
DataGrid2.DataBind();
} 

The Result

You can see in the image below that only the fields I have changed are retrieved from the DataTable object and nothing else.

Thursday 17 May 2012

static constructor from C#

1) The static constructor for a class executes before any instance of the class is created.
2) The static constructor for a class executes before any of the static members for the class are referenced.
3) The static constructor for a class executes after the static field initializers (if any) for the class.
4) The static constructor for a class executes at most one time during a single program instantiation
5) A static constructor does not take access modifiers or have parameters.
6) A static constructor is called automatically to initialize the class before the first instance is created or any static members are referenced. 
7) A static constructor cannot be called directly.
8) The user has no control on when the static constructor is executed in the program. 
9) A typical use of static constructors is when the class is using a log file and the constructor is used to write entries to this file.


http://www.functionx.com/csharp/topics/staticclasses.htm

What's the difference between the System.Array.CopyTo() and System.Array.Clone()?

The Clone() method returns a new array (a shallow copy) object
containing all the elements in the original array. The CopyTo() method
copies the elements into another existing array. Both perform a
shallow copy. A shallow copy means the contents (each array element)
contains references to the same object as the elements in the original
array. A deep copy (which neither of these methods performs) would
create a new instance of each element's object, resulting in a
different, yet identacle object.






Here are the differences:

MyArrayList2 = MyArrayList;

This will just copy the reference to MyArrayList into MyArrayList2. If
you add an element to MyArrayList2, then you will see that in MyArrayList,
because they both point to the same thing.

MyArrayList2 = MyArrayList.Clone();

This will create a shallow copy of the ArrayList. If the elements are a
reference, then those references are copied. If they are value types, then
that is copied to the new array list. Now, if they are all reference types,
then the two array lists are pointing to the same objects. However, if you
add a new item to MyArrayList2, then it will not be shown in MyArrayList,
because MyArrayList2 is a new object, not a reference to the same
MyArrayList.

Wednesday 16 May 2012

Managing the Content and Configuration of Databases in Windows SharePoint Services


There are two types of databases involved in the operations of Windows SharePoint Services:
  1. One database for storing data of one or multiple websites (content) using Windows SharePoint Services.
  2. Other database that holds the configuration information.
The configuration db is instrumental in configuration and helps the administration of all the websites that use WSS on a server. Whereas, the content databases hold the data of one or more WSS websites. It depends on the volume and the size of WSS websites supporting the server for WSS.
If you install WSS in your system, you’d have many content databases and just one database that holds the configuration. But if you consequently install SharePoint Portal Server, it wouldn’t use any of those databases but 3 other ie. Portalname_prof,Portalname_serv and Portalname_site, are created with the installation of SharePoint Portal Server which inturn updatethe configuration database that was created previously with the installation of WSS.

How to Create new application pool and change App Pool of SharePoint Website


If the application pool does not exist you can create it using the following code snippet:
   1:  SPFarm farm = SPFarm.Local; 
   2:  SPWebService service = farm.Services.GetValue<SPWebService>(); 
   3:  SPApplicationPool appPool = new SPApplicationPool("App Pool Title", service); 
   4:  appPool.CurrentIdentityType = IdentityType.SpecificUser; 
   5:  appPool.Username = "domain\\username"; 
   6:  appPool.Password = "password"; 
   7:  appPool.Update(); 
   8:  appPool.Deploy();
Be aware that application pools you created in IIS directly cannot be used with the SharePoint object model. The reason is that these are not known in the Config DB and they could also be with different configuration on different WFE's in the farm.
So you have to ensure that the application pool has been created using the method above. Once the application pool is created or it already exists you can look it up using the following code snippet and assign to the SharePoint application:
   1:  SPFarm farm = SPFarm.Local;
   2:  SPWebService service = farm.Services.GetValue<SPWebService>();
   3:  SPApplicationPool appPool = service.ApplicationPools["App Pool Title"];
   4:  
   5:  SPSite site = new SPSite("http://url-to-your-sitecollection");
   6:  SPWebApplication webApp = site.WebApplication;
   7:  webApp.ApplicationPool = appPool;
   8:  webApp.Update();
   9:  webApp.ProvisionGlobally();

http://blogs.msdn.com/b/malag/archive/2010/04/14/how-to-create-new-application-pool-and-change-app-pool-of-sharepoint-website.aspx

Application Pool

Dump password of application pool user from IIs>=6.0


IIS Application pools are used to separate sets of IIS worker processes that share the same configuration and application boundaries. Application pools used to isolate our web application for better security, reliability, and availability and performance and keep running with out impacting each other . The worker process serves as the process boundary that separates each application pool so that when one worker process or application is having an issue or recycles, other applications or worker processes are not affected.
One Application Pool can have multiple worker process. (Ref:http://technet.microsoft.com/en-us/library/cc735247%28WS.10%29.aspx)
Main Point to Remember: 
1. Isolation of Different Web Application
2. Individual worker process for different web application
3. More reliably web application
4. Better Performance
It may happen that while managing or testing multiple web applications we create many application pool(s) in the IIS. Thus, there is always the possibility that we may forget the password of an account that we have used for the some application pool. In order to retrieve the credentials we can use the utility called APPCMD.

1. Let us assume that we have forgotten the password of the account that is used by a “Demo User” application pool.
Application Pool
Application Pool
2. Open the command prompt by browsing Start menu -> Accessories -> Command Prompt. Right click on Command prompt and select “Run as Administrator” option from the context menu.
Tip: You can also select CMD and press CTRL + Shift + Enter to Start Command Prompt as Administrator or with Machine Administrator rights
3. Browse the following path on command prompt “%systemroot%\system32\inetsrv” and run
APPCMD list apppool “Demo User” /text:*
(The directory will most likely be C:\Windows\System32\inetsrv)
Replace “Demo User” with the App Pool name of which you want to retrieve the password.
Command
Command
4. Under the [processModel] section you will get the username and password which is in Clear Text .
Output showing credentials
Output showing credentials

The remediation for this is very simple; use service accounts like Network Service, Network, etc. So, even if someone has access to the system and tries same steps as above to retrieve the user account password, he wont be able to do that.
1. Application pool “Dos” with Network Service account
Application Pool for Network Service
Application Pool for Network Service
2. Running the same command as we ran in earlier in this post i.e. APPCMD list apppool “Dos” /text:*
Command
Command
3. Checking the output
Output for Network Service
Output for Network Service