Archive for February 21, 2012

InfoPath – Get the current user without writing code

Actually the exact same result can be achieved without writing any code. It’s a very common thing to do and I couldn’t find any guide for that, so here it is:

* If you are already familiar with this, this post might still be useful. I have included the complete set of default properties get returned and their proper naming syntax at the bottom.

* This works at InfoPath as well as InfoPath Forms Services.

With InfoPath opened go to Tools > Data Connections, and click ‘add…’ to add a new data connection to the form. This opens up the Data Connection Wizard.

  1. We want to receive data from the WS about the current user, so choose receive data’ and click next.
  2. Our data source is a WS so choose ‘Web Service’ and next.
  3. Now you will have to point the wizard to the WS. Type an address similar to this: http://ServerName/_vti_bin/UserProfileService.asmx  and click next.
  4. Here you get a list of all methods for that WS, choose GetUserProfileByName and click next.
  5. In this screen you can specify what parameters are sent to the method, we are relying on the method’s ability to return the current user name if no value is passed to it, so we will leave this as is (no value is passed to the method) andclick next.
  6. Click next and make sure ‘Automatically retrieve data when form is opened’ is checked.
  7. Finish the wizard.

The GetProfileByName method returns a PropertyData array. You can think of it as a repeating table of name and value pairs.
So Now that you have a data connection that can get the current users, you can use it values. In this example I will show the user’s first name in a textbox.

  1. Add a textbox to the form.
  2. Go to the first textbox’s properties (double click it).
  3. In the ‘Default Value’ part, click the ‘fx’ button next to the ‘Value’ field. this opens up the formula builder dialog.
    vc
  4. Click ‘Insert field or group’.
  5. In the data sources drop down, choose the GetUserProfileByName data source.
  6. Expand all groups under the ‘dataFields’ group, and choose the ‘value’ field. Don’t click OK yet!
  7. With data ‘value’ field selected, click the ‘Filter Data…’ button and ‘Add…’.
  8. In the first drop down (value) select ‘Select a field or group…’ and choose the ‘Name’ field under the ‘PropertyData’ group.

  9. Leave the middle drop down as is (‘is equal to’) and in the last drop down choose ‘type a text…’.
  10. This is the part where you specify which property to put in the textbox. As we said the method returns multiple properties about the user. For this textbox we want to put the user’s first name in, so type ‘FirstName’ (this is case sensitive!). I have included the property list you can use here (just below), so if you want some other property, just type its name instead.
  11. That’s it, all we have to do is to confirm everything so Click ‘OK’ for every open dialog box until you are back in the design mode.
  12. click ‘Preview’ and see the wonder!
  13. If you want more details repeat steps 1-11 and enter different property names in step 10.

Finally, as I Promised, here is the complete list of default profile properties get returned by the userprofileservice. I think they are pretty self explained:

UserProfile_GUID
AccountName
FirstName
LastName
PreferredName
WorkPhone
Office
Department
Title
Manager
AboutMe
PersonalSpace
PictureURL
UserName
QuickLinks
WebSite
PublicSiteRedirect
SPS-Dotted-line
SPS-Peers
SPS-Responsibility
SPS-Skills
SPS-PastProjects
SPS-Interests
SPS-School
SPS-SipAddress
SPS-Birthday
SPS-MySiteUpgrade
SPS-DontSuggestList
SPS-ProxyAddresses
SPS-HireDate
SPS-LastColleagueAdded
SPS-OWAUrl
SPS-ResourceAccountName
SPS-MasterAccountName
Assistant
WorkEmail
CellPhone
Fax
HomePhone

Accessing K2 API via K2 reference event

There is a way to access the K2 API from the reference event, although I will make the disclaimer that this is not supported in blackpoint. I will go over the steps of calling the GoToActivity method of the API from a reference event within the K2 designer.

Within K2 designer, you will need to drag a reference event onto the workspace. k2referenceevent

 

Configure an event name for the event, and after clicking next, you will come to a screen within the wizard to add a Constructor.

k2referenceevent_addevent

The next wizard you will want to click the “Add Reference” button and browse to “C:\Program Files (x86)\K2 blackpearl\Bin\SourceCode.Workflow.Management.dll” (if using a 64bit server). Select this DLL and add it to the list of available managed process references.

k2referenceevent_addref Click finish and then on the wizard where you select the constructor, expand the nodes as follows: 

SourceCode.Workflow.Management 
– SourceCode.Workflow.Management  
     – WorkflowManagementServer  

select Constructor(String host, UInt32 port).

k2referenceevent_addeventwms

 

For the configuration properties of the constructor, enter the following: 

host: value is the server name of K2 
port: value is the port that the K2 server is running on (typically 5555)

k2referenceevent_addeventwms_b

 

Once this constructor has been added, you will be brought back to the main wizard screen for the reference event and now it will allow you to add a Method event.

k2referenceevent_addmethodevent

After you click the add method option, you will need to expand the WorkflowManagementServer node and scroll down and find the method Open()

 

k2referenceevent_open Select Next and leave the default values for the configure properties and click Finish

 

 

 

Once more on the reference event main screen, click Add Method and expand out WorkflowManagementServer and find the method GoToActivity(Int32 procInstID, String activityName) : Boolean

k2referenceevent_goto

After clicking next, you will need to configure the method. The only values you need to worry about populating are the procInstID and activityName. 

procInstID – identifies the K2 process ID that you want to perform the GoToActivity method request. This values can be accessed many different ways. For my example, I stored the K2 process ID of my workflow in a SharePoint list and I called this workflow on the update of the list item (using the SharePoint event integration process within K2) and stored the ID in a data field. 

activityName – this field refers to the Activity in question that you want to “Go To”. If you reference the correct process ID, you can call an activity in any K2 process as long as you have the activity name correct. 

Click Next after configuring these 2 values, leave the connection properties as default (empty) and click Finish

k2referenceevent_gotoconfigure

 

k2referenceevent_finish

At this point, you are done configuring your Reference event and it should look like the screenshot to the left. Click Finish and you are done with the reference to the K2 API. Build and Deploy your process and test it out.

 

Working with Arrays in K2

I was asked recently how one can work with arrays in K2.  The specific scenario presented to me was where one had a SharePoint delimited values such as “7#;Acme Bank” into the individual elements.

This can be very easily handled with K2 Inline Functions.

FYI, you can use Inline Functions in nearly any wizard; they are accessed via the context browser here:

clip_image001

Ok, so how would we use Inline Functions to emulate the scenario below?  Attached is a simple self-contained example for your reference, but the highlights of it are:

  1. I created 3 process datafields
    • FullString – this simulates your SharePoint xml node, it contains a default value of: 7#;Acme Bank
    • ID
    • Value
  2. Drag out a Data Event onto the Design Canvas
  3. Select ‘Next’ on the welcome screen
  4. Select ‘Transfer Data’ on the 2nd dialog
  5. Click ‘Assign’ button
  6. In the ‘Destination’ field I drag “ID” from the Context Browser process datafields into it
  7. I select the Inline Functions tab in the Context Browser and then expand “Lists”
  8. I then select the “Index Item” method and drag and drop into the “Source” field
    • This will then open up a new dialog to configure the extraction of an array
    • I then set the following values:
      • Index:  1      (note:  in K2 arrays are 1 based not 0 based)
      • Expected when empty:   0
  9. In the ‘Values’ field I drag and drop the Inline Function Text > Split from the context browser
    • This will open up a new dialog to configure a string to be split into an array
    • I set the values of this Split dialog as follows:
      • Text:      [Process Data Field].FullString         (NOTE: you would use your xml field here)
      • Separator:           #;
  10. Click Ok
  11. Now repeat steps 5 – 10 but substitute:
    • In step 6:
      • Use ‘Value” process data field
    • In Step 8:
      • User Index of 2
  12. The final Data Event should look something like:

clip_image003

13. Save, deploy and run.  We should see the string split into individual values:

clip_image005

 

In addition to this scenario there are other usages potential usages for arrays in K2.  Such as:

– if a string held a delimited list of Domain\UserNames, one could use the Split Inline Function on that field within a Destination Rule in order to leverage generate a list of Destination Users.

– If a string held a delimited list of data for which sub workflows needed to be individually invoked in by an IPC event.  The Split Inline Function could be used within the Plan Per Slot – No Destination option of the Advanced Destination Rules.  For more information on Plan Per Slot – No Destination, which is essentially a For-Each loop within K2, please refer to this previous post:

http://www.k2underground.com/blogs/fromthebench/archive/2008/10/22/using-a-repeating-xml-node-to-start-child-ipcs.aspx

Downloading a remote file to a MemoryStream using C# (CSharp)

A MemoryStream is my preferred method of passing around file data throughout my .Net applications. The following code details a simple way to download a file and place it in the memory stream.

Situation:
Download a PDF from a remote location and store data in a MemoryStream. The MemoryStream needs will be accessed multiple times in a single instance from other OO objects.

Underlying Technology:
Microsoft .Net FCL (Framework Class Library)

The Code:
The following code is deigned for use in a class file that is a part of an object oriented architecture.

// Sample Url, Watch for Line Breaks
static string pdfUrl =
@"http://download.microsoft.com/download/c/a/9/
ca927411-504e-498a-ad2e-490ca4d9cd27/Journal_4_web.pdf"
;

// Member variable to store the MemoryStream Data
private MemoryStream pdfMemoryStream;

// Public MemoryStream property containing PDF Data
public MemoryStream PdfMemoryStream
{
get
{
// Check to see if the MemoryStream has already been created,
// if not, then create memory stream
if (this.pdfMemoryStream == null)
{
WebClient client = new WebClient();
try
{
this.pdfMemoryStream =
new MemoryStream(client.DownloadData(pdfUrl));
}
finally
{
client.Dispose();
}
}
return this.pdfMemoryStream;
}
}

Creating K2 Environment Fields with Environment Library API

I know that you can use a deployment package to move environment settings to different servers, but I wanted to see if I can create them programmatically. The process of creating Environment Fields can be a time consuming and tedious task, especially if you have a large number of fields. Typically in a real-world project, a list of Fields are already defined in a functional document somewhere, so to have a utility which can create fields from a list in a text file for example could be a big time saver. At the time of this writing, documentation on how to do this kind of thing was rather scarce, hence this post 😉

The trick is to get a new instance of an Environment Field since is doesn’t have a new() constructor, you have to get a new instance by using the CreateFieldInstance() method of the EnvironmentFieldType class.

Steps:

  1. Create a new EnvironmentSettingsManager Instance and Connect to the K2 Server using the ConnectToServer() method of the EnvironmentSettingsManager instance.
  2. Create a new EnvironmentTemplateCollection Instance and a new EnvironmentInstanceCollection Instance.
  3. Select the Environment Template to use (e.g. Default Template) and select the Environment to use (e.g. Development)
  4. Get a handle on the EnvironmentFieldType you want to use by calling the EnvironmentSettingsManager.EnvironmentFieldTypes.GetItemByFriendlyName(“Miscellaneous Field”)
  5. Get a new EnvironmentField instance by calling CreateFieldInstance() method of the EnvironmentFieldType instance.
  6. Set the properties of the EnvironmentField instance
  7. Add the Field to the EnvironmentFieldCollection of the Environment Instance with the Add(newField) method of the EnvironmentFieldCollection
  8. Call the SaveUpdate() method of the EnvironmentField

Code:

EnvironmentInstance ei = new EnvironmentInstance();
ei = eic.GetItemByName("Development");
esm.ChangeEnvironment(ei.EnvironmentId);
EnvironmentFieldType eft = esm.EnvironmentFieldTypes.GetItemByFriendlyName("Miscellaneous Field");
EnvironmentField ef = (EnvironmentField)eft.CreateFieldInstance();
ef.FieldName = "DeonTestField";
ef.FieldDescription = "Deon Test Field";
ef.DisplayName = "DeonTestField";
ef.Value = "Some Value in Here";
efc = new EnvironmentFieldCollection(ei);
efc = ei.EnvironmentFields;
efc.Add(ef);
ef.SaveUpdate();

Add an event receiver to a specific list programmatically

 

Creating an event receiver allows you to catch events for specific list types. Such as custom lists, document libraries, announcements, … When we want to catch an event for a specific list, the standard procedure for creating an event receiver changes a bit.

There’s an article on MSDN which describes a method by editing the elements.xml file of an event receiver project. However, the same result can be achieved with code.

Basically, an event receiver template will create a feature file which holds a reference to the elements.xml file from the event receiver project. Inside this elements.xml file, the properties of the event receiver are defined, such as the type of list it will be bound to. We want to bypass the elements.xml file and manually attach the event receiver to a specific list’s event receivers. The binding itself will be written in a feature event receiver.

Start out with creating a new SharePoint 2010 project and select the Event Receiver template. Fill in any desired properties and click on OK:

new event receiver project

Next, fill in the site where the list is at you want to attach the event receiver. Also choose “farm solution” as the desired trust level.

link farm solution

Click next, choose the event receiver settings. I’ve chosen for “List Item Events” where “An item was added” should be handled. The event source isn’t important, since we’ll override the binding:

event receiver settings

When finish is clicked, Visual Studio will create the files based on the template and the chosen settings. A feature will be created with a reference to the EventReceiver1 project. Inside this project an elements.xml file and a code file will be created. The elements.xml file holds the settings of the event receiver. The code file holds the code that will be executed:

event receiver solution explorer

Whenever you want to add more events that have to be captured, click on the EventReceiver1 project and look at the properties window. Here you can enable or disable events that have to be captured. Note that when you disable an already enabled event, the code inside the code file will not be removed. This is a safety built-in for when you accidentally disable an event:

event receiver properties

The next step is removing the connection between the feature and the event receiver project. By doing this we avoid that the elements.xml file is used to bind the event receiver. Double click on the feature file, select the EventReceiver1 project and click on the “<” arrow to remove the project from the feature:

remove event receiver from feature

Save the modification, and right-click the feature file to add a feature event receiver:

add event receiver

If it’s not already open, double-click the feature event receiver code file to open it up. Next, uncomment both FeatureActivated and FeatureDeactivating code blocks.

First, declare two constants in your feature class to keep constancy:

const string _listName = "test";
const SPEventReceiverType _eventType = SPEventReceiverType.ItemAdded;

Next, write the following code in the FeatureActivated block:

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPWeb oWeb = (SPWeb)properties.Feature.Parent;
oWeb.Lists[_listName].EventReceivers.Add(_eventType, Assembly.GetExecutingAssembly().FullName, "EventReceiverProject1.EventReceiver1.EventReceiver1");
}

You’ll notice that the Assembly namespace isn’t recognized so add the following line in your using statements:

using System.Reflection;

The last parameter of the Add() function can be found in the elements.xml file of the EventReceiver1 project. When you open this file you will see the 2 tags that are also referenced here in our code:

$SharePoint.Project.AssemblyFullName$
EventReceiverProject1.EventReceiver1.EventReceiver1

$SharePoint.Project.AssemblyFullName$ is replaced by Assembly.GetExecutingAssembly().FullName in the code.

The following code will remove the event receiver that was added:

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
SPWeb oWeb = (SPWeb)properties.Feature.Parent;

SPList oList = oWeb.Lists[_listName];
for (int i = oList.EventReceivers.Count - 1; i >=0 ; i--)
{
if (oList.EventReceivers[i].Type.Equals(_eventType))
{
try
{
oList.EventReceivers[i].Delete();
}
catch (Exception e)
{
// Write to logs
}
}
}
}