Category: SharePoint Development

SharePoint Development

Consume a SharePoint 2013 Online REST feed using .NET managed code

Home | Office 365 | Consume a SharePoint 2013 Online REST feed using .NET managed code

In this post, we’ll see how we can consume a SharePoint 2013 online REST feed using managed c# code. I’d be using a Provider Hosted App template in Visual Studio 2013 for this demonstration. It is very straight forward to consume a Restful .NET service by issuing HttpWebRequest from c# code and getting HttpWebResponse.

I will be invoking https://yoursite.sharepoint.com/_api/web/lists from c# code to get the list of SharePoint lists in this Office 365 site. The following screenshot shows the response for this Restful service in the browser.

image

Now let’s start creating a Provider hosted app project in Visual Studio 2013.

File –> New Project –> Visual C# –> Office/SharePoint –> App for SharePoint 2013 and name it as ‘ReadRESTCSharp’ & set the site for debugging and app type as ‘Provider-hosted’.

image

Specify the web project type as ‘ASP.NET Web Forms Application’. In the next step, Visual Studio 2013 would prompt for setting App Authentication Type, I did not see this option while using Visual Studio 2012 to create Provider hosted apps.

image

Set the App authentication type as ‘Use Windows Azure Access Control Service’ (mentioned in the above screenshot).

Click ‘Finish’ to create the app.

Go to  ASP.NET Web Forms project and open the default.aspx.cs

Import the following three namespaces at the top.

using Microsoft.SharePoint.Client;
using System.Net;
using System.IO;

In page_load comment out the following lines of code.

//var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);

            //using (var clientContext = spContext.CreateUserClientContextForSPHost())
            //{
              //  clientContext.Load(clientContext.Web, web => web.Title);
               // clientContext.ExecuteQuery();
                //Response.Write(clientContext.Web.Title);
            //}

Since I’m using my own developer tenant in Office 365, I would want to trust all the certificates issued by SharePoint Online to my browser. Otherwise, it will keeping popping up a message to trust the certificates in Visual Studio 2013, when I hit F5 and debug the app.

Open the TokenHelper.cs and the add the following static method ‘TrustAllCertificates’

public static void TrustAllCertificates()
        {
            //Trust all certificates
            System.Net.ServicePointManager.ServerCertificateValidationCallback =
                ((sender, certificate, chain, sslPolicyErrors) => true);
        }

If you are using Visual Studio 2012, it adds ‘TrustAllCertificates’ in TokenHelper.cs by default.

I will be using my Office 365 developer tenant for this demo, which forces the need to get the Access Token from Office 365 and pass it as a part of the header in the HttpWebRequest. First I need to get the ContextTokenString by invoking GetContextTokenFromRequest method in TokenHelper.cs. Then I need to get the actual SharePointContextToken by invoking ReadAndValidateContextToken method in the TokenHelper.cs. Finally I need to get AccessToken by invoking the GetAccessToken method in the TokenHelper.cs. I won’t go too detailed about this one. All the dynamics of the Token exchange is covered in one of my previous article.

Once the AccessToken is received, a HTTPWebRequest needs to be issued by setting the AccessToken with Bearer, also we need to set the HTTPRequest method as ‘GET’ and HTTPRequest accept headers as “application/json;odata=verbose”.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Net;
using System.IO;
using Microsoft.SharePoint.Client;

namespace ReadRESTCSharpWeb
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_PreInit(object sender, EventArgs e)
        {
            Uri redirectUrl;
            switch (SharePointContextProvider.CheckRedirectionStatus(Context, out redirectUrl))
            {
                case RedirectionStatus.Ok:
                    return;
                case RedirectionStatus.ShouldRedirect:
                    Response.Redirect(redirectUrl.AbsoluteUri, endResponse: true);
                    break;
                case RedirectionStatus.CanNotRedirect:
                    Response.Write("An error occurred while processing your request.");
                    Response.End();
                    break;
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            
            // The following code gets the client context and Title property by using TokenHelper.
            // To access other properties, the app may need to request permissions on the host web.
            //var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);

            //using (var clientContext = spContext.CreateUserClientContextForSPHost())
            //{
              //  clientContext.Load(clientContext.Web, web => web.Title);
               // clientContext.ExecuteQuery();
                //Response.Write(clientContext.Web.Title);


            //}

            TokenHelper.TrustAllCertificates();

            //Get the ContextTokenString
            string ContextTokenString = TokenHelper.GetContextTokenFromRequest(Request);



            if (ContextTokenString != null)
            {

                //Get the SharePointContextToken
                SharePointContextToken ContextToken = TokenHelper.ReadAndValidateContextToken(ContextTokenString, Request.Url.Authority);

                Uri sharepointUrl = new Uri(Request.QueryString["SPHostUrl"]);

                //Get the AccessToken
                string AccessToken = TokenHelper.GetAccessToken(ContextToken,sharepointUrl.Authority).AccessToken;

                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(@"https://yoursite.sharepoint.com/_api/web/lists");
                request.Method = "GET";
                request.Accept = "application/json;odata=verbose";
                request.Headers.Add("Authorization", "Bearer " + AccessToken);

                HttpWebResponse response =(HttpWebResponse)request.GetResponse();
                StreamReader reader = new StreamReader(response.GetResponseStream());

                Response.Write("<h2>List of SharePoint lists in SharePoint Online fetched from managed code</h2>");
                Response.Write("<p>" + reader.ReadToEnd() + "</p>");
                Response.Flush();
            
            
            }




        }
    }
}

After executing the above we get the successful HTTPResponse which can be seen in debug mode in Visual Studio 2013.

image

  Subscribe to my blog

How to retrieve current user in SharePoint 2013 Online using CSOM

Home | Office 365 | How to retrieve current user in SharePoint 2013 Online using CSOM

In this post, we’ll see how we can retrieve the current user in a SharePoint 2013 online site using client side object model (CSOM). We’ll  be using a console application for the purpose of this demonstration.

Open Visual Studio 2013

File –> New Project –> C# –> Console application

Add  reference to the following assemblies.

Microsoft.SharePoint.Client.dll

Microsoft.SharePoint.Client.runtime.dll

Import the following namespaces at the top of Program.cs

using  Microsoft.SharePoint.Client;
using System.Security;

namespace Retrievecurrentuser
{
    class Program
    {
        static void Main(string[] args)
        {

            using (ClientContext oClientContext = new ClientContext(@"https://yoursite.sharepoint.com"))
            {

                //Assign User Id for your SharePoint Online tenant     
                string UserName = "userid@yoursite.onmicrosoft.com";

                //Assign password for your SharePoint online tenant
                string Password = "password";

                //Create a SecureString object from password string, needed for SharePointOnlineCredentials class
                SecureString SecurePassword = GetSecureString(Password);
                oClientContext.Credentials = new SharePointOnlineCredentials(UserName, SecurePassword);


                //load the properties of web object
                Web oWeb = oClientContext.Web;
                oClientContext.Load(oWeb);
                oClientContext.ExecuteQuery();

                //retrieve the site name
                string SiteName = oWeb.Title;

                //retrieve the current user
                oClientContext.Load(oWeb.CurrentUser);
                oClientContext.ExecuteQuery();

            Console.WriteLine("Login Name"+ oClientContext.Web.CurrentUser.LoginName);
                Console.WriteLine("Is Admin"+ oClientContext.Web.CurrentUser.IsSiteAdmin);
                Console.WriteLine("Email"+ oClientContext.Web.CurrentUser.Email);
                
                Console.ReadLine();


            }
        }

        private static SecureString GetSecureString(String Password)
        {
            SecureString oSecurePassword = new SecureString();

            foreach (Char c in Password.ToCharArray())
            {
                oSecurePassword.AppendChar(c);

            }
            return oSecurePassword;
        }

    }
}

Then create a clientcontext in the program.cs, load the web object (execute query) and then load the current user based on the web object.

Now we’ll be able to fetch the user properties like the below.

image

 Subscribe to my blog

SharePoint Conference Videos 2014

Home | SharePoint Development | SharePoint Conference Videos 2014

The SharePoint Conference 2014 videos are available in Channel9.
Please check it out
http://channel9.msdn.com/Events/SharePoint-Conference/2014

How to create a simple Remote Event Receiver for a Custom List in Office 365 SharePoint 2013 site

Home | Office 365 | How to create a simple Remote Event Receiver for a Custom List in Office 365 SharePoint 2013 site

In this article, we’ll see how to create a remote event receiver for a custom list (in App Web) in SharePoint 2013 Online.  The Remote Event Receivers are components (classes) that makes SharePoint Apps to respond to events that occur in SharePoint lists or items.

Create a new App in Visual Studio 2012 and name it as ‘CustomListEventReceiver’

image

Set the Office 365 SharePoint site for debugging the App and select App Type as SharePoint Hosted App

image

Now the app project is created. The next step is to create or set up a Custom List in the App.

Right Click –> Add New Item –> List  and name it as ‘TestCustomList’

image

Select ‘Default(CustomList)’ for Create a custom list template and list instance of it –> Finish

image

Now the Custom List is created. The next step is to add the Remote Event Receiver.

Right Click –> Add New Item –> RemoteEventReceiver and name it as TestEventReceiver.

image

This creates a RemoteWeb Project containing .svc file listening for remote events . The whole ideas is that in SharePoint 2013, the event handling for Lists and Items happened outside of SharePoint in the WCF Service (inside RemoteWeb Project).

Select the following 3 events  to be handled

image

Now you’ll see a remote event receiver project (.svc file inside it) created as the part of the Solution.

image

Remove the ClientId and ClientSecret from Web.Config file

<add key="ClientId" value="b0b7eb35-8980-4910-a3f6-f7129bb16466" />
<add key="ClientSecret" value="oVS2tUbGHbnWEQMPk2i5VvwdyOH04iiWJZmp0N9HXSE=" />

Open the AppManifest.xml file and change the AppPrincipal to internal

<AppPrincipal>
   <Internal/>   
 </AppPrincipal>

Go to Project Properties in Visual Studio 2012 and set the following properties

image

Since this App is running in Office 365, we need to set an Azure Service Bus connection string is required for debugging the remote event receiver (.svc component). Otherwise, we’ll get this debugging error mentioned in one of my previous article.

Go to Elements.xml of default.aspx under Pages.xml.

Remove the following File tag in the Elements.xml

<File Path="PagesDefault.aspx" Url="Pages/Default.aspx" ReplaceContent="TRUE" />

Add the following File tag inside Elements.xml

 <File Path="PagesDefault.aspx" Url="Pages/Default.aspx" >
      <AllUsersWebPart WebPartZoneID="full" WebPartOrder="0">
        <![CDATA[ 
      <webParts>
      <webPart xmlns="http://schemas.microsoft.com/WebPart/v3">
      <metaData>
      <type
    name="Microsoft.SharePoint.WebPartPages.XsltListViewWebPart,
    Microsoft.SharePoint,Version=14.0.0.0,Culture=neutral,
    PublicKeyToken=71e9bce111e9429c" />
      <importErrorMessage>
      Cannot import this Web Part.
      </importErrorMessage>
      </metaData>
      <data>
        <properties>
          <property name="Title"
           type="string">TestCustomList</property>
          <property name="ListDisplayName"
           type="string">TestCustomList</property> 
           <property name="ChromeType"
           type="chrometype">TitleOnly</property>
        </properties>
      </data>
    </webPart>
  </webParts>
]]>
      </AllUsersWebPart>
    </File>

The above File element inserts an XSLST List View web part to render the list items of TestCustomList with the column name Title.

Open default.aspx and add the following webpart definition inside the  PlaceHolderMain (just outside of the div containing <p> with id as message)

<WebPartPages:WebPartZone runat="server" FrameType="TitleBarOnly" ID="full" Title="loc:full" />

Open TestEventReceiver and implement the ProcessEvent(SPRemoteEventProperties properties) method for the ItemAdding and ItemDeleted events

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.EventReceivers;

namespace CustomListEventReceiverWeb.Services
{
    public class TestEventReceiver : IRemoteEventService
    {
        public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties)
        {
            SPRemoteEventResult oResult = new SPRemoteEventResult();
                       
            

            switch (properties.EventType)
            {
                case SPRemoteEventType.ItemAdding:


                   
                    
                    oResult.ChangedItemProperties.Add("Title", properties.ItemEventProperties.AfterProperties["Title"] += "Sundar");
                    break;

                case SPRemoteEventType.ItemDeleting:
                    oResult.ErrorMessage = "You cannot delete this list item";
                    oResult.Status = SPRemoteEventServiceStatus.CancelWithError;
                    break;
            }


            return oResult;
        }

        public void ProcessOneWayEvent(SPRemoteEventProperties properties)
        {
            if (properties.EventType == SPRemoteEventType.ItemAdded)
            {
                //Do something here ...
            }
        }
    }
}

Hit F5 and run the CustomListEventReceiver app

Now we’ll see the  item Title appended with “Sundar” (execution of ItemAdding event)

image

 

image

When we try to delete the item, it throws an error message “You cannot delete this list item” (execution of item deleted event).

image

 Subscribe to my blog

Retrieve Person or Group field using SharePoint 2013 Client Object Model

Home | SharePoint Development | Retrieve Person or Group field using SharePoint 2013 Client Object Model

I’m involved in troubleshooting a crazy people picker field issue in SharePoint 2013, which necessitates me to programmatically query the Person or Group field of SharePoint list using Client Object model. I was trying to figure out the exact syntax that can be used to grab the Person or Group field using FieldUserValue objects. Here is the complete code below :-

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Client;
using System.Net;

namespace ReadApproverNameField
{
    public class Program
    {
        static void Main(string[] args)
        {
            GetApproverDetails();
            Console.ReadLine();

        }

        public static void GetApproverDetails()
        {
            ClientContext clientContext = new ClientContext(http://servername/sites/sitecollectionname);
            
            NetworkCredential oNetworkCredential = new NetworkCredential();
            oNetworkCredential.Domain = @"Domain Name";
            oNetworkCredential.UserName = @"User Id";
            oNetworkCredential.Password = @"Password";
            clientContext.Credentials = oNetworkCredential;

            List list = clientContext.Web.Lists.GetByTitle("Name of the list");

            CamlQuery camlQuery = new CamlQuery();
            camlQuery.ViewXml = "<View/>";
            ListItemCollection listItems = list.GetItems(camlQuery);
            clientContext.Load(list); 
            clientContext.Load(listItems);
            clientContext.ExecuteQuery();


            foreach (ListItem oListItem in listItems)
            {
                
                FieldUserValue name = oListItem.FieldValues["ApproverName"] as FieldUserValue;
                string person = name.LookupValue;                
                Console.WriteLine(oListItem.Id + "     " + oListItem["Title"].ToString() + "     " + person);


            }
        }
    }
}
Basically we cannot create a new instance of FieldUserValue object, it needs to be casted from the current item’s field using ‘as FieldValue’ syntax
and then the LookupValue need to be invoked to fetch the value. If we run the above code, we’ll get the output below.
pic1

 Subscribe to my blog

Programmatically update Author and Editor fields in SharePoint

Home | SharePoint Development | Programmatically update Author and Editor fields in SharePoint

I’m working on a data-migration scenario, where there is a need to update the CreatedBy (Author) and ModifiedBy(Editor) fields in SharePoint.

            using (SPSite oSPSite = new SPSite(http://yoursitecollectionurl))
            {
                using (SPWeb oSPWeb = oSPSite.RootWeb)
                {
                    SPList oSPList = oSPWeb.Lists["testlist"];


                    foreach (SPListItem oSPListItem in oSPList.Items)
                    {
                        SPFieldUserValue oSPFieldUserValue = new SPFieldUserValue(oSPWeb, oSPWeb.AllUsers[@"domainuser"].ID, 
                           oSPWeb.AllUsers[@"domainuser"].LoginName);
                        oSPListItem["Author"]= oSPFieldUserValue;
                        oSPListItem["Editor"]= oSPFieldUserValue;
                        oSPListItem.Update();                      

                                        }
                
                } 
The above code-snippet updates the Author and Editor fields of SharePoint list, based on the specific user (SPFieldUserValue object).

 Subscribe to my blog

Migrate SharePoint sites using Content Migration APIs

Home | SharePoint Development | Migrate SharePoint sites using Content Migration APIs

The export/import method provides the flexibility to migrate a site/sub-site from one web application to another web application (in a different content database) within a farm. It also provides the flexibility to export a sub-site and import it as a root site-collection in another web application. In this post I’d be discussing about how to programmatically migrate SharePoint sites using Content Migration APIs.

 

Code to export a site

                    string sourceSiteURL = "Your site url";//site to be exported
                    SPExportObject exportObject = "Path where you site to be exported";
                    string folderPath = "folder path";

                    using (SPSite sourceSite = new SPSite(sourceSiteURL))
                    {
                        using (SPWeb sourceWeb = sourceSite.OpenWeb())
                        {                            
                            //Create the Export Setting object and update the setting properties.  
                            SPExportSettings settings = new SPExportSettings();
                            settings.SiteUrl = sourceWeb.Url;
                            settings.ExportMethod = SPExportMethodType.ExportAll;
                            settings.BaseFileName = EXPORT_FILENAME; // "export.cmp";
                            settings.FileLocation = "provide file location";
                            settings.LogFilePath = @folderPath + LOG_FILENAME; // "\LogFile.log";                                
                            settings.IncludeSecurity = SPIncludeSecurity.All;

                            setExcludeDependencies(migrationSettings, settings);
                            settings.OverwriteExistingDataFile = true;
                            settings.CommandLineVerbose = true;
                            settings.FileMaxSize = 1024;
                            settings.FileCompression = true;

                            // Add the Export object to the ExportSetting Object  
                            settings.ExportObjects.Add(exportObject);


                            // add the Export Settings to the SPExport object and Run the Export .  
                            SPExport export = new SPExport(settings);
                            export.Run();

                            LogAll.logTextWriting(true, ServerConstant.exportSuccessfully);
                            isExportCompleted = true;
                        }
                    }
               

Code to import a site

                    // Get the Site collection Url from the config file.  

                    using (SPSite rootSiteColl = new SPSite(destinationSiteURL))
                    {
                        SPWebApplication webApp = rootSiteColl.WebApplication;
                        rootSiteColl.AllowUnsafeUpdates = true;
                        using (SPWeb rootWeb = rootSiteColl.OpenWeb())
                        {
                            // Package import
                            System.Uri siteURL = new Uri(destinationSiteURL);
                            string baseDataFileName = EXPORT_FILENAME; // "export.cmp";
                            string dataFileLocation = @folderPath;
                            string logFileLocation = @folderPath + LOG_FILENAME; // "\LogFile.log";

                            SPImportSettings importSettings = new SPImportSettings(siteURL, dataFileLocation, baseDataFileName);
                            importSettings.IncludeSecurity = SPIncludeSecurity.All;
                            importSettings.RetainObjectIdentity = true;                            
                            importSettings.CommandLineVerbose = true;
                            importSettings.LogFilePath = logFileLocation;
                            importSettings.WebUrl = destinationSiteURL;
                            importSettings.FileCompression = true;


                            SPImport import = new SPImport(importSettings);
                            import.Run();
                            rootWeb.AllowUnsafeUpdates = false;
                            webApp.FormDigestSettings.Enabled = true;
                            webApp.FormDigestSettings.Expires = true;
                            rootWeb.Close();
                        }
                        rootSiteColl.AllowUnsafeUpdates = false;
                    }

The power of the import functionality is that we can pick and choose whether to retain the security, versions, object ids etc. The main drawback of this approach
is that it does not preserve workflow instances, workflow associations, history and tasks. Every workflow association must be recreated and there is no way
to restore the running instances from original site. But nonetheless, the export/import has real power or re-arranging the site-hierarchy in the target.
 

 Subscribe to my blog

SharePoint 2013 Programmatically read list items using Java Script

Home | SharePoint Development | SharePoint 2013 Programmatically read list items using Java Script

Yesterday, I saw a question in MSDN forums on how to programmatically read SharePoint List items using JavaScript. Here is the full workable code below :-

var siteUrl = '/sites/MySiteCollection';

function retrieveListItems() {

    var clientContext = new SP.ClientContext(siteUrl);
    var oList = clientContext.get_web().get_lists().getByTitle('YourCustomList');
        
    var camlQuery = new SP.CamlQuery();
    camlQuery.set_viewXml('<View><Query><Where><Geq><FieldRef Name='ID'/>' + 
        '<Value Type='Number'>1</Value></Geq></Where></Query><RowLimit>10</RowLimit></View>');
    this.collListItem = oList.getItems(camlQuery);
        
    clientContext.load(collListItem);
        
    clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));        
        
}

function onQuerySucceeded(sender, args) {

    var listItemInfo = '';

    var listItemEnumerator = collListItem.getEnumerator();
        
    while (listItemEnumerator.moveNext()) {
        var oListItem = listItemEnumerator.get_current();
        listItemInfo += 'nID: ' + oListItem.get_id() + 
            'nTitle: ' + oListItem.get_item('Title') + 
            'nBody: ' + oListItem.get_item('Body');
    }

    alert(listItemInfo.toString());
}

function onQueryFailed(sender, args) {

    alert('Request failed. ' + args.get_message() + 'n' + args.get_stackTrace());
}

 Subscribe to my blog

SharePoint 2010 Developer Dashboard Faqs

Home | SharePoint Development | SharePoint 2010 Developer Dashboard Faqs

In this article, I’d be discussing about the SharePoint 2010 Developer Dashboard. The developer dashboard is one of the powerful features in SharePoint 2010, which is turned off by default. It comes into rescue while troubleshooting performance issues of the SharePoint Page. It provides performance (instrumentation) and tracing related information to troubleshoot the performance issues.

The SharePoint 2010 developer dashboard can be enabled by using both the STSADM command line tool and the powershell script. We’ll see how we can enable the SharePoint 2010 developer dashboard using powershell. We can enable the SharePoint 2010 developer dashboard in two modes like ‘On-Demand mode’ and ‘On Mode’.

On-DemandMode

In the on-demand mode, the developer dashboard does not get enabled in one-go. It enables a small icon right to the log in control in the  Ribbon. Once we click the icon, it enables the developer dasbhard which is visible in the bottom on the page

$spserver = [Microsoft.SharePoint.Administration.SPWebService]::ContentService.DeveloperDashboardSettings;
$spserver.DisplayLevel = [Microsoft.SharePoint.Administration.SPDeveloperDashboardLevel]::OnDemand;
$spserver.RequiredPermissions = 'EmptyMask';
$spserver.TraceEnabled = $true;
$spserver.Update();

pic1[3]

On Mode

In the on mode

$spserver = [Microsoft.SharePoint.Administration.SPWebService]::ContentService.DeveloperDashboardSettings;
$spserver.DisplayLevel = [Microsoft.SharePoint.Administration.SPDeveloperDashboardLevel]::On;
$spserver.RequiredPermissions = 'EmptyMask';
$spserver.TraceEnabled = $true;
$spserver.Update();
pic 22

pic3

Turning  Off

$spserver = [Microsoft.SharePoint.Administration.SPWebService]::ContentService.DeveloperDashboardSettings;

$spserver.DisplayLevel = [Microsoft.SharePoint.Administration.SPDeveloperDashboardLevel]::Off;

$spserver.Update();

Consuming a WCF service from SharePoint 2010 Sandbox Solutions

Home | SharePoint Development | Consuming a WCF service from SharePoint 2010 Sandbox Solutions

This article would focus on how to consume a WCF Service from a SharePoint 2010 Sandbox Solutions. We’ll start with a quick briefing of what are the limitations of  SharePoint 2010 Sandbox Solutions and What is a SharePoint 2010 Full trust proxy, before jumping on to the actual steps for consuming a WCF service from SharePoint 2010. We all know that a SharePoint 2010 Sandbox Solutions get executed inside a controlled environment (runs inside spucworkerprocess.exe) and it also has restrictions in terms of both internal restrictions and external restrictions.

                                                                                                                      The internal restrictions of SharePoint 2010 Sandbox Solutions means only a subsite of functionalities inside Microsoft.SharePoint.dll is available.  The external restrictions of SharePoint 2010 Sandbox Solution means only it can call assemblies which allows partially trusted callers, hence a sub-set (about one third) of .NET framework assemblies  is only available to SharePoint 2010 Sandbox Solutions. On top of this there are many more external restrictions like accessing file-system, web services / wcf services, databases etc. , a complete list of restrictions are available in msdn documentation.

The Full-Trust Proxy comes into picture when we want to reach the external world from the SharePoint 2010 Sandbox Solutions. The Full-Trust proxy runs inside a separate process called spucworkerprocessproxy.exe, which allows partially trusted callers.

I’ve the following WCF service hosted in IIS, which needs to be accessed from SharePoint 2010 Sandbox Visual Web Part. For the sake of the demonstration I’ve kept the service functionality simple, it takes an integer as a parameter and returns a hardcoded string. The following is the service method implementation.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace CreditCardService
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "VadlidationService" in code, svc and config file together.
    public class VadlidationService : IVadlidationService
    {
        public string GetCountry(int value)
        {
            return "India";
        }

        
    }
}
The service contract of the service looks like the following 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace CreditCardService
{
    [ServiceContract]
    public interface IVadlidationService
    {

        [OperationContract]
        string GetCountry(int value);

    

        // TODO: Add your service operations here
    }


    
}

Now let’s move to the development of full-trust proxy. To develop a full-trust proxy assembly, two component needs to be developed one is full-trust proxy  operation class and the other is full-trust proxy arguments class.

The full-trust proxy operation should be inherit from spproxyoperation class and it should be marked with [Serializable] attribute.  Then the required set of properties need to be implemented.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.UserCode;

namespace SimpleProxy
{
    [Serializable]
    [Microsoft.SharePoint.Security.SharePointPermission(System.Security.Permissions.SecurityAction.LinkDemand, ObjectModel = true)] 

   public class SimpleProxyArgs : SPProxyOperationArgs
    {

      public int CountryId { get; set; }

       public static string ProxyOperationTypeName
       {

           get
           {
               return "SimpleProxy.SimpleProxyOps";
           }
       }


       public static string ProxyAssemblyName

       {

           get
           {
               return "SimpleProxy, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a3daa9085766b846"; 
                       
           
           }
       
       
       
       }

    }
}

The property CountryId would be used by the full-trust proxy operation class to pass the arguments to the WCF service.  The two additional properties like

ProxyOperationType and ProxyAssemblyName is defined here and it would be used by the Sandbox Solution to get the assembly details while making the calls

to full-trust proxy components.

The full-trust proxy operation class should inherit from spproxyoperation class, override the Execute method to implement all the required full-trust logic.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.UserCode;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using System.Runtime.Serialization;
using System.ServiceModel;

namespace SimpleProxy

{

    [Microsoft.SharePoint.Security.SharePointPermission(System.Security.Permissions.SecurityAction.LinkDemand, ObjectModel = true)] 

    public class SimpleProxyOps : SPProxyOperation
    {
        
        
             
        public override object Execute(SPProxyOperationArgs args)
        {
            WSHttpBinding oWSHttpBinding = new WSHttpBinding(SecurityMode.Message);


            oWSHttpBinding.Name = "WSHttpBinding_IVadlidationService";

            oWSHttpBinding.CloseTimeout = new TimeSpan(0, 1, 0);
            oWSHttpBinding.OpenTimeout = new TimeSpan(0, 1, 0);
            oWSHttpBinding.ReceiveTimeout = new TimeSpan(0, 10, 0);
            oWSHttpBinding.SendTimeout = new TimeSpan(0, 1, 0);
            oWSHttpBinding.BypassProxyOnLocal = false;
            oWSHttpBinding.TransactionFlow = false;
            oWSHttpBinding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;


            oWSHttpBinding.MaxBufferPoolSize = 524288;
            oWSHttpBinding.MaxReceivedMessageSize = 65536;
            oWSHttpBinding.MessageEncoding = WSMessageEncoding.Text;
            oWSHttpBinding.TextEncoding = Encoding.UTF8;
            oWSHttpBinding.UseDefaultWebProxy = true;
            oWSHttpBinding.AllowCookies = false;


            oWSHttpBinding.ReaderQuotas.MaxDepth = 32;
            oWSHttpBinding.ReaderQuotas.MaxStringContentLength = 8192;
            oWSHttpBinding.ReaderQuotas.MaxArrayLength = 16384;
            oWSHttpBinding.ReaderQuotas.MaxBytesPerRead = 4096;
            oWSHttpBinding.ReaderQuotas.MaxNameTableCharCount = 16384;

            oWSHttpBinding.ReliableSession.Ordered = true;
            oWSHttpBinding.ReliableSession.InactivityTimeout = new TimeSpan(0, 10, 0);
            oWSHttpBinding.ReliableSession.Enabled = false;

            oWSHttpBinding.Security.Mode = SecurityMode.Message;

            oWSHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
            oWSHttpBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
            oWSHttpBinding.Security.Transport.Realm = "";

            oWSHttpBinding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
            oWSHttpBinding.Security.Message.NegotiateServiceCredential = true;


            EndpointAddress oEndPointAddress = new EndpointAddress(new Uri("http://lt012464.abc.com:1414/CreditCardService/ValidationService.svc"));

            
            
            var proxyArgs = args as SimpleProxyArgs;

            int CountryId = proxyArgs.CountryId;


            SimpleProxy.VadlidationServiceClient ovsc = new SimpleProxy.VadlidationServiceClient(oWSHttpBinding, oEndPointAddress);
                
            string result = ovsc.GetCountry(0);
            

            return result;

        }

    }
}

I’ve overridden the execute method and now I need to access the WCF service inside execute method. There are several ways of accessing a WCF service from a .NET assembly. If you create the client proxy for the WCF service using ‘Add Service Reference’ option in Visual Studio 2010, it would be difficult to configure and set the endpoint inside full-trust proxy class. Because full-trust proxy runs inside spucworkerprocesproxy.exe, which cannot access the WCF client endpoint configuration defined in the web.config. The only viable option to set the endpoint inside full-trust proxy component is to create the endpoint through code (programmatically).

Then, add this attribute [assembly: AllowPartiallyTrustedCallers] to the assemblyinfo.cs file  to allow the partially trusted callers (Sandbox Solutions) to invoke it.

The next logical step is to register the full-trust proxy assemblies to the User Code service of Sandbox infrastructure. Preferably, this action should be performed inside the feature activation of the full-trust proxy solution.

public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {

            SPUserCodeService userCodeService = SPUserCodeService.Local;
            var simpleOperation = new SPProxyOperationType(SimpleProxyArgs.ProxyAssemblyName,SimpleProxyArgs.ProxyOperationTypeName);
            userCodeService.ProxyOperationTypes.Add(simpleOperation);
            userCodeService.Update();
            
        }

Now we are all set to invoke this full-trust proxy from a SharePoint 2010 Sandboxed Visual Web Part. Invoke the SPUtility.ExecuteRegisteredProxyOperation method from the sandboxed visual webpart to make this happen.

namespace SharePointSaturdayWebPart.SharePointSaturdayWebPart
{
    [ToolboxItem(false)]
    public partial class SharePointSaturdayWebPart : System.Web.UI.WebControls.WebParts.WebPart
    {
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            InitializeControl();
        }

        protected void Page_Load(object sender, EventArgs e)
        {

            var proxyArgs = new SimpleProxyArgs();
            proxyArgs.CountryId = 1;



                var result = SPUtility.ExecuteRegisteredProxyOperation(SimpleProxyArgs.ProxyAssemblyName, 
                                                                        SimpleProxyArgs.ProxyOperationTypeName, proxyArgs);





                Label1.Text = (string)result;




        }
    }
}

 

 Subscribe to my blog