Sunday, September 22, 2013

SharePoint 2013 - Server Object Model: Common Practices

Today we will  go through some of the common practices that must be followed to effectively use server object model.

Disposing Resources
The Garbage collector in .NET framework run non-deterministically to clear all unallocated resources in managed code. But in the case of unmanaged code like window handles, files, streams, database connections, sockets, and so on must be released explicitly to avoid performance lags.

Common Practice for Disposing Resources
To invoke Dispose, you should adopt a standard technique, such as one of the following:
1) "Using" Keyword
Writing code with “Using” keyword ensures that any unmanaged resources will be released as soon as they are no longer needed. It also ensures that exceptions can be handled without overloading the environment.
using (SPSite site = new SPSite("http://home:3000/")){
  // Work with the SPSite object; }
The compiler converts the using keyword into a try/finally code block as follows:
  SPSite site = null;
  try {
  site = new SPSite("http://home:3000/");
  // Work with the SPSite object
  }
  finally {
  if (site != null)
  site.Dispose();
  }
2) "Dispose()" Method
To release unmanaged resources the .NET Framework infrastructure provides the IDisposable interface, which exposes a Dispose() method.
public interface IDisposable {
void Dispose();}

Point to remember
1) When you dispose resources with the "using" keyword, we must be careful to remove only those object that we have created. Context based objects need not be removed since SharePoint will handle them.
For example: Following doesnt required disposal.
SPSite objSite = SPContext.Current.Site  // No Disposal needed since Context based.
2) If you want to handle exception then, put the code block inside try..catch since "Using" keyword is converted to only try...finally.
try {
SPSite site = SPControl.GetContextSite(HttpContext.Current);
// Work with the SPSite object
}
catch (SPException ex) {
// Handle exception
}

Exception Handling
The SharePoint Server Object Model provides a base class named SPException, which is the default exception thrown by the SharePoint Server Object Model and is also the type from which almost every specific SharePoint exception inherits.

Common Practice for Exception Handling
1) Catch and handle only those exceptions that you anticipate and can manage. In other words, you should avoid simply catching all exceptions using a catch all block, or an empty catch block.
2) That way, when an exception that you don’t anticipate occurs, it will bubble up to higher-level code that is able to handle it, if any exists.
3) If the exception is unexpected through the entire stack of the current request, it’s best to let the software crash. That is exactly what SharePoint does by default for unhandled exceptions.
4) The Correlation ID (GUID) shown in the above image refers to the current request context, which you can use to search for the exception in the SharePoint log.
5) The default location for the Microsoft SharePoint 2013 log is in the SharePoint15_Root\LOGS folder. You can search the log manually using any basic text editor.

Concurrency Conflicts
Any server-side code has the potential to serve an unpredictable number of users, so changing data in a back-end DBMS carries the possibility of a concurrency conflict. Concurrency issues can also happen when working with data stored in SharePoint. Thus, due to the nature of SharePoint, which is a web-based product with (hopefully) a large number of concurrent users, it is highly probable that concurrency conflicts will arise while managing SharePoint’s items.

ChangeListItemConcurrently() Method
Observe the following code.
using (SPSite site = new SPSite("http://home:3000/")) {
using (SPWeb web = site.OpenWeb()) {
try {
SPList list = web.Lists["Contacts"];
SPListItem itemToChange = list.GetItemById(1);
itemToChange["Last Name"] += " - Changed!";
// Before Update, simulate a concurrent change
ChangeListItemConcurrently();
itemToChange.Update();
}
catch (SPException ex) {
Console.WriteLine(ex.Message);
}
}
}
When the above code invokes the "Update()" method to save changes, a concurrency conflict exception will be raised because the "ChangeListItemConcurrently()" procedure has already changed that item. The exception will be a "Microsoft.SharePoint.SPException" with this error message:
“Save Conflict. Your changes conflict with those made concurrently by another user. If you want your changes to be applied, click Back in your Web browser, refresh the page, and resubmit your changes.”
In order to solve this exception you must reload the SPListItem from the Content Database and then apply your changes again, just as a web user would do using his web browser.


AllowUnsafeUpdates and FormDigest
Lets analyse the difference between the security mechanism  provided by default and server object model.

The FormDigest field (Default security mechanism)
To avoid cross-site scripting issues, SharePoint applies a security check whenever you change data through the Server Object Model during HTTP requests. In fact, by default, SharePoint web forms use a form digest control to enforce security. The form digest is a hidden field POSTed by SharePoint web forms and checked by the security infrastructure on the server.

What happens to FormDigest in Object model?
When you make changes to objects by using the Server Object Model during an HTTP GET request, this input field will be missing, so by default SharePoint will throw an exception that looks like following: Microsoft.SharePoint.SPException: The security validation for this page is invalid. Similarly, if you send an HTTP POST request with a missing or invalid form digest value, you will receive the same error.

The AllowUnsafeUpdates() Method (Server Object Model)
This behavior applies only during HTTP requests. Therefore, when you reference the Server Object Model in a class library or a batch tool that runs outside of the ASP.NET pipeline, the security check will not occur.
With that in mind, if you are developing a webpage that will respond to HTTP GET requests, or a custom web form page that doesn’t inherit from the WebPartPage type and doesn’t use the Form Digest control, you will need to instruct SharePoint to skip the digest validation; otherwise, your code will not work.
SPWeb web = SPContext.Current.Web
SPList list = web.Lists["DevLeap Customers"];
try {
web.AllowUnsafeUpdates = true;  // Set the Boolean AllowUnsafeUpdates property of the current SPSite or SPWeb to true.
list.Title = list.Title + " - Changed!";
list.Update();
}
finally {
web.AllowUnsafeUpdates = false; // Set the Boolean AllowUnsafeUpdates property of the current SPSite or SPWeb to false.
}

No comments:

Post a Comment