Pages

Thursday 30 January 2014

Tool Part for Visual Web Part – SharePoint 2010

Tool Part for Visual Web Part – SharePoint 2010

Hi SharePoint Friends, 
I would like to discuss some cool stuffs for developing custom “Tool Parts” for SharePoint 2010 Visual web part.
“Tool Part” is nothing but the set of controls that are required for your web part which works based on the tool part properties. It will be available as a new section in the web part properties area.
There are two ways for developing a Visual Web part with custom tool part
1. Designing the entire tool part using the server side code.
2. Designing the tool part using user controls
In this part, I will drive you thru Option 1. R u ready, lets get started.
Step 1:
Create a “Empty Project” using Visual Studio 2010 and name it as “CustomToolpartOtion1” and choose the deployment type as a “Farm Solution”. You should see a similar project structure in VS 2010.
ProjectStructure
Step 2:
Open “VisualWebpartwithTP1.cs” file and write the below mentioned code.
propertydeclaration
The above mentioned code is to declare a property which has to be rendered in the web part properties window.
  • Category – To display under which category or section the property should be displayed. If there are multiple  properties then the category must be same and obviously it depends on your requirement.
  • Personalizable – To make the information available common across all the users accessing the site.
  • WebDisplayName – its nothing but the caption for the property defined.
  • WebDescription – It’s a detailed description about the property.
Step 3:
Open “VisualWebpartwithTP1UserControl.ascx.cs” and declare a property with the class name of the above mentioned “VisualWebpartwithTP1.cs” file. The declaration is to access the properties in the user control server side code.
webpartclasspropertydeclaration
Step 4:
Open “VisualWebpartwithTP1.cs” file and write the below mentioned code in the “CreateChildControls” method.
createchildcontrol_method
Basically we are declaring loading the user control with its type and assigning the declared property to “this” which means using the declared property, we will be able to access the custom tool part properties. Finally we are adding the controls to the page.
Step 5:
Open “VisualWebpartwithTP1UserControl.ascx” and add one label control just like the below mentioned.
LabelDeclaration
Step 6:
Now on the code behind file “VisualWebpartwithTP1UserControl.ascx.cs” assign the web part property to the above added “Label’s text property” on the “Page_Load” function.
Pageload_method
Step 7:
That’s it we are done with the coding. Rebuild the project and deploy it. After deploying add the web part to the page and edit the web part, now you will be able to see the custom properties. Enter any value in the textbox and click ok and then save the page to see the label which displays the value that you have entered in the web part properties and you can try to edit the values too.
Finalresult
Finalresult1

Tuesday 28 January 2014

InfoPath cannot save the following form... This libary was either renamed or deleted, or network problems are preventing the file from being saved.



InfoPath cannot save the following form: Form Name. This Document Library was either renamed or deleted, or network problems are preventing the file from being saved. Contact your network administrator.


    This issue occurs because the Desktop Experience feature is not enabled on the Windows Server 2008 R2 server. Therefore, connections cannot be made from the Windows Server 2008 R2 server to the SharePoint server.

To work around this issue, install the Desktop Experience feature, and restart the Windows Server 2008 R2 server. Then, start the Themes service from the Windows Services console.

As desktop Experience feature is being relocated to be under User interface and infrastructure many people might believe it’s no longer there ! but it’s and below screenshot shows the exact location of desktop experience feature.

5-1-2012 3-18-02 PM     
do the following three steps
  • Add Windows Server Feature: User Interfaces and Infrastructure -> Desktop Experience 
  • Reboot 
  • Start Windows Services -> Themes service

Friday 24 January 2014

InfoPath: Restrict visibility to users in a SharePoint Group

I receive lots of questions about how to limit a Section, a Button, or a View to only users within a specific SharePoint Group.  This is absolutely do-able, but a little tricky.  The trick is to use the UserGroup.asmx web service, and specifically the GetUserCollectionFromGroup method.
If you're familiar at all with the way that the Secondary Data Connections work in InfoPath, you will realize that the web service will pull in one or more resultant fields into an XML format structure that you can then retrieve with XSL - in other words, the data structure returned looks like and acts like the same as your Primary data source.  You can view secondary data sources by going to the Data Source Pane (Fields Pane in 2010), and clicking the dropdown at the top, and choosing your secondary data source.
 Data Source Dropdown 2007
Data Source Dropdown - InfoPath 2007
 Fields Dropdown 2010
Fields Dropdown - InfoPath 2010
The problem with the GetUserCollectionFromGroup web service, or more specifically with InfoPath itself (both 2007 and 2010) is that the data fields don't get pulled in correctly.
Using the references I list at the bottom of this post, I learned how to fix this.  However, I was hard pressed to find anyone who took it the final step and listed how to hook up the Button, Section, or View with Conditional Formatting and/or Rules to make it all happen.
So here I will put it all together for you.  Please let me be clear: the credit for the fixing of the service goes to Ian Chivers; I did not come up with this myself.  However I will list it here to make it easier for you to get this all in one post.
[EDIT - From here, I'm changing around the rest of my post based on trial and error. It requires more work, but is much more reliable.]

UserProfileService.asmx Web Service – GetUserProfileByName method

The first thing you need to do before you fiddle with getting the Group’s users, is to get the actual account name of the user that’s currently logged in. You need to do this because that is what you will use to compare against the list of users that come in from the Group.

Create the Data Connection

Steps for InfoPath 2007
 
Steps for InfoPath 2010
  • Open the Data Source Tool Pane.  If it is not open, go to View --> Task Pane and click "Data Source"
  • On the very bottom of the Data Source task pane, click "Manage Data Connections ..."
  • Click "Add..."
  • Click "Create a new connection to:" and choose "Receive Data"
  • Click "Next"
  • Click "Web service"
  • Click "Next"
  • Type in the url to your UserProfileService.asmx service.  It should be on your site you wish to get the group from.  Example:
    https://YourURLToServer/YourPath
    /YourSite/_vti_bin/UserProfileService.asmx
  • Click "Next"
  • You may have to authenticate at this point
  • Scroll down the list of methods and choose "GetUserProfileByName"
  • Click "Next"
  • You do not need to type in an Actual Value
  • Click "Next"
  • Click "Next"
  • Give the data connection a new name or keep the default, and make sure the checkbox is checked to automatically retrieve the data
  • Click "Finish"
 
  • Click the "Data" Ribbon Tab
  • Click "From Web Service"
  • Click "From SOAP Web Service"
  • Type in the url to your UserProfileService.asmx service.  It should be on your site you wish to get the group from.  Example:
    https://YourURLToServer/YourPath
    /YourSite/_vti_bin/UserProfileService.asmx
  • Click "Next"
  • You may have to authenticate at this point
  • Scroll down the list of methods and choose "GetUserProfileByName"
  • Click "Next"
  • You do not need to type in an Actual Value
  • Click "Next"
  • Click "Next"
  • Give the data connection a new name or keep the default, and make sure the checkbox is checked to automatically retrieve the data
  • Click "Finish"

Set up the first Dummy Field

Create a new field called CurrentUserAccountNameof type String.
  • Show the correct Pane
    • In InfoPath 2007, click to show the Data Source pane on the right-hand side
    • In InfoPath 2010, click to show the Fields pane on the right-hand side
  • Right-Click on the myFields or Top-Level data group (folder).
  • Click Add...
  • Type in CurrentUserAccountName for the field name
  • Keep the defaults of Field for Type and Text (string) for Data Type.  Press OK.

Set up the first Form Load Rule

Now we’re going to set a Form Opening (Form Load) rule so that we can populate the CurrentUserAccountName field. Keep in mind that the Form Opening rules will run after all the data connections retrieve their data (assuming you checked the checkbox to load the data as soon as the form opened).
In InfoPath 2007, you can get to this by selecting Tools --> Form Options --> Open and Save --> Open behavior --> Rules. In InfoPath 2010, you get to this by clicking the Data ribbon tab and then clicking “Form Load.”
  • Create a new Rule (Action rule in 2010)
  • Name the rule “Set Current User”
  • Do NOT set a condition – we want this to run every time the form loads
  • Add an action – “Set a Field’s Value”
  • For the field to set, Choose CurrentUserAccountName
  • For the value, press fx
  • Click “Insert Field or Group...”
  • On the top, press the dropdown box next to the word “Main”. Choose “GetUserProfileByName (Secondary)” .
  • Expand dataFields all the way out.
  • Expand Values all the way out.
  • Single-Click on Value – DO NOT PRESS OK
    GetUserProfileByName
  • Click “Filter Data...”
  • Click “Add...”
  • Click the first dropdown and select “Select a Field or Group”
  • Choose the field “Name” right underneath “PropertyData”
    GetUserProfileByName
  • Press OK
  • Keep “is equal to” in the second dropdown
  • Choose “Type text…” in the third Dropdown
  • Type in:
    AccountName
  • Press OK, Press OK (filter data), Press OK (select a field or group)
  • Your expression should look like the following:
    Insert Formula
  • Modify this function to make it all uppercase
    • Use the translate function to ensure that the AccountName that comes back is in all UpperCase
    • Formula is like this:
      translate(ValueYouWantToTranslate, "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
      Insert Formula
    • Click “Verify Formula” to ensure you typed in the function correctly.
  • Press OK, and press OK

UserGroup.asmx Web Service – GetUserCollectionFromGroup method

Now we need to pull in the list of users that are in the Group in question – the SharePoint group you set up with the people authorized to click that button.
Steps for InfoPath 2007
 
Steps for InfoPath 2010
  • Open the Data Source Tool Pane.  If it is not open, go to View --> Task Pane and click "Data Source"
  • On the very bottom of the Data Source task pane, click "Manage Data Connections ..."
  • Click "Add..."
  • Click "Create a new connection to:" and choose "Receive Data"
  • Click "Next"
  • Click "Web service"
  • Click "Next"
  • Type in the url to your UserGroup.asmx service.  It should be on your site you wish to get the group from.  Example:
    https://YourURLToServer/YourPath
    /YourSite/_vti_bin/UserGroup.asmx
  • Click "Next"
  • You may have to authenticate at this point
  • Scroll down the list of methods and choose "GetUserCollectionFromGroup"
  • Click "Next"
  • Click "Set Sample Value..."
  • Type in the name of the group you want to check against and press "OK"
  • Click "Next"
  • Click "Set Value..."
  • Again type in the name of the group you want to check against and press "OK"
  • Click "Next"
  • Click "Next"
  • Give the data connection a new name or keep the default, and make sure the checkbox is checked to automatically retrieve the data
  • Click "Finish"
 
  • Click the "Data" Ribbon Tab
  • Click "From Web Service"
  • Click "From SOAP Web Service"
  • Type in the url to your UserGroup.asmx service.  It should be on your site you wish to get the group from.  Example:
    https://YourURLToServer/YourPath
    /YourSite/_vti_bin/UserGroup.asmx
  • Click "Next"
  • You may have to authenticate at this point
  • Scroll down the list of methods and choose "GetUserCollectionFromGroup"
  • Click "Next"
  • Click "Set Sample Value..."
  • Type in the name of the group you want to check against and press "OK"
  • Click "Next"
  • Click "Set Value..."
  • Again type in the name of the group you want to check against and press "OK"
  • Click "Next"
  • Click "Next"
  • Give the data connection a new name or keep the default, and make sure the checkbox is checked to automatically retrieve the data
  • Click "Finish"

Take a look at what has been returned for Web Service

Remember in the other web service, that when we went to get the value for the Account Name, it presented us with information we had to drill down to. That was correct. However, for whatever reason, the GetUserCollectionFromGroup web service does not return the correct information. Let’s take a quick look at what it returns:
GetUserCollectionFromGroup
What we have to do here to fix this, is we have to actually manipulate the source files of the InfoPath form.

Create a Folder for your Source Files

On your file system (C Drive or Desktop for example), navigate to where you have saved your InfoPath form template. Create a new empty folder by the name of “TemplateName Source Files”. So if your Template Name is "Training Request Form” then name the folder "Training Request Form Source Files.”

Save as Source Files

In InfoPath 2007, Click the File menu, and click “Save As Source Files”. In InfoPath 2010, click the File ribbon tab, click “Publish” on the left hand side, and then click “Export Source Files”. Save the source files in the folder you just created. Close InfoPath completely.

Fix the GetUserCollectionFromGroup1.xsd file

Open the folder you created with the source files in it. You should see quite a few files in this folder. Using NOTEPAD, open the file named GetUserCollectionFromGroup1.xsd (choose GetUserCollectionFromGroup.xsd, GetUserCollectionFromGroup1.xsd, or GetUserCollectionFromGroup2.xsd based on which is the file with the greatest file size. This is usually the GetUserCollectionFromGroup1.xsd file).
At the top of the file, locate the following line:
<s:import namespace="http://www.w3.org/2001/XMLSchema"></s:import>
Right underneath that line, insert the following code:
<!-- Beginning of insert -->
<s:complexType name="GetUserCollectionFromGroupType">
 <s:sequence>
  <s:element minOccurs="0" maxOccurs="1" name="Users">
   <s:complexType>
    <s:sequence>
     <s:element maxOccurs="unbounded" name="User" >
      <s:complexType>
       <s:attribute name="Notes" type="s:string"></s:attribute>
       <s:attribute name="Name" type="s:string"></s:attribute>
       <s:attribute name="IsSiteAdmin" type="s:string"></s:attribute>
       <s:attribute name="Sid" type="s:string"></s:attribute>
       <s:attribute name="ID" type="s:string"></s:attribute>
       <s:attribute name="LoginName" type="s:string"></s:attribute>
       <s:attribute name="Email" type="s:string"></s:attribute>
       <s:attribute name="IsDomainGroup" type="s:string"></s:attribute>
      </s:complexType>
     </s:element>
    </s:sequence>
    </s:complexType>
  </s:element>
 </s:sequence>
</s:complexType>
<!-- End of Insert -->

[EDIT:  Please make sure there is no space in the above </s:complexType>]

Now find the following code:
<s:element name="GetUserCollectionFromGroup">
  <s:complexType>
    <s:sequence>
      <s:element minOccurs="0" maxOccurs="1" name="groupName" type="s:string"></s:element>
    </s:sequence>
  </s:complexType>
</s:element>

Comment out that code by placing a <!-- before the beginning and an --> after the end.  Result should look like this:
<!--<s:element name="GetUserCollectionFromGroup">
  <s:complexType>
    <s:sequence>
      <s:element minOccurs="0" maxOccurs="1" name="groupName" type="s:string"></s:element>
    </s:sequence>
  </s:complexType>
</s:element>-->

Right underneath that commented out code, insert the following code:
<!-- Beginning of Insert -->
<s:element name="GetUserCollectionFromGroup" type="tns:GetUserCollectionFromGroupType" />
<!-- End of Insert -->

Save and close the file
Go back to the folder where you saved those Source Files to.  Find the file "manifest.xsf" and RIGHT-click the file and choose "Design".  This will open your InfoPath file back up.  Click SAVE AS and save as a new .xsn file.

A few Notes to keep in mind, before we go on

It is important to note the following 2 things:
  • Don't modify your GetUserCollectionFromGroup secondary data source (or if you do, you'll have to do this all over again, from the part where you open up the files).
  • Make sure the group in question allows "Everyone" to see the membership of the group
    • Site Actions --> Site Settings --> People and Groups
    • Click on "Groups" on the left
    • Locate your Group
    • Click on the Edit button next to it
    • For "Who can view the membership of the Group" click the option "Everyone"

Take a new look at the fields for the Web Service

Let's take a quick look at what it returns now:
GetUserCollectionFromGroup Modified
These are the fields that we need.

Set up another dummy Field

Create a new field called IsCurrentUserInGroupof type True/False (boolean).
  • Show the correct Pane
    • In InfoPath 2007, click to show the Data Source pane on the right-hand side
    • In InfoPath 2010, click to show the Fields pane on the right-hand side
  • Right-Click on the myFields or Top-Level data group (folder).
  • Click Add...
  • Type in IsCurrentUserInGroup for the field name
  • Keep the defaults of Field for Type
  • Change the Data Type to True/False (boolean). Keep the default value equal to FALSE.
  • Press OK.

Set up another Form Load Rule

Now we’re going to set a Form Opening (Form Load) rule so that we can populate the IsCurrentUserInGroup field.
In InfoPath 2007, you can get to this by selecting Tools --> Form Options --> Open and Save --> Open behavior --> Rules. In InfoPath 2010, you get to this by clicking the Data ribbon tab and then clicking “Form Load.”
  • Create a new Rule (Action rule in 2010)
  • Name the rule “Set Current User”
  • Do NOT set a condition – we want this to run every time the form loads
  • Add an action – “Set a Field’s Value”
  • For the field to set, Choose IsCurrentUserInGroup
  • For the value, press fx
  • Click “Insert Field or Group...”
  • On the top, press the dropdown box next to the word “Main”. Choose “GetUserCollectionFromGroup (Secondary)” .
  • Expand dataFields all the way out.
  • Single-Click on LoginName. DO NOT PRESS OK.
    Select Field or Group
  • Press “Filter Data...”
  • Click “Add...”
  • In the first dropdown, keep “LoginName”
  • Keep the second dropdown at “is equal to”
  • Click the third dropdown and click “Select a Field or Group”
  • Change the Data Source (top dropdown) back to Main
  • Select the CurrentUserAccountName field
  • Press OK, press OK (filter Data), press OK (select a field or group)
  • Do not close the window “Insert Formula”. It now looks like this:
    Insert Formula
  • Add the boolean and count functions, to turn this into a True/False
    • We’re going to type in the following:
      boolean(count(expression) > 0)
    • So for our example, it should now look like this:
      Insert Formula

Modify the XPath Directly to set to Upper Case

Unfortunately, this does not give us exactly what we want, but it gets us really close. We’ll use what we currently have to change the XPath expression directly into what we need it to be.
  • Click the checkbox “Edit XPath (advanced)”
  • You will now see something like this:
    Insert Formula
  • Notice how I highlighted the period (.) in the picture above, right after @LoginName[
  • We’re going to put the translate function around that period:
    translate(., "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
  • So it should now look like this:
    Insert Formula
  • Click the checkbox again “Edit XPath (advanced)”
  • This will take it out of advanced mode and give you a little more simplified of a view.
  • It should read something like
    boolean(count(@LoginName[translate(., "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ") = CurrentUserAccountName]) > 0)
To recap, what this function is saying is this:
  • Go get the @LoginName from the web service
  • Translate it all to Upper Case
  • Find the number of times that the Upper Case LoginName is equal to the CurrentUserAccountName field
  • If it’s greater than 0 times, return true
  • Change the “true” word to a Boolean value

Set up the condition on the Button

And finally after all of that trouble, we use a reasonably simple Conditional Formatting condition to get the button to Hide when the current user is not part of that group.
  • In InfoPath 2007, right-click the button and choose Conditional Formatting
  • In InfoPath 2010, click Manage Rules in the Home ribbon tab, and add a new “Formatting” rule
  • Set the Condition
    • In the first dropdown, click “Select a Field or Group”
    • Choose “IsCurrentUserInGroup” from the Main data source
    • Keep “is equal to” in the second dropdown
    • Choose “FALSE” in the third dropdown (remember, we’re HIDING the button when the user is NOT in the group)
    • Click OK
  • Set the Formatting
    • Click “Hide this control”

Test the functionality

We need to make sure that we test the functionality. Even if you are the administrator for the site, you won’t see the button if you’re not in that group, so you can effectively test.
  • Publish the form to your SharePoint Site. Ensure that the Forms Library is set to serve up the form as a Web Page.
  • Put yourself INTO the group you set up in the form
  • Test the form by clicking New and switching views – do you see the button? You should.
  • Close the new InfoPath form.
  • Take yourself Out of the group you set up in the form
  • Test the form by clicking New and switching views – do you see the button? You should not.