views:

64

answers:

2

I'm doing a simple news importer for a sharepoint site using timer job that runs every few minutes. The code below runs fine if I run it in a web part but throws MissingMethodException when ran in timer job's Execute method.

The full exception:

System.MissingMethodException was unhandled by user code
  Message="No parameterless constructor defined for this object."
  Source="mscorlib"
  StackTrace:
       at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandle& ctor, Boolean& bNeedSecurityCheck)
       at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean fillCache)
       at System.RuntimeType.CreateInstanceImpl(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean fillCache)
       at System.Activator.CreateInstance(Type type, Boolean nonPublic)
       at System.Activator.CreateInstance(Type type)
       at Microsoft.SharePoint.WebPartPages.SPWebPartSerializer.get_DefaultControl()
       at Microsoft.SharePoint.WebPartPages.BinaryWebPartSerializer.Serialize(PersonalizationScope scope)
       at Microsoft.SharePoint.WebPartPages.BinaryWebPartSerializer.get_Links()
       at Microsoft.SharePoint.WebPartPages.SPWebPartManager.AddWebPartToStore(WebPart webPart, Int32 viewId, String viewGuid)
       at Microsoft.SharePoint.WebPartPages.SPWebPartManager.AddWebPartInternal(SPSupersetWebPart superset, Boolean throwIfLocked)
       at Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager.AddWebPartInternal(WebPart webPart, String zoneId, Int32 zoneIndex, Boolean throwIfLocked)
       at Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager.AddWebPart(WebPart webPart, String zoneId, Int32 zoneIndex)
       at Microsoft.SharePoint.Publishing.PublishingPage.CopyAllWebParts(String destinationPageUrlServerRelative, SPWeb destinationPageWeb, String sourcePageUrlServerRelative, SPWeb sourcePageWeb, Boolean shouldOverwriteDestinationWebParts)
       at Microsoft.SharePoint.Publishing.PublishingPageCollection.<>c__DisplayClass5.<Add>b__0()
       at Microsoft.Office.Server.Diagnostics.FirstChanceHandler.ExceptionFilter(Boolean fRethrowException, TryBlock tryBlock, FilterBlock filter, CatchBlock catchBlock, FinallyBlock finallyBlock)
       at Microsoft.Office.Server.Diagnostics.ULS.SendWatsonOnExceptionTag(ULSTagID tagID, ULSCat categoryID, String output, Boolean fRethrowException, TryBlock tryBlock, CatchBlock catchBlock, FinallyBlock finallyBlock)
       at Microsoft.SharePoint.Publishing.PublishingPageCollection.Add(String name, PageLayout layout)
       at Virtua.SharePoint.Mercator.NewsImportJob.Execute(Guid contentDbId)
       at Microsoft.SharePoint.Administration.SPTimerJobInvoke.Invoke(TimerJobExecuteData& data, Int32& result)
  InnerException: 

The code:

var SPWebUri = new Uri("http://.../News/");
using (SPSite site = new SPSite(SPWebUri.AbsoluteUri))
{
    using (SPWeb web = site.OpenWeb(SPWebUri.AbsolutePath)) // tried 0x29A's anwser, but it didn't work
    // using (SPWeb web = site.OpenWeb())
    {
        web.AllowUnsafeUpdates = true;

        PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web);
        SPContentTypeId contentTypeId = new SPContentTypeId("...");

        PageLayout layout = publishingWeb.GetAvailablePageLayouts(contentTypeId).First(l => l.Name == "....aspx");
        PublishingPageCollection pages = publishingWeb.GetPublishingPages();

        var spFilename = "testing";

        // error line below
        var newPage = pages.Add(String.Format("{0}.aspx", spFilename), layout);

        // set newPage's fields

        // check-in and publish page
    }
}
+1  A: 

Hi,

Not sure but could it be that you need to provide the url parameter for site.OpenWeb() If url parameter is empty, the top-level site must be opened. Which may explain why it works in a web part but not from the timer job. See MSDN - Site.OpenWeb Method for details.

Regards

0x29A
No, that didn't work. +1 for pointing out another possible bug :-)
Luc
A: 

The problem was a faulty web part on my page layout. I was using SPContext.Current... in constructor. Now, apparently, SPContext stuff just isn't there when executing timer job code (not so surprising either).

Since the error was not handled, web part manager tried to replace my part with an ErrorWebPart (the one normally telling the user something went wrong). For some reason this works fine when displaying page in browser. But in timer job, SharePoint tries to create ErrorWebPart through reflection using parameterless constructor which is not defined in ErrorWebPart and the whole thing just collapses with MissingMethodException.

Moving the offending code to CreateChildControls method (where I have error handling) solved the problem.

Luc