Archive for the ‘Infopath’ Category

When trying to set the value a data source element to a Boolean value my first attempt was using ToString() on the Boolean value. To me this seemed like a valid way to set the value as can be seen below.

Setting XPath using ToString
  1. this.MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:isTaskHighlight", this.NamespaceManager).SetValue(this.IsTaskHighlight.ToString());

However, when I tried to use this I received the following error. 

image

On further investigation I found that the ToString() method on a Boolean returns “True” or “False”, not the lower case “true” or “false” InfoPath is looking for.  

To resolve this I created  local method BooleanToString to return the correct value

Infopath boolean to string
  1. private string BooleanToString(bool isTrue)
  2.         {
  3.             return isTrue ? "true" : "false";
  4.         }

And called it to set the value

Setting XPathNavigator to Bool
  1. this.MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:isTaskHighlight", this.NamespaceManager).SetValue(this.BooleanToString(this.IsTaskHighlight));

job done ! Smile

Advertisements

To be able to use and InfoPath form in SharePoint it first has to be browser compatible.  To do this select Tools –> Form options and ensure the “Design a form template that can be opened in a browser or InfoPath” checkbox is ticked.

Enable Browser Compatablity

Now, select file –> publish and from the publishing wizard, select “To a network location” and click next.

Infopath Publishing Wizard

Select the path, you wish to publish to a select next a couple of times, then publish.

 

Now, you have the form published you need to upload it into Central Admin and deploy it to the site collection.

Open, Central admin and go to Application Management –> Upload Form Template from the InfoPath Forms Services

Infopath Forms Services

Browse to the form and click upload. All being well the form should upload. Now, return to the previous screen and select Manage Form Templates, find the form you have just uploaded and from the context menu select activate to site collections.

Activate to Site Collection

Now, to get the form displaying we need to create a new page and add the Page Viewer Web Part.

Once added, modify the shared web part and add form path into the link property.

Page Viewer Webpart Properties

The path should be similar to /_layouts/formserver.aspx?XsnLocation=/FormServerTemplates/<NameOfForm>.xsn&OpenIn=Browser

Click okay and the form should display in the page.

Okay, what I needed to do was to retrieve PropertyData from from Active Directory to populate values in an InfoPath form automatically. If you are using Windows Authentication, its quite straight forward, but if your using Claims Based it doesn’t work.

Firstly, I’m going to describe how to get this data using Windows Authentication and then, add the additional steps and changes needed to get it working with Claims-Based Security.

Firstly, the easy stuff, we need to create a reference to the web service UserProfileService.asmx and call the GetUserProfileByName web method as described below.

Data connection Wizard

  • On the next screens ensure that both “Store a copy of the data in the form template”  and “Automatically retrieve data when form is opened” are selected. Now, click finish.

Now the data source has been set up, we need to get the correct user profile data into the form.

Take the User field from a form shown below and from the context menu choose Text box Properties. image

Then choose the Function button adjacent to the default value box.

image

Then on the displayed dialog box, choose “Insert Field or Group”.

Now, select the GetUserProfileByName secondary data source from the dropdown and navigate down to the value element and click okay, as seen below.

image

Now, tick the Edit XPath box and you should see the following.

Edit XPath

This is the prefix of all the PropertyData you want to return. So, to get a particular value you need to append the attribute.

In this case we want PreferredName so add [../../../tns:Name = "PreferredName"]

Although, not all the available values, some of the other values which can be retrieved are:

  • AccountName
  • FirstName
  • LastName
  • PreferredName
  • WorkPhone
  • Office
  • Department
  • Title
  • Manager
  • AboutMe
  • PersonalSpace
  • PictureURL
  • UserName
  • QuickLinks
  • WebSite
  • PublicSiteRedirect
  • WorkEmail
  • CellPhone
  • Fax
  • HomePhone

Now, click okay twice and Preview the form. If you’ve done everything correctly, you should see your Name in the textbox.

Close the preview and publish the form, and activate it to the site collection.  Details on how to do this can be seen on a previous post, although its based on MOSS, not 2010. The principal is the same though!

If you are only using NTLM you can now deploy the form and everything will work okay.

Changes for  Claims Based

If you try to do the above using claims based authentication you will come across two problems:

  1. You will be denied access to the web service to retrieve the data
  2. When you eventually get the authentication working with the web service the user displayed is the user name defined in the sites application pool.

Below, I’m going to explain how to resolve these issues.

Denied access to the web service

To allow you to see problem two, you first have to get over the hurdle of the authentication against the service.

It would seem that InfoPath is trying to pass the Claims-Based token to call the web service, rather than the actual window identity of the user. Which makes sense, but not if you’re trying to figure out how to fix it.

The cause of this, is the fact that claims based authentication prefixes the user with 0#.w|

So, when you try to authenticate, the service doesn’t understand the credentials passed!

If you look in the log files “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\LOGS” and find an error similar to this.

InfoPath Forms Services           Runtime – Data Connections        Warning

The following query failed: GetUserProfileByName (User: 0#.w|domain\username)

To fix this, firstly, I moved the data connection into Central Admin and added explicit authentication in the data connection file as seen in the diagram below. I know plain text password, not good! I should have used SSO, but i just had to get it working.

image

Next, go to General Application Settings in Central Admin and select configure InfoPath Forms Services.

image

After selection, scroll down to the section Authentication to data sources (user form templates) and select the check box.

image

Now, republish the form and upload into central admin.

User displayed is wrong

Now that the above data source has been added, you should, if you have it published to SharePoint in Page Viewer web part, be able to view the form. However, as you may discover, it’s displaying the credentials of the site collection application pool!

What’s going on here? Eh… not entirely sure, but it seems to be how Claims based authentication works with InfoPath when the form is loaded.

How do I fix it?

Okay, here’s how i went about it.

  • Modify the Secondary Data source GetUserByProfileName and uncheck “Store a copy of the data in the form template”  and “Automatically retrieve data when form is opened”
  • Switch to the “Data” tab on the InfoPath Ribbon and select “Form Load”
  • Now, because we are not retrieving the account on form load we need to do it using a  rule.
  • Add a rule – call it GetUserByProfileName
  • Add an action to Set the AccountName of the data source to concat("your domain\", xdUser:get-UserName()) – this is the edit xpath value image
  • Add another action to query the GetUserByProfileName  data connection
  • Add another action to set the value of the fields of the main data source as before using the property data i.e. [../../../tns:Name = "PreferredName"]

Republish the form and you should now have the correct values

This is a challenge I’ve came across before: using the code behind of an InfoPath form to create a cascading dropdown. However, the last time i did this was around 3 years ago and all i really remembered was the fact that I had done it before!!!  So, I thought I’d blog it in case the situation comes up again, and to help anyone out there who is facing the same problem.

Okay first things, first. For this example I’ve used a SharePoint list

List Name: DropDownTypes

ColumnNames: DropDownType and DropDownSubTypes

Next, in InfoPath, create a data connection to receive data from the list.

image

image

And select the two columns, selecting the two columns mentioned above

image

Next, create an XML file with the following content and import it as a XML data source called DropDownOptions

<?xml version="1.0" encoding="UTF-8" ?>
<options>
  <option><value/></option>
  <option><value/></option>
</options>

Note: There are two option elements. This is to ensure the node is created as a repeating node

When importing the file, ensure that you use it as a form resource file

image

Now, create the nodes on the main data source to bind the values to and drag them on to the form canvas. This will create the two nodes as TextBoxes.

Change these to Drop-Down List Box by right clicking on the controls and choosing Change to from the context menu.

Okay, so far, so good. Now we need to retrieve the data. The type dropdown list is easy enough.

Just choose the DropDownList data source for the data source and DropDownType element as the entries.

image

 

Note: Make sure you select the “Show only entries with unique display names”

Preview the file you should now get the unique values populated in the DropDownType control.

To populate the DropDownSubTypes you need to add an event handler to the DropDownType control. To do this choose Programming –> Changed Event from the context menu of the control.

You should now be in Visual Studio for application with a newly create event handler DropDownType_Changed

 

Note: The reason this has to be done programmatically because you can’t use filters in browser enabled forms

We need  to populate the DropDownOptions data source with the values and bind it to the control.

Below is the Event handler to populate the control

Code Snippet
  1. public void DropDownType_Changed(object sender, XmlEventArgs e)
  2.         {
  3.             string dropDownType = MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:DropDownType", NamespaceManager).Value;
  4.  
  5.             // clear the value of the subtype dropdown in case it has already been selected
  6.             MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:DropDownSubType", NamespaceManager).SetValue(string.Empty);
  7.             XPathNodeIterator subTypesIterator = DataSources["DropDownTypes"].CreateNavigator().Select("/dfs:myFields/dfs:dataFields/dfs:DropDownTypes[@DropDownType='" + dropDownType + "']/@DropDownSubType", NamespaceManager);
  8.             XPathNavigator optionsNode = DataSources["DropDownOptions"].CreateNavigator().SelectSingleNode("/options/option", NamespaceManager);
  9.             XPathNodeIterator optionsIterator = DataSources["DropDownOptions"].CreateNavigator().Select("options/option", NamespaceManager);
  10.             
  11.             // Clear the existing values
  12.             if (optionsIterator.Count > 1)
  13.             {
  14.                 for (int i = optionsIterator.Count; i > 1; i–)
  15.                 {
  16.                     DataSources["DropDownOptions"].CreateNavigator().SelectSingleNode("/options/option[" + i + "]", NamespaceManager).DeleteSelf();
  17.                 }
  18.             }
  19.  
  20.             // Populate the new values
  21.             while (subTypesIterator.MoveNext())
  22.             {
  23.                 XPathNavigator newNode = null;
  24.                 newNode = optionsNode.Clone();
  25.                 optionsNode.InsertAfter(newNode);
  26.                 newNode.SelectSingleNode("value", NamespaceManager).SetValue(subTypesIterator.Current.Value);
  27.             }
  28.  
  29.             int index = DataSources["DropDownOptions"].CreateNavigator().Select("/options/option", NamespaceManager).Count;
  30.             DataSources["DropDownOptions"].CreateNavigator().SelectSingleNode("options/option[" + index + "]", NamespaceManager).DeleteSelf();
  31.         }

Now all we need to do is to bind the SubType drop down list to the DropDownOptions data source

image

Hope this helps someone because it took me a while to suss it out. Enjoy!!