Showing posts with label SharePoint 2010. Show all posts
Showing posts with label SharePoint 2010. Show all posts

Thursday, March 20, 2014

Obtain the URL of your root website using Javascript

If you ever need to obtain the URL to your root website via Javascript code (i.e. http://rootWebsite), I've got a couple of good methods for doing so which are presented as follows:

If you're on a SharePoint site want to use CSOM:

var clientContext = new SP.ClientContext();
var rootWebsiteUrl = clientContext.get_site.get_rootWeb();


If you're on a SharePoint site and don't want to use CSOM:

var rootWebsiteUrl = _spPageContextInfo.siteServerRelativeUrl;


If you're not on a SharePoint site or, actually, have no idea what SharePoint is:

var currentLocation = document.location.toString();
var webApplicationNameIndex = currentLocation.indexOf('/', currentLocation.indexOf('://') + 3);
var rootWebsiteUrl = currentLocation.substring(0, webApplicationNameIndex);

Thursday, September 12, 2013

Exception from HRESULT: 0x80131904

Over the years, I've periodically encountered an issue in which SharePoint will give you the following error message whenever you attempt to perform some simple write, update, or delete operations on a site (i.e. like adding a new list item to a SharePoint list):

Exception from HRESULT: 0x80131904

In my experience, this error message is indicating that SharePoint is not able to write information to the content database and the most common cause that I've encountered is that the location where SQL logs are stored has run out of drive space (i.e. this being the SQL server that hosts the SharePoint content database).  Typically, we've either deleted the older SQL transaction logs stored here or simply moved them to another location with more drive space (i.e. archive) in order to free up space on that drive location.  Once that delete/move operation of the log files is complete and more drive space is available, the SharePoint environment will return to normal operation immediately.

Tuesday, July 2, 2013

Obtain all files contained under folders and subfolders within a SharePoint Document Library

If you are looking for a way to programmatically return all documents of a specific content type located within a given SharePoint Document Library regardless of whether they are contained in folders and subfolders within the given library, I've provided the following sample method that will allow you to do just that:

private SPListItemCollection GetDocumentsByContentType(SPList docLibrary, string contentTypeName)
{
    SPQuery query = new SPQuery();
    query.ViewAttributes = "Scope=\"RecursiveAll\"";
    SPListItemCollection documents = null;
    try
    {
        query.Query = string.Format("<where><eq><fieldref name="ContentType"><value type="Text">{0}</value></fieldref></eq></where>", contentTypeName);
        documents = docLibrary.GetItems(query);
    }
    catch (Exception ex)
    {
        throw ex;
    }
    return documents;
}

The key to this code being able to return all documents, including documents contained under folders and subfolders, is that I've set the ViewAttributes property to be Scope="RecursiveAll".  Without this particular setting, the query would have only returned items that were located immediately under the SharePoint Document Library and would have skipped any documents contained under folders and subfolders.

Wednesday, March 27, 2013

Programmatically determine if a web-scoped feature has been activated

This may be of limited use, but if you're ever looking for a way to programmatically determine if a web-scoped feature has been activated on a given SharePoint site, here is a quick method you can use to obtain that information:

private bool IsFeatureActivated(Guid siteId, Guid webId, Guid featureId)
{
    bool isFeatureActivated = false;
    using (SPSite site = new SPSite(siteId))
    {
        using (SPWeb web = site.OpenWeb(webId))
        {
            if (web.Features[featureId] != null)
            {
                isFeatureActivated = true;
            }
        }
    }
    return isFeatureActivated;
}

Monday, March 11, 2013

View the XML data behind a Search Core Results Web Part


If you wish to view the raw XML data that is associated with a Search Core Results or People Search Core Results web part, you can do so via the following steps:

  1. Open IE and navigate to the page that contains the given Core Results web part
  2. Select Site Actions -> Edit Page
  3. Click on your web part's menu and select Edit Web Part
  4. Expand Display Properties and click on the XSL Editor... button
  5. In the Text Editor window, copy the existing XSL to a temporary location since you'll probably need it again.  Here is a possible option for you:
    1. Hit Ctrl+a to highlight all of the content
    2. Hit Ctrl+c to save the content
    3. Open Notepad
    4. Hit Ctrl+v to past the content to Notepad
  6. Return to the Text Editor window, hit Ctrl+a, and hit Delete
  7. Copy and paste the following XSL code into the Text Editor window:
  8. <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:template match="/"> <xmp><xsl:copy-of select="*"/></xmp> </xsl:template> </xsl:stylesheet>
  9. Click Save
  10. Click OK
  11. Return to the parent Search page and enter a valid search parameter
At this point, the page that contains the Search Core Results web part will be displayed with the XML contents available for your review.  Once your review of the data is complete, I recommend that you revisit the XLS Editor... and replace the XSL code with the code that you copied into Notepad earlier.  Unless, of course, your users like to view XML data in his/her search results which is not very likely...

Tuesday, February 26, 2013

Programmatically assign a SharePoint user to a "Person or Group" column in a SharePoint list

Here is some sample code that demonstrates how you can assign a given SharePoint user to a "Person or Group" column or field (in this case, I have a custom "Person or Group" field called "Owner") contained within a SharePoint list:

using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

...

Guid siteId = new Guid("GuidOfSiteCollection");
Guid webId = new Guid("GuidOfSite");
Guid listId = new Guid("GuidOfList");
string itemTitle = "My Item's Title";
string userName = "Domain//UserName";

using (SPSite site = new SPSite(siteId))
{
    using (SPWeb web = site.OpenWeb(webId))
    {
        // Find all list items that match your search criteria
        SPQuery query = new SPQuery();
        query.Query = string.Format("{0}", itemTitle);
        SPListItemCollection items = web.Lists[listId].GetItems(query);
        // Obtain a reference to SPUser object associated with the specified user
        SPUser user = web.AllUsers[userName];
        // Assign the user to the custom "Owner" field of my SharePoint list items
        web.AllowUnsafeUpdates = true;
        foreach (SPListItem item in items)
        {
            if (user != null)
            {
                item["Owner"] = user;
                item.Update();
            } 
        }
        web.AllowUnsafeUpdates = false;
    }
}
As you can tell, this is a super-simplified version of some actual code that I've got working. Naturally, you will want to organize this code to better suit your needs (as well as add some exception handling), but the purpose of this example is to show you the basics of how it's done. Enjoy!

Monday, February 25, 2013

How to obtain a copy of the InfoPath template file associated with a SharePoint Form Library

Here are the steps you can use for obtaining a copy of the InfoPath template file (i.e. template.xsn) after it has been published to a SharePoint form library:

  1. Open IE and navigate to the SharePoint site where your forms library exists
  2. Click on Site Actions -> View All Site Content
  3. Under the Document Libraries section, locate and click on the link for your form library
  4. On the Library Tools tab, click on Library


  5. Locate the Connect & Export section and click on Open with Explorer


  6. When Windows Explorer pops up, click on the Forms directory


  7. Locate the "template.xsn" file


  8. Copy and paste the "template.xsn" file to a location on your local hard drive
You may now edit that local copy of the template.xsn file using InfoPath and publish the form back to the SharePoint form library (i.e. the path information was saved to the form when it was published).

Thursday, January 31, 2013

List of "illegal" characters that cannot be included in a SharePoint file name

I've been working on a utility that our team is going to leverage for rapidly uploading a ton of existing Policy and Procedure documents from file shares into a SharePoint site (by the way, this includes defining the relevant document metadata which is why we aren't simply copying the files over).  During my investigation, I happened to notice that many of the file names in the file share contain characters that SharePoint is not going to like at all (i.e. '&' is the leading offender).  In case you're curious what these "illegal" characters are for file names, here is a complete list:

  • Tilde
  • Number sign
  • Percent
  • Ampersand
  • Asterisk
  • Braces
  • Backslash
  • Colon
  • Angle brackets
  • Question mark
  • Slash
  • Pipe
  • Quotation mark

The source of this information is the following link: http://support.microsoft.com/kb/905231

If you're looking for a solution to this problem, one option is to use the code that I created in one of my previous posts that will allow you to rename the file as you're adding to to your document library:  Remove special characters from a string using Regular Expression


Tuesday, January 22, 2013

Programmatically obtain a list of SharePoint Web Applications located under a SharePoint Farm

If you ever need to programmatically obtain a list of web applications contained under your SharePoint Farm, here is some code that will do just that...

SPSecurity.RunWithElevatedPrivileges(delegate()
{
    SPFarm farm = SPFarm.Local;
    SPWebService service = farm.Services.GetValue("");

    foreach (SPWebApplication webApp in service.WebApplications)
    {
        // The following code will need to be changed depending on your situation
        ComboBoxItem webAppItem = new ComboBoxItem(webApp.DisplayName, webApp.Id);
        cbWebApp.Items.Add(webAppItem);
    }
});

NOTE: In this particular instance, I'm writing my list of web applications to a combo box control of a Windows application. The idea is that this combo box control will be the first of several chained combo boxes that will allow you to dive deeper into the SharePoint objects based on the items selected in the combo box controls (i.e. Web Application -> Site Collection -> Site -> Document Library -> Document).  Perhaps this my inspire some ideas of how or why this code would be useful.

Tuesday, January 15, 2013

A solution for providing a "sum" operation on a calculated field in a SharePoint view

One of our site owners recently ran into a situation in which he was trying to create a SharePoint view that would provide a sum of all values contained within a calculated field, but was not able to do so via the simple configuration process.  By "simple configuration" process, I'm referring to the typical way that you would provide a sum on a standard number or currency field which would be to place your view in edit mode, scroll down to and then expand the Totals group, locate your field, select the "Sum" operation listed in the drop down control, and save the change to your view.  Unfortunately, this isn't possible for calculated fields due to the fact that calculated fields don't show up under the Totals group.  With this in mind, a few possible solutions that would provide the requested functionality are listed as follows:

  • Use a Content Query Web Part to host the XSLT code that would generate the desired view
  • Use SharePoint Designer to modify the XSLT code of the view directly.  In SharePoint 2007, you would do this by inserting a Data View web part and modifying the XLST of that web part. 
  • Change the calculated field to a regular number or currency field, add a workflow to the list that would perform the calculations previously associated with the calculated field, and place a sum operation on the field

After a discussion with the user about the requirements for this effort as well as the various options available, we came to the conclusion that it would be possible to use a simple, one-time solution to meet the needs of his effort.  In light of this, we chose the workflow option and decided to add our workflow to the list using SharePoint Designer.  If you're interested in this solution, here are the steps we took to make this happen:

Replace the calculated field with a standard number or currency field
  1. Using your browser, open the site and navigate to the list to be modified
  2. Under List Tools, click on the List tab
  3. Click on List Settings
  4. Under Columns, locate your calculated field and click on it's link
  5. Record the formula for your calculation
  6. Click Delete to remove the column
  7. Click on Create column
  8. For Column name:, enter the name of the original calculated field that you just deleted
  9. Select either the Number or Currency radio button depending on which you require
  10. Click OK
Create and publish the calculation workflow using SharePoint Designer
  1. Open Microsoft SharePoint Designer 2010
  2. Click Open Site
  3. For Site Name:, enter the URL of the site your list is contained under
  4. Click Open
  5. Under Navigation, click on Lists and Libraries
  6. Click on the list you wish to perform the calculations on
  7. Under Workflows, click on the New... icon
  8. Add an appropriate Title and Description for you workflow
  9. Click OK
  10. Once the Workflow Designer appears, click on the Action button
  11. Under Core Actions, select Do Calculation
  12. Click on the first value link
  13. Click on the function icon
  14. For Data source:, select Current Item
  15. For Field from source:, select your first field that is part of the calculation
  16. Click OK
  17. Click on the plus link and choose the appropriate option for your calculation
  18. Click on the second value link
  19. Click on the function icon
  20. For Data source:, select Current Item
  21. For Field from source:, select your second field that is part of the calculation
  22. Click OK
  23. Click on the Action button
  24. Scroll down to List Actions and click on Set Field in Current Item
  25. Click on the field link and select the field you just created previously that replaced the original, calculated field
  26. Click on the value link
  27. Click on the function icon
  28. For Data source:, select Workflow Variables and Parameters
  29. For Field from source:, select the Variable: calc item
  30. Click OK
  31. If needed, continue adding calculation steps until the workflow is complete
  32. Click the Save button
  33. Under Navigation, click on Workflows
  34. Click on the link associated with your newly created workflow
  35. Under Start Options, remove the check from the Allow this workflow to be manually started option
  36. Place a check in both the Start workflow automatically when an item is created and Start workflow automatically when an item is changed options
  37. Click the Save button
  38. Click the Publish button
Update your view to provide a sum on the new field
  1. Using your browser, open the site and navigate to the list to be modified
  2. Under List Tools, click on the List tab
  3. Click on List Settings
  4. Under Views, locate your view and click on it's link
  5. Scroll down to and then expand the Totals group
  6. Locate your new field and select the "Sum" operation listed in the drop down control
  7. Click Save
With these steps complete, the new "calculated" field will be updated by the workflow every time a list item is created or modified.  NOTE: Users will be able to enter values into the "calculated" field; however, the workflow will ultimately override this value when the items is created or saved.  At this point, you will now have a "sum" operation on your "calculated" field.

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:




Thursday, November 8, 2012

Hide/Display the form ribbon on an InfoPath 2010 form

On one of our SharePoint 2010 Team Sites, we're currently leveraging a custom InfoPath 2010 form to override the look and feel of the form that's used for creating/modifying items in one of our SharePoint lists as well as perform several custom actions during the form's Save operation which is controlled by button clicks.  As a result, we no longer need the ribbon and, in fact, would prefer to remove it since it's causing more problems and confusion.


In order to hide the ribbon, you may do so via InfoPath 2010 as follows:

  1. Using IE, navigate to your List view
  2. Under the List Tools tab, click on the List tab
  3. Click on the Customize Form ribbon item
  4. Once InfoPath Designer opens, click on File -> Info -> Form Options
  5. To completely remove the ribbon, uncheck the Show InfoPath command in Ribbon or toolbar checkbox
  6. Click OK
  7. Save the changes and publish your form
Once these steps are complete, the ribbon will no longer appear on the form whenever a user creates/modifies a list item.

Thursday, November 1, 2012

Programmatically creating a custom hyperlink within a content editor web part

Not certain how useful this is; however, I was recently asked if I could update the title of a web part hosting a view to a SharePoint list so that it would not only be larger, but would also incorporate the upcoming date of the next weekly meeting in the title's text.  The solution I decided to implement for this particular site consisted of the following activities:
  1. Set the Appearance -> Chrome Type of the list web part to "None" in order to hide the existing title of the list web part
  2. Added a new Content Editor Web Part immediately above the applicable list web part
  3. Used Notepad to create a javascript file, OutstandingRCATitle.txt, that would create the custom hyperlink within the content editor web part
  4. Uploaded the custom javascript file to the Site Assets library of the given SharePoint site
  5. Linked the content editor web part to this file via the Content Link parameter of the content editor web part
With that accomplished, I simply had to add the appropriate javascript code to the OutstandingRCATitle.txt file in the Site Assets library to provide the requested functionality.  This functionality is listed as follows:
  1. Increase the size of the link to make it stand out to the users (i.e. used <h1> for this purpose)
  2. Append the date of the next weekly team meeting to the link (i.e. the meeting always takes place on a Tuesday so I created code that would add additional days to the current date so that the upcoming Tuesday's date would be listed)
  3. Have the link reference the appropriate view to the list (i.e. I maintained the link to the original AllItems.aspx view of the list; however, you could specify another view)
Here is the javascript code that I used for meeting this particular user's needs:
<script language="javascript"> var now = new Date(); var todaysDay = new Date().getDay(); var nextTuesdaysDate = new Date(); var numDays; switch (todaysDay) { case 0 : numDays = 2; break; case 1 : numDays = 1; break; case 2 : numDays = 0; break; case 3 : numDays = 6; break; case 4 : numDays = 5; break; case 5 : numDays = 4; break; case 6 : numDays = 3; break; } nextTuesdaysDate.setDate(now.getDate() + numDays); var displayDate = "<h1><a href='../Lists/Outage/AllItems.aspx' class='customLink'>Outstanding RCAs to be reviewed on " + nextTuesdaysDate.toLocaleDateString() +"</a></h1>"; document.write(displayDate); </script>
Since this was a one-time request for a particular user (i.e. a priority one at that) and not something that would be applicable to multiple sites, I decided to use this solution; however, I would have used a radically different approach to solving this problem if this was something that was required across multiple sites.  Not certain how useful this might be to others, but I thought I'd share anyway.

Wednesday, October 24, 2012

Adding a custom CSS file to your Visual Web Part

If you would like to add a custom CSS file to a Visual Web Part that allows the styling of the web part to remain consistent no matter where it's installed, you can do so via the following steps:

  1. Using Visual Studio 2010, open your Visual Web Part solution
  2. In Solution Explorer, right-click on the project and select Add -> SharePoint "Layouts" Mapped Folder
  3. Right-click on the newly created Layouts folder and select Add -> New Folder
  4. Edit the name from "NewFolder1" to "1033"
  5. Right-click on the "1033" folder and select Add -> New Folder
  6. Edit the name from "NewFolder1" to "Styles"
  7. Right-click on the "Styles" folder and select Add -> New Folder
  8. Edit the name from "NewFolder1" to the name of your Project (i.e. MyProject in this example)
  9. Right-click on the "MyProject" folder and select Add -> New Item...
  10. Under the Installed Templates section, expand Visual C# and click on Web
  11. Click on the Style Sheet icon, update the name of your style sheet (i.e. Standard.css in this example), and click Add
  12. You may now enter the appropriate style sheet rules in this file and save the changes
During the deployment of your Visual Web Part, the custom style sheet will be deployed directly to the SharePoint farm under the following location on the web front end servers:  C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\1033\STYLES\MyProject.

Now, to reference the style sheet in your Visual Web Part, you may do so via the following steps:
  1. Open your Visual Web Parts .ascx file
  2. After the "<%@ Control" tag, add the following line:  <SharePoint:CssLink ID="cssLink1" runat="server" DefaultUrl="MyProject/Standard.css" />
  3. Save the change
At this point, you will be able to reference the new style sheet within the controls on your .ascx page.

Tuesday, October 16, 2012

Good technique for programmatically deleting items from SharePoint collections

If you're attempting to delete items from a SharePoint collection (i.e. this could include containers such as lists, groups, document libraries, workflow collections, etc), you'll often encounter a situation where you'll need to iterate through a given collection in order to find the appropriate item (i.e. using a "for" or "foreach" loop) and then delete that specific item.  Now, if you happen delete an item from the collection while you're iterating through it, your code will thrown an error message that will stop the process dead in its tracks due to the fact that you've actually changed the contents of the collection while your also in the process of looping through the contents.  Here is an example scenario in which I'm attempting to remove a given task list called "Expired Items Tasks" from a site:

Incorrect Code:

foreach (SPList expiredItemTaskList in web.GetListsOfType(SPBaseType.GenericList))
{
    if (expiredItemTaskList.Title == "Expired Item Tasks")
    {
        expiredItemsTaskList.Delete();
    }
}


This code will throw an error (i.e. often times "Collection was modified; enumeration operation may not execute") on the next iteration of the loop that takes place after you're deleted the selected item and will stop the process dead in it's tracks.  For your code to properly handle this scenario, a good strategy will be to temporarily store the specific object(s) targeted for deletion in a generic list until you've completed iteration process.  Once you've completed your review of the collection, you can then delete those objects at your liesure:

Correct Code:

List<SPList> listsToDelete = new List<SPList>();
foreach (SPList expiredItemTaskList in web.GetListsOfType(SPBaseType.GenericList))
{
    if (expiredItemTaskList.Title == "Expired Item Tasks")
    {
        listsToDelete.Add(expiredItemTaskList);
    }
}

foreach (SPList expiredItemsTaskList in listsToDelete)
{
    expiredItemsTaskList.Delete();
}

Anyway, I've run into this scenario on many occasions with other .NET code; however, I've found this scenario to be more prevalent in SharePoint due to the fact that most objects contained within it are collections.  Hope this helps!