Sunday, February 17, 2013

Custom Sharepoint jobs are not shown in the Sharepoint Central Administration

Sharepoint jobs allows you to execute tasks by scheduler, similar to the way how standard Windows scheduler works. You may consider to move time consuming tasks to the job, so they will run asynchronously and won’t affect user experience (e.g. won’t cause Timeout exceptions because of long task processing during synchronous requests). Sharepoint jobs are executed in separate Windows process called owstimer, so they are isolated from the w3wp process which serves your Sharepoint site and in theory won’t affect performance (I wrote in theory because it is always possible to write code which will slow down your site even from separate process. E.g. if it causes a lot of requests to the content database, which is also used from w3wp).

Here is the example of how you can install Sharepoint job which will run nightly between 1 AM and 2 AM via feature receiver:

   1: public class CustomJobEventReceiver : SPFeatureReceiver
   2: {
   3:     public override void FeatureActivated(
   4: SPFeatureReceiverProperties properties)
   5:     {
   6:         try
   7:         {
   8:             var site = properties.Feature.Parent as SPSite;
   9:             if (site == null)
  10:             {
  11:                 // log
  12:                 return;
  13:             }
  14:  
  15:             this.registerJob(site);
  16:         }
  17:         catch (Exception x)
  18:         {
  19:             // log
  20:             throw;
  21:         }
  22:     }
  23:  
  24:     public override void FeatureDeactivating(
  25: SPFeatureReceiverProperties properties)
  26:     {
  27:         try
  28:         {
  29:             var site = properties.Feature.Parent as SPSite;
  30:             if (site == null)
  31:             {
  32:                 return;
  33:             }
  34:  
  35:             this.deleteJob(site.WebApplication.JobDefinitions,
  36:                 Constants.JOB_NAME);
  37:         }
  38:         catch (Exception x)
  39:         {
  40:             // log
  41:             throw;
  42:         }
  43:     }
  44:  
  45:     private void registerJob(SPSite site)
  46:     {
  47:         if (site == null)
  48:         {
  49:             // log
  50:             return;
  51:         }
  52:  
  53:         this.deleteJob(site.WebApplication.JobDefinitions, Constants.JOB_NAME);
  54:  
  55:         var jonDefinition = new CustomJob(Constants.JOB_NAME,
  56:             Constants.JOB_TITLE, site.WebApplication);
  57:         var schedule = new SPDailySchedule();
  58:         schedule.BeginHour = 1;
  59:         schedule.EndHour = 2;
  60:         jonDefinition.Schedule = schedule;
  61:         jonDefinition.Update();
  62:     }
  63:  
  64:     private void deleteJob(SPJobDefinitionCollection jobDefinitions, string jobName)
  65:     {
  66:         foreach (SPJobDefinition job in jobDefinitions)
  67:         {
  68:             if (string.Compare(job.Name, jobName, true) == 0)
  69:             {
  70:                 job.Delete();
  71:             }
  72:         }
  73:     }
  74: }

Class CustomJob in the example above (see line 55) is defined in the custom assembly, probably the same which contains the code of the feature receiver shown above.

After activation of this feature if everything went well you will see your job in the Central administration > Monitoring > Job definitions. However sometimes you may encounter with the problem that your custom Sharepoint jobs are not shown on production, however on your local development environment everything works properly and jobs are displayed there. Why it may occur and how to fix it?

In order to describe the reason I need to provide more background information about Sharepoint jobs mechanism. Very often in Sharepoint development you have several environments:

  • development environment – in most cases it is all in one server, i.e. server which contains all roles: WFE, app server, database server and has Central administration installed on it of course;
  • QA or staging environment – environment , which is similar to the production environment. I.e. it has the same topology and software installed on it. In most cases it is real Sharepoint farm with several WFEs, separate app and db server (real configuration can be different from case to case, but this is common topology). It is used for preliminary testing of new features and user acceptance testing;
  • production – production Sharepoint farm where your site is running, which also has several WFEs, app and db server.

As we can see there is often difference between development and QA/production. On the dev we use single server Sharepoint installation, while on QA/production – real Sharepoint farm with several servers. You may specify on what server you want to execute the jobs in Central Administration > Manage content databases > select specific content database:

image

Dropdown list “Preferred Server for Timer Jobs” contains servers which have WFE role. On the farm environment it can be so that server which has Central Administration, doesn’t have WFE role. E.g. application server may not have WFE role, while CA is still can be used from it. The problem with this configuration is that custom wsp solutions, which you deploy using standard Install-SPSolution cmdlet (or old deploysolution stsadm operation), will be deployed only to those servers which have WFE role. So if your app server is not WFE, custom assemblies won’t be installed to its GAC. This is exact reason of the problem described above. In this case when you open Central Administration > Monitoring > Review job definitions, it sees your custom jobs, but it can’t find the type where job’s code is defined and can’t deserialize it for executing. That’s why it can’t display custom job.

You can fix this problem by manual adding custom assemblies to the app server’s GAC and performing iisreset. But note that in this case they won’t be updated next time you will upgrade your solutions because of the same reason: solutions are not upgraded automatically on the server without WFE role. You will need again manually update them in the GAC. More correct way to fix this issue is to add WFE role to your app server (and not configure app server without WFE role for the new installations). You can do it by Sharepoint Configuration Wizard as described here: Add a Web or application server to the farm. After that solutions will be deployed to the app server and custom jobs will appear in the Central Administration.

Hope this information will be helpful for you.

Convert Visual Studio Sharepoint 2010 project to Sharepoint 2013 project

Recently we performed migration of the several sites from Sharepoint 2010 to Sharepoint 2013. We have several standard Sharepoint 2010 Visual Studio projects (wsps) in solution which contain our customizations. As we didn’t find standard way of changing target platform in Visual Studio from Sharepoint 2010 to 2013, we created new empty Sharepoint 2013 project in Visual Studio 2012 and manually copied all files there. Also we changed references to Microsoft.SharePoint.dll and all other Sharepoint assemblies from 14 to 15 (Sharepoint 2013 is built on top of .Net 4.5, so its assemblies are located in different GAC: C:\Windows\Microsoft.NET\assembly\, not in C:\Windows\assembly\ as it was before. Here is the good forum thread about why MS put .Net 4 to the new GAC: .NET 4.0 has a new GAC, why?). After that we packaged wsp and compare content with comparison tool.

The described way worked, but it took some time to move all files from old project and verify that we didn’t miss anything.

Rainer Dümmler showed me the easier way to do that and with his approval I post it in my blog. In order to change target platform to Sharepoint 2013 you need to do the following. Edit your .csproj file in the notepad and replace value for TargetFrameworkVersion tag from v3.5 to v4.5. Then add TargetOfficeVersion tag right after it:

<TargetOfficeVersion>15.0</TargetOfficeVersion>

So it should look like this after the changes:

image

Then go to Package subfolder in your project folder and edit Package.package file: add attribute sharePointProductVersion="15.0" after existing resetWebServer attribute.

After that just reload your .csproj in Visual Studio 2012 (it will automatic upgrade of .csproj), change references to the 15 API, recompile it and package wsp.

Thanks for Rainer Dümmler who shared this trick with me. All credits go to him. Unfortunately he doesn’t have a blog yet, but I hope that it will be fixed in future :).

How to fix problem when incoming e-mail settings are not shown in Central Administration in Sharepoint

Incoming e-mail settings option in Central Administration allows you to configure Sharepoint to receive incoming emails and place them into document libraries. Configuration of the incoming emails is not simple and straightforward process and in most cases you will need to face with your environment’s specific problems. In general you need to do the following steps:

  1. Configure MX DNS record for your domain, so emails will be processed by your mail server
  2. Configure SMTP server
  3. Configure Sharepoint to receive incoming emails in Central Administration > Operations > Incoming emails settings
  4. Configure particular document library to allow incoming emails
  5. Ensure that “Windows Sharepoint Services Incoming E-Mail” job in enabled in CA > Timer job definitions and that timer service is running.

I won’t provide detailed description of each step because it is described in many articles already. E.g. here you can find detailed instructions: How to configure Incoming Email Enabled Libraries in MOSS2007 RTM using Exchange 2007 in an Active Directory Domain.

When you perform step 3, i.e. configure incoming emails in Central Administration, you may face with the following problem: “Incoming e-mail settings” link is missing in the Operations > Topology and Services:

image

In order to fix it, close all browser windows and run browser as administrator:

image

Then type Central Administration URL manually in the address bar. After that you should see missing “Incoming e-mail settings” on the Operations tab:

image

It also should contain “Services on server” link, which was also missing when you ran CA as non-administrator. In most cases when you launch CA Windows should automatically ask you to run it as administrator. However in some cases it doesn’t happen and you may encounter with this problem.

Saturday, February 9, 2013

Several reasons of why TaxonomySession.DefaultKeywordsTermStore and DefaultSiteCollectionTermStore can be null

When you work with Sharepoint managed metadata via object model you often need to write the code similar to the following:

   1: using(var site = new SPSite(url))
   2: {
   3:     var session = new TaxonomySession(site);
   4:     var termStore = session.DefaultKeywordsTermStore;
   5:     ...
   6: }

Sometimes TaxonomySession.DefaultKeywordsTermStore property may return null, i.e. termstore variable on line 4 in the example above will be null. In this case you can’t do any operations with managed metadata programmatically. What are the reasons of this behavior and how to fix it?

First of all check that your web application has connection with managed metadata service in Central administration > Manage web applications > Service connections:

image

This connection may be part of default connections set as shown on the picture above or included into the custom set. It is important that it will have only one connection, on one of the projects we encountered with situation when TaxonomySession.DefaultKeywordsTermStore returned null when there were several managed metadata connections defined for single web application.

If connection is defined properly go to Manage service applications > select Managed metadata service connection and click Properties button on the ribbon. On the opened dialog ensure that option “This service application is the default storage location for Keywords”:

image

There is also another option “This service application is the default storage location for column specific term sets”, but it affects another property: TaxonomySession.DefaultSiteCollectionTermStore.

If this step also didn’t help, check permissions. Go to Manage service applications > select Managed metadata service application and click Permissions button on the ribbon:

image

Ensure that account under which you run the code has at least “Read access to term store” right.

In most cases described steps should fix problem with null TaxonomySession.DefaultKeywordsTermStore or TaxonomySession.DefaultSiteCollectionTermStore properties. If you found some other reasons which can cause this problem, please share them in comments.

Sunday, February 3, 2013

File not found error after upgrade of customizations from Sharepoint 2010 to 2013

Some time ago we migrated several sites which were implemented for Sharepoint 2010. Project was started with Sharepoint 2013 Preview and then continued with RTM version (when RTM was released we made all steps which were made for Preview from beginning). I wrote about one of interesting problem which we faced during first part of upgrade here: Problems with upgrading claims based site from Sharepoint 2010 to Sharepoint 2013 Preview. During first part we made the following:

  • Configured SP2010 farm
  • Moved and migrated service applications databases (mostly managed metadata database in our case)
  • Created new empty web applications and applied SP2010 customizations into 14 folders (in Sharepoint 2013 there are now both 14 and 15 folders, so you can deploy wsps for Sharepoint 2010 as is on 2013 farm and run your sites in 2010 mode)
  • Copied and mount content databases from existing 2010 sites to empty web applications on 2013 farm.

This part went quite well. The major problem which we faced with was broken layout in pages edit mode (need to mention also that we migrated publishing sites). But it is caused by the fact that in 2013 you need also to update master pages in order to have all new scripts and necessary controls. E.g. you may use OTB seattle.master or oslo.master as base masterpages for updating your customizations.

The next part of work was migrating of customizations from 2010 to 2013. For 2010 we used standard Sharepoint project templates for Visual Studio 2010. But anyway it is not possible just change target platform from 2010 to 2013 as it is possible for .Net version. In Visual Studio 2012 you need to create empty Sharepoint projects and copy/paste all items one by one (Update 2013-02-17: there is a trick which allows to migrate Sharepoint project from 2010 to 2013. I wrote about it here: Convert Visual Studio Sharepoint 2010 project to Sharepoint 2013 project). In order to ensure that we didn’t forget anything after copying of files we compared content of wsps by comparison tool (we used Beyond Compare, which may compare folders, but you may use your favorite tool for this). The only difference was in feature guids and in SharePointProductVersion in manifest.xml which was set to 15 after upgrade:

   1: <Solution xmlns="http://schemas.microsoft.com/sharepoint/" SolutionId="..."
   2: SharePointProductVersion="15.0">

After this we retracted wsps for 2010 mode from 14 folder and deployed new wsps for 2013 mode into 15 folder. And then run upgrade of site collections to 2013 mode by PowerShell.

Upgrade went well, we only had several warnings without errors in the logs. But when we opened sites in the browser we got File not found error. After checking Sharepoint logs and using of FileMon tool we found the reason of this error: for uncustomized files (page layouts and master pages) Sharepoint still tried to search their content in 14/Template/Features folder, while correct path is 15/Template/Features, because after upgrade and deploy of customizations there were no files deployed in 14 folder. So Sharepoint couldn’t find content on file system and gave this File not found error.

We analyzed content database and found that AllDocs table (which contains rows for all documents and files in the Sharepoint web application) still has SetupPathVersion = 4. While the correct value for Sharepoint 2013 is 15. We tried to update page layouts’ and master pages’ vti-setuppathversion property but without luck. After updating it and calling SPFile.Update() it was reset to initial value 4. At the moment I know only one solution: update AllDocs.SetupPathVersion in content database directly:

   1: update [dbo].[AllDocs]
   2: set [SetupPathVersion] = 15

But as you probably know direct modifications in content database are not allowed and leaves system in unsupported state according to MS. So it is more like hack. Anyway after it File not found error was solved and we were able to move forward and resolve another problems (they are minor, like change of all paths for scripts, images, css and for ascx files for visual web parts from /_layouts/MyFolder to /_layouts/15/MyFolder. There is no need to change it for aspx files, because Sharepoint will automatically redirect your application layouts pages to /_layouts/15/).

At the moment we are still looking for the correct way of solving this problem. It may be so that it is caused by the bug in upgrade process, because I saw that other people faced with this problem in Sharepoint MVP distribution list. We ordered support ticket from MS to check this problem, I will update if will know new details. If you also encountered with described issue, please share it in comments.

Update 2013-07-07. Several fixes for this problem are described in the following post: Fix File not found error after upgrade from Sharepoint 2010 to 2013.