Saturday, November 10, 2012

Minimal Download Strategy


In SharePoint 2013 a new feature has been introduced named "Minimal Download Strategy". This feature is enabled by default in sites. One can enable or disable the feature by going to Site Features.

This is very interesting feature. This uses a single page "Start.aspx" for all your pages. It works like Start.aspx# followed by encoded URL of actual page as shown below.
http://sp2013/_layouts/15/start.aspx#/newsfeed.aspx

When users goes from one page to another page then only encoded URL after # will be changed. And Changes between the two pages will be loaded and not the whole page. This way page will appear more quickly as only fewer bytes will be downloaded. Start page is responsible for updating changes between two pages.

As in SharePoint each page includes tons of css and images, this feature will help in reducing burden on SharePoint and will make it more responsive.



Wednesday, July 25, 2012

Copy Files and Folder using Web Service


To copy files, folders and sub folders from one library to another library using web service we will make use of three web services.

1. Lists.asmx: To get all folders and lists.
2. DWS.asmx: To create folders
3. Copy.aspx: To copy files from one library to another


Add above mentioned web refrences to your project.

Sample Project


Below is the function to copy All files, Folders and subfolders




        private void GetAllListItemsRecursively(string sourcelistname, string sourceFolderURL, string destlistname, string destFolderURL)
        {
            XmlNode ndListFolders = null;
            XmlNode ndListItems = null;


            XmlDocument xDocFolders = new XmlDocument();
            XmlNode ndQueryFolders = xDocFolders.CreateNode(XmlNodeType.Element, "Query", "");
            XmlNode ndViewFieldsFolders = xDocFolders.CreateNode(XmlNodeType.Element, "ViewFields", "");
            XmlNode ndQueryOptionsFolders = xDocFolders.CreateNode(XmlNodeType.Element, "QueryOptions", "");
            ndQueryOptionsFolders.InnerXml = @"<Folder>" + sourceFolderURL + "</Folder>";
            ndQueryFolders.InnerXml = "";
            ndViewFieldsFolders.InnerXml = "";
            ndQueryFolders.InnerXml = "<Where><Eq><FieldRef Name='FSObjType' /><Value Type='Lookup'>1</Value></Eq></Where>";


            XmlDocument xDocItems = new XmlDocument();
            XmlNode ndQueryItems = xDocItems.CreateNode(XmlNodeType.Element, "Query", "");
            XmlNode ndViewFieldsItems = xDocItems.CreateNode(XmlNodeType.Element, "ViewFields", "");
            XmlNode ndQueryOptionsItems = xDocItems.CreateNode(XmlNodeType.Element, "QueryOptions", "");
            ndQueryOptionsItems.InnerXml = @"<Folder>" + sourceFolderURL + "</Folder>";
            ndQueryItems.InnerXml = "";
            ndViewFieldsItems.InnerXml = "";
            ndQueryItems.InnerXml = "<Where><Eq><FieldRef Name='FSObjType' /><Value Type='Lookup'>0</Value></Eq></Where>";


            try
            {
                ndListFolders = _Lists.GetListItems(
                                    sourcelistname,
                                    "",
                                    ndQueryFolders,
                                    ndViewFieldsFolders,
                                    null,
                                    ndQueryOptionsFolders, null
                    );


                ndListItems = _Lists.GetListItems(
                                   sourcelistname,
                                   "",
                                   ndQueryItems,
                                   ndViewFieldsItems,
                                   null,
                                   ndQueryOptionsItems, null
                   );
            }
            catch (Exception ex)
            {


            }


            //Copy Folders
            if (ndListFolders != null)
            {
                foreach (XmlNode node in ndListFolders.ChildNodes)
                {
                    if (node.Name == "rs:data")
                    {
                        for (int i = 0; i < node.ChildNodes.Count; i++)
                        {
                            if (node.ChildNodes[i].Name == "z:row")
                            {
                                string newfolderName1 = node.ChildNodes[i].Attributes["ows_LinkFilename"].Value;
                                string rootFolder = string.Format("{0}/{1}", destFolderURL, newfolderName1);
                                _Dws.CreateFolder(rootFolder);


                                GetAllListItemsRecursively(sourcelistname, sourceFolderURL + @"\" + newfolderName1, destlistname, rootFolder);
                            }
                        }
                    }
                }
            }


            //Copy Files
            if (ndListItems != null)
            {
                foreach (XmlNode node in ndListItems.ChildNodes)
                {
                    if (node.Name == "rs:data")
                    {
                        for (int i = 0; i < node.ChildNodes.Count; i++)
                        {
                            if (node.ChildNodes[i].Name == "z:row")
                            {
                                string filename = node.ChildNodes[i].Attributes["ows_LinkFilename"].Value;


                                string finalsourceFolderURL = sourceFolderURL.Replace(@"\", "/");
                                if (!finalsourceFolderURL.EndsWith("/"))
                                    finalsourceFolderURL = finalsourceFolderURL + "/";
                                finalsourceFolderURL = siteURL + finalsourceFolderURL + filename;


                                string finaldestFolderURL = destFolderURL.Replace(@"\", "/");
                                if (!finaldestFolderURL.EndsWith("/"))
                                    finaldestFolderURL = finaldestFolderURL + "/";
                                finaldestFolderURL = siteURL + finaldestFolderURL + filename;
                                string[] copyDest = { finaldestFolderURL };


                                CopyResult myCopyResult1 = new CopyResult();
                                CopyResult[] myCopyResultArray = { myCopyResult1 };


                                // string copyResult;
                                try
                                {
                                    _Copy.CopyIntoItemsLocal(finalsourceFolderURL, copyDest, out myCopyResultArray);
                                }
                                catch (Exception exc) { }
                            }
                        }
                    }
                }
            }
        }

Sample Project

Monday, July 23, 2012

SharePoint 2010 Feature Stapling



Feature Stapling allows you to create a feature and then associate it with any site definition without ever touching the site definition files themselves. Your feature will be activated when the site is provisioned.


Stapling basically consist of two features:
  1. Staplee Feature: The feature which will be stapled to an existing site definition
  2. Stapler Feature: The feature which will staple the staplee feature with site definition

Steps

  1. Create new Empty SharePoint Project.
  2. Create staplee feature which we want to get activated on site provisioning.
  3. Create Stapler feature with scope as Farm.
  4. Add new Empy Element "StaplerElementHelper" to the project.
  5. Edit Element.xml file
  6. Add follwing line<FeatureSiteTemplateAssociation Id="d3f566c2-b711-4ddb-808b-c4d0c00dac36" TemplateName="STS#0" />FeatureSiteTemplateAssociation is going to associate our steplee feature with site definition "STS#0"(team site).
    Note: Replace value of Id with your staplee feature ID. You can also specify your own TemplateName.

    your complete file will look like
    <?xml version="1.0" encoding="utf-8"?>
    <Elements xmlns="http://schemas.microsoft.com/sharepoint/"><FeatureSiteTemplateAssociation Id="d3f566c2-b711-4ddb-808b-c4d0c00dac36" TemplateName="STS#0" />
    </Elements>
  7. Double click your Stapler Feature and Include "StaplerElementHelper" in "Items in feature". Remember it should be included in Stapler feature and not in staplee feature.
  8. Deploy it.



Now whenever you create a new site using site definition specified in FeatureSiteTemplateAssociation staplee feature will automatically get activated.

Sample Project

Wednesday, May 9, 2012

Retrieving Credentials from Secure Store Service

MOSS 2007 makes use of Single Sign On Service which has been replaced by Secure Store Service in SharePoint 2010. Secure Store Service can be used authenticate External Applications.
To see how to configure SSS please visit Configure the Secure Store Service SharePoint 2010


We will create a custom web part to retrieve current user credentials.
Open Visual Studio and create new Empty SharePoint Project.
Add new Visual webpart.
Add reference to following dll
  • Microsoft.BusinessData (C:\Windows\assembly\GAC_MSIL\Microsoft.Office.SecureStoreService\14.0.0.0__71e9bce111e9429c\Microsoft.Office.SecureStoreService.dll )
  • Microsoft.Office.SecureStoreService.Server
    (C:\Windows\assembly\GAC_MSIL\Microsoft.BusinessData\14.0.0.0__71e9bce111e9429c\Microsoft.BusinessData.dll)
  • Microsoft.SharePoint
Add following method in visual webpart's usercontrol code behind

 private static string GetStringFromSecureString(SecureString secStr)
        {
            if (secStr == null)
            {
                return null;
            }

            IntPtr pPlainText = IntPtr.Zero;
            try
            {
                pPlainText = Marshal.SecureStringToBSTR(secStr);
                return Marshal.PtrToStringBSTR(pPlainText);
            }
            finally
            {
                if (pPlainText != IntPtr.Zero)
                {
                    Marshal.FreeBSTR(pPlainText);
                }
            }
        }

Now in user control design add two labels "lblUsername" and "lblPassword". Then in code behind file add following code in page load.

string _TargetApplicationID = "MyCustomApp";

            ISecureStoreProvider _ISecureStoreProvider = SecureStoreProviderFactory.Create();
            if (_ISecureStoreProvider == null)
            {
                throw new InvalidOperationException("Unable to get an ISecureStoreProvider");
            }

            ISecureStoreServiceContext _ISecureStoreServiceContext = _ISecureStoreProvider as ISecureStoreServiceContext;
            _ISecureStoreServiceContext.Context = SPServiceContext.GetContext(SPContext.Current.Site);
           
            try
            {
                SecureStoreCredentialCollection _SecureStoreCredentialCollection = _ISecureStoreProvider.GetCredentials(_TargetApplicationID);
                if (_SecureStoreCredentialCollection != null)
                {
                    foreach (SecureStoreCredential _SecureStoreCredential in _SecureStoreCredentialCollection)
                    {
                        if (_SecureStoreCredential == null)
                            continue;

                        switch (_SecureStoreCredential.CredentialType)
                        {
                            case SecureStoreCredentialType.UserName:
                                 lblUsername.Text = GetStringFromSecureString(_SecureStoreCredential.Credential);
                                break;

                            case SecureStoreCredentialType.Password:
                                  lblPassword.Text = GetStringFromSecureString(_SecureStoreCredential.Credential);
                                break;
                        }
                    }
                }
           }
            catch (SecureStoreException e)
            {
                throw;
            }



Sunday, May 6, 2012

Configure the Secure Store Service SharePoint 2010

The Secure Store Service is a claims-aware authorization service that includes a secure database for storing credentials. These credentials usually consists of username and passwords but can also contain some other fields. Then these credentials can be used to connect external systems like SQL server, BCS etc.


The first time you access the Secure Stored Service it will ask you generate a new encryption key. This key will be used to encrypt and decrypt credentials stored in Secure store.


Generate new encryption key
Open Central Admin site. 
Go to Application Management > Service Applications > Manage Service Applications.
Select Secure Store Service and click Manage in Ribbon.
On Ribbon click "Generate New Key". Enter Pass Phrase and click OK.


Next step is to create Target Application. A Target Application Maps credential of a user, group to a set of encrypted credentials stored in secure store.


Create Target Application
Click "New" in Ribbon under "Manage Target Application" Group.
"Target Application ID": This is unique string to identify target application.
"Display Name": Display name of target application.
"Email": Email of primary contact of target Application.
Target Application Type": Drop-down list, choose the target application type: There are two primary types for creating a target application:
  • Group, for mapping all the members of one or more groups to a single set of credentials on the external data source.
  • Individual, for mapping each user to a unique set of credentials on the external data source.
Click Next. 
On this screen we can define fields that can be supply to external sources. By default two fields will be listed "Window User Name" and "Window Password".

Click Next.
Specify the Target Application Administrators and click OK.


Now if you have chosen Target Application Type as Individual the users can add individual credentials using default page
http://{your site url}/_layouts/SecureStoreSetCredentials.aspx?TargetAppId={TargetApplicationID}, where  {TargetApplicationID}  is the string typed in the "Target Application ID" box.










Saturday, April 21, 2012

How to Add Property Restriction to Advance Search?

The property you want to add must be a crawled property and is mapped to a managed property. 


Steps to add property to crawled properties.

Open Central Administration site.
Go to Application Management. 
Under Service Applications click on Manage Service Applications
Open your Search Service Application.
Click on Content Sources under Crawling in quick launch as shown below. And click "Start Full Crawl".


After crawling completes. We need to map the property to a new managed property.


Steps to Create Managed Property and Add Mapping to crawled Property

Under Search service application management screen click Metadata Properties under Queries And Results in Quick launch. As shown below. 


Click on "New Managed Property".


On New screen give a Property Name
Select Type of Property.
Click Add Mapping. On add mapping screen search for your crawled property, select it and click Ok.
Check "Allow this Property to be used in scopes"

Click Ok on New Managed Property screen.
Re-run full crawler.


Note: Re-run the full crawler so that new managed property can be used for search in property restrictions.



Steps to Add Newly created Managed Property to Property restrictions.


Open Advance search page.
Click Edit Page Under Site Settings.
Click Edit webpart (Advance Search box webpart)
Expand Properties under webpart properties as shown below.


Click on square button after Property text box as shown below.


Copy contents. Open any xml editor tool and paste that content in editor.
Find ending tag </PropertyDefs>. Add new <PropertyDef> before this as shown below.


Now Add <PropertyRef> before all </ResultType> as shown below.


Copy All contents and replace Properties with this new xml.
Click ok on Webpart properties.
Save and Check in your page.
Check your Property restriction dropdown and your new property will be available to be used in advance search

Friday, April 6, 2012

Send Email in Sandbox Solution






In sandbox solution SPUtility.SendMail method has been blocked explicitly. So there is no way to send email using code in Sandbox solution.



I googled alot but not able to find any solution. Then I decided to try something and it worked :)



  • What I did was i created Custom Content Type using Visual Studio. 
  • Then created a Send Email Workflow Activity on my custom Content Type using Sharepoint Designer.
  • I saved that workflow as template and I exported that workflow to local Drive.
  • And then created a new Project using template "Import SharePoint Solution Package".
  • Then created another list programmatically using my custom content type.
  • Then associated my workflow with my custom list.
  • And then when ever I require to send an email. I just add records in my list. Workflow triggers and sends an email.

Steps in detail are as below:
  1. Create Empty SharePoint Project in Visual Studio. Create custom content type "EmailHelperContentType" with following custom FieldsEmailTo (single line)EmailCC (Single Line)EmailBodyText (MultiLine)EmailSubjectText (Single Line)
  2. Deploy this project.
  3. Open SharePoint Designer and open sharePoint Root web.Note: Always create Reusable Workflow at top level site.
  4. Click Reusable Workflow.
  5. On click will open up another window. Give Name and in Content type select your content type deployed in step 1.
  6. Under Actions > Core Actions > Send an Email
  7. Click "these users"
  8. For To field value click lookup > double click "Workflow Lookup for a user"
  9. Select Datasource = "Current Item"Field from source = "EmailTo"

  10. Similarly define CC, Subject and body as shown below.
  11. Click Save.
  12. Click workflow under Navigation. Select your Resuable Workflow. And in Ribbon click "Save as Template". The template will be saved in Site Assets". Refresh if you can't see it there.
  13. Select file and in Ribbon click "Export File". And save this file to desktop.
  14. Now Open Visual Studio and create new Project using template "Import SharePoint Solution Package"
  15. On next screen enter your site url and deploy as Sandbox as shown below. Click Next.
  16. Select the template created in step 12. And click Next.
  17. On next screen two items will shown up select both and click finish.
  18. You will notice one feature create for you.
  19. Add new Event receiver to feature
  20. In feature Activated Create new list " EmailHelper" and add Workflow association with list "EmailHelper" as show below.
string contentTypeName = "EmailHelperContentType";
            string workflowName = "Email Sender";
            string workflowTemplateName = "EmailHelperWorkflow";
           
            string listTaskName = "Tasks";
            string listHistoryName = "WorkflowHistory";
            string listEmailName = "EmailHelper";
            SPContentType siteContentType = web.Site.RootWeb.ContentTypes[contentTypeName];
            SPList historylist = web.Lists.TryGetList(listHistoryName);
            if (historylist == null)
            {
                web.Lists.Add(listHistoryName, listHistoryName, SPListTemplateType.WorkflowHistory);
                historylist = web.Lists.TryGetList(listHistoryName);
            }
            SPList tasklist = web.Lists.TryGetList(listTaskName);
            if (tasklist == null)
            {
                web.Lists.Add(listTaskName, listTaskName, SPListTemplateType.Tasks);
                tasklist = web.Lists.TryGetList(listTaskName);
            }
            SPList mainlist = web.Lists.TryGetList(listEmailName);
            if (mainlist == null)
            {
                web.Lists.Add(listEmailName, listEmailName, SPListTemplateType.GenericList);
                mainlist = web.Lists.TryGetList(listEmailName);
                mainlist.Hidden = true;
                mainlist.ContentTypesEnabled = true;
                mainlist.ContentTypes.Add(siteContentType);
                mainlist.ContentTypes.Delete(mainlist.ContentTypes["Item"].Id);
                SPWorkflowTemplate workflowTemplate = null;
                foreach (SPWorkflowTemplate template in web.WorkflowTemplates)
                {
                    workflowTemplate = template;
                    // We'll take a template everyone has.
                    if (workflowTemplate.Name == workflowTemplateName) break;
                }
                SPWorkflowAssociation association =
                   SPWorkflowAssociation.CreateListContentTypeAssociation(workflowTemplate,
                                                                          workflowName,
                                                                          tasklist,
                                                                          historylist);
                association.AllowManual = true;
                association.AutoStartCreate = true;
                association.AutoStartChange = false;
                mainlist.WorkflowAssociations.Add(association);
                mainlist.Update();


For more detail on Sandbox Solution Visit Here



Wednesday, February 15, 2012

Send to Connection using Code And Shell


New feature in SharePoint 2010 "Send To Connections" offers good support for managed Documents. A user can easily Move, Copy or send document to a new location.


Documents can be sent accross sites and even web application.
We can create Send To Connection in three ways.
  • Using Central Administration.
  • Using Code.
  • Using Power Shell.

Here I am not discussing about content organizer feature. I assume you know about "Content Organizer" feature.


Lets take an example to create "Send To Connection", source site is at url http://anmol-pc and your destination site is http://anmol-pc/Recordcenter/

First of all activate "Content Organizer" feature on both sites. Next step is create "Send To Connection". Below are three methods you can use any one you like.

How to create send to connection using Central Administration?

  • Go to Central Administration
  • General Application Settings 
  • "Configure send to connections" under heading "External Service Connections". This will open up a Send To Connection configuration page. 
  • Select checkbox "Allow sites to send to connections outside the site subscription" under Site Subscription Settings.
  • Under Connection give "Display Name" 
  • Send To Url, this is location of service on destination site. In our example it should be http://anmol-pc/Recordcenter/_vti_bin/officialfile.asmx 
  • Specify "Send To Action". Three options are available "Copy", "Move", "Move Leave a Link" 
  • Click Add Connection and click ok.

    Below is screenshot how it looks like.



How to create send to connection using Code?

using (SPSite site = new SPSite("http://anmol-pc"))
{   
   SPOfficialFileHost officialFileHost = new SPOfficialFileHost(true);   
   officialFileHost.OfficialFileUrl = 

          new Uri(site.Url+"/recordcenter/_vti_bin/officialfile.asmx");   
   officialFileHost.OfficialFileName = "Records Center";   
   officialFileHost.ShowOnSendToMenu = true; 
   officialFileHost.Action = SPOfficialFileAction.Move;   


   SPWebApplication webapp = site.WebApplication;
   webapp.OfficialFileHosts.Add(officialFileHost);    
   webapp.Update();
}


How to create send to connection using shell?

$SiteUrl = "http://anmol-pc"
$RecordCenterUrl = "recordcenter"



$SPSite = Get-SPSite | Where-Object {$_.Url -eq $SiteUrl}
$officialFileHost = New-Object Microsoft.SharePoint.SPOfficialFileHost
$officialFileHost.OfficialFileName = "Records Center"
$SubmissionServiceUrl = $SiteUrl + "/" + $RecordCenterUrl + "/_vti_bin/officialfile.asmx"

$officialFileHost.OfficialFileUrl = $SubmissionServiceUrl
$officialFileHost.ShowOnSendToMenu = $true
$officialFileHost.Explanation = "Send a file to Records Center"

$SPSite.WebApplication.OfficialFileHosts.Add($officialFileHost)
$SPSite.WebApplication.Update()



Write-Host "Send to Connection complete"
$SPSite.Dispose()

Friday, January 27, 2012

How Foundation Search Shows Results

To understand better how search works see the image below. Lets assume we have three site collections with different number of webs in each site collection.

Now if we do search for "Mydoc" file at different site levels we will get different results. 

If search is performed at Top Level Site Collection (S1): Search will be performed at each site collection level and each web.We will get results from all site collections and all webs.

If search is performed at W1: We will get results from W1 and W1a

If search is performed at W2: We will get result only from W2

If search is performed at Site collection 2(S2): We will get results from W3 and W4.

If search is performed at W3: We will get results from W3.

Similarly if we perform search at Site Collection 3(S3): We will get results from only W5. 

If you have noticed in above only Top level site collection returns results from all sites and webs. Where as from all other locations results are returned only from that location and down the tree.

Now the question arises why Top level site collection behaves different from all other levels?
If you see URL for search results at top level site collection it will look something like:
http://anmol/_layouts/searchresults.aspx?k=MyDoc&u=http%3A%2F%2Fanmol

There are two parameters k=MyDoc and u=http%3A%2F%2Fanmol, this means we are doing a search for MyDoc and return all documents that start with http://anmol

As every site collection and every web starts with this URL so we will get results from all locations when search is performed at top level.

Thursday, January 26, 2012

SharePoint Configuring Foundation Search


Configure Foundation Search
  • Open Central Administration
  • Go to System Settings > Manage Service on Server
  • Scroll down to bottom and click start against "SharePoint Foundation Search"
  • Service Account: Please specify managed account
  • Content Access Account: This should be an account dedicated only for search.
  • Search Database: Specify the Database Server and Database Name.
    Specify any Fail over server if you are using any.
  • Indexing Schedule: Here you need to specify proper schedule as per you requirement. If you are not sure then leave default settings as it is.
  • Click Start. It will take few minutes to start up the service.
Next Step is associate Content Database with Search Service.
  • Go to Application Management 
  • Under "Databases" > "Manage Content Databases"
  • Click on link of the content database.
  • For Search Server select the configured search server from drop down.
  • Click Ok. You need to repeat these steps for all content databases.
Remember you can search only after the indexer is run. It will run according to the scheduler you specified. If you want to run it immediately then
  • Go to Monitoring > Review Job definitions
  • Scroll down to "SharePoint Foundation Search Refresh", click on link.
  • Click on "Run Now" button.
or you can use stsadm command
  • stsadm -o spservice -action FullCrawlStart

Sunday, January 22, 2012

SharePoint 2010 Document Library Upload Issues

Issue 1:
Can't upload more than 100 documents at a one time in SharePoint 2010 Library.



Solution:
Open Library in Explorer View. This way you can upload as many as documents as you like.


Issue 2:
Can't upload documents more than some MB's size

Solution: 

  • Open Central Administration
  • Go to Application Management > Manage Web applications
  • Select Web application and click "General Settings"
  • Scroll down to modal window and change "Maximum Upload Size". You can set this to maximum of 2GB.
  • You may encounter "Security Validation error if upload is taking time more than 30 mins. To resolve this issue. Scroll up and change "Security validation expires"

Issue 3:
Upload Multiple Documents link is greyed out.

Solution 1
This will be greyed out if you have opened the site in Mozilla Firefox. Open site in Internet Explorer and it will be fine.

Solution 2
This is actually client integration component  and can be available if office 2010 client installed. First time you navigate to library you will be asked for an ActiveX Control. You need to install that and everything will work fine.

Popular Posts