Calling external web services and displaying data
Users can create external web service calls and display these data in a datagrid in the form.
Users can create external web service calls and display these data in a datagrid in the form.
NOTE: Other controls can also be connected with a web service call. In that case only the first attribute for the first record will be used and if the value is valid for that control it will be displayed properly.
To define a new web service call all of the followng properties must be defined:
- A custom Name for referencing the web service call
- The external Url of the web service
- The specific Method to call from the above web service
- The Xml Namespace used by the Web Service. This is required for a well formed request to the service.
- The Handle Namespace option to allow for simpler xpath queries (see below)
- The Parameters with their respective values. Each parameter is defined as pair of strings (ParameterName];[ParameterValue) and each pair is seperated by a pipeline (|) from the next one. For example, if two parameters exist, FirstName and LastName and their respective values are John Smith then one should input the following: FirstName;John|LastName;Smith. One can also enter the same values or edit them, using the provided pop-up form.
NOTE: As with everything that has to do with XML, the above values are case sensitive.
When all the above fields are filled properly pressing the Test button shows the result that the web service provides, to confirm their validity. If any error occurs while calling the web service the resulting error will be displayed instead.
The second part of a web service call, consists of defing an XPath Query to be used for extracting the needed information. For each element returned a row will be displayed in the DataGrid with all of its attributes (Auto Populate)
If Handle Namespaces is selected simple xpath queries can be used, e.g.: //z:row[@ows__Level=2].
If Handle Namespaces is not selected the xpath cannot contain prefixed elements and one should reside to the use of local-name(), e.g. //*[local-name() = ‘row’][@ows__Level=’1′].
Any element of the form can be referenced inside the XPath Query, by enclosing its name inside brackets. For example: //sales[@customerId={c_customer_id}.
The {c_customer_id} will be replaced with its specific value before Xpath Querying the Web Service Call result.
You can also select specific Attributes to display using their names, seperated by a semicolon (;), e.g. ows_UniqueId;ows_FileLeafRef.
A different name can be used for displaying purposes, other than the name of the Attribute, if a similar list of headers is filled in the Headers textbox. The Headers should match the respective Attributes one-to-one. If fewer Headers are provided the remainng attributes will use the default (the Attribute’s name). If more Headers are provided they will be ignored.
Example :

Once the user has defined a Web Service call, he can then connect it to a WebServiceDataGrid control. In the Advanced tab one has to select a Value Type of Web Service Call, and then pick a specific web service call from the list box Web Service Post Url. The control will display the matching data using the xpath query and the (optionally) defined attributes in a read-only grid.
The same advanced parametrization can be used in all controls but the resulting value might not be valid. For example a checkbox will parse 0 as not checked and 1 as checked but any other value will be ignored and the checkbox will remain not checked.
NOTE: If the web service is external and in a different domain with .xap file, you will have to place the clientaccesspolicy.xml file in site root folder as shown in the instructions here.
Manually Calling Web Services
With PowerForms, users could bind specific controls to existing web services and retrieve values automatically during form initialization or whenever another control that affected the web service call occurred.
In version 2.0, a new Button control is introduced, which allows users to manualy call web services, or list queries and apply the retrieved data to controls on the form.
Lets see a complete walkthrough to perform this task :
We assume that we already have a web service available.
For our example the web service only has one method (GetCustomer) that returns a Customer object.
The Soap Request and Response follows :

A test execution returns the following sample data :
One Customer record. 3 properties (ID, Name, Balance).

Notice that the “ID” property is serialized as attribute wheras the rest of the properties follow the default pattern (elements).
We now go to our form which looks like this :

We must add the Button control as well as the placeholders for the web service data.
We open the designer and drag-n-drop the controls from the toolbox.

As soon as we place the controls on the form, we switch to the Web Serices section, in order to define the Web Service Call.
We Create a new Web Service call and define the basic parameters (url, method name, xml namespace). Note that all these properties should be available in the Soap Definition.

Next, press the TEST button to read the xml response of the service. It sould be something like the following :

In order to get the required data from the xml, we should use XPATH.
An easy approach to escape from the namespace hell, is to use local names.
Here is my example to retrieve the GetCustomerResult xml node:
/*[local-name()=’Envelope’]/*[local-name()=’Body’]/*[local-name()=’GetCustomerResponse’]/*[local-name()=’GetCustomerResult’]
After setting the XPath property, we define the attributes we want to retrieve (ID, Name, Balance separated with semicolon).
While in the web service designer screen, we can try the web service and examine the retrieved data in the grid.

If everything seems to be fine, we must return to the Button properties and bind it to the Web Service.

We select the Web Service, and we bind the target controls with the attributes retrieved from the service.
We are ready to go now!
Save the configuration and test the button in the final form:

Getting external values using web posts
You can retrieve information from web posts and use them inside your form.
For example, as soon as you select a customer from a combobox, you want to display the balance of the selected customer in a label next to the customer.
In order to achieve this, you must declare a new unbound control (you do now set the Target Field Name property) and place it inside the form.
Next, go to the Post Info tab and select Value Type=”Url” Post.
Finally inside the Web Post Url property type the url you want to use to retrieve the required information.
For example :
http://servername/balance.aspx?id={c_Customer}
Where balance.aspx is a web page hosted inside a web site. The parameter {c_Customer}, will retrieve the selected value from the c_Customer combobox and use it to create the final uri for the web post.
The web post is asynchronus, so it may take some time from the user selection until the result appears on the form.
Note : In order to get the value, you should first allow the target web site to accept calls from the silverlight form.
To do that, you have to add a file called clientaccesspolicy.xml at the root of the site.
This file should look something like this:
<?xml version=”1.0″ encoding=”utf-8″?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers=”*”>
<domain uri=”*” />
</allow-from>
<grant-to>
<resource include-subpaths=”true” path=”/” />
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
IMPORTANT : The above file provides unlimited access to silverlight components trying to access the site. You have to setup the parameters inside the file according to your needs. See full documentantion for clientaccesspolicy.xml file Here.
Building Custom Controls
Power Forms is designed with extensibility in mind.
There are some cases where you need some special customization for your form. For these cases, developers can build and register their custom controls (using Visual Studio & Silverlight). Since any Silverlight control can be registerer inside Power Forms, the possibilities are endless.
For this example, we will use MS Visual Studio 2010 to implement an alternative control for boolean fields. Instead of the default checkbox control, we will create a control that will display radio buttons for TRUE and FALSE boolean values.
In order to develop your own custom controls, you will have to build a Silverlight Control that implements the IInputControl interface (BPC.PowerForms.Core.IInputControl). Some of the interface methods are only required for lookup controls.
Note: This procedure requires a reference to the BPC.PowerForms.Core.dll library that contains the required interfaces. Please contact us to request for the SDK containing the dll.
The interface definition follows:
public interface IInputControl
{
/// <summary>
/// The event should be raised whenever the
/// value of the control changes
/// </summary>
event EventHandler InputControlValueChanged;
/// <summary>
/// In case of Lookup controls, this event should be raised
/// at the end of the data-loading procedure.
/// The dynamic form will then take control
/// and set the control value
/// </summary>
event EventHandler LookupLoaded;
/// <summary>
/// In case of choice controls containing static values,
/// the datasource (a string array) will be provided
/// </summary>
/// <param name=”datasource”></param>
void SetDataSource(IEnumerable datasource);
/// <summary>
/// This method is called to set the value to the control.
/// The value provided has the format provided by Sharepoint.
/// </summary>
/// <param name=”value”></param>
void SetValue(object value);
/// <summary>
/// This method should be implemented to provide values back to the form
/// </summary>
/// <returns></returns>
string GetValue();
/// <summary>
/// This function should return a human friendly representation of the control value.
/// You should implement this method because there is a system function
/// (FDV = FieldDisplayValue) that may be used during calculation
/// for formulas that retrieves the display value of the control
/// For example, you may have a combo loookup, persisting the ID and displaying
/// the title of countries and another one for cities
/// If want to create a new calculated field containing a friendly representation
/// of the address, you could use the following formula:
/// FV(“c_Address”) & ” ” & FDV(“c_City”) & ” ” & FDV(“c_Country”)
/// </summary>
/// <returns></returns>
string GetDisplayValue();
/// <summary>
/// This method should be implemented to clear the value of the control
/// </summary>
void ClearValue();
/// <summary>
/// This method should only be implemented for lookup controls and
/// should query the undelying datasource to fill its data
/// Filter criteria are provided
/// </summary>
/// <param name=”queryFieldName”></param>
/// <param name=”queryFieldValue”></param>
void LoadLookupData(string queryFieldName, string queryFieldValue);
/// <summary>
/// This method should only be implemented for lookup controls and
/// should query the undelying datasource to fill its data
/// Filter criteria are provided
/// </summary>
/// <param name=”queryFieldName”></param>
/// <param name=”queryFieldValue”></param>
/// <param name=”queryType”></param>
/// <param name=”op”></param>
void LoadLookupData(string queryFieldName, string queryFieldValue, string queryType, SearchOperators op);
/// <summary>
/// Implement to enable or disable the control
/// </summary>
/// <param name=”enable”></param>
void SetEnable(bool enable);
/// <summary>
/// Implement to show or hide the control
/// </summary>
/// <param name=”visible”></param>
void SetVisible(bool visible);
/// <summary>
/// Implement to set or clear the readonly status of the control
/// </summary>
/// <param name=”readOnly”></param>
void SetReadOnly(bool readOnly);
/// <summary>
/// Implement to set the display properties of the control
/// </summary>
/// <param name=”thickness”></param>
void SetBorderThickness(Thickness thickness);
/// <summary>
/// Implement to set the display properties of the control
/// </summary>
/// <param name=”brush”></param>
void SetBorder(Brush brush);
/// <summary>
/// Implement to set the display properties of the control
/// </summary>
/// <param name=”brush”></param>
void SetForeground(Brush brush);
/// <summary>
/// Implement to set the display properties of the control
/// </summary>
/// <param name=”brush”></param>
void SetBackground(Brush brush);
/// <summary>
/// Implement to set the display properties of the control
/// </summary>
/// <param name=”weight”></param>
void SetFontWeight(FontWeight weight);
/// <summary>
/// This method is called during form initiation.
/// </summary>
/// <param name=”Url”>The Url of the customized list.</param>
/// <param name=”control”>The control properties as defined in the form designer</param>
/// <param name=”template”>The complete form template containing definitions
/// for all the available controls of the form</param>
void Init(string Url, IFormControl control, IFormTemplate template);
/// <summary>
/// The constraint value for cascading lookups is provided in this field.
/// For example in controls like lookup controls that perform the
/// loading at a later stage (like popup lookup pickers)
/// the value of a constraint field is stored here.
/// </summary>
string ConstraintFieldValue { get; set; }
/// <summary>
/// Gets whether the control’s value type is complex and cannot be represented by plain text.
/// XML is used for this kind of detail information, when you need to store more than one
/// records or an entire structure.
/// Usually the GetDisplayValue() method has to return HTML when IsValueXML=true.
/// </summary>
bool IsValueXML { get; }
/// <summary>
/// Indicates whether the control stores a value or is used to perform actions
/// in the form (i.e. a button control)
/// </summary>
bool IsActionControl { get; }
}
Using Visual Studio 2010, create a new Silverlight Class Library Project called MyControlPack.
Choose Silverlight 4 for the target version.
Add a Reference to the BPC.PowerForms.Core.dll library that contains the required interfaces. Please contact us to request for the SDK containing the dll.
Create a new UserControl (Project > Add New Item > Silverlight User Control) and name it MyRadioBooleanControl.xaml
Next, design the user interface of the control.
We want to keep the control simple so a simple grid with one row and two columns will do.
<Grid x:Name=”LayoutRoot” Background=”Transparent”>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<RadioButton x:Name=”rd_True” GroupName=”main” Grid.Column=”0″ HorizontalAlignment=”Center”IsChecked=”False” Checked=”RadioButton_Checked” Unchecked=”RadioButton_Checked” >True</RadioButton>
<RadioButton x:Name=”rd_False” GroupName=”main” Grid.Column=”1″ HorizontalAlignment=”Center”IsChecked=”False” Checked=”RadioButton_Checked” Unchecked=”RadioButton_Checked” >False</RadioButton>
</Grid>
Now turn to the code behind and implement the IInputControl Interface.
ClearValue method should clear the check state of both controls.
public void ClearValue()
{
this.rd_True.IsChecked = false;
this.rd_False.IsChecked = false;
}
GetValue function should return 1 (one), 0 (zero) or nothing, as these are the values that sharepoint expects for Boolean fields.
public string GetValue()
{
if (this.rd_True.IsChecked.Value) return “1”;
if (this.rd_False.IsChecked.Value) return “0”;
return “”;
}
GetDisplayValue is optional and could return something like YES when true and NO when false.
public string GetDisplayValue()
{
if (this.rd_True.IsChecked.Value) return “Yes”;
if (this.rd_False.IsChecked.Value) return “No”;
return “”;
}
SetValue must be implemented to fill the control.
public void SetValue(object value)
{
string val = “” + value;
this.rd_True.IsChecked = (val == “1”);
this.rd_False.IsChecked = (val == “0”);
}
We should also raise the InputControlValueChanged event whenever the user changes value in the control so we handle the “Checked” and “UnChecked” events of both controls.
private void RadioButton_Checked(object sender, RoutedEventArgs e)
{
this.rd_False.FontWeight = this.rd_False.IsChecked.Value ? FontWeights.Bold : FontWeights.Normal;
this.rd_True.FontWeight = this.rd_True.IsChecked.Value ? FontWeights.Bold : FontWeights.Normal;
if (this.InputControlValueChanged != null)
this.InputControlValueChanged(this, null);
}
The complete code behind follows:
public partial class MyRadioBooleanControl : UserControl, IInputControl
{
public MyRadioBooleanControl ()
{
InitializeComponent();
}
#region IInputControl Members
public event EventHandler InputControlValueChanged;
public event EventHandler LookupLoaded;
public void SetDataSource(System.Collections.IEnumerable datasource)
{
}
public void SetValue(object value)
{
string val = “” + value;
this.rd_True.IsChecked = (val == “1”);
this.rd_False.IsChecked = (val == “0”);
}
public string GetValue()
{
if (this.rd_True.IsChecked.Value) return “1”;
if (this.rd_False.IsChecked.Value) return “0”;
return “”;
}
public string GetDisplayValue()
{
if (this.rd_True.IsChecked.Value) return “Yes”;
if (this.rd_False.IsChecked.Value) return “No”;
return “”;
}
public void ClearValue()
{
this.rd_True.IsChecked = false;
this.rd_False.IsChecked = false;
}
public void LoadLookupData(string queryFieldName, string queryFieldValue)
{
}
public void LoadLookupData(string queryFieldName, string queryFieldValue, string queryType, SearchOperators op)
{
}
public void SetBorderThickness(Thickness thickness)
{
this.rd_True.BorderThickness = thickness;
this.rd_False.BorderThickness = thickness;
}
public void SetBorder(Brush brush)
{
this.rd_False.BorderBrush = brush;
this.rd_True.BorderBrush = brush;
}
public void SetForeground(Brush brush)
{
this.rd_True.Foreground = brush;
this.rd_False.Foreground = brush;
}
public void SetBackground(Brush brush)
{
}
public void SetFontWeight(FontWeight weight)
{
this.rd_False.FontWeight = weight;
this.rd_True.FontWeight = weight;
}
public void Init(string Url, IFormControl control, IFormTemplate template)
{
}
public string ConstraintFieldValue {get; set;}
public void SetEnable(bool enable)
{
this.rd_False.IsEnabled = enable;
this.rd_True.IsEnabled = enable;
}
public void SetVisible(bool visible)
{
this.Visibility = visible ? Visibility.Visible : Visibility.Collapsed;
}
public void SetReadOnly(bool readOnly)
{
this.SetEnable(!readOnly);
}
public bool IsValueXML
{
get { return false; }
}
public bool IsActionControl
{
get { return false; }
}
#endregion
private void RadioButton_Checked(object sender, RoutedEventArgs e)
{
this.rd_False.FontWeight = this.rd_False.IsChecked.Value ? FontWeights.Bold : FontWeights.Normal;
this.rd_True.FontWeight = this.rd_True.IsChecked.Value ? FontWeights.Bold : FontWeights.Normal;
if (this.InputControlValueChanged != null)
this.InputControlValueChanged(this, null);
}
}
Build the project and we are ready to attach the control to our form.
First you should upload the class library at the path that the xap file resides.
If you use a document library for the xap file, then the class library should be renamed, since SharePoint by default, blocks *.dll files.
Rename the binary file to “MyControlPack.dl_” for example and upload.
Using the form designer, go to the Assemblies tab and add a new item called MyControlPack and set the filename to MyControlPack.dl_.
Next go to the Control Types tab and add a new control type.
Name is the required name for your control. Class Name is the full name (Namespace + ClassName) of your control. Assembly Name is the name of the assembly you previously registered.
Save the form and enter design mode again.
The new control type will be available in the “Control Type” drop down for use.
The final result is a new functional and reusable control type for your dynamic forms:
Network Security Access Restrictions in Silverlight
Cross-domain service access in Silverlight
Silverlight uses services as its primary source of retrieving data across domain boundaries. To prevent applications from launching malicious attacks on web sites, Silverlight uses opt-in cross-domain access. A web site needs to be allowed to receive and respond to requests being made from a particular domain. This safe-guarding role is being undertaken by a clientaccesspolicy.xml file.
Suppose we have a Silverlight application hosted on http://sharepointSite.com/ (where the XAP file is deployed). This application has a service backend that retrieves data from http://sharepointService.com/. These are obviously located on two separate domains and we have a cross-domain issue. By default, this scenario will not work. We need to create a clientaccesspolicy.xml file on the http://sharepointService.com/ site that will allow calls from http://sharepointSite.com/. The file must be copied on the root of the site (http://sharepointService.com/clientaccesspolicy.xml). On IIS, we would simply copy the clientaccesspolicy.xml file on the root of our website (default IIS: c:\inetpub\wwwroot folder).
The clientaccesspolicy.xml file is located where the service is hosted. This is a very important point. The clientacesspolicy.xml NEEDS to be deployed on the server hosting the WCF service so that Silverlight can properly consume it.
Example clientaccesspolicy.xml file that grants all domains access:

Example clientaccesspolicy.xml file that grants access ONLY to sharepointSite.com:

Silverlight Policy File Format
• allow-from
Nested within this part of the policy lie all the domains/sites which are allowed access to Silverlight resources. All domains not listed in the policy will be denied access. If allow-from is left empty, then no sites will be allowed access.
• http-request-headers
By Default, no headers are allowed. Wildcard character “*” can be used to declare that all request headers can be sent. Example http headers: MyHeader, X-API-*
<allow-from http-request-headers=”MyHeader, X-API-*”>
• domain uri
E.g.
<domain uri=”*” />
<domain uri=”http://*” />
<domain uri=”http:// sharepointSite.com:8080″/>
<domain uri=”http://sharepointSite.com” />
<domain uri=”http://*.sharepointSite.com” />
Used to list the domains that are allowed to access the Silverlight sources defined in the clientaccesspolicy.xml policy file.
The following types of wildcards are accepted:
1. Wildcard character ‘*’ can be used alone to declare that all connections are allowed from same Silverlight schemed applications hosted on any domain.
2. “http://*” accepts all connections from HTTP applications on any domain.
3. Port numbers can also be used to restrict access, defining that connections from the said port will only be allowed access.
4. ‘*.’ is defined as the sub domain wildcard option followed by the rest of the hostname. This will allow connections from Silverlight applications hosted on any sub domain of “sharepointSite.com “.
• grant-to
Defines the server’s resources affected by the policy.
• path, include-subpaths
It refers to a specific path that can represent a web service or a file.
<resource path=”/test” include-subpaths=”false”/>
“include-subpaths” specifies whether sub-paths of the defined resource path are allowed access. A “true” value will allow access to a designated path and any appended sub-paths. A “false” value will only allow a match to the exact path designated by the path attribute. The default value is false.
For the above resource path, these resources can be accessed from Silverlight HTTP applications hosted on any site:
/test#intro
/test?id=1
For the above resource path, these resources cannot be accessed:
/test/
/test.txt
/test/example
/test/example.txt
/test/example?id=1
/test/example#intro
/web
The Silverlight policy file for connections can also be used for sockets:
<socket-resource port=”4502-4506″ protocol=”tcp” />
Setup an audit mechanism
System.IO.StreamWriter w = new System.IO.StreamWriter(path, true);
w.WriteLine(“###########################”);
foreach (string key in this.Request.Form.Keys)
{
w.WriteLine(key + ” = ” + Request.Form[key]);
}
w.Close();
Something like the following will appear in the log file:
_action = postupdate
_user = administrator
ContentTypeId = 0x01000CE17A83B943CD42A44746C0A4C20AE7
Title = This is the Title
_ModerationComments =
LinkTitleNoMenu = This is the Title
LinkTitle = This is the Title
File_x0020_Type =
ID = 1
ContentType = Item
Modified = 2011-10-14 11:15:49
Created = 2011-10-14 10:55:42
Author = 1;#administrator
Editor = 1;#administrator
_HasCopyDestinations =
_CopySource =
owshiddenversion = 5
WorkflowVersion = 1
_UIVersion = 512
_UIVersionString = 1.0
Attachments = 0
_ModerationStatus = 0
Edit =
SelectTitle = 1
InstanceID =
Order = 100
GUID = {FFCB0333-0760-4E0D-A915-DB5ECFDCCF42}
WorkflowInstanceID =
FileRef = /ET/Lists/Departments/1_.000
FileDirRef = 1;#ET/Lists/Departments
Last_x0020_Modified = 2011-10-14 10:55:42
Created_x0020_Date = 2011-10-14 10:55:42
FSObjType = 0
PermMask = 0x7fffffffffffffff
FileLeafRef = 1_.000
UniqueId = a6b9763b-f0e3-438e-86fe-8f77932dc40f
ProgId =
ScopeId = {E98C719C-C0F4-4151-81BC-BDC753D63E62}
HTML_x0020_File_x0020_Type =
_EditMenuTableStart = 1_.000
_EditMenuTableEnd = 1
LinkFilenameNoMenu = 1_.000
LinkFilename = 1_.000
DocIcon =
ServerUrl = /ET/Lists/Departments/1_.000
EncodedAbsUrl = http://serverName/ET/Lists/Departments/1_.000
BaseName = 1_
MetaInfo =
_Level = 1
_IsCurrentVersion = 1
