Thursday, November 15, 2012

Getting the full name of a feature by code

When you use the SPFeatureDefinition object, and you want to get the name of the feature you are manipulating, the "DisplayName" property of that object returns a string that is NOT the display name of the feature as you see it when you view the feature list on the site. For example, the display name of "Publishing Infrastructure" feature will be returned as "PublishingSite".

The reason is that the feature list is showing a localized version of the display name - so depending on the language of the site, the name of the feature displayed will be different than the display name the object exposes.

So, how to get the full display name? the SPFeatureDefinition object has a function called "GetTitle", which, when specifying a language, will return the full name of the feature. The following code sample loops over all features installed in the local farm, and using the English locale:

 foreach (SPFeatureDefinition def in SPFarm.Local.FeatureDefinitions)
                    {
                        CultureInfo locale = CultureInfo.CreateSpecificCulture("en-US");   
                                                if (def.Hidden)
                            continue;
                        Console.WriteLine(def.GetTitle(locale) + ":" + def.Id.ToString());
                        }

Wednesday, September 05, 2012

Repeated authentication prompts from SharePoint

In the past few weeks I had two clients with a similar issue - both had some users expiriencing multiple requests for user name and password whenever they accessed the site. With one client entering the user name and password sometimes worked, and sometimes would request 10 times and then show the site, and sometimes would just result in a blank, empty page. With the other client, they would always get to a "internet explorer cannot display the web page" error page.

If you research the issue on your favorite search engine, you will find a lot of references to authentication providers (forms, claims and so on), registry issues, trusted sites or intranet zone settings or maybe the users are on the server and the loopback check was not disabled. Well, none of these were valid in the case of these two clients - for one thing, the users were not on the server - they were on their desktops. For another thing - even when the site was added to trusted sites it still happened. Most perpelxingly - with one client it only happenned to users on windows XP, not the users who were on Windows7...

After wasting a lot of time troublshooting the issue, I finally realised what must be different between those users and the rest, and why it sometimes worked and sometimes it didn't - it was the proxy server!

Turns out both clients had a proxy server, with proxy settings deployed to desktops via group policy. The proxy would behave differently every time it was asked for the new web site address, and would cause an authentication prompt for each image on the page. In one organisation, the proxy settings that were deployed were different for Windows XP users - which explains why only those users expirienced the issues.

The solution? I told the network admins to either add the web site to the proxy exception list in IE (via group policy) or fix the proxy server itself.

Tuesday, August 28, 2012

Setting a default to the site collection administrator value

If you are like me, you may find yourself constantly creating site collections manually to test and retest something or other, and scripting the site collection creation doesnt always make sense - depending on what you are testing.

Today I got tired of entering the user name over and over again in the site collection administrator box - it is always the name of my user - which is the only user in my domain as it is a stand along development box. So...I hacked the page for site collection so it would have a default and I won't have to worry about it. Note that this should only be done in development boxes, and at your own risk.

My solution was to edit the built-in "createsite.aspx" file, sitting at "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\ADMIN\createsite.aspx". In that file I located the "PeopleEditor" control with ID "PickerOwner" and added CommaSeparatedAccounts="mydomain\ishai". Save, and done!

Thursday, August 23, 2012

Activating Features using PowerShell does not trigger feature event code

If you ever try to activate a feature using powershell, and the code the feature was supposed to run doesnt run (or it runs, but doesnt reflect your changes) consider this- PowerShell, much like IIS, scans the GAC when it is started and caches the assemblies there. If you redeployed your code with modifications to your feature event handler (or anything else) and use an already open powershell window, the code will fail or will run the old version of the code, because it is cached.

Lesson learnt: always close the powershell window and open a new one when deploying a package...

Tuesday, August 21, 2012

Setting the "AllowedContentTypes" for a document set doesnt work

I really liked Cory's article on how to deploy documents sets using declartive XMl. However, when implementing it, I noticed two issues that prevented sharepoint from using the AllowedContentTypes declartion I used.

The first - the culprit was Inherits="TRUE" Version="0" in the content type declaration. If I removed those, sharepoint created the content type with the allowed content types properly defined.

The second one is that the content type that is referenced inside the AllowedContentTypes has to be created by a seperate feature. I had carefully made sure that all the document content types are declared before the document sets, but nothing worked until I seperated the document sets to a seperate feature, with a dependancy on the document content types' feature.

Duplicate content type "report" error

If you have a visual studio project that deploys a content type with the name "Report" - it may work...until you try to deploy it to a different site template. Different site templates in sharepoint contain different built-in content types, which explains why you should test your content type deploying solutions on different templates before announcing them ready for production!

Tuesday, July 31, 2012

CAML Query on datetime columns

I always forget (and end up looking it up again), so I might as well write a blog post so I can search my own blog instead of the entire internet.

The issue is when you are doing a CAML query to get items from a sharepoint list, and want to specify a filter based on a datetime column in that list - to be greater than the current date for example.

There are two issues when querying datetime fields - the first, is comparing datet time values in the correct format, and the second is relevant if you want the query to include the time, and not just the date.
To handle the first, the query requires you to convert the date value you are comparing to, to a format recognised by sharepoint's caml. To do so, you should use
the SPUtility.CreateISO8601DateTimeFromSystemDateTime function on the date value you want to compare to.
Here is an example of testing that the "Expires" column is greater or equal to the current date:

<geq>
             <fieldref name="Expires">
             <value type="DateTime">" + SPUtility.CreateISO8601DateTimeFromSystemDateTime(DateTime.Now) + @"</value>
          </fieldref></geq>

The second issue is when we want to make the same comparison, but include the time in the query. we have the "Expires" field set to accept both date and a time, the query above will only compare the date - so even items that should have expired an hour ago, would still show - until tomorrow.
To fix that, we need to add IncludeTimeValue='TRUE' to the value node:
<value includetimevalue="TRUE" type="DateTime">" + SPUtility.CreateISO8601DateTimeFromSystemDateTime(DateTime.Now) + @"</value>

Thursday, July 26, 2012

Securing custom application pages

When you create a custom application page in sharepoint (a page deployed to the layouts folder) as part of a visual studio project, often you will want to make sure it is used by the right people. Especially if the actions on the page happen with elevated privilages.

The only security settings you get out of the box is setting rules on when the links to those pages are shown through custom actions. In a custom action you can specify required permissions on the site, and so the link isnt shown to people who are not supposed to use the page.

The problem is - any user can open the page if they just type the URL in the browser. To avoid this, I always add a bit of script that checks if the user is allowed to use the page. Where? In the Page_Load function!

Here is an example of how I secured a page to only show to web administrators, and I also added a check that a required feature has to be activated in the site or the page will not display. For this purpose, I made sure all the controls in the web page are in a panel called pnlControls - so I can easily hide them when the user shouldnt be using the page. I also created a lable called lblErrors outside the panel - so I can so an error to the user if they are not supposed to use the page. An alternative would be to just redirect the user to the site's home page.


Here is the sample:

protected void Page_Load(object sender, EventArgs e)
{
            lblErrors.Visible=false;
            if (!IsFeatureActivated(SPContext.Current.Web, new Guid(Constants.C_SiteActionsFeatureID)))
            {
                lblErrors.Visible=true;
                lblErrors.Text = "The required feature is not activated in this site. This page is not available when the feature is not activated.";
                pnlControls.Visible = false;
                return;
            }
            if (!SPContext.Current.Web.UserIsWebAdmin)
            {
                lblErrors.Visible = true;
                lblErrors.Text = "You don't have permissions to view this page. Only web administrators are allowed to use the functionality on this page.";
                pnlControls.Visible = false;
                return;
            }
}

public static bool IsFeatureActivated(SPWeb web, Guid featureId)
        {
            return web.Features[featureId] != null;
        }

Friday, July 20, 2012

Troubleshooting SharePoint 2010 issues

Friend and colleague in Extelligent Design Jeremy Taylor is doing a webcast on Troubleshooting SharePoint 2010 issues (with some 2013 coverage). Head over to his blog to register!
http://www.jeremytaylor.net/webcast/

Wednesday, July 11, 2012

Reporting code errors when running code in SPLongOperation

As we all know, SPLongOperation is a great device to run a bit of code that takes a long time, while showing the user a turning cogwheel, and then redirecting when the operation is done.
However, when I checked, I saw people are on the search for a way to properly report on errors that happen during the long operation.
Some solutions involve redirecting to a new page, and passing the errors' details in the query string, or in some other way. Another way is to use the "EndScript" method to show a javascript "alert" (a messagebox, with the details.
I'd like to propose a different way. The page that is showing the cogwheel can be modified using the same javascript ("EndScript" method) by injecting html with the error details into the 's4-simple-card-content' div. This is critical if the page that is doing the long operation was opened as a dialog - in which case redirecting can be confusing, and we want to show the error if there was one, or close the dialog if there wasnt.
Example:

SPLongOperation longOp = new SPLongOperation(this.Page);
StringBuilder sbErrors = new StringBuilder();
longOp.Begin();try
{
throw new Exception("Sample");
}
catch(Exception ex)
{
  sbErrors.Append("An error occurred: " + ex.MEssage);
}

if
(sbErrors.Length > 0)
{
longOp.EndScript(
"document.getElementById('s4-simple-card-content').innerHTML = \"Errors have occurred during the submission. Details: " + sbErrors.ToString() + " \";");
}
//close the dialog if there were no errors

longOp.EndScript("window.frameElement.commitPopup();");

Thursday, May 17, 2012

SharePoint Upgrade or Migrate

Hello again everyone.
In March I have published an article in IDM magazine (australia) about upgrading sharepoint and what is the difference between that and migration, and the pros and cons of each one. I even gave tips to successfull upgrade\migration projects. If you want to read it, I have now republished it in my company's site:
http://www.extelligentdesign.com/Articles/UpgradingSharePoint.aspx
Feel free to drop me comments on the article here (and please feel free to tell people about it).

Monday, May 14, 2012

Useful Event handlers for SharePoint

In a few of my recent posts, I wrote about event handlers to set titles and permissions on items automatically as items are created. Since then, I have received a lot of questions from none developers who wanted to use the code samples, but didnt want to compile themselves, and didnt want to go through making the code more generic and robust. So I have done the work for everyone out there who wants to have the code samples as a downloadable product.
The product I am now selling as part of my Company's offerings is called "Extelligent Design's SharePoint List Events Package". The idea is that I will keep adding event handlers to that package, so you pay once, and get a whole lot of functionality. The event handlers are as flexible as possible - allowing you to configure what permissions are assigned and to whome, or what format the title of the list items or documents should be, and even hide the title field from users in the editing forms.
If you purchase, not only do you get the code compiled, you also benefit from 1 year support (patches and added features).
To read more, and to purchase, go to the product's page in our web site.

Monday, February 06, 2012

Enabling Managed Metadata in Office365 (includes download)

If you have office365 or other hosted sharepoint solutions, you may find that the managed metadata column is not available to use - it shows an error that "the required feature is not enabled for this column type".
There are two possible reasons. The first - you don't have a hosted site that supports managed metadata. To check if that is the case, check with your hosting company, or, if you have Office365, you should have a "manage term store" link in your sharepoint online administration centre. If you dont have that link, then you cannot have managed metadata - sorry.
The other possibility is because a feature that is needed on the site is not enabled by default, and because it is a hidden feature you will not be able to activate it yourself.
If you search for this, you will find a lot of articles about how to solve it on a regular sharepoint farm using either command line or powershell. However, what happens if you don't have access to the server, such as in the case of SharePoint online (Office365) or a hosted environment?
In such a case, you need to use a sandboxed solution to enable the feature. To simplify this, I have created a sandbox solution that has a single feature called "Enable Managed Metadata":
This feature simply activates and deactivates the managed metadata feature.
To download this solution, visit my company's web site's code sample library or click this direct download link.
After you have downloaded the solution, you need to upload it to your site. Go to the site's settings page, and click the "Solutions" link to go to the solution gallery. Here, click on "Solutions" in the ribbon and then "upload solution" button. Browse to the file you downloaded, and upload the file. Once uploaded you will have the option to Activate the solution. This should also automatically activate the feature, so from that moment on you can start creating managed metadata columns!

While you'r there, would you mind clicking the "like" button for our web site?

Sunday, January 15, 2012

The importance of synchronous event handlers

In SharePoint, we can create list item event handlers (or receivers). I have written about this in the past, and even posted some code for setting the security automatically on a list item as it is created.
Now, there is one thing I wanted to write about this topic. Event handlers can be defined as either Synchronous or Asynchronous - regardless of the event type. By default, events were always asynchronous if they had the "ed" suffix (ItemAdded, ItemUpdated), and synchronous if they had the "ing" suffix (ItemAdding, ItemUpdating). However, sometimes we want to run our code in an "ed" event, but have it synchronous (notice that the opposite is impossible have the "ing" properties to run asynchronously)- for example, when we want to modify item properties when its added, but before the user has been redirected to a new page.
A classic example is the upload of a document to a document library. The user gets prompted to browse for a file and clicks upload. The next page would be the properties page for the file that was uploaded. If we want to set some of the properties to be pre-filled for the user, we have to do that after the file has been uploaded - but we cannot do that in ItemAdding, as at that point we don't have access to the item - it wasn't created yet. In ItemAdded we can set values to the item - but by default this event is asynchronous - and sharepoint will show the user the properties dialog while the event is still happening in the background. The result is disastrous : the user sees the properties screen, clicks "Save" and gets an error telling him or her that the item has been modified by another process or user.

To resolve this we use the "Synchronization" XML tag in the receiver's registration XML with the value set to "Synchronous" or, if the receiver is registered using server object model code, we set the "Synchronization" property of the receiver class to SPEventReceiverSynchronization.Synchronous. To quote MSDN: "Synchronous processing provides the ability to run the event in the same thread before sending the Web response back to the browser."

As an example, lets create an event receiver that sets the title of a file to the file name, as the file is being uploaded. The code is simple:

public override void ItemAdded(SPItemEventProperties properties)
       {
           base.ItemAdded(properties);
           if (properties.ListItem["Title"] == null)
           {
               int startingPoint = properties.AfterUrl.LastIndexOf("/");
               properties.ListItem["Title"] = properties.AfterUrl.Substring(startingPoint + 1);
               properties.ListItem.Update();
           }
       }

Now, the XML that registers the receiver is :
<Receivers ListTemplateId="101">
      <Receiver>
        <Name>SetTitleFromFileNameItemAdding</Name>
        <Type>ItemAdded</Type>
        <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
        <Class>DocumentTitleSetter.SetTitleFromFileName.SetTitleFromFileName</Class>
        <SequenceNumber>10000</SequenceNumber>
        <Synchronization>Synchronous</Synchronization>
      </Receiver>

  </Receivers>
Now, when uploading a file, the users are first asked for the file:
And when they upload, they see the dialog allowing them to change the file's name, and by magic the title is already filled for them!

Where can this be useful? I can think of a very real world example: assigning a number to a document as it is being uploaded. The title setting event can be critical in some scenarios where we have lists with lookup columns to a document library - since the lookup column cannot show the file name column we need to show the title, which means we cannot have an empty title (in which scenario you will also want to set the title to unique, and add extra code to make sure the title you are setting is not unique - dont assume that because it is a copy of the file name there wont be duplicates - remember that users may edit both file names and titles!).

Just in case someone finds this useful, I am uploading the code, and the compiled solution package to my company's web site as a free, open source solution for anyone to use on their own risk. I have tested this to work with Office365 (SharePoint online) and as a farm solution - so enjoy!. You can find all my company's free code samples and solutions in our document library on our web site. The specific files are: [Source Code] and [Sandbox Ready Package].