SyntaxHighlighter

Thursday, December 17, 2015

Merging DLL project Settings with WebApp web.config

Recently I was working on MVC Web API project and needed to store key / value pairs. I decided to use <applicationsettings> because it is strongly typed and compiler auto-generates Settings class with each key as property. But I wanted to create Settings in referenced DLL project with external XML file to hold configuration items. As DLL can’t have their own .config file, I have to merge settings to Web application web.config file. This post describes steps to merge settings DLL project settings with Web application web.config file.

Creating new Settings was easy. Open DLL project Properties, click on “Settings” tab, click Create new settings link. New file will be created under Properties folder named: Settings.settings and App.config will be updated as follows:

<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
      <section name="{Project Namespace}.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    </sectionGroup>
  </configSections>
  <applicationSettings>
    <{Project Namespace}.Properties.Settings>
      <setting name="MyFirstSetting" serializeAs="String">
        <value>1234</value>
      </setting>
    </{Project Namespace}.Properties.Settings>
  </applicationSettings>
</configuration>

Step 1 – Externalize setting file in DLL project


This can done by updating App.config file as below.
...
<applicationSettings>
    <{Project Namespace}.Properties.Settings configSource="serviceSettings.config" />
</applicationSettings>
Create new xml file “serviceSettings.config” (same folder as App.config) and move all settings to this new file.
<{Project Namespace}.Properties.Settings>
  <setting name="MyFirstSetting" serializeAs="String">
    <value>1234</value>
  </setting>
</{Project Namespace}.Properties.Settings>
At this point you have created external settings file.

Step 2 – Merge with web.config


Open web.config and copy following fragment from App.config to web.config under <configuration> >> <configSections> node.
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
      <section name="{Project Namespace}.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
And add these line under <configuration> node.
<applicationSettings>
  <{Project Namespace}.Properties.Settings configSource="serviceSettings.config" />
</applicationSettings>
And copy “serviceSettings.config” file from DLL project to Web application (same folder as web.config)

Finally you are done. You can now access strongly typed Settings in your DLL project.
{Project Namespace}.Properties.Settings.Default.MyFirstSetting
To automate copy operation, you can write post build command to move serviceSettings.config file from DLL project to Web application project folder.
  
Hope this helps someone.

Thanks,
-Javed

Wednesday, December 2, 2015

SharePoint + TypeScript + Angular + Gulp + Visual Studio 2015 + more

I have been playing with Angular, Node and Gulp frameworks for a while mostly with WebStorm IDE and recently started using TypeScript and I love it. To learn and understand how these framework will integrate with SharePoint solution, I created simple Web Part farm project which does nothing at the moment, except few text boxes binding with Angular. WebStorm does not support SharePoint Solution, but luckily the recent release of Visual Studio 2015 has built-in support for Node, Task Runner and Bower. You can also add Task Runner support in Visual Studio 2013 by installing this plugin.

This post is about my learning experience integrating all these technologies together with SharePoint, Visual Studio and Gulp workflows. Here is the list of tools/frameworks I used:

Node – JavaScript runtime engine
Angular – JavaScript framework
jQuery – JavaScript framework
Gulp – Automation and build workflow (install global only)
Typescript – Built-in support in VS.NET 2015. Other version requires WebEssentials
TSD – DefinitelyType definition for Typescript repository.
Bower – Front-end optimized framework/libraries package manager. VS.NET 2015 has built-in support for Bower.
NPM – Node package manager (comes with Node)
Git – required by NPM and Bower

You can open link for instructions to install on your environment.


Step 1 – Create SharePoint Project


Create empty SharePoint 2013 project and added SharePoint Project Item: EmpDir_Module. This is the folder where we will be generating compiled/bundled/minified typescript file and other JavaScript files which we will be deploying to SharePoint. You can create dummy placeholder files and include it in Elements.xml or once files are copied (by Step 6) you can use "Include in Project" and update Elements.xml.


Step 2 – Setup


I assume all tools are installed and ready to go. First we need to initialize *.json files which contains references to files dependencies with versions installed, which can be used by other developers to bring in all dependencies.

Open Command Prompt, navigate to root Project directory and run following commands. I tried running this command from Visual Studio Package Manager Console but it hanged. These commands will ask series of questions to initialize *.json file.

$ npm init
- this command creates package.json file
$ bower init
- this command creates bower.json file
$ tsd init
- this command creates tsd.json and folder “typings”


Step 3 – Install Dependencies


Once we have all the *.json files, we can begin installing dependencies for our project. We can run these command either from external command prompt of Visual Studio Package Manager Console window.

$ npm install --save-dev gulp
- install gulp for the project and save as DEV dependency in package.json
$ npm install --save-dev gulp-concat gulp-print gulp-rename gulp-sequence gulp-typescript -uglify run-sequence
- install gulp plugins and save as DEV dependency in package.json

* Note : npm installs all components under “node_modules” folder in root.

$ bower install jquery angular --save
- install jquery and angular framework and save dependency in bower.json

* Note : bower installs all components under “bower_components” folder in root.

$ tsd install jquery angular --save
- install jquery and angular DefinitelyTyped definitions and save dependency in tsd.json

* Note : tsd installs all components under “typings” folder in root.

* Note : --save switch will record dependency as minimum required and if latest version available, will download the latest build. If you want to stick to any version, you can use --save-exact switch.


Step 4 – Write code


Before you start writing Typescript files, it’s better to decide the project folder structure. There is awesome Angular style guide compiled by John Papa here. As we are not going to deploy *.ts (typescript files) to SharePoint, I prefer to keep those files away in a separate folder. Here is how my project folder structure looks like:


I have created folder: “App” which contains typescripts source and compiled JavaScript files under “TScripts” and “compiled” folders. I have not included “bower_components”, “node_modules” and its contents to the project, as we are not deploying these files. We do need files from “bower_components” and will see how to deploy those as Module. I added “typings” folder, as I sometimes open *.d.ts files to see method signature or interface description. In Visual Studio you can select any method on typescript file and hit F12 will take you to method definition in *.d.ts file. Pretty handy.

I will not discuss about writing angular in Typescript, as that is a huge topic in itself. Pluralsight has several trainings on this subject.

Typescript file naming convention is for a reason we will see when we go to Gulp section. The naming convention will come handy during bundling and order of files.


Step 5 – Write Gulp Workflow


This is where all magic happens. Create a new JavaScript file: “gulpfile.js” in the root and copy/paste content below:
/// <binding BeforeBuild='default' />
/**
 * Created by Javed on 8/15/2015.
 */
'use strict';

var gulp = require('gulp'),
    gprint = require('gulp-print'),
    runSequence = require('run-sequence'),
    ts = require('gulp-typescript'),
    bundle = require('gulp-concat'),
    minify = require('gulp-uglify'),
    rename = require('gulp-rename');

var paths = {
    "TSSrc": 'App/TScripts/',
    "JSCompiled": 'App/compiled/',
    "JSDest": 'EmpDir_Module',
    "BowerSrc": "bower_components/"
}

var config = {
    "TypeScriptFiles": [
        paths.TSSrc + '**.ts'
    ],
    "BowerFiles": [
        paths.BowerSrc + 'jquery/dist/jquery.min.js',
        paths.BowerSrc + 'angular/angular.min.js'
    ],
    "BundleSrc": [
        paths.JSCompiled + '*.module.js',
        paths.JSCompiled + '*.config.js',
        paths.JSCompiled + '*.run.js',
        paths.JSCompiled + '*.constant.js',
        paths.JSCompiled + '*.directive.js',
        paths.JSCompiled + '*.service.js',
        paths.JSCompiled + '*.controller.js'
    ],
    "BundleFileName": "ed.bundle.js",
    "MinifyFileName": "ed.bundle.min.js"
}

gulp.task('compile', function () {
    var tsc = gulp
        .src(config.TypeScriptFiles)
        .pipe(gprint())
        .pipe(ts({ "noImplicitAny": true, "removeComments": true }));

    return tsc.js.pipe(gulp.dest(paths.JSCompiled));
});

gulp.task('bower', function () {
    return gulp
        .src(config.BowerFiles)
        .pipe(gprint())
        .pipe(gulp.dest(paths.JSDest));
});

gulp.task('prod_build', function() {
    return gulp
        .src(config.BundleSrc)
        .pipe(bundle(config.BundleFileName))
        .pipe(gprint())
        //.pipe(rename(config.MinifyFileName))
        //.pipe(minify())
        .pipe(gulp.dest(paths.JSDest));
});

gulp.task('default', function () {
    runSequence('compile', 'bower', 'prod_build');
});

You can read more on Gulp here. I will explain in brief about gulpfile.js and each task.

As gulpfile.js is plain JavaScript file, you can define your own variable and functions. I have defined 2 variables “paths” and “config” objects with property for source, destination or file name which we will be using in gulp tasks. I found this approach to be better than hard coding paths in tasks definition itself.

Compile task:
  1. Grab all *.ts files under “App/TScripts” folder
  2. Compile to JavaScript
  3. Copy output to “App/compiled” folder
Bower task:
  1. Grab bower_component files like jquery, angular
  2. Copy to SharePoint module folder “EmpDir_Module”
Prod_Build task:
  1. Grab all compiled JavaScript from “App/compiled” folder in same order as defined in config.BundleSrc array
  2. Conact all files and save “ed.bundle.js”
  3. Rename file to “ed.bundle.min.js”
  4. Minify/uglify this file
  5. Copy to SharePoint module folder “EmpDir_Module”   
Default task:
  1. Run all tasks in sequence.
* Note : When default task in defined executing “gulp” command with no parameter runs default task. You can run individual task by executing “gulp bower” from command line or VS Package Manager Console.


Step 6 – Attaching Gulp task with Visual Studio build event


The last step. Open Task Runner from View > Other Windows > Task Runner Explorer. You should see Gulpfile.js node with all task names. Right click on any task and select Bindings to attach to any build event. See the screenshot below, where default task is attached to Before Build event.


* Note : While in development mode, you can write new task "dev_build" and instead of copying to Module folder, you can map Style Library or any other library (where you are deploying your .js files) and copy to this mapped location. No need to deploy WSP package :)

This concludes the long post. Hope this help someone.

Thanks,
-Javed

Tuesday, June 17, 2014

JSLink: Display Form and jQuery animation

This is short 3rd post of JSLink series where I added customization to display form with jQuery animation. If you are not adding jQuery through master page or custom action or delegate control, you can add jQuery before override script, as JSLink allows us to include multiple JavaScript files separated by pipe symbol '|'.

Here is the override script:

// JavaScript source code
(function () {
    var overrideCtx = {};
    overrideCtx.Templates = {};

    overrideCtx.Templates.Fields = {
        'PercentComplete': {
            'NewForm': customField,
            'EditForm': customField,
            'DisplayForm': customDisplayField //override display form
        }
    }

    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);
})();

function customDisplayField(ctx) {
    //get percent complete and return div element with id to be used in animation
    var completed = ctx.CurrentItem["PercentComplete"].replace(/\s+/g, '');
    return "<div id='pctComplete' style='background-color:red;width:0%'>" + completed + "</div>";
}

function customField(ctx) {
    .... (removed for clarity)
}

//load animation
$(document).ready(function () {
    //get percent complete eg: 50% for using as animate width
    var pct = $('#pctComplete').text();

    //animate width property
    var config = {}
    config.width = pct;

    //start animation
    $('#pctComplete').animate(config, 1500);
});

Deploy override script and jQuery to master page library and update JSLink property as below on DisplayForm.aspx of list.

~site/_catalogs/masterpage/CSR-jquery-2.1.1.min.js|~site/_catalogs/masterpage/CSRTasksForm.js

If everything went as planned, display page will show animation for 'Percent Complete' field as below:


Hope this helps.

-Javed

Friday, May 30, 2014

JSLink: Edit and New Form

This is my second post on JSLink and I will show how to customize "New" and "Edit" forms using JavaScript and JSLink. I will not spend time on setup and deployment, which I briefly touched on my last post here.

As a ShaePoint developer, most of us have worked on customizing New or Edit form using JavaScript which works but it's a workaround, not an elegant solution. But with JSLink, we don't have to add Content Editor web part to OOTB NewForm.aspx or EditForm.aspx, instead we just have edit the page and set JSLink property.

In this post I am using the same Tasks list as in previous post and will enhance the new and edit forms, by replacing "% Complete" input control with dropdown list with predefined values. Here is the final result:



To achieve this result, create JavaScript file and copy/paste following code snippets. See comments for explanation:

// JavaScript source code
(function () {
    var overrideCtx = {};
    overrideCtx.Templates = {};

    //override 'PercentComplete' field and provide custom rendering functions
    //for NewForm.aspx and EditForm.aspx pages.
    overrideCtx.Templates.Fields = {
        'PercentComplete': { 'NewForm': customField, 'EditForm': customField }
    }

    //register our override
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);
})();

function customField(ctx) {
    //get form context for our field
    var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);

    //local vars:
    var fldName = "cbo_" + formCtx.fieldName;    //used to set id of dropdown
    var fldValue = parseInt(formCtx.fieldValue); //get current value for edit form

    //register value callback. this function is called before submitting form
    //returned value will be saved in PercentComplete field. make sure the 
    //return type is compatible with field data type.
    formCtx.registerGetValueCallback(formCtx.fieldName, function () {
        var cbo = document.getElementById(fldName);
        return cbo.options[cbo.selectedIndex].value;
    });

    //return <select> html to replace input control
    var html = [];
    html.push("<select id='" + fldName + "'>");</select>
    html.push(getSelectItem(0, fldValue));
    html.push(getSelectItem(25, fldValue));
    html.push(getSelectItem(50, fldValue));
    html.push(getSelectItem(75, fldValue));
    html.push(getSelectItem(100, fldValue));
    
    return html.join('');
}

//build <option> tag 
function getSelectItem(value, selValue) {
    if (value === selValue) 
        return "<option selected='selected' value='" + value + "'>" + value + "'</option>";
    return "<option value='" + value + "'>" + value + "</option>";
}

Upload JS file to Master Page library and set metadata as below:

Content TypeJavaScript Display Template
Target Control TypeForm
StandaloneOverride
Target ScopeServer relative URL of site
Target List Template IdList template Id (optional)

At this point only task remaining is to edit "NewForm.aspx" / "EditForm.aspx" pages and set JSLink proerty of "ListFormWebPart". You can do this through UI (edit page), Feature receiver or PowerShell script.

Go back to Tasks list and add or edit item to see customization. In next post, will see how we can add custom field validation.

Hope this help.

-Javed

Saturday, May 10, 2014

Working with JSLink

Recently I have been looking at CSR (client side rendering) feature which was introduced with SharePoint 2013. I did some display customizations with 2007 and 2010 version by modifying XSLT but when I try to replicate the same customizations with CSR feature, I immediately realized the power and usefulness of this new addition.

JSLink is the new property, available on many web parts, which allows you to override some parts or all of webpart UI on client side. SharePoint 2013 now uses JavaScript display templates to render contents on clients and falls back to XSLT, if for example: JavaScript is disabled on browser. This JavaScript framework provides many advantages compare to previous XSLT based rendering:
  1. Not many developers are familiar with XSLT and it is difficult to develop XSLT and debug.
  2. Most web developers are already familiar with JavaScript development.
  3. CSR – JSLink are easy to deploy and rolling back customization are straight forward too.
  4. With CSR – JSLink, the processing moves from server to client browser, thus freeing up server resources.
In this article, I will focus on overriding display of “% Complete” field of custom Tasks list. The goal is to display some kind of progress bar based on percent complete data. In order to implement this feature we have to follow below tasks:
  1. Created JavaScript file with override code
  2. Upload JavaScript file to SharePoint master page gallery using “JavaScript Display Template” content type
  3. Set JSLink property of webpart.
Here are the details of each task and for this article I am using SharePoint UI to complete these task, but it can be deployed as WSP Solution.

Created JavaScript file with override code

Open notepad (or your favorite text editor) and copy/paste the following code:

(function () {
    //create override object
    var overrideCtx = {};
    overrideCtx.Templates = {};

    //we are interested in 'PercentComplete' field. 

    //Note: field name is Internal Field Name which may be 
    //different than display name
    //you can use SharePoint Manager 2013 to find internal field name

    overrideCtx.Templates.Fields = {
        'PercentComplete': { 'View': customField }
    }

    //these are optional, but in case of multiple webparts on 

    //page and these are not set will affect all list view.
    overrideCtx.BaseViewID = 1;
    overrideCtx.ListTemplateType = 100;

    //register the override
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);
})();

//this function gets called for each row while rendering 'PercentComplete' field
function customField(ctx) {
    //check if 'PercentComplete' field is populated
    if (ctx.CurrentItem["PercentComplete"]) {
        //remove whitespace
        var completed = ctx.CurrentItem["PercentComplete"].replace(/\s+/g, '');
        //build and return the html to be rendered
        //NOTE: make sure you rename the red.png with your file on 15/images folder. 

        //Mine is 5x5 pixel with solid red
        var result = "<div style='background-image:url(/_layouts/15/images/red.png);width:" + completed + "'><b>" + completed + "</b></div>";
        return result;
    }
}


Upload JavaScript file to SharePoint master page gallery using “JavaScript Display Template” content type


  • Navigate to Site Settings > Master pages and page layouts screen.
  • From ribbon click “Upload Document” > Browse and select above JavaScript file > click OK
  • On next screen; enter as follows:
Content TypeJavaScript Display Template
Target Control TypeField
StandaloneOverride
Target ScopeServer relative URL of site
Target List Template IdList template Id (optional)
  • Click “Save”

Set JSLink property of webpart

  • Expand “Settings” menu and click on “Edit Page”
  • Open webpart menu and click “Edit Web Part”
  • Expand “Miscellaneous” tab and add JavaScript URL with site token eg: ~site/_catalogs/masterpage/CSRTasks.js
  • Click “OK” to save.
  • Save and close the edit page screen.

At this point you are ready for testing, hit F5 to refresh the list web part page and if all went fine the UI would look like this:

clip_image002

Next article will talk about overriding Edit and View forms.

Hope this helps.

-Javed

Tuesday, April 29, 2014

How to disable event firing in custom code


Recently I worked on application page which updates list item, which in turn causes item update event to fire. The goal was to avoid any event execution. I have done this many times before, but had a hard time recalling. This post is a note to myself, so I know where to look for code sample, if I forgot again. :)

If I am writing event receiver, I can use EventFiringEnabled property to disable events temporarily. But in application page I don’t’ have access to SPEventReceiverBase
which exposes this property. So here is the coed I used to temporarily disable event firing.

public class DisableItemEventFiring : SPItemEventReceiver, IDisposable 
{
public ItemEventFiring()
{
this.EventFiringEnabled = false;
}

public void  Dispose()
{
this.EventFiringEnabled = true;
}
}


Now we have defined class for disabling list item event, I can use this class in application page,

using (DisableItemEventFiring disableEvt = new DisableItemEventFiring ())
{
//no event will be fired
item.SystemUpdate();
}

//event firing enabled again
item.SystemUpdate();


Hope this helps.

-Javed

Wednesday, April 2, 2014

JavaScript Frameworks


With arrival of SharePoint 2013 last year and Microsoft push to move your code away from SharePoint server to the client browsers, JavaScript is now considered an important skill. The new SharePoint App model allows developers to use JavaScript to write entire application and in case of SharePoint-hosted app, is the only option. Now it is a good idea to spend some time understanding and learning JavaScript and many freely available Frameworks. If you are writing Single Page Application or just DOM manipulation or implementing user notifications, there are at least couple of open source JavaScript frameworks available. I have been using some of these and below is the list of some of those frameworks.

jQuery I think the most popular and useful library.
AngularJS Recently completed Single Page App on SharePoint using Angular and I love this framework for its powerful bi-directional data binding, routing, REST support and much more.
Knockout.js Great bi-directional data binding framework, but the only thing bothers me is to convert JSON (from server) to observable collection.
Underscore.js Makes life lot easier handling arrays and collection
moment.js Date and time utility functions. Data validation, formatting, international formatting.
noty.js A jQuery plugin to display success/error notification. Highly configurable.
toastr.js Similar to noty.js
Open XML SDK for JavaScript Now you can create Office documents right in the browser with this library. Check out these links for more info:
Introducing the Open XML SDK for JavaScript
Open XML SDK for JavaScript

I will continue adding more libraries and frameworks as and when I get a chance to play with.

Hope this helps.

-Javed

Thursday, March 27, 2014

Change Certificate for Trusted Identity Provider


Many times we are required to update X.509 certificate for Trusted Identity Provider because certificate may have expired or may be we were using self-signed certificate and now wants to replace with commercial CA issued certificates.

Use this PowerShell commands to update certificate for existing Trusted Identity Provider.

$newCert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("C:\MyCerts\CA_Issued_Cert.cer")
New-SPTrustedRootAuthority -Name "New CA Issued Cert" -Certificate $newCert 

Set-SPTrustedIdentityTokenIssuer -Identity "My Id Provider" -ImportTrustCertificate $newCert

If you want to remove the old/expired certificate from SharePoint trust root, use this command to delete the certificate.

Remove-SPTrustedRootAuthority -Identity "My Old Cert"

Hope this helps.

-Javed.

Saturday, March 1, 2014

Sign Out from STS in ASP.NET web application

This post is related to my last post about Claims Provider from IP-STS. STS was used by ASP.NET web application and require single sign out. But even after calling Session.Abandon() and FormsAuthentication.SignOut(), users were still logged in to STS.

After some looking around I found the answer on stackoverflow. The problem was Session.Abandon() and FormsAuthentication.SignOut() were clearing the user cookies and session state but STS token were never cleaned up. Use this code to complete Sign out process:
WSFederationAuthenticationModule fam =
FederatedAuthentication.WSFederationAuthenticationModule;

string wrealm = string.Format("wtrealm={0}", fam.Realm);

string signOutUrl =
WSFederationAuthenticationModule.GetFederationPassiveSignOutUrl(
fam.Issuer, null, wrealm);

string wreply = Request.Url.AbsoluteUri;

WSFederationAuthenticationModule.FederatedSignOut(
new Uri(signOutUrl), new Uri(wreply));


You can paste this code in your logout handler and should clean up STS token. After logout STS will redirect browser to URL set by “wreply” and can be set to any URL. You don’t need to set this parameter, in case of null, STS will redirect to default application page set during STS configuration.

This routine send “wsignout1.0” command to STS to clean up token for the user. Here is the signout URL:

http://localhost:8888/?wa=wsignout1.0&wtrealm=http%3a%2f%2flocalhost%3a58077%2f&wreply=http%3a%2f%2flocalhost%3a58077%2fdefault.aspx


Hope this helps.

-Javed

Thursday, February 13, 2014

Creating Claims Provider for custom IP-STS


I was recently involved in troubleshooting Claims Provider written specifically for custom IP-STS provider. The STS authenticate external user to access public facing SharePoint site collection. The issue was occurring while adding external users to SharePoint group. After selecting User (through people picker control) and adding them to SP group, users were not able to login to the site.

But if I add external users through PowerShell script (see link below for script), users can login and see everything they are suppose to see. After some initial debugging I noticed, the user identity of user added with PowerShell and user added through people picker control were not matching.

//User identity from people picker control (incorrect identity)
c:0Ç¿.c|myprovider|testuser2@rtest.com

//User identity using PowerShell script (correct identity)
i:05.t|my provider|testuser2@rtest.com

I googled and found this nice blog link which describes all parts of claims identity. People picker was generating “other claim type” (denoted by “c”) but SharePoint required “identity claim type” (denoted by “i”). And there was one more issue, the trusted issuer (‘myprovider’ and ‘my provider) were not matching either. “my provider” is name of IP-STS provider and “myprovider” is the name of Claims Provider.

With this information, I took another look at claim provider class and could see the issue with code. Here are all the changes which fixed the issue:

First, the claim provider was offering only 1 claim but STS was providing lot more than that. So I updated FillClaimTypes and FillClaimValueTypes.

protected override void FillClaimTypes(List<string> claimTypes)
{
 if (claimTypes == null)
  throw new ArgumentNullException("claimTypes");

 claimTypes.Add(Microsoft.IdentityModel.Claims.ClaimTypes.Role);
 claimTypes.Add(Microsoft.IdentityModel.Claims.ClaimTypes.Upn);
 claimTypes.Add(Microsoft.IdentityModel.Claims.ClaimTypes.Email);
 claimTypes.Add(Microsoft.IdentityModel.Claims.ClaimTypes.Surname);
 claimTypes.Add(Microsoft.IdentityModel.Claims.ClaimTypes.GivenName);
 claimTypes.Add(Microsoft.IdentityModel.Claims.ClaimTypes.System);
}

protected override void FillClaimValueTypes(List<string> claimValueTypes)
{
 if (claimValueTypes == null)
  throw new ArgumentNullException("claimValueTypes");

 claimValueTypes.Add(Microsoft.IdentityModel.Claims.ClaimValueTypes.String);
 claimValueTypes.Add(Microsoft.IdentityModel.Claims.ClaimValueTypes.String);
 claimValueTypes.Add(Microsoft.IdentityModel.Claims.ClaimValueTypes.String);
 claimValueTypes.Add(Microsoft.IdentityModel.Claims.ClaimValueTypes.String);
 claimValueTypes.Add(Microsoft.IdentityModel.Claims.ClaimValueTypes.String);
 claimValueTypes.Add(Microsoft.IdentityModel.Claims.ClaimValueTypes.String);
}

I am using only String types for all claims, but if you are using other value types, make sure the order of ClaimTypes and ClaimValueTypes matches.

Second, to fix trusted issuer mis-match, I replaced base CreateClaim function with this function.
private SPClaim MyCreateClaim(string myClaimType, 
    string myClaimValueType, 
    string myClaimValue)
{
 SPClaim myClaim = new SPClaim(myClaimType, myClaimValue, myClaimValueType,
     SPOriginalIssuers.Format(
        SPOriginalIssuerType.TrustedProvider, “xxx provider”));

    return myClaim;
}

The base CreateClaim function by default creates claim using Name property of SPClaimProvider class as trusted issuer.

Third, return the correct claim type i.e. identity claim. FillSearch method was creating and returning claim of type “FormsRole” which is good for adding additional claims (claim augmentation) but not identity claim. Here is the updated code:
protected override void FillSearch(Uri context, string[] entityTypes, 
    string searchPattern, string hierarchyNodeID, 
    int maxCount, SPProviderHierarchyTree searchTree)
{
    try
    {
        var ldapServer = ConfigurationManager.ConnectionStrings["LDAPConn"];
        var connectionString = ldapServer.ConnectionString;
        var de = new DirectoryEntry(connectionString, 
            LDAPCredentials.UserName, LDAPCredentials.Password,
            AuthenticationTypes.Secure);
        var search = new DirectorySearcher(de);

        search.Filter = 
            string.Format(
                "(&(objectClass=inetorgperson)(|(anr={0})(mail={0}*)))",
                 searchPattern);

        search.SearchScope = SearchScope.Subtree;
        search.PropertiesToLoad.Add("displayName"); 
        search.PropertiesToLoad.Add("mail"); 

        var searchResults = search.FindAll();
        if (searchResults.Count > 0)
        {
          var matches = new List<PickerEntity>();
          foreach (SearchResult profile in searchResults)
          {
            var ups = profile.GetDirectoryEntry();
            var pe = GetPickerEntity(ups.Properties["mail"].Value.ToString(),
               ups.Properties["displayName"].Value.ToString());
            matches.Add(pe);
          }
          searchTree.AddEntities(matches);
    }
    catch (Exception ex)
    {
        LoggingService.LogErrorInULS(ex, TraceSeverity.Unexpected);
    }
}

private PickerEntity GetPickerEntity(string claimValue, string preferredName)
{
    PickerEntity pe = CreatePickerEntity();
    //pe.Claim = CreateClaim(myClaimType, claimValue, myClaimValueType);     
    pe.Claim = MyCreateClaim(myClaimType, myClaimValueType, claimValue);
    pe.Description = string.Format( "{1} [{1}]", “My Provider”, claimValue);
    pe.DisplayText = preferredName ;
    pe.EntityData[PeopleEditorEntityDataKeys.DisplayName] = claimValue;
    pe.EntityType = SPClaimEntityTypes.User; // SPClaimEntityTypes.FormsRole;
    pe.IsResolved = true;
    return pe;
}

The change was simple, change EntityType to SPClaimEntityTypes.User from FormsRole and use custom function to create claim.

Build and deploy package to server.

Here are few links which helped me in resolving the issue:
Claims Walkthrough
Claims Encoding
Writing your own Trusted Identity provider for SP2010 (3) (this link has script to create user through PowerShell)

Hope this helps.

-Javed

Friday, January 31, 2014

Configuring Federated Search for SharePoint 2010


In this post I will discuss how to leverage external search engines which supports OpenSearch protocol and display their results in SharePoint environment.

SharePoint 2010 provides 2 ways to search external data sources. The “content crawling”, in this approach the text context and attributes are indexed and stored by SharePoint search server and the “federated search”, the topic of this post. In this approach SharePoint passes search term and other parameters to external search engine and formats/displays the returned results.
The Federated Search approach provides following benefits :
  1. No need for additional storage, as SharePoint does not index the external content.
  2. We can use external system's native search capabilities.

Federated Result Web Parts:


Federated Results Web Part:

This displays result from specific federated search location. You can only specify one search location per web part.

Top Federated Results Web Part:

You can configure multiple federated search locations with priority and the web part returns result from first federated location which returns search result.
To configure new federated location, follow these steps:
  1. Log in to your SharePoint Central Administration site as a SharePoint farm administrator.
  2. Click "Manage service applications" under the "Application Management" heading.
  3. Click "Search Service Application".
  4. Click "Federated Locations" under the "Queries and Results" heading in the left-hand navigation panel.
  5. Click "New Location".
  6. Fill in the information for the new federated location, and then click 'OK'.
Here are some guidelines on the important fields:
Location Type:
Search Index on this Server: The search happens locally and can be customized to return result from specific scope.

OpenSearch 1.0/1.1: This setting uses external search engine which receives and processes parameter from SharePoint and return structured XML result like RSS or Atom.
Query Template:
The URL template called by SharePoint with search term and other configured tokens. At runtime the tokens are replaced by actual values before calling the URL . The URL should return structured XML like RSS or Atom feed.

http://<server url>/_layouts/CCESearchSF/SearchSF.aspx?q={searchTerms}&start={startItem}&count=3&format=rss

Supported Token Description
{searchTerms} Replaced with search term user types in search box
{startIndex} When fetching results in pages, this token replaced with start index of the first result.
{startPage} When fetching results in pages, this token replaced with page number of set of results to return.
{count} Replaced with number of results to display per page.
More Results Link Template:
The html template contains link to external system search result page.
Triggers:
Always: The search query is always forwarded to federated location.

Prefix: A prefix contains specific term which must be prefixed with search term. eg: "office" prefix with search query like "office New York" will match and "New York" search term is sent to federated location.

Pattern: A regular expression pattern must match the search term to trigger the query to be forwarded to federated location.
Display transformations:
The default transformation provided by SharePoint is good enough in most cases and can be left to default values. But if you prefer to customize the result output, you can replace the default XSLT with your customized XSLT.

Restrictions:

The use of federated location can be un-restricted or restricted to few specific sites or domain.
Authentications:
Anonymous: The federated location does not require authentication.

Common: Every connection uses the same set of credentials to connect to federated location.

Per-User: The credentials of the user who initiated the query is used to connect to federated location. If using Per-user authentication type and the resource is located on different machine, make sure to select "Kerberos" as authentication type.

Hope this helps.

-Javed

Welcome to my blog


This is my second attempt to writing and keeping the blog. My last blog post was around early 2010 and this time I hope to write at least one post every month.

This time I am planning to share all kinds of learning and challenges big or small I faced on the field. I am also planning to convert all my notes, tips/tricks and gotchas I have accumulated on OneNote to blog post.

Lately I have been busy playing with Angular JS, specially building single page application for SharePoint 2013 app model using REST API. I love the power and simplicity it brings to client side development. I will start writing my learning and experience with Angular JS pretty soon.

Happy blogging!

-Javed

Sunday, February 7, 2010

Manually overriding document expiration date


Some time back I implemented interesting functionality which is the topic of this article.
Requirements:
The client wanted to have override feature where users can override expiration date and it should be configurable meaning user can specify number of days/months/years to extend current expiry date. Fortunately we had implemented Custom Expiration formula to calculate expiry date which helps in designing solution for this requirement.
Assumptions:
You are using Custom Expiration formula to calculate expiry date.
Solution:
I took following steps to implement the solution.
  • Create new hidden field "Ignore" of type Number in document library.
  • Create new .aspx page and code behind files. You will find several articles on internet on how to create new application page.

Part of aspx file where all controls are defined.


Part of button click event handler

  • Create feature xml file to provision .aspx file and add "Override Expiration" menu to ECB (Editor Control Block) of list item.
ApplicationPageNavigation.xml (elements xml file)

Feature.xml

  • Modify custom expiration formula code to return already set expiration date when "Ignore" field contains value "1".
  • Build solution (WSP) and deploy to your SharePoint farm.
When user selects "Override Expiration" menu item, he/she is presented with screen where user enters number of days/months/years to extend expiration date. After hitting "Ok" button, the button event code fire and extend current expiration date and redirect user back to list view.

Here are screenshots of final product.

List item with "Override Expiration" ECB menu item and current "Expiration Date"


Screen to capture user inputs (expiry date to extend by 3 days)

List item with updated "Expiration Date"




Attachment:
OverrideExpirationECBMenu.zip

Note the project I have attached is actually taken from proof of concept, so there are no validation and exception handling implemented.

Leave comments if you have any question.

Hope this helps.
-Javed

Friday, February 5, 2010

Validating document approval and sending email notification


Today I was working on a requirement to validate document approval (we are using OOTB document approval feature) based of some external business rules.

Requirement:
If business validation fails, I have to cancel document Approval process and if validation succeeds then I have to generate email notifying team with links to approved document.

Solution:
My first option was to use Workflow using Visual Studio (I have to re-use the functionality for many other document libraries), but soon found out it's not possible to retrieve before and after values inside Workflow and to cancel list item update. Please let me know if you think otherwise. The other option was to use Event Receiver which I followed. I override synchronous ItemUpdating event and again struggled to retrieve after "Approval Status" value. After couple of hours of debugging, I found key named vti_doclibmodstat in AfterProperites collection containing integer values 0, 1 or 2 which is nothing but Approved, Rejected or Pending statuses. So here is the complete code to retrieve before and after "Approval Status" inside event handler:

public override void ItemUpdating(SPItemEventProperties properties)
{
base.ItemUpdating(properties);
SPModerationStatusType beforeStatus = properties.ListItem.ModerationInformation.Status;
SPModerationStatusType afterStatus = 
(SPModerationStatusType)Int32.Parse(properties.AfterProperties["vti_doclibmodstat"].ToString());
if ((beforeStatus != afterStatus) && 
(afterStatus == SPModerationStatusType.Approved))
{
if (Validate(properties) == false)
{
properties.Cancel = true;
properties.ErrorMessage = "";
}
else
{
SendEmail(properties);
}
}
}

And now I can validate document approval process, cancel approval process and send email notifications.

Hope this helps.
-Javed