Friday, September 27, 2013

SharePoint Asynchronous Webpart Load

Issue Description

While working on SharePoint application development, we usually go with the development of custom web parts. These web parts are then placed on the respective pages as per the application requirements.
This is all good and easy from the development side. But looking at this from a performance perspective, the page load time depends on the total load time of the web parts. This load time can be effectively reduced by loading the web parts’ content asynchronously, as below.

Solution

1.       Using XMLHttpRequest in JavaScript

We can use AJAX to load the web part content, a sort of lazy loading, hence making the page load independent of their load times. A combination of client-side and server-side script is used to implement this.
The client-side XMLHttpRequest object is used to exchange data with a server behind the scenes. This means that it is possible to update parts of a web page, without reloading the whole page.
When a request to a server is sent, we want to perform some actions based on the response. The onreadystatechange event is triggered every time the readyState changes. The readyState property holds the status of the XMLHttpRequest, while the status property indicates whether the response was retrieved successfully or not.
In the onreadystatechange event, we specify the processing to be done for the ready server response. When readyState is 4 and status is 200, the response is ready.
Three important properties of the XMLHttpRequest object:
Property
Description
onreadystatechange
Stores a function (or the name of a function) to be called automatically each time the readyState property changes
readyState
Holds the status of the XMLHttpRequest. Changes from 0 to 4:
0: request not initialized
1: server connection established
2: request received
3: processing request
4: request finished and response is ready
Status
200: "OK"
404: Page not found

2.       Using jQuery Ajax

The ajax() method is used to perform an AJAX (asynchronous HTTP) request. The parameters specify one or more name/value pairs for the AJAX request.
Some possible names/values in the table below:
Name
Value/Description
async
A Boolean value indicating whether the request should be handled asynchronous or not. Default is true
beforeSend(xhr)
A function to run before the request is sent
cache
A Boolean value indicating whether the browser should cache the requested pages. Default is true
complete(xhr,status)
A function to run when the request is finished (after success and error functions).
data
Specifies data to be sent to the server
dataType
The data type expected of the server response.
error(xhr,status,error)
A function to run if the request fails.
success(result,status,xhr)
A function to be run when the request succeeds
timeout
The local timeout (in milliseconds) for the request
type
Specifies the type of request. (GET or POST)
url
Specifies the URL to send the request to. Default is the current page
xhr
A function used for creating the XMLHttpRequest object

3.       jQuery $.get() Method

The $.get() method requests data from the server with an HTTP GET request.
This is a shorthand Ajax function, which is equivalent to:
$.ajax({
  url: url,
  data: data,
  success: success,
  dataType: dataType
});
The success callback function is passed the returned data, which will be an XML root element, text string, JavaScript file, or JSON object, depending on the MIME type of the response. It is also passed the text status of the response.

Syntax:
$.get(URL,callback);
The required URL parameter specifies the URL you wish to request. The optional callback parameter is the name of a function to be executed if the request succeeds. The following example uses the $.get() method to retrieve data from a file on the server:

Example for this implementation:
1)       Create a visual webpart NewsFeedWebpart that will display news articles and will also change news dynamically based on the category selected by the user from a drop down menu.
2)       When user selects a category from the dropdown, the getSelectedNewsFeeds() javascript function will be called, specified on client click for dropdown.  This function will create a new XMLHttpRequest object.
3)       Create a request to the AJAXServiceRequest.aspx application page, along with the required query string parameters, as required (action name and category Id, in this case).
4)       Once the response is received, the existing HTML of the news div is replaced with the new HTML fragment.
Add following code in NewsFeedWebpartUserControl.aspx.
a)       Script for XMLHttpRequest in JavaScript

<script language="javascript" type="text/javascript">

    function getSelectedNewsFeeds() {
        var ajaxRequest;
        var dropdown = document.getElementById('<%=ListSelectedNewsCat.ClientID %>');
        var filterVal = dropdown.options[dropdown.selectedIndex].value;

var ajaxDisplay = document.getElementById('<%=divNews.ClientID %>');

//This is to indicate to user about the processing
ajaxDisplay.innerHTML = 'Loading...';

if (window.XMLHttpRequest)
{ // code for IE7+, Firefox, Chrome, Opera, Safari
  ajaxRequest =new XMLHttpRequest();
}
else
{ // code for IE6, IE5
  ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
}       

        ajaxRequest.onreadystatechange = function () {
            if (ajaxRequest.readyState == 4 && xmlhttp.status == 200) {
                var response = ajaxRequest.responseText;
                ajaxDisplay.innerHTML = response;
            }
        }

        var queryString = "?queryaction=ProcessForNewsFeed&category=" + filterVal;
        ajaxRequest.open("GET", "/_layouts/AJAXServiceRequest.aspx" + queryString, true);
        ajaxRequest.send(null);
    }
 
</script>

b)       Script for  $.ajax() in jQuery

<script language="javascript" type="text/javascript">

    function getSelectedNewsFeeds() {
     
    var filterVal = $("[id$='ListSelectedNewsCat'] option:selected").val();
    var ajaxDisplay = $("[id$='divNews']");

    //This is to indicate to user about the processing
    ajaxDisplay.html('Loading...');

    var queryString = "?queryaction=ProcessForNewsFeed&category=" + filterVal;
    var requestString = "/_layouts/AJAXServiceRequest.aspx" + queryString;

    $.ajax({
       url: requestString,
       success: function (result) {
           ajaxDisplay.html(result);
       }
    });
    }
 
</script>

c)       Script for $.get() in jQuery

<script language="javascript" type="text/javascript">

   function getSelectedNewsFeeds() {

        var filterVal = $("[id$='ListSelectedNewsCat'] option:selected").val();
        var ajaxDisplay = $("[id$='divNews']");

        //This is to indicate to user about the processing
        ajaxDisplay.html('Loading...');

        var queryString = "?queryaction=ProcessForNewsFeed&category=" + filterVal;
        var requestString = "/_layouts/AJAXServiceRequest.aspx" + queryString;

        $.get(requestString, function (data, status) {
            if(status == "success")
            {
                ajaxDisplay.html(data);
            }
        });
   }
 
</script>


HTML snippet to add dropdown and div on the page

<div>
    <asp:DropDownList ID="ListSelectedNewsCat" runat="server" onclientclick=" getSelectedNewsFeeds();” DataTextField="Title" DataValueField="ID">
    </asp:DropDownList>
</div>
<div class="divNews" runat="server" id="divNews">
</div>


5)       Get query string parameters in the server side script and call appropriate method to generate news feed HTML for selected category.
For this, create an application page AJAXServiceRequest.aspx in layouts folder. This page will be called by all AJAX requests. Add following code in AJAXServiceRequest.aspx.cs to format the HTML and return it as response for the request.
Return final html using AntiXss.GetSafeHtmlFragment.
AntiXss.GetSafeHtmlFragment: Returns well-formed HTML fragments (does not try and add <html> or <body> tags).

protected void Page_Load (object sender, EventArgs e)
{

//// Process For News Feed
if (Request.QueryString[“queryaction”] != null &&   Request.QueryString[“queryaction”].ToString().Equals(“ProcessForNewsFeed”))
     {
                string formattedText = string.Empty;
                string category = Request.QueryString[“category”];
                formattedText = NewsFeedHelper.ProcessMainNews(category);
                Response.Write(formattedText);
                Response.End();
     }
}
public static string ProcessMainNews (string id)
{
//// code to generate news feed html
                return AntiXss.GetSafeHtmlFragment(html);
}

Sunday, July 28, 2013

Copy \ Add Document to Document Set

In this article we can explore the copy document from a document library to document set through code.

Following are the activities involved in copying document:
  • Find the document library
  • Find the document by name
  • Create a byte array from document
  • Find document set and add document to document set
Inside Visual Studio

Create a new console application and name it as DocLibCreation. Make sure you change the target framework to .Net 3.5.

Add the following code into the Program.cs file:

public static void CopyDocument( SPWeb objProjectSite, SPWeb rootSite)
{
objProjectSite.AllowUnsafeUpdates = true;
SPList objList = rootSite.Lists.TryGetList("Source Document Library");
SPFile objFile = null;
Foreach (SPListItem itm in objList.Items)
{
if (itm.Name == "My Document")
{
objFile = itm.File;
break;
}
}
byte[] sourceFileContent = objFile.OpenBinary();
SPList prjDocsList = objProjectSite.Lists.TryGetList("Destination Document Library");
SPFolder folDocSet = objProjectSite.GetFolder("Destination Document Library" + "/" + "Document Set Name");
folDocSet.Files.Add("Document Name" , sourceFileContent, true );
FolDocSet.Update();
ObjProjectSite.AllowUnsafeUpdates = false;
}

Monday, July 22, 2013

Get all seach scopes for current site collection


In this article we will be seeing about search scopes in SharePoint 2010.|

In this article:
  • Add namespaces
  • Get search context
  • Get all scopes
  • Skip default scopes
  • Add scopes in dropdown
Get all the search scopes:

Add following namespaces.

using Microsoft.Office.Server;
using  Microsoft.Office.Server.Search.Administration;

Use following method to populate all scopes of current site collection in dropdown.

private void GetScopes()
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(SPContext.Current.Site.ID))
{
// Get the search context object.
SearchContext context = SearchContext.GetContext(site);
Scopes scopes = new scopes(context);
foreach(Scope scope in scopes.GetSharedScopes())
{
// Skip following default scopes
// Global Query Exclusion - Everything that should be omitted from all search by default
// Rank Demoted Sites - Sites whose rank will be demoted in click - distance calculation.

if(scope.Name != "Global Query Exclusion" && scope.Name !="Rank demoted Sites")
// Show scopes in dropdown
ddlscopes.Items.Add(scope.Name);
}
}
});
}

Sunday, July 7, 2013

CAML Query to get all documents from a Document Library

CAML query to retrieve all documents from all folders in a document library.

SPList lstDocs = SPContext.Current.Web.Lists.TryGetList("myDocLib");
SPQuery query = new SPQuery();
query.Query = @"<Where><BeginsWith><FieldRef Name = 'ContentTypeId' /><Value Type= 'ContentTypeId'>0x0101</Value></BeginsWith></Where>";
query.ViewAttributes = "Scope = 'RecursiveAll'";
SPListItemCollection itmsDocs = lstDocs.GetItems(query);

Wednesday, March 13, 2013

Deploy Administrator Approved Forms - InfoPath 2010

Administrator-approved form templates

Administrator-approved form templates are available to any site collection on the SharePoint site and can contain code that requires full trust. They are individually verified, uploaded, and activated by a SharePoint site administrator. Administrator-approved form templates are maintained in a special document library that can be accessed only by administrators.

Deploy administrator-approved form templates

To deploy an administrator-approved form template, you must complete three actions after the form template has been designed: verify, upload, and activate. These steps can either be performed through the command-line interface or through the Central Administration site. You can upload a form template by using the Publishing Wizard in the InfoPath program, using the command line on a server running InfoPath Forms Services in the farm to which the form template will be deployed, or by using the Central Administration interface.
To deploy the form using central admin you can refer
http://technet.microsoft.com/en-us/library/cc262921.aspx
Using central admin method we can deploy one form at a time but if we need to deply many forms this process takes lot of time and effort. So I tried to automate this process using powershell. I have wrote a small powershell script to deploy these forms.
# Set the required variables
$siteURL = "
http://MySiteURL"
$publishingDirectory = "Source file location"
$settingsFile = "$publishingDirectory\InfoPathFormsList.txt"
$category = "My Category"
function Show-Progress([string]$activity, [string]$status, [int]$count)
{
if ($count % 4 -eq 1) {write-progress -activity $activity -status $status " _" ;}
if ($count % 4 -eq 2) {write-progress -activity $activity -status $status " \" }
if ($count % 4 -eq 3) {write-progress -activity $activity -status $status " |" }
if ($count % 4 -eq 0) {write-progress -activity $activity -status $status " /" }
}
foreach ($i in Get-Content -Path $settingsFile)
{
$formLocation = "$publishingDirectory\$i.xsn"
# Deactivate the InfoPath form
Write-Output "Deactivate " $i
Disable-SPInfoPathFormTemplate -Identity $i -Site $siteURL -ErrorAction:SilentlyContinue
# uninstall the InfoPath form
Write-Output "Uninstalling " $i
$formTemplate = Get-SPInfoPathFormTemplate -Identity $i -ErrorAction:SilentlyContinue
if ($formTemplate -ne $null)
{
Uninstall-SPInfoPathFormTemplate -Identity $i -ErrorAction:SilentlyContinue
}
$percent = 1
while ($formTemplate -ne $null -and $formTemplate.FormTemplateStatus -eq "Removing")
{
if ($count -eq 100) {$count = 0;}
write-progress -activity "Uninstalling $i" -status "Removing" -percentcomplete (++$count);
$formTemplate = Get-SPInfoPathFormTemplate -Identity $i -ErrorAction:SilentlyContinue;
}
write-progress -activity "Uninstalling $i" -status "Removing" -percentcomplete 100;
# Verify the InfoPath form
#Write-Output "Verifying " $i
#Test-SPInfoPathFormTemplate -Path $formLocation
# Upload the InfoPath form
Write-Output "Uploading " $i
Install-SPInfoPathFormTemplate -Path $formLocation -Confirm:$false
# Activate the InfoPath form
Write-Output "Activating " $i
Enable-SPInfoPathFormTemplate -Identity $i -Site $siteURL
# Modify the category of the form
Set-SPInfoPathFormTemplate -Identity $i -Category $category
}

To use this script

1. Copy this script in a notepad.
2. Change $siteURL =
http://MySiteURL
3. Create a folder sourcesFiles and paste your InfoPath form template (.xsn) files in it.
4. Enter your source folder path in $publishingDirectory = "Source folder path"
5. Save this notepad text as PowerShell script (myScript.ps1).
6. Create a InfoPathFormsList.txt file in the same folder and write all InfoPath form template names (i.e. myTemplate.xsn) in it.
7. Open SharePoint 2010 management shell and run this PowerShell script