Generic Getting parameters from ssrs Report - c#

After long and frustrating google search I have come here in search for help.
I'm making a fun little program that get feed a URL for a SSRS report and (if it is even possible) gets all the parameters names that the report accepts, so that the user can fill them in. But I haven been successful in finding any information on how to get these parameters.
I know you can just use the GUI that the report spits out into the browser, but I need the names specifically. Also the GUI is for the user, but the program is mean to function as a sort of Data fetcher for another program so no user interaction is supposed to happen.
To make this even more frustrating the reports I need are made by a 3rd party company so i don't have access to the code
Is this at all possible? When I google all I get as a response is how to fill the parameters into the URL when I have them, not how to get them.
I hope some of you can point me in the right direction

You can get the parameters report use the ServerReport.GetParameters () method
Returns report parameter properties for the report.
This method returns a ReportParameterInfoCollection object
Try this code:
ReportParameterInfoCollection parameters = ReportViewerViewReport.ServerReport.GetParameters();
foreach (ReportParameterInfo parameter in parameters)
{
name = parameter.name;
}
Let me know if this was helpful.

Related

I would like to clear my querystring after using it on page load c#

Before I ask this question, I'm not even sure what I'm using is a query string (I'm so clueless on this, what I have is the result of some other confusing StackOverFlow research). It is a parameter I'm passing from my SSRS report viewer to my app via a hyperlink expression. It works and everything is grand except for I'd like to clear it from the url right afterwards.
http://10.155.54.101/Update?CurrencyId=67
And I am getting the parameter with this logic on page load.
if (Request.Params["CurrencyId"] != null)
int CurrencyId = int.parse(Request.Params["CurrencyId"]);
I am successfully capturing that information and populating asp.net controls with it but I want to clear it from the address bar now as it lingers after submitting the update (postback?).
Through another Stack Overflow Answer: Clear QueryString on PostBack , I've attempted to clear the querystring through the following code.
Request.Params.Clear();
But I get a collection is read-only error, which is addressed in the stack overflow question above. So I try to use System.Reflection to change the read only property of the collection with the following code.
PropertyInfo Isreadonly = typeof(System.Collections.Specialized.NameValueCollection).GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
Isreadonly.SetValue(Request.Params, false, null);
Request.Params.Clear();
I don't get the error but nothing is removed, so I might not be referencing the querystring properly because of however the heck Request.Params works.
Can someone nudge me in the right direction with this? I'm so sorry I'm clueless as heck on this.
You can't just change the URL in the address bar of a browser. You could redirect the browser to the URL without the query string, but seeing how you are using the value to populate controls on the page being render that would mean you would need to still need to have that value.
When you say "it lingers after submitting the update", do you mean the user chooses the currency and is redirected to the the page with this query string? If so could you change this action to a POST instead of a GET? Then you could put the currencyId in the body of the POST. If you can't switch it to a POST, then there are a few ideas I listed below.
If you are using session, you could store the currencyId in the user's session. But that would only make sense if you needed to use this value on other requests; as using session is a big decision and if you can keep your website stateless you should.
With that being said, there are two viable options to keep your site stateless. If you need this value on future requests, you can store it in a cookie. If you only need it on this request, you could have the page do post to the URL without the query string but with the value in the POST body.

Return a response to indicate "No Data" via the ReportExecution.RenderReport() API method

I am looking for a tip, trick or hack that will allow a return of an empty byte array, an out warning flag or some other indicator to let the caller of ReportExecution2005.RenderReport() be aware that no data was returned for the report.
I believe that I know what you're doing now, but correct me if I'm wrong.
You created the dataset and the required parameters in the report and set the stored procedure there. Then you just pass the parameters from code and then you just render the report which causes SSRS to automatically fill the dataset with respect to the parameters.
This is a good approach but this causes you to have no knowledge of the datasource until the report is rendered.
I believe the solution to your problem is to generate the datasource outside the reporter, so executing the procedure from code. Then you have access to any information about the dataset before sending it to the reporter. So if the procedure returned no data this allows you to not render the report at all.
And when you do render the report, you won't gave to execute the procedure anymore (efficiency).
The easiest way to achieve this is to use the Local Reporting
Services (often refered to as rdlc).
There is no need to use a shared datasource because you have the
wanted dataset already. You can just pass the datatable to the
reporter and it will render correctly without needing to execute the
procedure anymore.
There are many tutorials that should make this easy for you, here is
a simple example: Using a Local Reporting Services 2008 Report with
an ADO.NET Data Set
If you really insist on using the older Reporting Services then it'll
be slightly more complicated to setup but it's still possible. Here
is detailed tutorial: Using an ADO.NET DataSet as a Reporting
Services Data Source
Before rendering the report, you simply fill your dataset by executing the procedure. And check whether or not you wish to continue rendering the report.
Example:
SqlDataAdapter daVendor = new SqlDataAdapter();
daVendor.SelectCommand = cmd;
DataSet dsVendors = new DataSet();
daVendor.Fill(dsVendors);
if(dsVendors.Any()){
//Render the report (passing the dataset to the reporter) and attach it to the mail.
}
else {
//Don't render the report and create corresponding message to send as email.
}
I strongly suggets using the Local Reporting Services. You don't want to add extra functionality anyway, as you're only sending it as attachment to an email.
I hope this helps you along, if you have any more trouble just leave a comment.
Use visibility to mimic this. Check count of your dataset and if its 0 dont show anything and then also create a text box that says no data available or something like that and set the visibility to only show when count is 0. Hope this make sense.

jquery datatables fnfilter + script performace

I am away from my development workstation so I thought I'd ask this in hopes of getting an answer when I try it tomorrow. I have a two part question relating to a web application i built using c# jquery and jquery datatables:
1) I know that we can set the value of fnfilter as metioned on their page using something like:
var oTable;
$(document).ready(function() {
oTable = $('#example').dataTable();
/* Filter immediately */
oTable.fnFilter( 'test string' );
} );
however is there a way to retrieve the value entered by the use in the search bar? I was thinking along the lines of
var aContainer= oTable.fnFilter()
or
var aContainer= oTable.fnFilter($(this).html())
2) My application has to retrieve values from another source on the web. These are the value displayed in the datatable. Most of my processing(counting, etc..) is done client side and has drastically slowed down generating the web app. Does anyone know of any suggestions to increase performance of client side scripts specifically datatables?
If your datatable is really instantiated as oTable = $('#example').dataTable(); then doing this:
var textEntered = $('#example_filter input:text')[0].value;
Should return whatever the user entered on the field for filtering.
In answer to #1, you can get the value of the text entered into the search box by doing
// Assume the table's id attribute is 'blah'
var search_string = $('#blah_filter>input').val();
As far as #2, have you considered server-side processing of the data and sending the result to the client?
This article
might give you a big help if you decide to write server side code. Now researching it myself (and not looking forward to implementing custom filtering!).

Getting more than one item from a database in ASP .NET MVC 3

I'm creating a database where users can enter some Error Reports and we can view them. I'm making these database with C# in the ASP MVC 3 .NET framework (as the tags imply). Each Error Report has a unique ID, dubbed ReportId, thus none of them are stored under the same Id. However, whenever a User creates a new Error, I pass their User Name and store it in with the rest of the report (I use User.Identity.Name.ToString() to get their name and store it as a string). I know how to get a single item from the data using a lambda expression, like so:
db.DBSetName.Single(g => g.Name == genre)
The above code is based on an MVC 3 tutorial (The Movie Store one) provided by ASP. This was how they taught me how to do it.
My major question is: is there a member function like the .Single one that will parse through the whole database and only output database entries whose stored User Name matches that of the currently logged in user's? Then, I can use this to restrict User's to being only able to edit their own entries, since only their entries would be passed to the User's View.
What would be the best way to implement this? Since the ReportId will not be changed, a new data structure can be created to store the user's Errors and passed through to the Index (or Home) View of that particular controller. From there they should be able to click any edit link, which will pass the stored ReportId back to the Edit Action of this particular controller, which can then search the entire database for it. Am I right in assuming this would work? And would this be ideal, given that the other items in the database are NOT passed through to the Index in this method, meaning the User does not have access to the other items' ReportId's, which the user needs to pass into the Edit Action for it to work? If this is ideal, this is the method that requires me to know how to parse through a database and grab every element that fits a particular description (stored User Name matches User's current User Name).
Or would a better approach be to pass the whole database to the Index View and only output the database entries that have User Name values that match the current logged in user's? I guess this could be done in a foreach loop with a nested if loop, like so:
#foreach(var item in db.Reports)
{
if(item.UserName == User.Identity.Name.ToString())
{
...code to output table...
}
}
But this passes the whole database which gives the user a lot more info than they need. It also gives them potential access to info I don't want them to have. However, I don't have to make a new data structure or database, which should lower server memory usage and fetch time, right? Or are databases passed by copy? If so, this method seems kinda dumb. However, I don't know if the first method would fracture the database potentially, this one certainly would not. Also don't remember if I NEED an else statement in C#, I'm more familiar with C++, where you don't need one and you also don't need {}'s for single line if's, if I need one: please don't judge me too harshly on it!
Small note: I am using CRUD Controllers made with the Entity First Framework in order to edit my database. As such, all creation, reading, updating, and deletion code has been provided for me. I have chosen not to add such basic, common code. If it is needed, I can add it. I will add what the Edit Action looks like:
public ActionResult Edit(string id)
{
Report report = db.Reports.Find(id);
return View(report);
}
It accepts a string as an id, ReportId is the id used and it IS a string. It is a randomly generated GUID string made with the GUID.NewGuid().ToString() function. I will also be doing the comparison of names with:
Model.UserName == User.Identity.Name.ToString()
Which was shown earlier. Sorry if this is too much text, I wanted to provide as much info as possible and not make anyone mad. If more info is needed, it can certainly be provided. So at the end of the post, the major question actually comes down to: which of the above two methods is best? And, if it's the first one, how do I implement something like that?
Thanks for your help!
Unless I'm completely misunderstanding you, you just want .Where()
Like this:
var reports = db.Reports.Where(r => r.genre == inputGenre);
This would get you an IEnumerable of Report, which you could then use however you wish.

SSRS URL Parameter won't set

I have the following c# code in a web form:
protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{
string url;
string startdate;
string enddate;
string costcenter;
string account;
//url = "http://server/reportserver?/Finance/Cost Spending/Cost Center Details&rs:Command=Render&rc:Parameters=false";
url = "http://server/reportserver?/Finance/Cost Spending/Cost Center Totals&rs:Command=Render&rc:Parameters=false";
costcenter = "&costcenter=990";
startdate="&startdate=" + Convert.ToString(txtStartDate.Text);
enddate = "&enddate=" + Convert.ToString(txtEndDate.Text);
account="&account=" + Convert.ToString(GridView1.SelectedRow.Cells[1].Text);
url =url + startdate + enddate + costcenter + account;
//TextBox1.Text = Convert.ToString(GridView1.SelectedRow.Cells[1].Text);
Response.Redirect(url, false);
}
I've tested a very similer version of this code against another report, the only different being the costcenter parameter. The other report worked fine, but every time i run this code i get the error: "the 'costcenter' parameter is missing a value". The only thing i can think of that's significantly different between the two reports is that in the Cost Center Totals report the costcenter parameter is used to populate the accounts parameter (both are multi-select).
Here's what the parameters page looks like:
Are you using multiple datasets in your report? If so, try setting the datasets to execute serially:
Open the data source dialog in report designer
Select the "Use Single Transaction" checkbox
Some other troubleshooting steps you can try:
Try removing the Report Server Command "&rs:Command=Render" from the query string and see what happens.
Also, if you change the Viewer Command to true, are you able to at least see that the parameters are populated properly (ie: "&rc:Parameters=true"?
I've been under the impression that one difference between running a report on the web server and running it in code is that in code it does not bother with the "Available Values" queries for parameters. In code, you aren't selecting a human-readable label from a drop-down which then passes in the corresponding value. Instead, you just provide the value to the parameter.
So, have you tried not specifying the cost center parameter at all? If the account parameter is all the report's recordsets really are based on, then it may be superfluous to set it.
Update:
Since the time I wrote this answer originally I've learned that dependent parameters (at least in SSRS 2008) must be after the parameter(s) they're dependent on. Make sure your parameters are ordered in a sensible way.
It looks like that's what you've done, I just wanted to mention the possibility.
Check that the Costcenter 990 is in your database!
I did some testing. I have a table "Person" with 4 rows and a PersonID 1 to 4. If set &PersonID=5 for a required single value parameter with "&rc:Parameters=true" then I get a drop-down box so I can choose one of the 4 valid persons.
If I set &PersonID=5 with "&rc:Parameters=false" then I get the message "the PersonID parameter is missing a value".
I faced similar kind of issue. Removing the parameter dependency made it work. I had parameter B depending on parameter A. It worked perfectly when you access the report server directly. But when I tried to bind it programmatically to the report viewer control, even after supplying the parameter using ReportParameter and adding to Parameters list, it was merely saying that "The 'Parameter B' is missing".
So, I went back to the report server. Redeployed the report by removing parameter dependency. It worked. :-)
Ok, I figured out the issue thanks to Alison's poke at the parameters/data sets. What was happening was I had 4 parameters, start date, end date, cost center, and accounts. In the report the account data set relies on the cost center parameters to populate the drop down list. I created a copy of the report, removed the cost center parameter, and removed the data set from the account parameter. I updated the code and ran it and BAM! It worked.

Categories