ReportingT Dark_1200x303

Learn how to use the Telerik Report Server API to enhance the functionality of your applications by giving the user a list of reports they can view.

The Telerik Report Server is, obviously, a repository for the reports that you display in your applications. However, it also includes a rich API that lets you take advantage of that repository to incorporate additional functionality into your applications. You can, for example, give users a list of all the reports they’re allowed to view and then display their selected report. It’s not as easy as you might like, but it will save you from having to create a dedicated View for every report in your ASP.NET MVC application.

To implement this plan, you’ll probably need want to use two Views because the ReportViewer does tend to take over your whole page: One View to display the dropdown list of reports and another View to display the actual report. I’ll start by constructing the View with the dropdown list of reports.

Setting Up to Call the Report Server API

To give the user a list of reports, you first need to retrieve that list from the Telerik Report Server. While you could use the standard .NET HttpClient object and craft your own RESTful requests to the server, Telerik Report Server provides a dedicated client (ReportServerClient) that makes it much easier to work with the server’s API.

To use the Telerik client, you’ll need to add references to Telerik.ReportServer.HttpClient.dll and Telerik.ReportServer.Services.Models.dll. Those are installed with the Telerik Report Server and can be found in the Tools folder of the Report Server’s installation folder (on my computer I found them in C:\Program Files (x86)\Progress\Telerik Report Server\Tools). You’ll also need the NuGet packages for Microsoft.AspNet.WebApi.Client and Newtonsoft.Json.

The next obvious step is to retrieve a set of ReportInfo objects from the server using the client. However, this is where you’ll run into a problem. The ReportInfo object has a number of properties, including the report file’s name (in the Name property), the report file’s extension (Extension property), and the Id of the category that the report belongs to (CategoryId). To use the report with Telerik’s ReportViewer, however, you need to pass the ReportViewer the report’s Uri, consisting of the report’s category name, file name, and file extension. This means that you need assemble the Uri from the ReportInfo’s properties.

This isn’t something that you’ll want to do more than once, so it makes sense to store the generated URIs in the Session object. To support that (and, eventually, to display reports in an ASP.NET dropdown list), I created a class to hold a ReportInfo’s Name and URI:

public class ReportName
{
    public string Name { get; set; }
    public string Uri { get; set; }
}

With that in place, the first thing I do is try and retrieve my collection of ReportName objects from the Session object. If I don’t find it there (if it’s the first time the user has visited this reporting page), I start the process of creating the collection of ReportNames:

public ActionResult Index()
{
   List<ReportName> rNames = (List<ReportName>) Session["ReportNames"];
   if (rNames == null)
  {

Calling the Report Server API

I start the process of retrieving ReportInfo objects by creating a Settings object and setting its BaseAddress to the URL for the Report Server (this example assumes that you’re running against a Report Server running on the same computer as the client):

var st = new Settings();
s.BaseAddress = "http://localhost:83";

Now I’m ready to create the ReportServerClient object that handles talking to the ReportServer, passing it the settings object I created. The client has a Dispose method so I create it in a using block so I can ensure that Dispose method gets called. After creating the client, my next step is to use its Login method, passing a username and password that have been set up on the Report Server. This ensures that the user only sees the reports that user is allowed to run.

In this code, I’ve hardcoded a name and password in this example but, in real life, you’d want to query the user or pull the information from the ASP.NET Identity object:

using (var rsc = new ReportServerClient(st))
{
   rsc.Login("PeterVogel", "milesdavis1");

I can now retrieve a list of all the reports available to the login Id by calling the client’s GetReportInfos method. This code does the job and, additionally, sorts the objects by their CategoryId (this sort will matter later when I retrieve the category name):

IEnumerable<ReportInfo> reps = rsc.GetReportInfos().OrderBy(ri => ri.CategoryId);

If there are no reports that can be accessed by the user, GetReportInfos returns an empty collection which means I can safely use my ReportInfo collection in a loop—if there are no reports accessible for the user, the loop will be skipped.

Building the List

I’m now almost ready to start building my list of report names. I first initialize a collection to hold my ReportName objects. I’m going to (eventually) use this collection in a dropdown list in my first View, so I also load the collection with a dummy object to display an initial message in the list:

rNames = new List<ReportName>();
rNames.Add(new ReportName { Name = "Please Select a Report", Uri = string.Empty });

Now, I’ll loop through my collection of ReportInfo objects building a ReportName object for each one. As the category Ids change, I’ll use the client’s get GetCategory method to retrieve the category name for the report. I set each ReportName object’s to the Name property of the ReportInfo and the Uri property to the concatenation of the category name, the report name, and its extension:

reps.ForEach(ri =>
{
   string cIdOld = string.Empty;
   string cName = string.Empty;
   if (ri.CategoryId != cIdOld)
   {
       cName = rsc.GetCategory(ri.CategoryId).Name;
   }
   rNames.Add(new ReportName { 
                                     Name = ri.Name, 
                                     Uri = cName + "/" + ri.Name + ri.Extension });
   });

Finally, I add my collection of ReportName objects to the Session object so that I don’t have to do this again:

Session["ReportNames"] = rNames;

Since I’m going to display this collection in a dropdown list, regardless of whether I create it or retrieve it from the Session, I create a SelectList from my collection. In creating the SelectList, I specify that the Name property is to be displayed to the user and the Uri property is to be used as the value to be returned to the server when the user has made their selection. Finally, I invoke the View that includes my dropdown list:

ViewBag.ReportList = new SelectList(rNames, "Uri", "Name");
return View("ReportsList");

Displaying the List and the Report

After all that code in the action method, the good news is that the code in the View to create the dropdown list is pretty simple. I just pass the HtmlHelper’s DropDownList method the name I want applied to the HTML element and the SelectList from the ViewBag. I also add some JavaScript code to trigger a page refresh and request the View that will display my report.

I gave my dropdown list the name Uri so I can use the value posted back to the server with my ReportName class:

  <form action="home/report">
       @Html.DropDownList("Uri", 
(SelectList) ViewBag.ReportList, 
new { onchange = "form.submit();" })
</form>

Now, when the user selects a report from the dropdown list, I’ll post the value of the user’s selection (the report’s URI) back to the server under the name Uri. In my action method, I chose to recycle my ReportName class as the method’s parameter—model binding will stuff my dropdown list’s value into the object’s Uri property. After checking that I got a value from the browser, I pass that ReportName object to my View (and if I don’t get a value, I’ll send the user back to my ReportsList View after recreating the SelectList):

public ActionResult Report(ReportName rName)
{
   if (rName.Uri != null)
   {
       return View(rName);
   } 
   List<ReportName> rNames = (List<ReportName>) Session["ReportNames"];
   ViewBag.ReportList = new SelectList(rNames, "Uri", "Name");
   return View(“ReportsList”);
}

To display the selected report in Telerik’s ReportViewer control, all I have to do is to pass the report’s URI to the Report property in the ReportViewer’s ReportSourceOptions object. The following markup in an ASP.NET MVC View will do the trick:

@(Html.TelerikReporting().ReportViewer()
            .Id("reportViewer1")
            .ServiceUrl(Url.Content("http:localhost:83/api/reports"))
            .ReportSource(new UriReportSource() { Uri = Model.Uri })
            .ViewMode(ViewMode.Interactive)
            .ScaleMode(ScaleMode.Specific)
            .Scale(1.0)
            .PersistSession(false)
            .PrintMode(PrintMode.AutoSelect)
           .EnableAccessibility(false))

And there you have it: Two Views that will show the user all the reports they can access and display the report to them.

There are lots of ways to improve this code: It might make more sense to you to keep the SelectList in the Session object than the base collection of ReportNames. Alternatively, if you have lots of users but a small number of report login Ids, it might make sense to keep the list of reports in a dictionary in the MemoryCache, with each list stored under a report user name. And it might also make sense to wrap the code that generates the collection of ReportName objects up in a class because, I bet, you’ll end up using it in other applications.


Peter Vogel
About the Author

Peter Vogel

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter also writes courses and teaches for Learning Tree International.

Related Posts

Comments

Comments are disabled in preview mode.