Monday, October 13, 2014

SharePoint 2013: Use the cross-domain library in a tenant-scoped app (JSOM)

You will find code sample for cross-domain library in a tenant-scope app based on REST call on Microsoft site but not based on JSOM. I am not very much comfortable in REST calls so i decided to created similar example in JSOM.

Download sample code from here and just replace JavaScript in CrossDomainExec.js with below script




var web;
var hostweburl;
var appweburl;

function execCrossDomainRequest() {
    hostweburl =
         decodeURIComponent(
             getQueryStringParameter('SPHostUrl')
     );
    appweburl =
        decodeURIComponent(
            getQueryStringParameter('SPAppWebUrl')
     );

    var scriptbase = hostweburl + '/_layouts/15/';

    $.getScript(scriptbase + 'SP.Runtime.js',
        function () {
            $.getScript(scriptbase + 'SP.js',
                function () { $.getScript(scriptbase + 'SP.RequestExecutor.js', GetWebInfo); }
            );
        }
    );
}

function getQueryStringParameter(param) {
    var params = document.URL.split("?")[1].split("&");
    var strParams = "";
    for (var i = 0; i < params.length; i = i + 1) {
        var singleParam = params[i].split("=");
        if (singleParam[0] == param) {
            return singleParam[1];
        }
    }
}

function GetWebInfo() {
    var context;
    var factory;
    var appContextSite;
   
    context = new SP.ClientContext(appweburl);
    factory = new SP.ProxyWebRequestExecutorFactory(appweburl);
    context.set_webRequestExecutorFactory(factory);
    //appContextSite = new SP.AppContextSite(context, hostweburl);
    appContextSite = new SP.AppContextSite(context, document.getElementById("sitecoll1").value);//host url replaced by site collection url

    var web = appContextSite.get_web();
    context.load(web);

    context.executeQueryAsync(
        successHandler, errorHandler
    );

    function successHandler() {
        var oli = document.createElement("li");

        oli.innerText = web.get_title() + " (" + web.get_url() + ")";
        document.getElementById("WebTitles").appendChild(oli);
    }

    function errorHandler(sender, args) {
        document.getElementById("WebTitles").innerText = "Could not complete cross-domain call: " + args.get_message();
    }
}

Wednesday, October 9, 2013

Access data from other site collection in SharePoint Hosted Apps

When we want to access data from other site collection in same web application in SharePoint-Hosted Apps then there is no option other than cross-domain library(SP.RequestExecutor.js).

Microsoft SharePoint team has provided one of the best code sample for start point. Download solution from below link

https://code.msdn.microsoft.com/SharePoint-2013-Use-the-6b3e4c1e

After download don't deploy it on your Developer Site, every new SharePoint App developer makes this mistake, even i. 


Steps to deploy and test

  • Just publish this solution from Visual Studio to any location so you will get an App package with extension .app. 
  • Next, Create an App Catalog site collection for testing purpose and  upload this package to "Apps for SharePoint" library on this site.
  • Go to "Site Contents" page of App Catalog site and click on "add an app", select app "CrossDomainApp". You will get installing app message, wait until app get installed.
  • Once installation done, click on the app. 
  • Now you will get page not found message like below


you get this error because your DEV machine couldn't find the DNS mappings for this url so the next step is to add DNS mapping. On most of the DEV machines DNS Manager isn't present then how we can do this? Simple, add domain name host entry in machine hosts file but which domain name to add here.

When you get page not found error your url is like below

http://devmachine:1010/sites/AppCatalog/_layouts/15/appredirect.aspx?client_id=i%3A0i%2Et%7Cms%2Esp%2Eint%7C51a99a6e%2Df3eb%2D4708%2Db586%2D8cfb32360f6e%4039134774%2D6e9d%2D45b2%2D9b2c%2Dae59c3421caa&redirect_uri=%7EappWebUrl%2FPages%2FReadTitle%2Easpx%3F%7BStandardTokens%7D

You can't add domain name devmachine:1010 as host entry but you need to add app domain host entry which is something like app-22bee6440ed9fc.spapp. How we'll get this entry?

If you have Fiddler then start it and refresh that page not found page, now you will get message like below.


[Fiddler] DNS Lookup for "app-22bee6440ed9fc.spapp" failed. System.Net.Sockets.SocketException The requested name is valid, but no data of the requested type was found 

Copy this app domain DNS entry app-22bee6440ed9fc.spapp (in your case this would be different) and add it to hosts file like below, here 127.0.0.1 is localhost IP.

127.0.0.1    app-22bee6440ed9fc.spapp
::1    app-22bee6440ed9fc.spapp

Save hosts file and refresh the app page. You will get login prompt, put your credentials and you will get app home page.





One obvious question comes in the mind, When i deploy any app directly from Visual Studio, i don't need to add any such host entry in the hosts file? The reason is, this work is done by the Visual Studio when you deploy an app. For test purpose, just deploy an app using Visual Studio and check host file.

Thursday, November 1, 2012

Service based custom timer job in SharePoint 2010

Hi Friends,

There are many articles you will find on internet about Timer Jobs in SharePoint 2010 which is based on web application but not on service. That is the reason i am sharing this article.

Timer job based on web application having one major problem. i.e- Job will not work if that application not worked or crashed or say front end on which web application hosted is down.

Here i will not tell whole story of Timer Job, you will get better information here

A Complete Guide to Writing Timer Jobs in SharePoint 2010

To create timer job based on service or say service application, we will have to do few things, this are below
  • Create custom service and add to the local farm
  • Create service instance based on above custom service and add this to all the servers in the farm
  • Create timer job
  • Associate timer job to service


Steps in detail

1: Open Visual Studio 2010 and create farm based SharePoint Solution (use blank SharePoint Project Template), add class file named CustomTimerJobService.cs, code is below


using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint.Administration;

namespace CustomTimerJobService
{
    [System.Runtime.InteropServices.Guid("6D53ECA1-E5E4-47CF-961F-28D80C8C5B98")]
    public class CustomTimerJobService : SPService
    {
        public const string serviceName = "Custom Timer Job Service";

        //private static CustomTimerJobService local;

        public CustomTimerJobService() { }

        public CustomTimerJobService(SPFarm farm) : base("CustomTimerJobService", farm)
        { }

        //public static CustomTimerJobService Local
        //{
        //    get
        //    {
        //        if (CustomTimerJobService.local == null)
        //        {
        //            CustomTimerJobService.local = SPFarm.Local.Services.GetValue<CustomTimerJobService>("CustomTimerJobService");
        //        }

        //        return CustomTimerJobService.local;
        //    }
        //}

        public override void Provision()
        {
            base.Provision();
        }

        public override string TypeName
        {
            get
            {
                return serviceName;
            }
        }

        public override string DisplayName
        {
            get
            {
                return serviceName;
            }
        }       
    }   
}


2: Add class file named CustomTimerJobServiceInstance.cs, code is below

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint.Administration;

namespace CustomTimerJobService
{
    public class CustomTimerJobServiceInstance : SPServiceInstance
    {
        public const string serviceDescription = "Custom Service for service based timer jobs";

        public CustomTimerJobServiceInstance() : base()
        { }

        public CustomTimerJobServiceInstance(string name, SPServer server, CustomTimerJobService service) : base(name, server, service)
        { }

        public override string Description
        {
            get
            {
                return serviceDescription;
            }
        }
    }
}


3: Add feature of scope Farm to the solution and then add feature receiver.

Here we will add service to the local farm, then instantiate above service on all the servers in the farm.

using System;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Administration;

namespace CustomTimerJobService.Features.AddTimerJobService
{
    [Guid("8daf90a1-df8a-4646-a606-0646498a6242")]
    public class AddTimerJobServiceEventReceiver : SPFeatureReceiver
    {
        public const string serviceName = "Custom Timer Job Service";

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            //1: Add service in local farm
            //2: Add service instance of this service on every server in the farm

            //Create service definition instance
            CustomTimerJobService timerJobService = new CustomTimerJobService(SPFarm.Local);

            //Get all services from local farm and add our custom service in farm
            SPServiceCollection services = SPFarm.Local.Services;
            services.Add(timerJobService);
            SPFarm.Local.Update();

            //Get all servers in local farm
            SPServerCollection servers = SPFarm.Local.Servers;

            //Add service instance on all the servers
            foreach (SPServer server in servers)
            {
                //Create new service instance based on our custom service and add in server
                CustomTimerJobServiceInstance timerJobServiceInstance = new CustomTimerJobServiceInstance(serviceName, server, timerJobService);
                server.ServiceInstances.Add(timerJobServiceInstance);
                server.Update();
            }
        }

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            //1: Remove service instance of this service on every server in the farm
            //2: Remove service in local farm

            //Get all servers in local farm
            SPServerCollection servers = SPFarm.Local.Servers;

            foreach (SPServer server in servers)
            {
                //Remove instance on every server
                CustomTimerJobServiceInstance timerJobServiceInstance = server.ServiceInstances.GetValue<CustomTimerJobServiceInstance>();
                    
                if (timerJobServiceInstance != null && timerJobServiceInstance.DisplayName.ToString().Equals(serviceName, StringComparison.OrdinalIgnoreCase))
                {
                    server.ServiceInstances.Remove(timerJobServiceInstance.Id);
                    server.Update();                       
                }
            }

            //Remove service from the farm
            CustomTimerJobService timerJobService = SPFarm.Local.Services.GetValue<CustomTimerJobService>();

            if (timerJobService != null)
            {
                timerJobService.Delete();
                SPFarm.Local.Update();                   
            }           
        }
    }
}


Next step is to create timer job and associate it to service


Steps in detail

1: Open Visual Studio 2010 and create farm based SharePoint Solution (use blank SharePoint Project Template), add class file named CustomTimerJob.cs.cs, code is below


using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

namespace CustomTimerJobDemo
{
    public class CustomTimerJob : SPFirstAvailableServiceJobDefinition
    {
        //If you are taking configuration values from the site where you are going
        //to activate this timer job feature then make persisted property
        //By doing this we can use it further
        [Persisted]
        public string configSiteURL = null;

        public CustomTimerJob()
            : base()
        { }

        public CustomTimerJob(string jobName, SPService service, SPSite site)
            : base(jobName, service)
        {
            this.Title = jobName;
            this.configSiteURL = site.Url;
        }


        public override void Execute(SPJobState jobState)
        {
            if (jobState.ShouldStop != true)
            {
                this.UpdateProgress(10);

                //To Do: Do some activity here

                this.UpdateProgress(100);
            }
        }
    }
}


2: Add feature of scope Site to the solution and then add feature receiver.

Here we will associate timer job to service


using System;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Deployment;

namespace CustomTimerJobDemo.Features.CustomTimerJobDemo
{
    [Guid("a26f0c48-6464-4438-bbd0-35fac5218a0b")]
    public class CustomTimerJobDemoEventReceiver : SPFeatureReceiver
    {
        public const string jobName = "Custom Timer Job for demo";

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            SPSite currentSite = properties.Feature.Parent as SPSite;

            //Check current context whether it is a normal feature activation or through any custom deployment job
            //Timer job should not be created if feature activation occurs through any custom deployment job
            if (!SPImportContext.Current.IsRunning)
            {
                SPService timerJobService = GetCustomTimerJobService();

                if (timerJobService != null)
                {
                    // Remove job if it already associated with the service
                    foreach (SPJobDefinition job in timerJobService.JobDefinitions)
                    {
                        if (job.Name.Equals(jobName, StringComparison.OrdinalIgnoreCase))
                        {
                            //Deleting existing job
                            job.Delete();
                        }
                    }

                    //Create new job here
                    CustomTimerJob timerJob = new CustomTimerJob(jobName, timerJobService, currentSite);

                    SPDailySchedule dailySchedule = new SPDailySchedule();
                    dailySchedule.BeginMinute = 0;
                    dailySchedule.EndMinute = 59;
                    dailySchedule.BeginHour = 0;
                    dailySchedule.EndHour = 12;

                    timerJob.Schedule = dailySchedule;
                    timerJob.Update();
                }
            }                                     
        }

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            //Get custom timer service
            SPService timerJobService = GetCustomTimerJobService();

            if (timerJobService != null)
            {
                // Remove job
                foreach (SPJobDefinition job in timerJobService.JobDefinitions)
                {
                    if (job.Name.Equals(jobName, StringComparison.OrdinalIgnoreCase))
                    {
                        //Deleting job
                        job.Delete();
                    }
                }
            }
           
        }

        private static SPService GetCustomTimerJobService()
        {
            SPService timerJobService = null;           
            string serviceName = "Custom Timer Job Service";
                           
            //Get all services from the farm
            SPServiceCollection services = SPFarm.Local.Services;

            foreach (SPService service in services)
            {
                if (service.DisplayName.Equals(serviceName, StringComparison.OrdinalIgnoreCase))
                {
                    timerJobService = service;
                    break;
                }
            }

            if (timerJobService == null)
            {
                throw new Exception("Service not available. Please check service on servers.");
            }           
           
            return timerJobService;
        }
    }
}


This is done now, you can go to central admin and run timer job or it will run based on schedule you configured for it.

Bye Good Day....!


Wednesday, September 26, 2012

Threading example in C#

using System;
using System.Text;
using System.Threading;
using System.Collections;
using System.Collections.Generic;

namespace Threading_Demo
{
    public class Threading
    {
        ArrayList data = null;

        ManualResetEvent[] totalEvents = null;
        
        public Threading(ArrayList data)
        {
            this.data = data;
            this.totalEvents = new ManualResetEvent[data.Capacity];
        }

        public void ProcessThreads()
        {
            WaitCallback callBack = new WaitCallback(ProcessData);

            int resetIndex = 0;

            foreach (object item in data)
            {
                //Create thread and add it in pool
                ThreadPool.QueueUserWorkItem(callBack, resetIndex + "#" + item);

                //Create new event
                totalEvents[resetIndex++] = new ManualResetEvent(false);
            }

            if (totalEvents != null)
            {
                WaitHandle.WaitAll(totalEvents);
            }
        }

        private void ProcessData(object state)
        {
            string objState = state as string;
            string[] stateParam = objState.Split('#');

            if (stateParam.Length == 2)
            {
                int threadId = Convert.ToInt32(stateParam[0]);

                if (!string.IsNullOrEmpty(stateParam[1]))
                {
                    string data = stateParam[1];

                    //Process data
                    Console.Write("Thread Id: " + threadId.ToString() + " Data: " + data.ToString() + "\n");

                    //Signal to pool after current thread finished it's porceesing
                    totalEvents[threadId].Set();
                }
            }
        }        
    }

    class Program
    {
        static void Main(string[] args)
        {
            ArrayList data = new ArrayList(5) { "One", "Two", "Three", "Four", "Five"};

            Threading thread = new Threading(data);
            thread.ProcessThreads();

        }
    }
}

Tuesday, July 17, 2012

SharePoint Server 2013 released in preview along with Pro and Developer training materials

Today is good news for SharePoint professionals, finaly Microsoft released SharePoint new version that is SharePoint Server 2013 in preview edition, though it's preview we get chance to look into it and play with new features

Here below are few usefull links

SharePoint 2013 new features and capabilities

SharePoint 2013 training for developers

What's new for developers in SharePoint 2013

Download Microsoft SharePoint Server 2013 Preview