Monday, October 14, 2013

Project Server 2013 Online. OData localization

When you deal with on-premise installation of Project Server 2010/2013, you can use Reporting database to access data for reporting purposes. But when we are talking about Project Server Online, the data access gets more complex. The thing is that you don’t have direct access to the databases, and the only way to get your data is to use OData protocol.

There are lots of nice posts all over the Internet (like this or this) which describe how to use OData with Project Online. One of the features of OData is localization - you request and get the data based on language you like.

This is done by adding language prefix to the URL, something like this:

https://site.sharepoint/sites/pwa/_api/ProjectData/[en-US]/

If you don’t specify the language explicitly, the OData feed will have the same language as your site default one (you’ve specified it during PWA provisioning). But other supported languages are available as well.

One thing we’ve noticed: once you’ve provisioned a new instance of PWA site, you get only one, default locale working. For all other locales you’ll get error messages similar to following:

<m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
   <m:code/>
   <m:message xml:lang="ru-RU">
      The requested langauage en-US is not supported or currently installed.
   </m:message>
</m:error>

Even if you navigate to the BI site, you’ll see reports only for site default language. The good thing is that both reports and OData languages will become available after a while. In our case it was about half of a day. For some reason, the languages are “installed” to the PWA instance with some delay. So if you need this feature working on your PWA site, be patient and you’ll get it… soon…

Read more...

Monday, July 15, 2013

SharePoint JSGrid. Creating custom Widgets

Hi! There are not so many info all over the Internet explaining how to use complex features of SharePoint 2010 JSGrid control, such as custom prop types, display controls and widgets. In this post we’ll show how to create custom prop type and attach custom widget to it. In addition, you’ll see the way to handle data validation for columns of such types.

Creating custom Prop Type

First of all, we should create custom property type. The Init method of JSGrid controller is the place to do that. The easiest way is to derive new type from existing one. We’ll use standard String prop type:
this._MyCustomPropType = createMyCustomPropType('String');
function createMyCustomPropType(basePropType) {
            var newPropType = SP.Internal.JS.object(basePropType);
            newPropType.ID = 'MyCustomPropType';
            newPropType.BeginValidateNormalizeConvert = function (recordKey, fieldKey, newValue, bIsLocalized, fnCallback, fnError) {
                if (!newValue) {
                    fnCallback({ isValid: false, dataValue: newValue, normalizedLocValue: newValue, errorMsg: 'Value is not set.' });
                } else {
                    $.ajax({
                        url: 'some_validation_url',
                        data: {
                            value: newValue
                        },
                        success: function (result) {
                            fnCallback(result);
                        },
                        error: function (request) {
                            fnCallback({ isValid: false, dataValue: newValue, normalizedLocValue: newValue, errorMsg: request.responseText });
                        }
                    });
                }
            };
            newPropType.widgetControlNames = ['MyCustomWidget'];
            return newPropType;
        }

The ID property should be unique to identify the prop type between others.

BeginValidateNormalizeConvert method contains the validation logic. In our case we make the field required and add server-side validation (jQuery ajax call in our case). If you don’t need a delayed validation, you can directly call fnCallback function which comes as an argument of validation fuction.

It is important to set widgetControlNames property of newly created prop type to the same value as the ID of the widget you’d like to use for editing data. Please pay attention that this is not the ID itself, but rather an array containing this ID.

Registering custom Prop Type

When the prop type is created, it should be registered in JSGrid infrastructure. You'll have to specify both edit and display controls for the prop type. In our case we use OOB Text display control and EditBox edit control. The code:

SP.JsGrid.PropertyType.RegisterNewCustomPropType(this._MyCustomPropType,
            SP.JsGrid.DisplayControl.Type.Text, SP.JsGrid.EditControl.Type.EditBox, this._MyCustomPropType.widgetControlNames);

Creating custom Widget

Now you can create and register the widget control itself:

SP.JsGrid.PropertyType.Utils.RegisterWidgetControl(
            'MyCustomWidget',
            function (gridContext) {
                return new MyCustomWidget(gridContext);
            },
            []);
MyCustomWidget = function (gridContext) {
    this.SupportedWriteMode = SP.JsGrid.EditActorWriteType.DataOnly;
    this.SupportedReadMode = SP.JsGrid.EditActorReadType.DataOnly;
    var self = this;
    this.cellContext = null;

    this.Dispose = function () {
    };
    this.GetIcon = function () {
        return new SP.JsGrid.Image('../images/editheader.png').Render('');
    };
    this.OnValueChanged = function () {
    };
    this.Expand = function () {
        var options = {
            allowautoresize: false,
            allowmaximize: false,
            title: 'Pick Resource',
            width: 600,
            height: 400
        };

        SP.UI.ModalDialog.showModalDialog ({
            url: 'some_url',
            args: { },
            dialogReturnValueCallback: function (oDialogResult, oRet) {
                if (oDialogResult) {
                    self.cellContext.SetCurrentValue({ data: oRet.Guid, localized: oRet.Name });
                    self.cellContext.NotifyEditComplete();
                }
                self.Collapse();
            }
});
    };
    this.Collapse = function() {
        this.cellContext.NotifyCollapseWidget();
    };
    this.BindToCell = function (cellContext) {
        this.cellContext = cellContext;
    };
    this.Unbind = function () {
    };
};

The most important part in the widget definition is Expand method. In our case we open modal dialog and use the data returned when the dialog is closed.

The only thing left is to specify the ID of new prop type when the grid data are being built and serialized. PropertyTypeId field of GridField should be used for this purpose.

Read more...

Wednesday, May 22, 2013

Project Server Timesheets. Programmatic tricks and work-arounds

Programmatic update of Project Server timesheets is designed to be done via PSI Timesheets web service. Everything looks pretty simple until your code needs to support the whole set of Project Server Timesheet functionality. Below is the list of “non-trivial” timesheet-related tasks we managed to accomplish.

Updating task actuals in Single Entry Mode. Dealing with new tasks.

Problem - GeneralItemDoesNotExist error on QueueUpdateTimesheet web service method call. The issue was described here. The solution we've proposed was “fixing” timesheet in case if some assignments were created later than timesheet. The workaround would be any minor change of the timesheet, i.e. change the timesheet name to itself to mark the dataset row changed.

Adding new assignments in Single Entry Mode.

This operation requires the same timesheet “fixing” work (described above).

Updating task actuals in Single Entry Mode. Non-administrative tasks.

This action requires additional action – creating StatusingChangeLog row. All the properties should be properly set - ENTITY_TYPE, ENTITY_UID, PID, PROJ_UID and VALUE.

Deleting Assignment rows.

The changes dataset should be appended with new RemovedAssignments data table, which is not in dataset schema. It should contain a row with ASSN_UID column set. In addition, in case if Single Entry Mode is turned on, this action requires adding two StatusingChangeLog rows – with PID s_apid_update_needed and s_apid_removed_by_res.

Determining the erroneous state of the timesheet.

The initial dataset schema does not allow doing this. But this task can be accomplished by checking “invisible” timesheet row column TS_QUEUE_JOB_STATUS.

We’ve spent quite a lot of our time to make these things working. As usual, the working code is encapsulated to the FluentPS library.

Have fun!

Read more...

Monday, April 29, 2013

Project Server 2013 PSI from the web context. Unauthorized issue

There are number of changes in SharePoint 2013 and Project Server 2013. One of them is that the Claims Authentication becomes default authentication mechanism now.

Project Server 2013 is claims aware, so all out of the box functionality works fine with claims authentication. But things get worse when you try to use Project Server ClientOM or PSI services from the web context where the claims authentication used. Result - "Unauthorized" message.

This post is about to show some workarounds to cope with the issue.

The scenario

PSI services are ok to be called from console app, but fail when they are called from the web part in the web application with claims authentication set up. Current user Windows identity is known in the first scenario, which is ok. But in the second scenario current identity is not the identity of logged on user ("iusr" by default). Below are 4 approaches to make PSI working from the web context.

Approach #1. Use Windows classic authentication

Pros: The easiest way; no code changes required.

Cons: Not recommended way. Microsoft highly recommends using claims authentication for all new solutions. The use of classic mode authentication, also known as Windows classic authentication, is discouraged in SharePoint 2013 and you can only create or configure web applications for classic mode authentication with Windows PowerShell cmdlets. (See Create web applications that use classic mode authentication in SharePoint 2013).

Approach #2. Use Application Pool account

This approach is applicable when your web application uses the domain account as the application pool account. In this case you can use "Service account" pattern. For example you can make PSI calls using the application pool account. The code:

SPSecurity.RunWithElevatedPrivileges(delegate()
{
    //PSI call
});

This code impersonates current thread under the application pool identity, so any call within the supplied delegate will be done under the application pool account. Do not forget to grant appropriate permissions to pool account (For example, you can add it to Project Server administrators group). This trick will not work as expected if NETWORK SERVICE account is used as an application pool account. Also, external system will not have access to identity of the original user of web page. It will think that application pool made a call.

Pros: It works :)

Cons: Code changes required; service won't be aware of the actual caller - Project Server impersonation will have to be used; application pool needs to be configured with domain account.

Approach #3. Use UpnLogon method of "Claims to Windows Token Service"

The most complex one. It requires you to manually call the UpnLogon method of “Claims to Windows Token Service”. First, you need to get your current user claims identity. It can be done as follows:

if (Thread.CurrentPrincipal.Identity is ClaimsIdentity)
{
    var identity = (ClaimsIdentity)Thread.CurrentPrincipal.Identity;
}

Than you need to extract UPN-Claim from the identity. It indicates a Kerberos-style user principal name (UPN), for example, user@realm. Only one claim can be of the UPN type. Additional UPNs can be configured as a custom claim types. the code:

string upn = null;
foreach (Claim claim in identity.Claims)
{
   if (StringComparer.Ordinal.Equals(System.IdentityModel.Claims.ClaimTypes.Upn, claim.ClaimType))
   {
       upn = claim.Value;
   }
}

After you got the UPN-Claim, you can get the windows user identity from this claim with help of “Claims to Windows Token Service”. By default, this service is disabled. You need to enable it in SharePoint central administration (See Claims-based identity and concepts in SharePoint 2013). Steps:

1. Go to Central Administration -> System Settings -> Manger services on server and ensure that “Claims to Windows Token Service” state is “Started”.

2. Edit “C:\Program Files\Windows Identity Foundation\v3.5\c2wtshost.exe” and ensure that your application pool account is in the list of allowed callers. The best way to do this is to add your application pool account to WSS_WPG security group. Your “allowedCallers” section would look like this:

<allowedCallers>
    <clear />
    <add value="WSS_WPG" />
</allowedCallers>

More info can be found at Claims to Windows Token Service (C2WTS).

Now you can do the call to “Claims to Windows Token Service”. The code:

WindowsIdentity windowsIdentity = null;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
     windowsIdentity = S4UClient.UpnLogon(upn);
});

Now you can perform the impersonation and actual call:

using (windowsIdentity.Impersonate())
{
    // PSI call
}

Pros: Recommended way to work with legacy systems; this approach does not work if there is no user with given UPN in the domain where “Claims 2 Windows Token Service” is running.

Cons: The manual configuration required; code changes required.

Approach #4. Enable the mapToWindows

There is also fourth solution of this problem. If your application always requires impersonation-level Windows security tokens, then you may choose to enable the mapToWindows property on samlSecurityTokenRequirement on the <securityTokenHandlers> element. You need to enable Claims 2 Windows Token Service” as described above.

Pros: no code change required

Cons: PSI services are not configured to use securityTokenHandlers. Not sure it this can be done for PSI in particular.

Read more...

Monday, March 18, 2013

How to use security tokens in SharePoint / ProjectServer 2013

Hi! As we know, SharePoint / Project Server 2013 Online allows to extend its functionality with help of SharePoint apps. In order to identify users and perform communication between the app and SharePoint itself, special mechanism is proposed - security tokens are used for this purpose. This post describes how to create such app and access SharePoint / Project Server 2013 Online data using security tokens mechanism. In our case we will consider reading Project Server data from provider-hosted web app via OData protocol.

1. Create App for SharePoint 2013 (provider-hosted app) in Visual Studio 2012. MS Office development Tools should be installed for this purpose (Web Platform Instaler is used for this purpose). This will create 2 projects in your solution - SP App project and Web App project.

2. Fill in the ClientId app settings in Web.config of Web project. It should be your Company’s ClientId received when you register as MS Seller here. For dev purposes you can generate it yourself using http://SP_HOST_NAME/SP_SITE_NAME/_layouts/15/AppRegNew.aspx page.

3. Declare all necessary permissions. This can be done in AppManifest.xml file. In our case we are adding Reporting permission for future OData requests.

4. Publish SP App and upload it to the App Store. For development purposes it can be deployed to local App Store.

5. Add app to SharePoint site

6. Click on app icon to get to the hosted site

Hosted site actions:

7. Get context token from request. This can be done with help of TokenHelper class generated by Visual Studio. The code looks like the following:

var contextToken = TokenHelper.GetContextTokenFromRequest(Page.Request);

8. Get ClientContext instance with context token. Code:

var hostWeb = Page.Request["SPHostUrl"];
var clientContext = TokenHelper.GetClientContextWithContextToken(hostWeb, contextToken, Request.Url.Authority);

9. Get access token. Code:

var accessToken = TokenHelper.GetAccessToken(contextToken, targetHost);

10. In case if you need delayed assess to SP / PS data, you can use Refresh token. It can be built from the context token the following way:

var appToken = GetAppToken(Page.Request);
var refreshToken = TokenHelper.ReadAndValidateContextToken(appToken, null).RefreshToken;
var accessToken = new TokenHelper().GetAccessToken(refreshToken, targetPrincipal, targetHost, realm);
public string GetAppToken(HttpRequest request)
{
   string[] paramNames = { "AppContext", "AppContextToken", "AccessToken", "SPAppToken" };
            foreach (string paramName in paramNames)
            {
                if (!string.IsNullOrEmpty(request.Form[paramName])) return request.Form[paramName];
                if (!string.IsNullOrEmpty(request.QueryString[paramName])) return request.QueryString[paramName];
            }
}

11. Obtain client context with access token. Code:

var context = TokenHelper.GetClientContextWithAccessToken(targetUrl, accessToken.AccessToken);

12. Now we can finally perform data request. In our code we use OData:

var req = (HttpWebRequest)WebRequest.Create(url);
       req.Credentials = CredentialCache.DefaultCredentials;
       req.Headers["Authorization"] = "Bearer " + accessToken;
       req.Accept = "application/atom+xml";
var response = req.GetResponse();
Hope these instructions will save someone's time. Have fun!
Read more...

Thursday, February 14, 2013

FluentPS 2.2 Released

Hi! Last week we've released the new version of FluentPS and FluentSP library. As always, you can get it from fluentps.codeplex.com.
Below is the list of major improvements we've done:

FluentSP library

  • SharePoint 2013 support (FluentSP15 library) built for Microsoft.Net 4.0 platform
  • Mapping of different field types for SharePoint List Items i.e. user, single/multiple value choice, DBC fields etc.
  • Improved LINQ for querying SharePoint lists. Now you can get list items with more complex expressions which will be translated to CAML query. Sample expressions:
    listItemService.GetAll(_ =>
        new List<string> { "note1", "note2" }.Contains(_.NoteField)
        || _.TextField.Contains("sometext"));
    

FluentPS library

  • Project Server 2013 support (FluentPS15 library) built for Microsoft.Net 4.0 platform
  • Cover PSI methods for accessing Portfolio Analysis, Resource Plans and most of Project Server settings

Have fun!

Read more...

Tuesday, February 12, 2013

Free Status Report and Project Dashboard for Project Server 2010


Free Project Dashboard and Status Report

We are happy to announce that FluentPro Project Dashboard for Project Server 2010 and FluentPro Status Report for Project Server 2010 are FREE. $0.00

Download FluentPro Status Report for Project Server 2010
Download FluentPro Project Dashboard for Project Server 2010

Instructions:

  1. Click on the the link above
  2. Download the product (there is button at the bottom. Please fill the form and system will send you email  with URL for download
  3. Download and install product
  4. To receive a free license for product, send a product code from Server Settings to license@fluentpro.com and you will get a free license.
  5. Enjoy!
Read more...

Sunday, January 20, 2013

Implementing Program Support in Project Server 2010


Many organizations that have a more than average number of projects, usually are grouping projects into programs and portfolios. In this post and next one I will describe the best ways how to enable support of "Programs" in Project Server 2010 and how our products can help.

Out-of-the-box solution - Master Projects / Sub Projects

In Project Server by default there is no concept of "Program", but project sever supports the so called "master project" / "subproject" functionality. That means, that users can insert projects into one project (usually a "container" project) and that project can become master project and a "program".

This approach has multiple advantages and disadvantages (you can see everything in one place but the same time there are multiple challenges with edit / read-only, it is very hard to deal with projects that contain tens of subprojects).

Several blog posts:



You can search in Google /Bing for more information using the keywords "master project subproject project server 2010" and will find additional information.

Custom solution - Using Custom Fields

Another approach is to create one field with lookup table - Program Name and use it as selection / dropdown for selecting programs from that dropdown.

There is one big disadvantage of this approach - user needs to support content of that lookup table manually, but with small number of programs this works better and is a more "cleaner" solution.

FluentPro has 2 products that can help with this :


In this post, we will create overview for implementing this approach with help of one of our products - Lookup Manager, product that allows sync of custom lookup table with data from SharePoint list or any database.

We will create 1 lookup table and 2 fields:

Lookup table:

      Program

Fields:

  • IsProgram (Flag, project level)
  • Program (Text, project level, referencing Program lookup table).

we will add both fields (IsProgram and Program) to Project Information PDP.

As next step, we will configure installed Lookup Manager to read data from Reporting Database. We want to select all project names that are programs (have IsProgram set to 1 (Yes)) and add them to than lookup table.

1. Go to Site Actions -> View All site Content and click on the list"FluentPro Lookup Manager".

2. Go to Items -> New item -> SQL Data Source. That will open window where you need to define a sync rule.


3. Enter all information and press Save button. This will create a SharePoint job, and you can adjust schedule to work as you want.  Please use information from your project server configuration (server name, database name):



4. For this scenario, we will set it to work every 5 minutes - it means, system will query database every 5 minutes and if required will try to update lookup table with values.
- Go to Central Administration -> Monitoring -> Timer Jobs -> Review Timer Job Definitions.

- Find job with name: LookupSynchronizationJob/<pwaname>  and click on it
- Change schedule and click OK.


5. Let's create 2 projects that are programs: Program A and Program B (do not forget to set IsProgram field).

6. Wait for 5 minutes and start creation of new projects - and check values in dropdown for Program field:


That's it. If you do not create programs very often, you can set the job to run once a day or on any desired schedule.

Few more features of FluentPro Lookup Manager:

- Data can be synchronized from SQL Server as well as SharePoint data sources.
- We support multi-level lookup tables (data in source should use the separator for each element: Level1.Level2.Level3) Any number of hierarchy levels is supported and separator is configurable.
- Lookup Manager is not deleting elements, only adding new ones

In next post, we will describe how to implement support of programs using Autocomplete Manager.
Read more...

Tuesday, January 15, 2013

Self-Service Business Intelligence / Data Visualization platform for Project Server


REDMOND, WA, USA, January 15, 2013 — FluentPro Software Inc, a leading software development company for Microsoft Project Server platform, is pleased to announce the release of the new product for building dashboards for Project Server platform – FluentPro EPM Pulse – to the general public! Effective immediately, customers can purchase EPM Pulse directly from www.fluentpro.com or from over 15 partners and resellers all over the world.

As the one of leading software development companies for Project Server platform, FluentPro developed over 400 reports and dashboards for customers and partners. All these reports and dashboards solve specific problems of EPM reporting for customers and require IT engagement, however, they do not enable organizations to see all the data that Project Server stores or provide the ability to analyze the data and present it without additional processing.
EPM Pulse is closing this gap – platform allows any Project Server user to build contemporary project and portfolio dashboards using over 130 pre-built building blocks in dashboard designer using drag-and-drop, just in minutes, without any training and writing any code; share it with peers and present them to executives. Supporting over 12 different types of charts – from gauges and bar charts to the tables and scattered charts, EPM Pulse provides a solid platform for quality EPM dashboard design in minutes instead of days or weeks.

Sample dashboard:


“EPM Pulse is a revolutionary product for Project Server industry and is a great fit for companies that use or plan to start using Project Server. Project managers can start reporting and analyzing project progress the way they want to. Companies can increase transparency of their project management process and make it measurable. Building new dashboards with EPM Pulse takes just minutes, not days or weeks and there is no need to engage IT. Great advantages for business.” said Anton Kravtsov, co-founder of FluentPro Software Inc.

 EPM Pulse is available for 3 MS EPM Platforms:

  • Project Server 2007 
  • Project Server 2010
  • Project Server 2013 

To get started today, just go to http://www.fluentpro.com/productsepmpulse.html

FluentPro EPM Pulse is available as hosted option from Bemo (http://www.bemopro.com), our premier Project Server hosting provider.
Premier implementation partner for EPM Pulse is adaQuest, Inc. (http://www.adaquest.com)

About FluentPro 

FluentPro (http://www.fluentpro.com) is a certified Silver Microsoft Partner that specializes exclusively in product development, complex custom development and Business Intelligence for Microsoft Project Server 2010/2013. FluentPro has developed over 15 products, including popular FluentBooks – the only configuration management and migration software for Project Server 2010 / 2013, FluentPro Cloud Migrator that enables migration of Project Server 2010 configuration and data to Project Online. With one of the biggest team of software developers among MS EPM Partners, FluentPro delivered a number of custom development projects to customers and other EPM partners; helped partners to develop their products and bring them to the Project Server marketplace. FluentPro has offices in Redmond, WA, USA and Richmond Hill, ON, Canada and software development center in Ukraine. Read more...