SharePoint High Trust App – 401 Error Intermittently

We recently encountered an issue in our SharePoint High Trust App.

Problem:

System.Net.WebException: The remote server returned an error: (401) Unauthorized.

at System.Net.HttpWebRequest.GetResponse()

at Microsoft.SharePoint.Client.SPWebRequestExecutor.Execute()

at Microsoft.SharePoint.Client.ClientRequest.ExecuteQueryToServer(ChunkStringBuilder sb)

Root Cause:

Security Token Service Application is not available in one of our servers.

Resolution:

Restart the timer service on the server.

 

Advertisements

Getting incorrect email for SharePoint user

Recently, we experienced an interesting issue regarding SharePoint profile, and I would like to share it to everyone.

We used JSOM code to pull current user’s emaill address; however, we found some users either have empty email or outdated email address.

Below is the code we used to pull user’s email address:

var user;
var defer = $q.defer();
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', sharePointReady);
function sharePointReady() {
var clientContext = SP.ClientContext.get_current();
user = clientContext.get_web().get_currentUser();
clientContext.load(user);
clientContext.executeQueryAsync(onQuerySucceeded, onQueryFailed);
}
function onQuerySucceeded() {
defer.resolve(user.get_email());
}
function onQueryFailed(sender, args) {
defer.reject(args.get_message);
}
return defer.promise;

After some investigation, we found that the user.get_email() actually pull the email address from User Information List rather than User Profile Service. And our User Information List is not in sync with User Profile.

SharePoint JSLink (Client Side Rendering)

// List New and Edit Forms  – HTML5  Input Sample

(function () {

    // Create object that have the context information about the field that we want to change it’s output render

var ageFiledContext = {};

ageFiledContext.Templates = {};

ageFieldContext.Templates.OnPreRender = onPreRender;

ageFiledContext.Templates.OnPostRender = onPostRender;

ageFiledContext.Templates.Fields = {

        // Apply the new rendering for Age field on New and Edit forms, Using InternalName

“Age”: {             “NewForm“: ageFiledTemplate        }

};

SPClientTemplates.TemplateManager.RegisterTemplateOverrides(ageFiledContext);

})();

// This function provides the rendering logic

function ageFiledTemplate(ctx) {

var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);

        // Register a callback just before submit.   IMPORTANT to ensure the field would still work when user save/update

formCtx.registerGetValueCallback(formCtx.fieldName, function () {

return document.getElementById(‘inpAge’).value;

});

var testValue = “ABC”;

return “<input type=’text’ id=’inpAge’ min=’18’ max=’110′ value='” + testValue + “‘/>”;

}
function onPostRender(ctx) {
}
function onPreRender(ctx) {
}

Content Migration using Web Service and Client Side Object Model

Most of our intranet sites have been moved from SharePoint 2007 to SharePoint 2013, like Team sites and MySite. The only one left is the our corporate portal site, which serves the entire company.

Background

In MOSS 2007, we implemented many Farm solutions, such as, custom web parts, list event receivers, workflow and custom site template. Those are the bits that make upgrade challenging. For team sites, we re-complied the Farm solution (there is only one Farm solution for Team sites) and deployed to SharePoint 2013. Then take the content database to SharePoint 2010 first, then SharePoint 2013. However, for our corporate portal site, which is heavily customized, we don’t want to follow the same road-map since we try to avoid Farm solutions and convert everything to App Model. Business also want to split this one site collection to 3 new site collections in SharePoint 2013.

Solution

I developed a custom migration tool in a short period. It will allow site admin to migrate the MOSS 2007 site to SharePoint 2013 remotely as well as converting custom web parts to App parts and updating the links in the list items.

MigrationTool

SharePoint 2007 SharePoint 2013
http://portalsite.com https://w3.portal.com/sites/corp

https://w3.portal.com/sites/admin

https://w3.portal.com/sites/sbu

For MOSS 2007, I’m using Web Services like /_vti_bin/Webs.asmx, /_vti_bin/Lists.asmx,  /_vti_bin/Views.asmx and /_vti_bin/WebPartPages.asmx. There is also a custom web service developed due to the limitation of OOTB web service. For SharePoint 2013, Web Services are used as well as Client Side Object Model. Using this custom migration tool, site admins can move a site/list to anywhere they want.

 

Create Query Rule and Prompted Results SharePoint 2013

string siteUrl = "https://dev.search.com";
string resultSourceName = "Local SharePoint Results";
using (SPSite site = new SPSite(siteUrl))
{
  using(SPWeb web = site.OpenWeb("/en"))
  {

    SPServiceContext context = SPServiceContext.GetContext(SPServiceApplicationProxyGroup.Default,
                              SPSiteSubscriptionIdentifier.Default);

    SearchServiceApplicationProxy searchAppProxy = context.GetDefaultProxy(typeof(SearchServiceApplicationProxy))
                                       as SearchServiceApplicationProxy;

    SearchServiceApplicationInfo ssai = searchAppProxy.GetSearchServiceApplicationInfo();

    if (searchAppProxy != null)
    {
      Guid searchAppId = searchAppProxy.GetSearchServiceApplicationInfo().SearchServiceApplicationId;
      // Get the application itself
      SearchServiceApplication searchApp = SearchService.Service.SearchApplications.GetValue&lt;SearchServiceApplication&gt;(searchAppId);

      QueryRuleManager queryRuleManager = new QueryRuleManager(searchApp);
      // SPWeb Level
      SearchObjectOwner searchOwner = new SearchObjectOwner(SearchObjectLevel.SPWeb, web);

      SearchObjectFilter searchFilter = new SearchObjectFilter(searchOwner);

      FederationManager federManager = new FederationManager(searchApp);

      Source resultSource = federManager.GetSourceByName(resultSourceName, searchOwner);

      QueryRuleCollection qrCollection = queryRuleManager.GetQueryRules(searchFilter);

      CreateQueryRule(queryRuleManager, qrCollection, searchFilter);
    }
  }
}

private void CreateQueryRule(QueryRuleManager queryRuleManager, QueryRuleCollection qrCollection, SearchObjectFilter searchFilter)
{
     QueryRule queryRule = qrCollection.CreateQueryRule("QueryRuleName", null, null, true);
     // Query Matches Keyword Exactly
     List<string> keyWords = new List<string>();
     keyWords.Add("Test1");
     keyWords.Add("Test2");
     KeywordCondition kwCondition = queryRule.QueryConditions.CreateKeywordCondition(keyWords, true);

     // Promopted Results
     Microsoft.Office.Server.Search.Query.Rules.BestBetCollection bestbets = queryRuleManager.GetBestBets(searchFilter);
     QueryAction queryAction = queryRule.CreateQueryAction(QueryActionType.AssignBestBet);
     Microsoft.Office.Server.Search.Query.Rules.BestBet bestBet = bestbets.CreateBestBet("Resutl1", null, "Description", true);
     bestBet = bestbets.CreateBestBet("Result2", new Uri("http://mysearch.com"), "Description", true);

     RegularExpressionCondition pnCondition = queryRule.QueryConditions.CreateRegularExpressionCondition("pattern", true);

}

 

Configure Site Navigation via CSOM

We would like to configure site navigation when a new site got created using CSOM. 
Here is the code I figured it out.
using(ClientContext ctx = new ClientContext(siteUrl)
{
   Web web = ctx.Web;
   TaxonomySession taxonomySession = TaxonomySession.GetTaxonomySession(ctx);
   WebNavigationSettings webNavSettings = new WebNavigationSettings(ctx, web);
   webNavSettings.CurrentNavigation.Source = StandardNavigationSource.PortalProvider;
   webNavSettings.CreateFriendlyUrlsForNewPages = false;
   webNavSettings.Update(taxonomySession);

   // show only current site's navigation items in current navigation
   web.AllProperties["__InheritCurrentNavigation"] = "False";
   web.AllProperties["__NavigationOrderingMethod"] = "2";
   web.AllProperties["__NavigationShowSiblings"] = "True";
   web.AllProperties["__CurrentNavigationIncludeTypes"] = "3";
   web.AllProperties["__CurrentDynamicChildLimit"] = "100";

   // show subwebs and pages in navigation
   web.AllProperties["__IncludeSubSitesInNavigation"] = "True";
   web.AllProperties["__IncludePagesInNavigation"] = "True";

   web.Update();
   ctx.ExecuteQuery();

}

SP2013 Search REST API Error: Method not found

We have a large SharePoint 2013 Farm and recently encountered a strange issue on some front end servers.

The REST API of Search return 400 Bad Request Error with even a simple query like “test”.
RequestError

After googling, we found a quick fix but don’t understand how it make this trick.
You have to run Install-SPApplicationContent on the servers that have this issue.
RESTAPIIssue