Programmatically Accessing ReportViewer Webpart through SPLimitedWebpartManager

Thursday, February 11, 2010

18

If you have many pages with SSRS ReportViewerWebparts, you'd probably want to create a feature to programmatically configure the webparts, then deploy the feature with a script.

But, if you try to activate the feature using STSADM, the ReportViewerWebparts will all show up in SPLimitedWebpartManager as ErrorWebparts. In our case, the ReportViewer webpart works fine through the UI, and other webparts on the page show up correctly in the webpart manager.

It turns out that when Sharepoint instantiates a ReportViewer, it tries to get the site URL and browser information from SPContext.Current. But, if you're not adding the webpart through the UI, SPContext.Current is null!

One workaround is to create a dummy SPConext. SPContext.Current is readonly, but it derives from HttpContext.Current, which we can create and populate with the minimum information required to instantiate a ReportViewer:

using(SPWeb web = site.OpenWeb())
{
  if (SPContext.Current == null && HttpContext.Current == null)
  {
    HttpRequest request = 
         new HttpRequest(String.Empty, web.Url, String.Empty);
    HttpResponse response = new HttpResponse(TextWriter.Null);

    HttpContext.Current = new HttpContext(request, response);

    HttpContext.Current.Request.Browser = new HttpBrowserCapabilities();
    HttpContext.Current.Request.Browser.Capabilities =
         new Dictionary();
    HttpContext.Current.Request.Browser.Capabilities["type"] = "IE7";
    HttpContext.Current.Request.Browser.Capabilities["majorversion"] = "7";
    HttpContext.Current.Request.Browser.Capabilities["minorversion"] = "0";
    HttpContext.Current.Items["HttpHandlerSPWeb"] = web;
  }
}

Once SPContext.Current is set, you should be able to get an instance of the ReportViewer webpart from the LimitedWebpartManager as normal:

using(SPLimitedWebPartManager manager =
   web.GetLimitedWebPartManager(pageUrl, PersonalizationScope.Shared))
{
  foreach (WebPart webPart in manager.WebParts)
  {
    Console.Out.WriteLine(webPart.Title);
    Console.Out.WriteLine(webPart.GetType().ToString());
  }
}

Finally, when done using the ReportViewerWebpart, be sure to set HttpContext.Current back to null before performing other operations.

Thanks to BlakeBlackShear's blog post on how to set SPContext.Current.


18 comments:

Are you kidding me? Did you really post this 2/11/2010? I ran into this problem today, and found nothing other than your post to give me an answer.

That's some coincidence! I'm glad you found it helpful :)

I have been trying to get at the ReportViewerWebpart and have always run into the "ErrorWebPart" and am trying your solution. However, when trying the code I get an exception at the HttpContext.Current.Request.Browser.Capabilities=new Dictionary() when trying to compile. the message is "Using the generic type 'System.Collections.Generic.Dictionary' requires '2' type arguments"

Can you tell me where I've gone wrong? thanks

Whoops. That should be "new Dictionary< string, string >();". Edited the post.

Thanks for the quick reply. With that fixed it worked like a charm, with one caveat. I am building a site definition solution (to create sub-sites) and after a site is provisioned I have to do some customization of various web parts on some of the pages. The ReportViewerWebPart has been onerous as before I found your post I had never been able to get at it (it always showed up as an ErrorWebPart). The site definition is called by a button on an Infopath form in a form library on the parent site. In the provisioning code it seems I have to grab the HttpContext.Current and store it in a variable, then set it to null, then run your code. Then like magic I can access the ReportViewerWebPart, update the Report Path, then reset the HttpContext.Current to its original value.

Thanks again. Dan

worked like a charm!
Perfect thank you!

You saved my life! After trying other proposed solutions from the web, this worked perfectly. I used this code to programmatically setup a sitecollection with (previously exported) reportviewer webparts.

Second Jan's comment above. This is a life saver!

I had a similar requirement, to set up a whole site collection complete with reports and parameter connections, and your code works like a charm.

I had to set the context back to the previous context before attempting to set connections for the report parameters, though. Hopefully this helps someone who is pulling their hair apart!

Thanks again.

Hello,

My euphoria was short lived after all - when I port my code to a fresh environment, every time the code adds a report viewer web part, an error is thrown to the effect of 'cannot find file c:\users\username\appdata\local\.dll'.

Now this isnt unique to the report viewer, but also intermittently comes up for the content editor web parts I add. Since it's only these two webparts that are affected, I am tempted to believe this has something to do with the context. However, I've got no idea how to troubleshoot this nor am i aware of any work arounds.

its also worth mentioning that a couple of times logging off *sometimes* works for the report viewer and it gets added, but the content editor web parts consistently throw the error.

Any ideas?

AR, I can't imagine SharePoint itself looking for a DLL under C:\users. There must be some other custom code running in the environment. What happens if you manually add the webparts through UI?

Manually adding the web parts works. Obviously, the challenge is doing it outside of the SharePoint context (as in your post) - which is where the problem arises.

Further reading suggests that this might be because of faulty intereaction between Powershell and the XMLSerializer class, which creates temporary dlls in the appdata/local/ folder.

As far as the report viewer itself is concerned, we're not doing anything custom with it - it's the out of the box web part pointing to a report URL. With the content editor, we have to pass content (simple javascript to set title of the page) in an XMLElement object if we are to add the web part using code (be it C# or Powershell).

What has me really confused is the fact that this behaviour is erratic. Most of the times, the scripts run smoothly.

Thanks a million for this article man!!! I was trying to find it out for a few days! Thanks!

Thanks a ton Boss!!!! Struggled for 2 days...you are the champ.

This didnt help me, i am writing this in a console application if that makes a difference?
I am still getting all the webparts on page as ErrorWebPart

It's 2016 and still the same problem. Thanks so much for this :)

Post a Comment