Search This Blog

Saturday, 22 December 2012

Response.Redirect throws an Exception “Thread was being aborted”

Usually when I involve in SharePoint development, I log the exception in a SharePoint list to refer the exception details. Then I identified “Thread was being aborted” exception while using Response.Redirect() in my WebPart. So I refer the below link to handle this, also I write the solution to handle this issue here.


Post from http://briancaos.wordpress.com/2010/11/30/response-redirect-throws-an-thread-was-being-aborted/
 
Response.Redirect causes the browser to redirect to a different URL. It does so by sending a 302 – Object Moved to the browser, requesting it to do another roundtrip to the new page. Here is an example: 

protected void Page_Load(object sender, EventArgs e)
{
try
{
if (somethingIsTrue)
Response.Redirect("URL");
}
catch (Exception ex)
{
// All exceptions are caught and written
// to a log file
}
} 

But here is something I didn’t know. When doing the Response.Redirect, .net will automatically throw an System.Threading.ThreadAbortException when the redirect is called. Apparently this is by design (although I’m nor sure I agree with the design).
 
The code above will write a log line for each time the Response.Redirect is called. This will flood my log file.

There are 4 solutions.
1) Set the EndResponse (the 2nd parameter) to false. The thread is aborted when the response is ended, so if you do not end the response, no abortion is done (this is untested, but according to several blogs valid).

2) Move the Response.Redirect outside the try/catch block.

3) Filter the exceptions. Do nothing if the ThreadAbortException occurs:
protected void Page_Load(object sender, EventArgs e)
{
try
{
if (somethingIsTrue)
Response.Redirect("URL");
}
catch (ThreadAbortException ex1)
{
   // do nothing
}
catch (Exception ex)
{
// All exceptions are caught and written
// to a log file
}
} 

4) Do not use Response.Redirect. Instead, modify the response headers (this is the rather stupid solution, but I have added it to show that you can redirect without using Response.Redirect):
Response.Clear();
Response.Status = "302 Object Moved";
Response.RedirectLocation = "URL";
Response.End();

Thursday, 20 December 2012

SharePoint People Picker Control - II



SharePoint People Picker Control (PeopleEditor Control)
 
 
Introduction

The PeopleEditor control is a great control to easily select one or more users from the users known in the directory service of the server.

  



The control consists of 3 controls:
  • a text box where you can fill out part or complete user name
  • a button to check the filled out name(s)
  • a Browse button to search for a user name
When you click the Browse button a dialog opens where you can search for specific user(s).





















When you entered part of a name and click the Check Names button the entrance is checked agains the users in the directory service. When no exact match is found, the value is marked with a red line. Clicking on it will display a list with all matches from which you can select one.













Syntax
You can use this PeopleEditor control when developing application pages or control templates using the following syntax:
<spuc:PeopleEditor ID="PeopleEditor1" runat="server" width="350px"
                   AllowEmpty="true" MultiSelect="false" SelectionSet="User"  />
But only after you have added a directive at the top of the application page or control template:
<%@ Register TagPrefix="spuc" Namespace="Microsoft.SharePoint.WebControls"
             Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
If you are developing a web part you have to create the PeopleEditor control completely in code:
private PeopleEditor peopleEditor;
private void EnsureChildControls()
{
    peopleEditor = new PeopleEditor();
    peopleEditor.AutoPostBack = true;
    peopleEditor.ID = "PeopleEditor1";
    peopleEditor.AllowEmpty = false;
    peopleEditor.MultiSelect = false;
    Panel1.Controls.Add(peopleEditor);
}
This control is part of the Microsoft.SharePoint.dll and is located in the Microsoft.SharePoint.WebControls namespace.

Properties
There are also a number of properties/attributes you can set to configure the functionality of the PeopleEditor control:
  •  AutoPostBack: if you want the control to react immediately when a user works with it, you have to set this property to true. Otherwise the control will react on page postback.
  • AllowEmpty: Setting this to false obliges the user to fill out a user name. The default value is true. (Pay attention to this property: I was not able to make it work, and I’m not the only one).
  • AllowTypeIn: Setting this property to false prevent users from filling out part of a name or complete name. In this case users can only use the Check Names button and Browse button to populate the control.
  • CommaSeparatedAccounts: you can initialize the PeopleEditor control by entering a string of login names separated by a comma.
  • EntitySeparator: the default is a ‘;’.
  • ErrorMessage: you can change the default message by setting this property to a custom error message.
  • ID: id of the control.
  • MultiSelect: Setting this property to true allows users to select more than one user.
  • NoMatchesText: you can change the default message that is displayed when no matches are found by setting this property to a custom error message.
  • PlaceButtonsUnderEntityEditor: Setting this property to true displays the Check Names button and Browse button under the text box. The default is false.
  • PrincipalSource: if you have more than one source from where users can be selected, you can set this property to the desired source.
  • SelectionSet: this property accepts a comma-delimited string containing the different account types (defined in the AccountType enumeration) like User, DL, SecGroup, SPGroup
      objEditor.SelectionSet = "User,SecGroup,SPGroup";
  • SharePointGroup: you can also limit the users that can be selected in the PeopleEditor control by setting this property to the name of a SharePoint group defined on the current web.
  • ShowButtons: set this property to false if you don’t want to have the Check Names and Browse button displayed.
  • ValidatorEnabled: if set to true, the entries in the text box are validated client-side.
  • ValidateResolvedEntity: the default value is true to validate the resolved entity. You can set this property to false to prevent validation. 
The list above is not complete. You can find the complete list on MSDN

Methods
There are also a number of methods you can use:
  • GetAccountFromSid: Retrieves the login name of an account associated with the security ID (Sid) that is passed into this method.
  • UpdateEntities: you can use this method to f.e. initialize the PeopleEditor control.
      // populate the PeopleEditor with the current user
      System.Collections.ArrayList entityArrayList = new System.Collections.ArrayList();
      PickerEntity entity = new PickerEntity();
      entity.Key = SPContext.Current.Web.CurrentUser.LoginName;
      // this can be omitted if you're sure of what you are doing
      entity = PeopleEditor1.ValidateEntity(entity);
      entityArrayList.Add(entity);
      PeopleEditor1.UpdateEntities(entityArrayList);
  • ValidateEntity: calling this method passing in an object instance of type PickerEntity ensures that the user exists in the directory service.
      entity = PeopleEditor1.ValidateEntity(entity);

Objects
When the CheckNames button is clicked a number of properties are populated by the internals of the control. You can inspect these properties:
  • Accounts: this is an ArrayList of strings and contains the login names of all selected users 
  • Entities: the contents of this property is unpredictable and I advise you not to use it. Use the ResolvedEntities property instead.
  • ResolvedEntities: this is an ArrayList of PickerEntity objects (more details below)
The PickerEntity object contains following properties:
  • Description: contains the login name of the user
  • DisplayText: contains the display name of the user
  • IsResolved: a boolean indicating whether the user was found in the directory service
  • Key: contains the login name of the user
  • EntityData: is an object with user data
The EntityData object consists of the following properties:
  • DisplayName
  • Email
  • Department
  • Title
  • PrincipleType
The PickerDialog is a property of the the PeopleEditor control and represents the dialog that is displayed when the user clicks the Browse button.

Retrieving User Profile
One of my readers recently asked if it was possible to retrieve the user profile based on the selected user in the PeopleEditor control. Working with user profiles is only possible if you have a Shared Services Provider installed and the have the user profiles imported.
User Profile information can programmatically be accessed throught the UserProfileManager class. This class is located in the Microsoft.Office.Server.dll.
With the outcome of the PeopleEditor control you can show user profile details of the selected user. The Key property of the PickerEntity object contains the login name of the user. This value can be used to retrieve the user profile from the User Profile Manager.
        // retrieve profile information
        ServerContext ctx = ServerContext.GetContext("Litware SSP");
        UserProfileManager mgr = new UserProfileManager(ctx);
        try
        {
          PickerEntity selectedEntity = (PickerEntity)PeopleEditor1.ResolvedEntities[0];
          UserProfile profile = mgr.GetUserProfile(selectedEntity.Key);
          AddProfileRow("Title", profile["Title"].Value.ToString());
          AddProfileRow("Department", profile["Department"].Value.ToString());
          AddProfileRow("Email", profile["WorkEmail"].Value.ToString());
          if (profile.PersonalSite != null)
            AddProfileRow("Personal site", profile.PersonalSite.Url);
        }
Remark: The AddProfileRow method is a private method that adds a row and two cells to the UserProfileTable.
If you want to show all properties of the user profile, you can loop through the defined properties and retrieve them from the user profile:
        PickerEntity selectedEntity = (PickerEntity)PeopleEditor1.ResolvedEntities[0];
        UserProfile profile = mgr.GetUserProfile(selectedEntity.Key);
        //Get the properties
        PropertyCollection props = mgr.Properties;
        foreach (Property prop in props)
        {
          if (profile[prop.Name] != null && profile[prop.Name].Value != null)
             AddProfileRow(prop.Name, profile[prop.Name].Value.ToString());
          else
            AddProfileRow(prop.Name, string.Empty);
        }




















But what if you want to use this control from within a web part?
When trying to use this control from within a web part (the classic web part for SharePoint 2007 or the Visual Web Part for SharePoint 2010), all of a sudden the PeopleEditor textbox is not visible anymore:







Unless you place it within a <div> element with a background color different from white:
<div style="background-color: Aqua">
    <spuc:PeopleEditor ID="PeopleEditor1" runat="server" Width="350px" AllowEmpty="true" MultiSelect="false" SelectionSet="User" />
</div>
 resulting in







But propably this is not what you want. If you really really want a similar behavior as in a SharePoint application page with a border around the text box, you have to override some styles:
<style  type="text/css">    
    .ms-inputuserfield{ font-size:8pt; font-family:Verdana,sans-serif; border:1px solid #a5a5a5;}  
    div.ms-inputuserfield a{color:#000000;text-decoration: none;font-weight:normal;font-style:normal;}    
    div.ms-inputuserfield{padding-left:1px;padding-top:2px;}    
</style>  
<spuc:PeopleEditor ID="PeopleEditor1" runat="server" Width="350px" AllowEmpty="true" MultiSelect="false" SelectionSet="User" />
And this results in the desired layout: