Tuesday, December 18, 2012

Prevent a postback from triggering on a button control when the Enter key is pressed

If you would like to prevent a postback from occurring on an ASP button control whenever the user presses the "Enter" key, one possible option for overriding this functionality is to add "UseSubmitButton = false" as an attribute/property of the appropriate button controls as follows:

<asp:Button id="btnSubmit" runat="server" UseSubmitBehavior="false" ... />

or

Button btnSubmit = new Button();
btnSubmit.UseSubmitBehavior = false;

In case you're curious, the reason we were asked to do this was due to a problem that our users were encountering with a postback being triggered on the "wrong" command button in our gridview control whenever a user would hit the "Enter" key.  Essentially, our gridview's rows contained several command button controls that, when clicked, would perform a variety of activities on the given row depending on which button was clicked.  Naturally, the first button on the selected row, the button with the focus, would be triggered whenever the user hit the "Enter" key; therefore, we all came to conclusion that the best route was to simply disable the "Enter" key postback functionality across all of the button controls contained in the gridview.

Monday, December 17, 2012

SharePoint List Filter web parts not displaying on a SharePoint 2010 Page in Edit mode

Our Business Analyst and I recently ran into an interesting problem in which we were attempting to install a couple of SharePoint List Filter and Apply Filters Button web parts on a page that would help users filter items in a connected list.


After adding the required web parts, our BA noticed that these controls were not appearing on the page as he would have expected despite the fact that the page was undoubtedly in Edit mode.  As a result, he wasn't able to configure the newly added filter web parts as well as set their connections to the associated list web part.


Anyway, I just happened to place the list view web part that these parts were supposed to connect to in Edit Web Part mode and, voilĂ , all of the filtered web parts suddenly appeared on the page.



At that point, our BA was able to proceed with his configuration and connection work without issue.


Thought it would be nice to share just in case anyone out there happens to encounter the same situation.

Tuesday, December 11, 2012

Obtaining custom configuration settings from a web.config for a Visual Web Part

If you're looking for a possible route for obtaining special configuration settings/information for a Visual Web Part that will be consistent across all sites contained under a given SharePoint Web Application, one possible route is to reference those configuration settings from the <appSettings> node of the web application's web.config file.  NOTE:  Only pursue this route if you know beyond a shadow of a doubt that the config settings will be consistent across all sites contained within the given web application.  If there is even a remote chance that you'll need to adjust those settings for each given site, you will wish to pursue another route for configuring your web part such as adding a custom property.  With that said, I'll now proceed with the steps you can use to make this possible:

Add the Custom Configuration Settings to the Web.config

Before you deploy you're web part, you will wish to open the web.config files for each of the SharePoint web applications under which your SharePoint web part will be deployed and add the new configuration setting to the <appSettings> node.  On your SharePoint Web Front End (WFE) server(s), the web applications will be located under the C:\inetpub\wwwroot\wss\VirtualDirectories directory and the web.config file will be located immediately under each given web application.  In this particular instance, I'm going to reference a custom setting called "dbConnectionString" which is presented as follows:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<configuration>
  <configSections>
  ...
  <appSettings>
    <add key="dbConnectionString" value="Data Source=dbServer;Initial Catalog=dbName;Integrated Security=True" />
  </appSettings>
</configuration>

After making the change, be sure to save the updated web.config file and, now, we move on to actually putting this info to good use...

Referencing the Custom Configuration Settings

To reference the custom configuration settings in your Visual Web Part, you will need to carry out the following steps:
  1. Open your Visual Web Part in Visual Studio
  2. In Solution Explorer, expand the Project tree, right-click on References and select Add Reference...
  3. Click on the .NET tab
  4. Locate and click on the System.Configuration component
  5. Click OK
  6. Open your Visual Web Part's .ascx.cs file
  7. Add the following code that will reference the custom configuration setting:
using System.Configuration; using System.Web.Configuration; ...
protected void Page_Load(object sender, EventArgs e) {     if (!IsPostBack)     {         string dbConnectionString = string.Empty;         string errorMessage = string.Empty;         try         {             using (SPSite site = SPContext.Current.Site)             {                 Configuration config = WebConfigurationManager.OpenWebConfiguration("/", site.WebApplication.Name);                 if (config.AppSettings.Settings["dbConnectionString"] != null)                 {                     dbConnectionString = config.AppSettings.Settings["dbConnectionString"].Value;                 }                 else                 {                     throw new Exception(string.Format("The 'dbConnectionString' <appSettings> node could not be located in the web application's, {0}, web.config file.", site.WebApplication.Name));                 }             }             ... Do something with the configuration info         }         catch (Exception ex)         {             ...Handle the exception properly         }     } }
At this point, you can now deploy your web part to sites contained under the web applications that you added the custom setting to (via updating the web.config file, of course) and they will reference the value that you've specified.

Tuesday, November 27, 2012

Programmatically obtain an SPUser object from a SharePoint "Person or Group" field

Within a document library that's contained in our custom Team Site template, we have defined a custom content type (i.e. called Enterprise Document) in which we've specified a "Person or Group" field called "Owner" to store the person who has overall responsibility of the document and may be different from the person who created or last modified the document. The value of this field is set by the user who uploads the document to the library. Naturally, I would like to put this field to use and obtain information about the user that is defined in this field in one of our custom workflows.  In this sample case, I'm going to obtain the owner's email address:

SPList docLibrary = web.Lists["Enterprise Documents"];
SPQuery query = new SPQuery();
query.Query = "<where><eq><fieldref name="ContentType"><value type="Text">Enterpise Document</value></fieldref></eq></where>";
SPListItemCollection documents = docLibrary.GetItems(query);
foreach (SPListItem doc in documents)
{
    if (doc.Fields["Owner"] != null)
    {
        SPFieldUser ownerField = doc.Fields.GetField("Owner") as SPFieldUser;
        SPFieldUserValue ownerValue = ownerField.GetFieldValue(doc[ownerField.Id].ToString()) as SPFieldUserValue;
        SPUser owner = ownerValue.User;
        string ownersEmail = owner.Email;
        ...

Because we have multiple content types in this library, I added code to make certain that the content type of the document under review is based on our custom "Enterprise Document" content type since only that content type contains the "Owner" field mentioned above.  Anyway, I thought this might be useful to share since it took me several iterations before I figured it out.

Monday, November 26, 2012

Adding configuration settings to a custom SharePoint timer job

If you wish to add custom configuration settings to a custom SharePoint, web application scoped timer job, one possible option is to add those configuration settings into the <appSettings> node of the web.config file of the applicable SharePoint web application(s) and then reference those settings from your custom SharePoint timer job's code.

Your first step is to add your configuration settings into the <appSettings> node of your SharePoint web application.  The custom configuration settings can be added to your web.config file via the following steps:
  1. Log on to your SharePoint WFE server(s)
  2. Open Windows Explorer
  3. Navigate to the C:\inetpub\wwwroot\wss\VirtualDirectories folder
  4. Locate the applicable SharePoint web application listed here and open on that folder
  5. Right-click on the web.config file and select Open with -> Notepad
  6. Scroll down until you find the <appSettings> node
  7. Add a new element within the <appSettings> node to define the key and value of your configuration setting (i.e. "<add key="hoursToExpiration" value="10200" />")
  8. Click File -> Save
  9. Repeat steps 1 - 8 for all web applications that your timer job is activated on
Your next step is to add code to your timer job's class file, that will reference your custom <applicationSettings> elements.  The following code sample provides one possible option for obtaining these settings using my sample "hoursToExpiration" setting:

...
using System.Configuration;
using System.Web.Configuration;
...
public override void Execute(Guid contentDbId)
{
    int hoursToExpiration = 0;
    Configuration config = WebConfigurationManager.OpenWebConfiguration("/", this.WebApplication.Name);
    if (config.AppSettings.Settings["hoursToExpiration"] != null)
    {
        if (!Int32.TryParse(config.AppSettings.Settings["hoursToExpiration"].Value, out hoursToExpiration))
        {
            // Write code to handle that the custom appSetting couldn't be converted to the appropriate data type
        }
    }
    else
    {
        // Write code to handle that the custom appSetting couldn't be found
        ...

Once you've deployed the code update, be certain to cycle the SharePoint timer service to make certain that the change has been picked up (see my previous blog entry for instruction on how to do that).  At that point, your timer job will obtain the custom setting information upon execution of the timer job on that web application.

Thursday, November 22, 2012

Custom SharePoint timer job code doesn't seem to be updating

If you're running into a situation in which your making code updates to a custom SharePoint timer job and the code doesn't seem to be updating, you may want to try restarting the OWS Timer service to see if that helps resolve your issue.  To restart the OWS Timer service on SharePoint 2010, you can perform the following steps:
  1. Open the SharePoint 2010 Management Shell as an administrator 
  2. Enter “net stop SPTimerV4” and press enter. (The service will be stopped)
  3. Enter “net start SPTimerV4” and press enter. (The service will be started again)
In my particular example, I had just deployed a code update to one of the custom timer jobs on my SharePoint farm and, upon attaching the debugger to the OWSTimer, noticed that the debugger was simply skipping over the new lines of code that I had just added.  Anyway, refreshing the OWS Timer service made certain that the latest code I had just deployed was refreshed.  As a result, the debugger immediately started picking up the new lines associated with the code that I had previously deployed.

Wednesday, November 21, 2012

Adding a description to a custom SharePoint timer job

If you've ever dug through a bunch of SharePoint timer jobs installed on a SharePoint farm wondering what the purpose of a given job is as well as why the Description field always seems to be blank for the custom timer jobs, I feel your pain and would like to offer you a potential solution to this problem.


The most likely reason that the Description field is blank for custom timer jobs is because the property associated with it is read-only. To make a long story short, the property only has a "get", but no "set" operation; therefore, the developer of the custom timer job can't set the text of that property directly. To overcome this issue, you or your developer will need to do three things:
  1. Create a custom property, CustomDescription, in the custom timer job's class which will reference a private field, m_description
  2. Override the Description property and have it obtain the value of your custom description's private field, m_description
  3. Set the value of the CustomDescription property in each of the timer job's constructors
Here is some sample code that highlights all of the steps within my custom timer job called EmailNotificationTimerJob as follows:

class EmailNotificationTimerJob : SPJobDefinition
{
    private string m_description;
    public override string Description
    {
        get
        {
            return m_description;
        }
    }

    public string CustomDescription
    {
        get
        {
            return m_description;
        }
        set
        {
            m_description = value;
        }
    }

    public EmailNotificationTimerJob() : base()
    {
        this.Title = "CHCO Doc Retention - Email Notifications";
        this.CustomDescription = "This timer job will be used to send email notifications to users who are responsible for documents that are about to expire";
    }

    public EmailNotificationTimerJob(string jobName, SPService service, SPServer server, SPJobLockType targetType)
        : base(jobName, service, server, targetType)
    {
        this.Title = "CHCO Doc Retention - Email Notifications";
        this.CustomDescription = "This timer job will be used to send email notifications to users who are responsible for documents that are about to expire";
    }

    public EmailNotificationTimerJob(string jobName, SPWebApplication webApplication)
        : base(jobName, webApplication, null, SPJobLockType.ContentDatabase)
    {
        this.Title = "CHCO Doc Retention - Email Notifications";
        this.CustomDescription = "This timer job will be used to send email notifications to users who are responsible for documents that are about to expire";
    }

    ...

Once you have deployed the timer job code and performed an IISReset on the farm, your SharePoint Admins will now be provided with a description of the custom timer job on the Edit Timer Job page as follows: