Wednesday 14 November 2007

RSViewer WebPart and Managed Urls

I have recently been developing a SharePoint solution that runs Reporting Services in SharePoint integration mode. I have a Site Definition for provisioning site collections and found that when I created a page with a ListView WebPart and connected it to a Reporting Services Report Viewer WebPart I received the following message in the report viewer web part.


The item 'http://www.mysite.com/[managedurl]/[SiteCollectionUrl]/[managedurl]/[SiteCollectionUrl]/[ReportLibrary]/MyReport.rdl' cannot be found. (rsItemNotFound)

I quickly found that this is because the list view web part provides a a datarowview with a column called DocUrl that contains the server relative url to the document. But on consumption, the report viewer wewbpart prefixes this url with the site collection's url.


Example

I have a report library called "My Reports" that contains a report called "Report1.rdl". When on the root of the web application the site collection url is "http://www.mysite.com/" and the server relative url of the document is "/My Reports/Report1.rdl". The report view web part adds them together to get.

http://www.mysite.com/My Reports/Report1.rdl - That's fine

Now lets consider the effect of the site collection being on a managed url.

The site collection url would become "http://www.mysite.com/sites/site1" the server relative url of te report would be "/sites/site1/my reports/report1.rdl". Put them together

http://www.mysite.com/sites/site1/sites/site1/My Reports/Report1.rdl - ooops



To fix this I created a web part to act as a proxy between the ListView web part and the RS Viewer WebPart.


Code

using System;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Serialization;

using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.ComponentModel;
using System.Data;
using System.Collections.Generic;

public class MyWebPart : System.Web.UI.WebControls.WebParts.WebPart, IWebPartRow
{
    Queue callbackQueue = new Queue();
    object rowData;
    PropertyDescriptorCollection rowSchema;

    public MyWebPart()
    {
        this.ExportMode = WebPartExportMode.All;
    }

    protected override void CreateChildControls()
    {
        return;
    }

    [ConnectionConsumer("AttrReportPathRowConsumer", "ReportDefinition", AllowsMultipleConnections = false)]
    public void SetRowProvider(IWebPartRow reportPathProvider)
    {
        if (reportPathProvider != null)
        {
            reportPathProvider.GetRowData(new RowCallback(this.OnReportPathFromProvider));
        }
    }

    [ConnectionProvider("Row", "blagh", typeof(DataFormProviderConnectionPoint), AllowsMultipleConnections = true)]
    public IWebPartRow GetProviderInterface()
    {
        return this;
    }

    protected override void RenderContents(HtmlTextWriter writer)
    {
        if (this.rowData != null)
        {
            DataRowView view = this.rowData as DataRowView;
            if (view != null)
            {
                int index = view.Row.Table.Columns.IndexOf("DocUrl");
                if (index != -1)
                {
                    writer.Write(view.Row.ItemArray[index].ToString());
                }
            }
        }
    }

    private void OnReportPathFromProvider(object rowData)
    {
        DataRowView view = rowData as DataRowView;
        if (((view != null) && (view.Row != null)) && ((view.Row.ItemArray != null) && (view.Row.ItemArray.Length > 0)))
        {
            int index = view.Row.Table.Columns.IndexOf("DocUrl");
            if (index != -1)
            {
                if (!SPContext.Current.Site.ServerRelativeUrl.Equals("/"))
                {
                    string url = SPContext.Current.Web.Site.ServerRelativeUrl;
                    string serverRelativeReportPathUrl = view.Row.ItemArray[index].ToString();
                    string siteRelativeReportPathUrl = serverRelativeReportPathUrl.Remove(0, url.Length);
                    view.Row[index] = siteRelativeReportPathUrl;
                    view.Row.AcceptChanges();
                }
            }
        }
        this.rowData = view;
        this.rowSchema = null;
        sendRow();
    }

    private void sendRow()
    {
        while (callbackQueue.Count > 0)
        {
            RowCallback callback = callbackQueue.Dequeue();
            callback(this.rowData);
        }
    }


    #region IWebPartRow Members

    void IWebPartRow.GetRowData(RowCallback callback)
    {
        if (this.rowData != null)
        {
            callback(this.rowData);
        }
        else
        {
            callbackQueue.Enqueue(callback);
        }
    }

    PropertyDescriptorCollection IWebPartRow.Schema
    {
        get
        {
            if (this.rowSchema == null)
            {
                try
                {
                    this.rowSchema = TypeDescriptor.GetProperties(this.rowData);
                }
                catch (Exception)
                {
                    return new PropertyDescriptorCollection(null);
                }
            }

            return this.rowSchema;
        }

    }

    #endregion
}

No comments: