Pass context parameters to SSRS reports in a web application

When viewing reports within an application, the application can provide context that SSRS otherwise would not have. With this context the experience of using the application can be better than the report manager. Parameters that the user would otherwise have to set for every report can be assigned programmatically.

In my case, the logged-in user belongs to a medical practice. Every report takes the practice ID as a parameter, called “Domain”. I want to pass that parameter without the user ever seeing it.

Render the menu

Earlier, we wrote code to navigate the reports. Let’s display this structure in a hierarchy.

public string GetMenu()
{
    StringBuilder result = new StringBuilder();
    WriteItems(result, ReportNavigator.GetRootFolder(_credentials).Items);
    return result.ToString();
}

private static void WriteItems(StringBuilder result, IEnumerable<Item> items)
{
    foreach (Item item in items)
    {
        Folder subFolder = item as Folder;
        if (subFolder != null)
        {
            WriteFolder(result, subFolder);
            continue;
        }

        Report report = item as Report;
        if (report != null)
        {
            WriteReport(result, report);
            continue;
        }
    }
}

private static void WriteFolder(StringBuilder result, Folder folder)
{
    if (folder.ContainsAnyReport)
    {
        result.Append(String.Format("<li class=\"folder\">{0}: {1}<ul>",
            HttpUtility.HtmlEncode(folder.Name),
            HttpUtility.HtmlEncode(folder.Description)));
        WriteItems(result, folder.Items);
        result.Append("</ul></li>");
    }
}

private static void WriteReport(StringBuilder result, Report report)
{
    result.Append(String.Format("<li class=\"report\"><a href=\"ViewReport.aspx?Path={1}\">{0}: {2}</a></li>",
        HttpUtility.HtmlEncode(report.Name),
        HttpUtility.UrlEncode(report.Path),
        HttpUtility.HtmlEncode(report.Description)));
}

This mutually-recursive set of methods renders a tree of unordered lists. It shows only the folders that contain a report. When it gets down to a report, it renders a link to the ViewReport page. This is our page containing a report viewer control.

Display the report

The ViewReport page simply contains a report viewer control. Page_Load sets the path, the credentials, and the Domain parameter.

protected void Page_Load(object sender, EventArgs e)
{
    _path = Request["Path"];

    if (Request.HttpMethod == "GET" && !string.IsNullOrEmpty(_path))
    {
        ReportViewer1.ServerReport.ReportPath = _path;
        _reportTitle = _path.Split('/').LastOrDefault();

        // MLP: Get the user's credentials from forms auth.
        IIdentity identity = HttpContext.Current.User.Identity;
        FormsIdentity formsIdentity = (FormsIdentity)identity;
        string username = formsIdentity.Name;
        string encryptedPassword = formsIdentity.Ticket.UserData;

        // MLP: Decrypt the password.
        byte[] usernameHash = Crypto.ComputeStringHash(username, _hashAlgorith);
        byte[] encryptedMessage = Convert.FromBase64String(encryptedPassword);
        string password = Crypto.DecryptMessage(encryptedMessage, _symmetricAlgorithm, _key, usernameHash);

        NetworkReportServerCredentials credentials = new NetworkReportServerCredentials(username, password, "ABSG");
        ReportViewer1.ServerReport.ReportServerCredentials = credentials;

        string domain = GetDomainOfUser(username);
        ReportParameterInfoCollection parameters = ReportViewer1.ServerReport.GetParameters();
        if (parameters.Any(p => p.Name == "Domain" && p.DataType == ParameterDataType.String))
            ReportViewer1.ServerReport.SetParameters(new ReportParameter("Domain", domain, false));
    }
}

The app looks up the domain based on the user name. Then it checks the parameters to see if this report accepts “Domain”. If so, it sets it.

The “false” in the ReportParameter tells the report viewer to hide the parameter from the user. If it were “true”, the user would still see the parameter, even though it was set to a default value.

Now my business administrators can create any report they need in SSRS report manager. Their report will appear on the menu automatically. If they follow the convention and specify a “Domain” parameter, the report will be context sensitive. This gives the end user of my application be best experience possible.

Leave a Reply

You must be logged in to post a comment.