Monday, May 14, 2012

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:  }
   9:  
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();
   4:     
   5:      builder.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><ows:Batch OnError=\"Return\">");
   6:   
   7:      foreach (SPListItem itm in items)
   8:      {
   9:   
  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>";
  16:   
  17:           builder.AppendFormat(methodFormat, itm["ID"], list.ID, itm["ID"], 0);
  18:      }
  19:   
  20:      builder.Append("</ows:Batch>");
  21:   
  22:      web.ProcessBatchData(builder.ToString());
  23}
  24:   
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 http://msdn.microsoft.com/en-us/library/cc404818(v=office.12).aspx
Case 2: SPListItemCollection\GetItemByID inside loop
See the code below:
   1:  SPList list = SPContext.Current.Web.Lists["Custom"];
   2:   
   3:  for (int i = 0; i < 10; i++)
   4:  {
   5:        SPListItem item = list.GetItemById(itm[i]);
   6:       //Doing something
   7}
   8:   
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"];
   2:   
   3:  for (int i = 0; i < 10; i++)
   4:  {
   5:   
   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>”;
   9:   
  10:        SPListItemCollection collection = list.GetItems(query);
  11:   
  12:        SPListItem item = collection[0];
  13:   
  14:        item["Count"] = 0;
  15:   
  16:        item.Update();
  17}
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:  {
   3:   
   4:       using (SPSite site = new SPSite(url))
   5:       {
   6:              site.CatchAccessDeniedException = false;
   7:   
   8:              using (SPWeb web = site.OpenWeb())
   9:              {
  10:                       SPList list = web.Lists[listName];
  11:   
  12:                       list.Items.DeleteItemById(idItem);
  13:              }
  14:        }
  15}
  16:   
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:      }
  13}
  14:   
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();
   2:   
   3:  query.Query = "<Where><Gt><FieldRef Name='ID'/><Value Type='Number'>1</Value></Gt></Where>";
   4:   
   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;
   7:   
   8:       SPListItemCollection col = GetData(query, list);
   9});
  10:   
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();
   2:   
   3:  query.RowLimit = 2000;
   4:  query.Query = "<Where><Gt><FieldRef Name='ID'/><Value Type='Number'>1</Value></Gt></Where>";
   5:   
   6:  do
   7:  {
   8:         SPListItemCollection col = GetData(query, list);
   9:         query.ListItemCollectionPosition = col.ListItemCollectionPosition;
  10}
  11:   
  12:  while (query.ListItemCollectionPosition != null);
  13:   
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:  {
   3:   
   4:       CheckBox chk;
   5:   
   6:       public void InstantiateIn(Control container)
   7:       {
   8:           chk = new CheckBox();
   9:           chk.ID = "chk";
  10:   
  11:           container.Controls.Add(chk);
  12:        }
  13}
  14:   
And create an object in CreateChildControl method of web part:
   1:  protected override void CreateChildControls()
   2:  {
   3:   
   4:      SPGridView grid = new SPGridView();
   5:      grid.AutoGenerateColumns = false;
   6:   
   7:      TemplateField tplFeild = new TemplateField();
   8:      tplFeild.HeaderTemplate = new ItemDetail();
   9:   
  10:      grid.Columns.Add(tplFeild);
  11}
  12:   
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:  {
   3:   
   4:       CheckBox chk;
   5:   
   6:       private bool disposed = false;
   7:   
   8:       public void InstantiateIn(Control container)
   9:       {
  10:         chk = new CheckBox();
  11:         chk.ID = "chk";
  12:         container.Controls.Add(chk);
  13:        }
  14:   
  15:       public void Dispose()
  16:       {
  17:          Dispose(true);
  18:          GC.SuppressFinalize(this);
  19:        }
  20:   
  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:        }
  32:      
  33:        ~ItemDetail()
  34:        {
  35:            Dispose(false);
  36:         }
  37}
  38:   
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 http://weblogs.asp.net/pwilson/archive/2004/02/20/77435.aspx and http://msdn.microsoft.com/library/ms182172(VS.90).aspx
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;
   4}
   5:   
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");
   2:   
   3:  if (field is SPFieldDateTime)
   4:  {
   5:       SPFieldDateTime fDateTime = field as SPFieldDateTime;
   6:       //DO SOMETHING
   7}
   8:   
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: http://msdn.microsoft.com/library/ms182271(VS.90).aspx

Best Practice fix issues from MSOCAF checking – Part 1

Best Practice fix issues from MSOCAF checking – Part 1

Microsoft SharePoint Online Code Analysis Framework (MSOCAF) is a tool published by Microsoft to check the code with the rules which are pre-defined online. This tool is not a desktop application, and because it is using an extensible framework, so every time the program runs, it updates the rules from SharePoint online engineering team. There are a lot of areas like memory management, security vulnerabilities, exception handling…that MSOCAF focuses on. MSOCAF is including FxCop, CAT.NET and SPDisposeCheck checking.

Use this tool to test deployment, roll back deployment and submit your code to Microsoft to prepare to push your product on cloud.

To download MSOCAF tool, click this link: https://caf.sharepoint.microsoftonline.com/Default.aspx

Installation


After downloaded, click on setup.exe

clip_image001

After installed, there is an icon on desktop. Click on icon to start running the tool. For the very first time, it will update the rules from SharePoint Online engineering team, so it takes a little long time. Be patient! But for the next time, its speed is faster and if there is no internet connection, all the rules are loaded from cache. We also could not customize, change or remove any rules from MSOCAF.

First screen of MSOCAF look like this:

clip_image003

Before analyze the code of your product, prepare the folders structure and copy all related files.


  • Create root folder, this is a top most folder. You can create it anywhere in your local drive.
  • Create a child folder named “Release documents” and copy all files *.doc (*.docx), *.xml for application note or guidance to use your product.
  • Create a child folder named “Solutions artifacts” and copy all files *.dll, *.exe, *.pdb, *.stp, *.wsp, *.xml of your product. Note: all of referent dlls or files should be copied to here unless it will stop analyzing.
  • Create a child folder named “Installation scripts” including almost files to install your product. It also include PowerShell scripting, xslt or sql script.
  • Create a child folder named “Test documents” and copy all test case documents or any files related to product.


The root folder and Solutions artifacts folder are required existing, other folders does not need to create. If you don’t have any files about test case, release documents or installation scripts, don’t worry about that, just copy dll and exe to Solutions artifacts folder and leave other folders to be empty. For the next time, to check another project, let delete all files in Solutions artifacts and copy dll’s another project then paste into this folder.

Analyze the code


Click on Analyze button, the structure folder guideline window shows and click next (if you are acquainted with usage this tool, stick the check box “Skip this step in the future”) and the rules review window shows (you are also doing stick the check box “Skip this step in the future) then click next. The next screen, select a Root folder that you’ve created before. Finally, click on analyze to start checking.

After checking finished, there is a folder named “Caf reports” is created and there are 3 report files inside.
Note: for the next time checking, MSOCAF will notify a warning about the folder “Caf reports” is existed, that means you had run checking before and if you would like to load previous report or run new analysis. Depend on your purpose to decide what you need to do.

clip_image004

If you click on Run New Analysis, you will get the next window warning/error about the structure of folders. Because you have copied incorrect files and pasted into the folder. For example, “Release documents” is only hosted by *.doc, *.docx or *.xml but there is another file type. So, MSOCAF shows error folder structure. However, if there is not important for your purpose checking, you could answer ‘Yes’ to continue and bypass any error about folder structure.

clip_image005

We recommend that you should correct any error before start analyzing the code.

Now, take a rest and drink a cup of coffee to wait until the MSOCAF finish checking. The result look like:

clip_image007

To view the issue easily, use filter dropdown control to select exactly assembly to view. You also scope down the issue to view by using test cases dropdown to select the rule. Failed issue only contains error issues, so please focus on error as a high priority and warning as low priority.

I love this tool very much because it not only shows the error and bad code in our code but also shows how to fix the issue and explain why it is recognized as an error.

clip_image008

Just click a link attached to know how the best practice code is and follow the instruction to fix your issues. However, some easy issues just have the very short explanation and no link is attached.

Wednesday, April 11, 2012

SharePoint 2013 recommendations

SharePoint 2013 recommendations

SharePoint 2010 had been improved a lot of things that SharePoint 2007 could not be done as well. However, the collaboration for now is not an important thing that needs to be cared as the top of feature. But the social, sharing and publishing are the most important. Almost people transfer from other system to SharePoint step by step and there are so many reasons to convert to SharePoint.

Until now, SharePoint 2010 still had exposed the social weakness and that is the main reason to leave SharePoint and continue using very old system, especially is open source system.

I hope that SharePoint 2013 (Office 15) will improve the following things:


  • Improve the social for discussion board plus. Take it easy to post a comment, reply or any response on Discussion list.
  • Add more event receiver for SharePoint Object Model, especially when I restore all items from recyle bin. In recently, no event receiver catch the handling for that, it's really difficult to check, or do something when they are restored.
  • Still hard to handle the large list and forest sites in site collection. The performance still is so bad or even not responded.