SharePoint 2013 CSOM Error : Custom Login Page (Forms Based / Mixed mode authentication)

If you have a SharePoint On Premise installation with a Custom Login Page , you might encounter issues working with CSOM. The error would be primarily related to Authentication Failure. The following solution worked for me.

Step 1: The Custom Login Page should be placed in IIS Virtual Directory.

As a general practise the custom login page is normally placed in the 15 Hive Layouts folder. Move/Copy the ASPX file of your custom login page from the 15 hive layouts folder to  the following folder in IIS Virtual directory of the concerned Web Application:

“C:inetpubwwwrootwssVirtualDirectories<yoursite>_forms”

Step 2: Edit the Custom Login page file to make sure the master page url is correct.

After the movement of the ASPX file, open the file in a notepad and check for the MasterPageFile value and change it to the following =”~/_layouts/15/simple.master“.

Step 3: Change the Custom Login Page Url in Central Administration.

Navigate to Central Admin and change the Url defined in Custom Login Page for the Web App ( Manage Web Application –> Select Web App –> Authentication Providers) to the following :     “~/_forms/customlogin.aspx”

Step 4: For Mixed Mode Authentication Only.

If you are using Forms based authentication , you are already ready to go , however if you have mixed mode authentication then make sure to add the following event handler in the CSOM code :

ClientContext clientContext = new ClientContext(“http://servername/“);
clientContext.ExecutingWebRequest += new EventHandler<WebRequestEventArgs>(clientContext_ExecutingWebRequest);
Web site = clientContext.Web;
clientContext.Load(site);
clientContext.ExecuteQuery();

static void clientContext_ExecutingWebRequest(object sender, WebRequestEventArgs e)
{
                    e.WebRequestExecutor.WebRequest.Headers.Add(“X-FORMS_BASED_AUTH_ACCEPTED”“f”);
}

CSOM should work fine now !!

 

Simultaneously start multiple Sharepoint 2007 workflows using C# for a List

Its known that we can start SharePoint 2007 workflows programmatically.  Here is the code that loops through all items in a list and starts the workflow for each item:

foreach(SPListItem item in list.Items)
{   
    SPListItem wrkItem =list.GetItemById(item.ID);   
    wrkflowmgr.StartWorkflow(wrkItem,wflassociation,
    wflassociation.AssociationData);
}

However the SharePoint Paradox here is that you can start only one workflow at a time , and have to wait for it to take its sweet time to finish, before you start the workflow for next item in list.  So what do you do if you have ( like i had ) a requirement to start a workflow on multiple items in a list simultaneously ?  Obviously you post a question shouting for help in stackoverflow. I was told:

there is no simultaneous method to start workflows for multiple list items at the same time.

But  i eventually figured out, that Multi Threading is the solution.

Steps

  • Create a Class “startWorkflow” that starts the workflow for a list item
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.Utilities;
using System.Threading;

namespace SimultaneousWorkflows
{
	class startWorkflow
	{
		int itemID;
        string siteURl;
        Guid gid; // GUID of the Workflow

        public startWorkflow(int iID, string sURl, Guid guidWfl)
        {
            itemID = iID;
            siteURl = sURl;
            gid = guidWfl;
        }
        public void startworkflowThread()
        {
           SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                 using (SPSite site = new SPSite(siteURl))
                    {
                        SPWeb web = site.RootWeb;
                        web.AllowUnsafeUpdates = true;
                        SPList list = web.Lists["Your List Name"];
                        SPWorkflowManager wrkflowmgr = site.WorkflowManager;
                        SPWorkflowAssociation wflassociation = list.WorkflowAssociations[gid];
                        SPListItem wrkItem = list.GetItemById(itemID);
                        wrkflowmgr.StartWorkflow(wrkItem, wflassociation, wflassociation.AssociationData);                                  
                    }   
            });                        
		}
	}
}

 

  • Implement Multithreading in the Timer Job Definition class file

I am just adding the relevant code here . Note: i was creating a timer job that would start the workflow , hence i updated the Timer Job Definition file , you can however do the following changes to the relevant class in your project.

Include the System.Collections.Generic and System.Threading namespaces.

 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.Utilities;
using System.Threading;
using System.Diagnostics;

Create a variable holding the GUID value of Workflow you want to start.

 public Guid wfguid = "The GUID value of Workflow you want to start" ;

Instantiate a Generic List ( Collection) of thread objects.

List<Thread> resThreadCollection = new List<Thread>();

Instantiate a Generic List ( Collection) of “startWorkflow” objects from the class you created above.

List<startWorkflow> startWorkFlowCollection = new List<startWorkflow>();

Update the Loop code as follows :

foreach(SPListItem item in list.Items)
{     
    startWorkflow thisItem = new startWorkflow(item.ID, siteUrl, wfguid);
    startWorkFlowCollection.Add(thisItem);
}

// Create a thread for each item added into startWorkFlowCollection
if (startWorkFlowCollection.Count > 0)
{
	foreach (startWorkflow itm in startWorkFlowCollection)
		{
			Thread MyThread = new Thread(new ThreadStart(itm.startworkflowThread));
			resThreadCollection.Add(MyThread);
		}
}

// Start the Threads	
 if (resThreadCollection.Count > 0)
{
	foreach (Thread tobeStarted in resThreadCollection)
		{
			tobeStarted.Start();
                }
} 

This is it , the workflows would start simultaneously now.

FTP C# Error : “The remote server returned an error: (530) Not logged in .”

Recently working on a FTP solution using C# , i encountered an error The remote server returned an error: (530) Not logged in.”

The code i used was following

FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftp://xxxxxx/file.txt); 
request.Method = WebRequestMethods.Ftp.UploadFile
request.Credentials = new NetworkCredential(usernameVariable, passwordVariable); 

What was more bewildering was if i modified the code to following, the solution was working fine. But this for obvious reasons is not an option as the username cannot be hardcoded

//works but implausible to use in realtime solutions
request.Credentials = new NetworkCredential("dmn/#gsgs", password);  

Some googling revealed that special charcters create issues in the NetworkCredential Object. Hence some playing around worked for me, and it works irrespective of wether i do a FTPWebRequest or WebRequest.

Solution:

Instantiate NetworkCredential object with three paramters (username, password, domain) and make sure to normalize the string variables while instantiating the NetworkCredential Object.

i.e:

//this works
request.Credentials = new NetworkCredential(usernameVariable.Normalize(),passwordVariable.Normalize(),domainVariable.Normalize()); 

Note: Normalize the string while instantiating the NetworkCredential object like above . The following doesnt work:

string usr = usernameVariable.Normalize()
string pwd= passwordVariable.Normalize()
string dom = domainVariable.Normalize()
request.Credentials = new NetworkCredential(usr,pwd,dom);  // wont work

 

Hope it helps !!

SharePoint MySite – PowerShell script to get the “Activities I am following” preferences

So i was asked to collect the preferences of “Activities I am following” (image below) for all the users of our SP2010 My Site.

The resources on web for this being  surprisingly limited , i was left with no other option but to turn to my cup of coffee  for solution . The coffees helped, the following script lists out the status of options available under “Activities i am following ” of My Site Edit Profile page in SharePoint 2010 , for each user.

$mySiteURL = "https://xxxx"
$site = Get-SPSite $mySiteURL
$context = Get-SPServiceContext $site;
$upm = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($context);

$val = "Username,ActivityName,Value"
Add-content -path "d:activity_preference.txt" -value $val

foreach ($profileupm in $upm.GetEnumerator())
{
$myprofile = $profileupm;
$usrprofile = $profileupm;

$am = New-Object Microsoft.Office.Server.ActivityFeed.ActivityManager($myprofile,
 $context)
$type = $am.GetType()

$methodInfo = $type.GetMethod("CopyBasicUserInfo", 
 [reflection.bindingflags]"nonpublic,instance",
 $null, $usrprofile.GetType(), $null)

$methodInfo.Invoke($am, $usrprofile)

$preftype = $am.ActivityPreferences.GetActivityPreferencesPerType();

foreach($pr in $preftype)
{
foreach($a in $am.ActivityTypes)
{
if ($pr.ActivityType -eq $a)
{
$val = $usrprofile["AccountName"].ToString() +
 "," + $a.ActivityTypeName.ToString() + 
 "," + $pr.IsSet.ToString()

 Add-content -path "d:activity_preference.txt" -value $val
} }  } }