Monday, October 1, 2012

Deploy solution to both SharePoint 2013 UI and SharePoint 2010 UI from Visual Studio

From SharePoint 2013, we can create a site collection for both new UI and old UI of SharePoint 2010. If you have more experience from SharePoint 2010, you should create a new site collection by select 2010 in dropdown list, and if you need to spend a time work live with new UI, by default SharePoint selected 2013 UI.

Today, I create 2 site collections, 1 from 2013 and another from 2010 to make some checking on my web part UI functionalities. Visual Studio 2012 lets you create new project from SharePoint 2013 template including Apps and Projects. Download here

However, after finish developing the code and deploy solution to SharePoint, it’s only a feature from SharePoint 2013 UI in Site Collection Feature even thought the scope of feature is to be farm or site. Because we often forget to consider about package item in project solution and thus we don’t know exactly what about the place where SharePoint 2013 will install our solution.

Just open solutions package (from xml file) as a editor, we can see the property named “SharePointProductVersion” and change the value as you want.

For SharePoint 2013, you could change to “15.0″ as a valued and ”14.0″ for SharePoint 2010. If you need to be available for both 2013 and 2010, please remove this property and re-deploy again. Take it easy baby! :D

Saturday, September 8, 2012

Restore Web Application from a Database File (*.mfd) in SharePoint 2010

You discover your server is down and there is no way to start it. You think the OS has problems or the hard disk is a disaster and has some bad sectors. Unfortunately, the server is never restarted again, but the data is able to be recovered and restored along with a lot of files from your hard disk. The challenge is to think about the way to restore your web application from the database file (*.mdf). In this article, I will show the easy way to restore the web application from the *.mdf file with the same information as your old system environment, securities and other things.
I don’t remember the exacy old environment such as the network topology, the farm configuration, the security for each department, group permission…thus, I only can setup the new server as similarly as possible. And now I have the database file from web application at port 80, named “WSS_Content.mdf”, the content looks like this:
There are some sub-sites for department and a lot of documents, folders and other resources and I need to restore all of them. Here is the step by step that I did to recover my data, that’s so easy.
Step 1: Copy *.mdf to Data folder of SQL Server
Open SQL Studio Management and connect to your SQL Server for SharePoint, then attach the database file.
Step 2: Address to your Central Administration and create the new web application with 1 site collection. You can create the new web app without the same information as the old environment, as it’s not required. In this example, I’ve created the new web app at port 8087 and the server name is also completely different from the old version.
Click on Application Management on the left navigation, then click on the Manage content databases on the right pane.
The new page is opened and you can select the web app to be restored. In my example, I’ve worked on port 8087
Next click on the link of this content database associated to web application, you will see this:
Forget other information, just focus on the option named “Remove content database” and check this option. You will get the popup to confirm that this option should be checked, the content database of this web application will be deleted after you click OK which is fine. That’s my goal.
Step 3: Run SharePoint PowerShell, and type the command

1New-SPContentDatabase -Name <ContentDbName> -WebApplication <WebApplicationName>

Where <ContentDbName> is the name of the content database to create and <WebApplicationName> is the name of the Web application to which the new database is attached.
In my example:
New-SPContentDatabase –Name WSS_Content –WebApplication http://laptop-hai
That’s all; see the result:
My purpose is to restore all files and folders from the old system. I can now work as I did on the old system and never worry about disaster and recovery data. If you run into the same problem, just follow these steps and enjoy the result. Good luck.
You can read more about the solution here.

Monday, July 16, 2012

Download SharePoint Server 2013 for preview

There are some new app as a required installing for SharePoint 2013 Microsoft SharePoint Server 2013 system requirements
Here's the Installation Key for SharePoint Server: 6RNT8-XV26M-GWH36-VMGQH-94MMH
The first blog for SharePoint 2013: How to Install SharePoint Server 2013
SharePoint Foundation 2013 Preview
Language Packs for SharePoint Foundation 2013 Preview – English, Japanese, and Spanish
Filename: SharePointFoundationLP_en-us_x64.exe
Download Microsoft SharePoint Server 2013 Preview
Language Packs for SharePoint Server 2013 Preview – English, Japanese, and Spanish
Filename: serverlanguagepack_en-us_x64.exe
SharePoint Designer 2013
They always release 2 version of SPD: 64 and 32 bits
Filename: sharepointdesigner_en-us_x64.exe
Filename: sharepointdesigner_en-us_x86.exe
SharePoint 2013: presentation: IT pro training

Monday, May 14, 2012

Best Practice fix issues from MSOCAF checking – Part 3

Case 7: Information disclosure through exception

When you are building a web part and catch the exception to show the detail error on web part UI. However, there is no trouble if that exception is showed without customzation, unless you will get the error “Information disclosure through exception”. See example:

Exception without customization as safe security:

     //TODO: your code here
catch (Exception ex)
     lblError.Text  = ex.Message;

Exception with customization:

   //TODO: your code here
catch(Exception ex)
   lblError.Text = "Error: <b>" + ex.Message + "</b>";

The second example will show error if we do check by MSOCAF because the error message is not encrypted and make it be weakness security. 

To fix this issuse, just encrypt the message before assign to control. Use AntiXSS or HttpUtility.JavaScriptEncode.

Case 8: File canonicalization

In generally, when we work on File System we forget the validation of file name or file path. We process the data based on the default string of file. In many case, SharePoint and Windows System is a little different acceptable formatting file name/path. To make sure the input file name is validated, checking file name before pass it to procedure or function.

See example:

for (int i = 0; i < bn.Count; i++)
    string fileName = bn[i].FileName;
    FileInfo f = new FileInfo(fileName);
    SPWeb web = item.Web;
    SPFile file = folder.Files.Add(f.Name, buffer, true);
    item = file.Item;

Fix this issue:

   1:  for (int i = 0; i < bn.Count; i++)
   2:  {
   3:     //...  
   4:      string fileName = Path.GetFileName(bn[i].FileName);
   5:      if(fileName != string.Empty)
   6:      {
   7:          FileInfo f = new FileInfo(fileName);
   8:          //....
   9:          SPWeb web = item.Web;
  10:          //....
  11:          SPFile file = folder.Files.Add(f.Name, buffer, true);
  12:          item = file.Item;
  13:      }
  14:   }

The method Path.GetFileName will check there is any invalid character of the path is existed.

Case 9: SQL Injection

The data was enterred by user is always checked/validated before pass it into the routines. Especially the data will be sent to SQL command and execute under code behide. Thes issue is very common and easy to fix.

To resolve this issue, just use the parameter instead of concatenate directly in the string. Look example:

   1:  sqlCommand.CommandText = "SELECT * FROM tb_cus WHERE cusname='" + cusName + "'";
   2:  SqlDataReader reader = sqlCommand.ExecuteReader();

The code fixed:

   1:  sqlCommand.CommandText = "SELECT * FROM tb_cus WHERE cusname= @cusName";  
   2:  sqlCommand.Parameters.Clear();
   3:  sqlCommand.Parameters.AddWithValue("cusName", cusName);
   5:  SqlDataReader reader = sqlCommand.ExecuteReader();

Best Practice fix issues from MSOCAF checking – Part 2

In the previous post, I introduced how to use MSOCAF to check the custom solution. There are a lot of issues after checked, and now I will focus on the issue that happens frequently. Read this article to improve your habits, change the mind and build a good product.
Case 1: use SPListItem.Update
Even though the Update() method is found in SPListItem and use to update any field in item. But it’s only available when we have separate updating on each item. Don’t use this method in loop statement, especially for large list. See the code
   1:  public void UpdateAll(SPListItemCollection items)
   2:  {
   3:       foreach (SPListItem itm in items)
   4:      {
   5:         itm["Count"] = 0;
   6:         itm.Update();
   7:       }
   8:  }
It should be changed to use update command and execute by SPWeb object. Best practice code is as below:
   1:  public void UpdateAll(SPListItemCollection items)
   2:  {
   3:      StringBuilder builder = new StringBuilder();
   5:      builder.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><ows:Batch OnError=\"Return\">");
   7:      foreach (SPListItem itm in items)
   8:      {
  10:          string methodFormat = "<Method ID=\"{0}\">" +
  11:                                                "<SetList>{1}</SetList>" +
  12:                                                "<SetVar Name=\"Cmd\">Update</SetVar>" +
  13:                                                "<SetVar Name=\"ID\">{2}</SetVar>" +
  14:                                                "<SetVar Name=\"urn:schemas-microsoft-com:office:office#Count\">{3}</SetVar>" +
  15:                                                 "</Method>";
  17:           builder.AppendFormat(methodFormat, itm["ID"], list.ID, itm["ID"], 0);
  18:      }
  20:      builder.Append("</ows:Batch>");
  22:      web.ProcessBatchData(builder.ToString());
Because the Update() method is called in the loop, so that’s not best practice to improve performance. It is reported under custom rules of Microsoft Online when we run the MOSCAF checking. That is to be able to understand in the context of cloud environment. However, if there is a large list, please don’t add many thousands items into an update string, just less than 2000 that’s fine. To read more the performance when item is updated, please read here
Case 2: SPListItemCollection\GetItemByID inside loop
See the code below:
   1:  SPList list = SPContext.Current.Web.Lists["Custom"];
   3:  for (int i = 0; i < 10; i++)
   4:  {
   5:        SPListItem item = list.GetItemById(itm[i]);
   6:       //Doing something
Almost developers think about the code above is very normal and nothing wrong. Of course that’s not, but it isn’t the best practice too. Because when we call list.GetItemById method that means the collection of SPListItem is retrieved and call again in the next index.
The code is changed:
   1:  SPList list = SPContext.Current.Web.Lists["Custom"];
   3:  for (int i = 0; i < 10; i++)
   4:  {
   6:       SPQuery query = new SPQuery();
   7:       query.RowLimit = 1;
   8:       query.Query = “<where><Eq><FieldRef Name=’ID’/><Value Type=’Number’>” + itm[i] + “</Value></Eq></Where>”;
  10:        SPListItemCollection collection = list.GetItems(query);
  12:        SPListItem item = collection[0];
  14:        item["Count"] = 0;
  16:        item.Update();
However, when we call the Update() method in loop statement we will get the error as case 1, we must combine case 1 and case 2 to fix together.
Case 3: Use SPList.Items
See the code:
   1:  public void DeleteSchemaItem(string url, string listName, int idItem)
   2:  {
   4:       using (SPSite site = new SPSite(url))
   5:       {
   6:              site.CatchAccessDeniedException = false;
   8:              using (SPWeb web = site.OpenWeb())
   9:              {
  10:                       SPList list = web.Lists[listName];
  12:                       list.Items.DeleteItemById(idItem);
  13:              }
  14:        }
The code above seem to work well for the functioning, however, it is only for very small list (a very little items in list). And with the large list, the code above is not good performance and need to be improved. Because when we call list.Items that means the collection of SPListItem is retrieved and after delete an item, this collection was re-modified.
The code is changed:
   1:  public void DeleteSchemaItem(string url, string listName, int idItem)
   2:  {
   3:     using (SPSite site = new SPSite(url))
   4:     {
   5:           site.CatchAccessDeniedException = false;
   6:           using (SPWeb web = site.OpenWeb())
   7:           {
   8:               SPList list = web.Lists[listName];
   9:               SPListItem item = list.GetItemById(idItem);
  10:               item.Delete();
  11:            }
  12:      }
The code seems good with performance because it doesn’t reach to the very large collection at least.
Case 4: SPQuery object without RowLimit property
We often forget the most important property of SPQuery object, that is the RowLimit propery. If this property is not set, what is the default value? And as we know this value is accepted from range [1…2000]
It’s so excited when I work on this object, because most of us forgot the work as design of this object and thought to leave RowLimit property to wish getting all data when they match with the query CAML. And the code looks like:
   1:  SPQuery query = new SPQuery();
   3:  query.Query = "<Where><Gt><FieldRef Name='ID'/><Value Type='Number'>1</Value></Gt></Where>";
   5:  SPListItemCollection col = GetData(query, list);
The code will return all items in the list; however it will throw exception if the number of list item is greater than default value of Throttling in Central Administration configuration. The default value of Throttling is 5000 and this value is able to be overwritten by the code.
   1:  SPSecurity.RunWithElevatedPrivileges(delegate()
   2:  {
   3:       SPQuery query = new SPQuery();
   4:       query.Query = "<Where><Gt><FieldRef Name='ID'/><Value   Type='Number'>1</Value></Gt></Where>";
   5:       query.QueryThrottleMode = SPQueryThrottleOption.Override;
   6:       query.RowLimit = 5500;
   8:       SPListItemCollection col = GetData(query, list);
We must run the code under Full Control account, so the code is reverted to web application pool account to apply the overwrite throttling.
But with the MSOCAF, the RowLimit item is only valid in range [1...2000] unless you will get the error issue for performance. The important thing is the code above is a weakness security. For many purpose, we need to get all data with good performance and security but not violate the rule of MSOCAF.
The code is changed again:
   1:  SPQuery query = new SPQuery();
   3:  query.RowLimit = 2000;
   4:  query.Query = "<Where><Gt><FieldRef Name='ID'/><Value Type='Number'>1</Value></Gt></Where>";
   6:  do
   7:  {
   8:         SPListItemCollection col = GetData(query, list);
   9:         query.ListItemCollectionPosition = col.ListItemCollectionPosition;
  12:  while (query.ListItemCollectionPosition != null);
Case 5: Types that own disposable fields should be disposable
That means if we have implemented the class with some methods or properties return the object that implemented IDisposable interface, we also must inherit IDisposable and implement the code to dispose object or dispose object manually. In case, the class has shipped we can create a new method to manage the disposing object.
See the code
   1:  public class ItemDetail : ITemplate
   2:  {
   4:       CheckBox chk;
   6:       public void InstantiateIn(Control container)
   7:       {
   8:           chk = new CheckBox();
   9:           chk.ID = "chk";
  11:           container.Controls.Add(chk);
  12:        }
And create an object in CreateChildControl method of web part:
   1:  protected override void CreateChildControls()
   2:  {
   4:      SPGridView grid = new SPGridView();
   5:      grid.AutoGenerateColumns = false;
   7:      TemplateField tplFeild = new TemplateField();
   8:      tplFeild.HeaderTemplate = new ItemDetail();
  10:      grid.Columns.Add(tplFeild);
CheckBox is ASP.NET control and have implemented IDisposable interface, but we don’t care about disposing control when we add it into ASPX page because they are disposed when the page is disposed. And regarding code above, when the page is diposed there is only grid object is disposed and tplField.HeaderTemplate didn’t disposed, but chk object need to be disposed, so we must dispose manually.
See the code is changed:
   1:  public class ItemDetail : ITemplate, IDisposable
   2:  {
   4:       CheckBox chk;
   6:       private bool disposed = false;
   8:       public void InstantiateIn(Control container)
   9:       {
  10:         chk = new CheckBox();
  11:         chk.ID = "chk";
  12:         container.Controls.Add(chk);
  13:        }
  15:       public void Dispose()
  16:       {
  17:          Dispose(true);
  18:          GC.SuppressFinalize(this);
  19:        }
  21:        protected virtual void Dispose(bool disposing)
  22:        {
  23:           if (!this.disposed)
  24:          {
  25:                if (disposing)
  26:                {
  27:                     if (chk != null) chk.Dispose();
  28:                 }
  29:               disposed = true;
  30:           }
  31:        }
  33:        ~ItemDetail()
  34:        {
  35:            Dispose(false);
  36:         }
We can use the keyword ‘using’ to dispose object automatically. There are also some objects do not need to dispose and we know that when method dispose is called, so it does nothing but we still use ‘using’ as a habit. Read more here and
Case 6: Do not cast unnecessarily
There are many times we cast the variable to the same type and think about that as a safety. For example:
XmlElement tempElement;
   1:  foreach (XmlNode node in nodes)
   2:  {
   3:       string realDisplayName = ((XmlElement)node).Attributes["DisplayName"].InnerText;
It is so clearly that variable named ‘node’ is an element of XML document, even though it is retrieved from XmlNode collection (XMLNodeList) but it’s still an element. Thus, the casting value of node variable to XmlElement is not necessary.
Another example in SharePoint:
   1:  SPField field = list.Fields.GetFieldByInternalName("OurColumnsName");
   3:  if (field is SPFieldDateTime)
   4:  {
   5:       SPFieldDateTime fDateTime = field as SPFieldDateTime;
   6:       //DO SOMETHING
The ‘is’ statement is casted object and the assignment object fDateTime with ‘as’ is duplicated casting. So we must change the code, please read this document to know how to change the code to match the rule of MSOCAF. Here is the link: