Showing posts with label InfoPath. Show all posts
Showing posts with label InfoPath. Show all posts

Tuesday, May 31, 2011

Getting the Current User's SharePoint Group Name - SharePoint 2010, InfoPath 2010

Since I did not write a post about SharePoint 2010 for some time, thought to write a pretty interesting post about how to get the logged in user's SharePoint group name using InfoPath functionalities. And for those who don't like to do some coding to get the thing done, they will surely like this approach. Since this is going to to be a longer post, I think it's better to go as a step by step approach, so I will start from Step 01.

Step 01.

Select the Custom List and on Ribbon under List click Customize Form. Then the List will be opening in the Microsoft InfoPath Designer 2010 .

Step 02.

Click on Manage Data Connections in InfoPath Designer. Then add two receiving data connections as following.
  • First we will add a receiving data connection for web service UserProfileService.
Receive Data Connection for UserProfileService
SOAP Web Service
  • In the text box type, http://ServerName/_vti_bin/UserProfileService.asmx.
UserProfileService.asmx?WSDL
  • From the list of web methods, select GetUserProfileByName.
Web Method - GetUserProfileByName
  • Click Next and you'll be asked for set the value for Account Name, leave it blank as doing it would get the current User.
AccountName - Leave it blank
  • Tick Automatically retrieve data when the form is opened.
Tick - Automatically retrieve data when the form is opened
  • Click Finish.
  • Then let's start creating the receiving data connection for web service UserGroup.
Receive Data Connection for UserGroup

SOAP Web Service
  • In the text box type, http://ServerName/_vti_bin/UserGroup.asmx.
UserGroup.asmx?WSDL
  • From the list of web methods, select GetGroupCollectionFromUser.
Web Method - GetGroupCollectionFromUser
  • Click Next. You will be asked to set sample value for UserLoginName. In that screen click Set Sample Value and in the appearing box type domain\Administrator.
userLoginName - Domain\Administrator
  • Click OK and Next. In the appearing screen Untick Automatically retrieve data when the form is opened.
Untick - Automatically retrieve data when the form is opened
  • Click Finish. Now you have successfully created two receiving data connections.

Step 03.

Now we will have to modify the xml schema for GetGroupCollectionFromUser data connection. For that we we will need to extract the InfoPath form. To extract the form, in InfoPath form go to File and Publish and then Export. Select a Folder to export the files and the form will be extracted.

Export

Step 04.

Now when the form has finished exporting, go to the folder you have selected. You will see a list of files that has been created in Export process.  But in our case we only focus on GetGroupCollectionFromUser.xsd (the xml schema for GetGroupCollectionFromUser data connection).

Exported Files
  • First Close the InfoPath Designer. Because you can't edit files when are being used by the InfoPath designer.
  • Open GetGroupCollectionFromUser1.xsd in a text editor (I prefer Notepad++) and edit it as below.
    • Find the following line. Normally it's the 2nd line of the file.
                <s:import namespace="http://www.w3.org/2001/XMLSchema">
    • Add following below above line.
<s:complexType name="GetGroupCollectionFromUserType">
    <s:sequence>
      <s:element minOccurs="0" maxOccurs="1" name="userLoginName" type="s:string"/>
      <s:element minOccurs="0" maxOccurs="1" name="Groups">
        <s:complexType>
          <s:sequence>
            <s:element maxOccurs="unbounded" name="Group" >
              <s:complexType>
                <s:attribute name="ID" type="s:unsignedShort"></s:attribute>
                <s:attribute name="Name" type="s:string"></s:attribute>
                <s:attribute name="Description" type="s:string"></s:attribute>
                <s:attribute name="OwnerID" type="s:unsignedByte"></s:attribute>
                <s:attribute name="OwnerIsUser" type="s:string"></s:attribute>
              </s:complexType>
            </s:element>
          </s:sequence>
        </s:complexType>
      </s:element>
    </s:sequence>
  </s:complexType>
    • Find the following part.
<s:element name="GetGroupCollectionFromUser">
   <s:complexType>
     <s:sequence>
  <s:element minOccurs="0" maxOccurs="1" name="userLoginName" type="s:string">
         </s:element>
</s:sequence>
    </s:complexType>
  </s:element>
    • Replace it with the following code.
<s:element name="GetGroupCollectionFromUser" type="tns:GetGroupCollectionFromUserType">
</s:element>



Step 05.

Now right click on the manifest.xsf and choose Design. Choose GetUserProfileByName data connection and apply rules on the PropertyData field as following.
  • In Fields bar click on Show Advanced view.
Advanced view of Fields
  • Under Fields Select GetUserProfileByName (Secondary).
  • Then Add a rule. 
GetUserProfileByName (Secondary)
  • The rule condition is Name="AccountName", rule type is Action.
Select a field or group
GetUserProfileByName - Name
Type Text
    • Type "AccountName".
Type "AccountName"
  •  The rule actions are:
    • Set field’s value. Under Field, Set Field as follows.
GetGroupCollectionFromUser (Secondary) - Name
    • Then Under Value, Set Value as follows. Click fx and then Insert Field Or Group.
GetUserProfileByName - Value
    • Don't Click OK yet. Click Filter Data. The Click Add.
Select a field or group
GetUserProfileByName - Name
    • Click OK.
Type Text
Type "AccountName"
    • Click OK. Then you will get something like this.
Complete Formula (fx)
    • Click OK.
    • Then add another Action. Action is Query for data from GetGroupCollectionFromUser. 
Query for data - GetGroupCollectionFromUser
    • Click OK.
Step 06.

Now create a formatting rule for a field that you want to disable/hide if current user is not member of a given SharePoint Group. Put a condition as below, where the "LCGD Clerk" is the SharePoint Group Name.

Select a field or group
  • Set the Name in GetGroupCollectionFromUser (Secondary Data source).
GetUserProfileByName - Any occurrence of Name
Type "LCGD Clerk" (SharePoint Group Name)

Step 07.

Now Everything is completed. Final step is Publish the form.

Hope you all got a good idea about how to get the Current User's SharePoint Group Name using InfoPath functionalities. Appreciate your feedback.

Happy Coding.

Regards,
Jaliya

Monday, April 4, 2011

Start a SharePoint Designer Workflow using C# and Workflow Status keeps appearing as 'Starting' - SharePoint 2010

Back to SharePoint programming again. I needed to programmatically start a workflow from a InfoPath form using C#, which was designed using Microsoft SharePoint Designer 2010. So started writing the code using Windows SharePoint Services. Wrote the code and it was triggering the workflow nicely.

Code snippet for starting the workflow, I am writing down.

//oListItem is the item I am running the workflow on and "Create Items" is the name of my workflow
oListItem.Web.AllowUnsafeUpdates = true;
SPWorkflowManager workflowManager = oListItem.Web.Site.WorkflowManager;
SPWorkflowAssociationCollection workflowAssociation = oListItem.ParentList.WorkflowAssociations;
foreach (SPWorkflowAssociation Association in workflowAssociation)
{
    if (Association.Name == "Create Items")
    {
         workflowManager.StartWorkflow(oListItem, Association, Association.AssociationData, true);
         break;
    }
}

Of course it was triggering the workflow nicely, so I waited for the workflow to complete. And that's when I noted that the status of workflow keeps appearing as 'Starting'. First I thought it's because of the performance in my Virtual Machine and after waiting for around 2,3 minutes I knew, there is something else that is going wrong. I clicked on the workflow status and in that page there was a message "Due to heavy load, the latest workflow operation has been queued. It will attempt to resume at a later time". I went back to the list and I kept refreshing the page and after around 5 minutes status changed into 'In Process' and then after 2 or 3 minutes status changed into 'Completed'. Then I was pretty sure that something is not working properly. I did some googling and found out some possible reasons.

Possible reasons for this is,
  • SharePoint 2010 Timer service in Windows Services is not running.
  • You are kicking off the workflow from the user account Administrator.
  • The Start option in settings and the poor design of the workflow in SharePoint Designer.
First I checked SharePoint 2010 Timer service in Windows Services to see whether it is down or not. It was up and running. Then my second option was to check workflow kick off user. I checked it, I am not logged in as Administrator, it is some other user(lets say user1) I have created in Active Directory and granted permission to SharePoint server. Then I checked the workflow Start option and the design of the workflow. I have checked 'Allow this workflow to be manually started' and I checked the design of the workflow, to me it is nicely designed and no bottlenecks.

Apart from my situation, I thought I might give you some idea about how a poor design of workflow can decrease the execution speed of workflows. Lets say that you want to trigger off the workflow each time an Item is updated. So in SharePoint designer you can set under the Start options in the workflow to 'Start workflow automatically when an item is changed'. Now you have designed the workflow to Update List Items and you are giving the parameters to update(set field in Current Item). Here there is a important thing, that you will have to consider when designing the workflow. When the first parameter has updated, it has done another change to the item. And now the workflow fires again. So if you have not been careful enough, this will happen repetitively. Because of that your workflow status will be "Starting" when you check the workflow status in the browser. After a timeout it will stop updating that particular field and go to update the next field and the same process repeats again and again for all parameters. So for these kind of situations, the best practice is to test the field for whether has it already been changed to the new value that you are about to change it to. If yes do not update it again, move to the next field. I think now you might have some idea about increasing the execution speed of a workflow specially when the Start option is set to 'Start workflow automatically when an item is changed'.

And back to my situation, Everything seems perfect and still I am getting this status of workflow as 'Starting' for some long time. I was having enough of this and again I started rechecking everything. SharePoint 2010 Timer service is doing good and again checked the kicking off user of the workflow. No, I am not logged in as Administrator. And here something came to my mind that, I might not be logged in as the Administrator. But in the code I have written, I did not give any Authentication details. So there is a possibility that it uses the Administrator privileges. To check that I clicked on the workflow status 'Starting' for the item. I was astonished by one single thing from the page that appeared. That is under Workflow Information the Initiator of workflow is still 'System Account'. First I felt happy, because I knew that this can be the reason for my problem and then my problem was when I am logged in not as the Administrator and I am kicking off the workflow from a different user account and still how can be the Initiator of workflow is 'System Account'? To me, my only explanation is I am not giving the Authentication details in the code, so thought to add the Authentication part for the code to access the list from the user account User1.

Wrote the code and again added a new item to the list from InfoPath form which I have written all the code in. Kept looking at status of the workflow. Again it was 'Starting' and this time it was around for 30 seconds. Then 'In Progress' and then 'Completed'. For the whole process it took less than 1 minute to complete. I felt so happy and at last it did solve my problem.

I am writing the code down for Authentication part.

SPSite oSPSiteGetToken = new SPSite("http://ravanaserver/");
SPUserToken token = oSPSiteGetToken.RootWeb.EnsureUser("user1").UserToken;

using (SPSite oSPSite = new SPSite("http://ravanaserver/", token))
{
     using (SPWeb oSPWeb = oSPSite.OpenWeb())
         {
               //your code
          }
}

So from what I have learned, there is one thing we all should consider when writing codes.
  • Always use Authentication. For example if you are writing a code for CRUD actions on a list item and if you are not doing it as the Administrator, always use the specific user authentication in the code. Because default authentication is the System Account.
So hope someone gets something from this. Feel feel to correct me and give me your feedback.

Happy Coding.

Regards,
Jaliya

IMPORTANT NOTE :

Thursday, June 16, 2011

I just found out another reason that could keep Workflow Status appearing as 'Starting' for long time.
  • In your computer's Services "SharePoint 2010 Timer" service should be started, Startup Type should be "Automatic" and Log On As should be your SharePoint Administrator.

Happy Coding.

Regards,
Jaliya

Monday, March 21, 2011

Trigger a Scanner using a button in InfoPath form - C#

As I have mentioned in one of my previous post I was spending some quality time with a scanning requirement. Requirement is simple, which is in a SharePoint form there should be separate buttons for scanning multiple documents. There are a lot of plugins  for SharePoint that can trigger a scanner and the most funniest thing is they only provides a limited functionality. And that is, first we should insert a item and then select the item and do the scanning. We can scan multiple documents and the same time it attaches them to the item. (people who might not familiar with SharePoint, might not understand what i told above about the scanning plugins for SharePoint).

But my requirement was not that. The form should have multiple buttons for trigger the scanner. Finally I planned to do some programming with InfoPath and somehow getting my thing done. Finally I have managed to develop multiple buttons to do multiple scanning and attaching to the same document same time, but of course it has some boundaries. I will explain the boundaries later in my post.

I have used Windows Image Acquisition Library 2.0 which can be downloaded for free from Microsoft. It has nice capabilities as well as some limitations. The one of the main limitations is Windows Image Acquisition Library is used for mainly capturing images from imaging devices such as scanners and cameras. So from what I have done, i was only able to get the output of the scanned documents as image type outputs such as JPEG, PNG etc. And the other main limitation is, it does not provide multi page scanning and the reason behind that is again WIA is used for mainly capturing images.

If I talk about the main boundaries of my scanning requirement development, first one is InfoPath form should be uploaded as a form template and should be set to open in the Client Application. The reason for this is if we enabled the InfoPath form to open in the browser, that means the InfoPath form is running on the Server. But the Client machine does not allow the Server to communicate with the Client machine's ports which simply means we cant trigger the scanner. So the InfoPath form should be opened in the Client machine. The other boundary is with the WIA, which is what I have explained above.

I am thinking and doing some things to overcome these boundaries. My solution for communicating with the Client machine from the Server is developing a service or a Client application which is fully separated from the Server and forget about the InfoPath form. Then design a form as a Visual Web Part using Visual Studio and deploy it to the Server. And then using a javascript or a vbscript, trying to communicate with the service or the Client Application, which is so far some what successful.

And for the second boundary, still I have not tried anything. I thing for that either I will have to convert JPEG/PNG into PDF file and add the functionality to add multiple pages to a single document, which seems pretty hard. So I think I might have to change my track into TWAIN scanning.

Will update all of you as soon as I have manage to overcome these boundaries. But I am fully happy with what I have done, because I am not using any of the plugins which you will have to buy to use it.

Happy Coding.

Regards,
Jaliya

Monday, March 7, 2011

Submitting data to a SharePoint 2010 List using InfoPath - CAML

After moving around with some heavy tasks in SharePoint I wanted to Submit data to a SharePoint list through a InfoPath web form which has a Submit button in it. Did some googling and saw a way of submitting data through SharePoint in built web services. Thought of trying it and started to work on it. But after some time trust me, what i felt was this way is not hard, neither so easy.

So I thought of giving you all a step by step guide to learn how to do this without much frustration.
For this task, you will need SharePoint 2010 and Microsoft Office InfoPath Designer 2010 installed in your machine. You will need to have good understanding about CAML(Collaborative Application Markup Language), knowledge of the methods of the SharePoint Lists web service and that would be all and you are ready to go.

First of all CAML is an XML based markup language used with the family of Microsoft SharePoint technologies. Unlike plain XML, CAML contains specific groups of tags to both define and display (render) data. To get more information visit,
http://en.wikipedia.org/wiki/Collaborative_Application_Markup_Language

To get more information about the SharePoint Lists web service, in your IE navigate to "http://servername/_vti_bin/lists.asmx?WSDL" and you will be able to see all the web methods associated with the Lists web service. For our purpose we will be using UpdateListItems web method.

Now let's start. I am assuming you as a beginner, so I am adding a lot of step by step screen shots to ease your work.

1. Create a Custom List in a SharePoint Site. I have named it as Employee. Now create some columns as per your need. Note that there will be a default column called 'Title' and lets not change it and keep it that way to store EmployeeName, I have created EmployeeAddress, EmployeeNo, EmployeeEmail as columns which are Single text. Note that when Column names does not contain any spaces and later I will describe the reason to put them in that way.

2. Open Microsoft Office InfoPath Designer 2010 and select a Blank Form and click Design Form. Then do as follows.

Form Options

Security and Trust

Full Trust

Programming

Design

Design

Design

Renaming the button


Add fields






3. In SharePoint site under Employee list, in ribbon under List Tools select List and then select List Settings. In that page click Advanced Settings and select Allow management of content types to Yes.

List Settings



4.  Again go to List Settings click Metadata navigation settings and copy the list GUID.

Copy list GUID

5. Go back to InfoPath form right click on listID and paste GUID under value field.




6. Open Notepad and type,

<?xml version="1.0" encoding="UTF-8" >?
<Batch>
<Method ID="1" Cmd="New">
     <Field Name='Title' />
     <Field Name="EmployeeAddress" />
     <Field Name="EmployeeNo" />
     <Field Name="EmployeeEmail" />
</Method>
</Batch>

Save the file as an xml file and name it Submit.xml.

7. Now lets create Data Connections. Go to InfoPath form and click Manage Data Connections. First we need to create a Receive Data connection. I am naming it as 'Submit'.


Receive Data

XML Document

Browse for the created Submit.xml file


Naming the connection as 'Submit'

8. Now we need to create a Submit Data Connection. Again in Manage Data Connections click Add.

Add

Submit Data

To a Web Service

http://servername/_vti_bin/lists.asmx?WSDL

UpdateListItems

listname

listID

Include : Text and child elements only

Updates

Secondary


Batch

Include : XML Subtree, including selected element


Web Service Submit


Edit Form Code

9. Click Edit Form Code and btnSubmit_Clicked event will be created. In that block, type the following code.

try
{
    XPathNavigator root = MainDataSource.CreateNavigator();

    // Retrieve the values for the separation list item
    string listID = root.SelectSingleNode("/my:myFields/my:listID", NamespaceManager).Value;
    string eNameDS = root.SelectSingleNode("/my:myFields/my:EmployeeName", NamespaceManager).Value;
    string eAddressDS = root.SelectSingleNode("/my:myFields/my:EmployeeAddress", NamespaceManager).Value;
    string eNoDS = root.SelectSingleNode("/my:myFields/my:EmployeeNo", NamespaceManager).Value;
    string eEmailDS = root.SelectSingleNode("/my:myFields/my:EmployeeEmail", NamespaceManager).Value;

    if (listID == null)
    {
    
    }
    else
    {
        //This is CAML xml file. it contains batch and method nodes
        XPathNavigator batch = DataSources["Submit"].CreateNavigator();

        batch.SelectSingleNode("/Batch/Method/Field[@Name='Title']", NamespaceManager).SetValue(eNameDS);
        batch.SelectSingleNode("/Batch/Method/Field[@Name='EmployeeAddress']", NamespaceManager).SetValue(eAddressDS);
        batch.SelectSingleNode("/Batch/Method/Field[@Name='EmployeeNo']", NamespaceManager).SetValue(eNoDS);
        batch.SelectSingleNode("/Batch/Method/Field[@Name='EmployeeEmail']", NamespaceManager).SetValue(eEmailDS);

        DataConnections["Web Service Submit"].Execute();
}
catch (Exception ex)
{
    ex.Message.ToString();
}

10. And finally thats all. Preview the form and try submitting the data. After that publish the form and upload the form template into SharePoint and start using.

There are few important things to remember carefully. 
  • There is a significant difference between Display name and the Field name. When we are doing the coding we are using the value under the Field name. If you can remember, I have mentioned to keep the default 'Title' column as it is, because if we rename the 'Title' column it will just change the display name. The Field name will be remain as 'Title'.
  • No of updating list fields should be the same as no xml field names.
  • When I am creating columns in SharePoint list, if you can remember I have included no spaces between words. Thats because it will add characters into Field names. So when we are referring to Field names from looking at Display names, the Field name is actually differs from the Display name.
  • List fieldname should be same as xml fieldname.
  • Make sure when creating the Submit Data connection 'Web Service Submit' to select following things,
    • listName - listID : Include : Text and Child elements only
    • updates - Batch : Include : XML subtree, including selected element

Appreciate your feedback. 

Happy Coding.

Regards,
Jaliya