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.
Related
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.
I have a crystal report and in design time on VS2010 I apply a parameter field via the [Database Expert][Add cmd][create parameter] wizard. But this prompts me for a specific value for my new parameter. I don't see why it should as its going to be dynamic!
In my c# code, my solution only works if the dynamic value at run time matches the design-time prompted value. This seems to defeat the purpose.
In my run-time code I have:
crystalReport.SetParameterValue("TenantID", tenantID);
TenanID is the CR parameter in design time
tenanID is the picked up dynamic value
Can't i make this truly dynamic?
Use:
crystalReport.ParameterFields(1).AddCurrentValue (num)
where "num" is your parameter value
Part of our solution is a page that displays company-specific information using an ASP Gridview. Our method of constructing the SQL that feeds the Gridview is by using C# to build a custom SELECT statement based on a series of user inputs.
Once the user applies their filters through a button click, C# loops through all of their selections (check boxes and text boxes) and then propagates those selections to a separate method which constructs a WHERE clause to append to a simple SELECT statement. We use a Table-Valued Function in the FROM statement, and the only input parameter is from the Querystring and this does not change throughout the process.
Once the query has been assembled using C#, we apply this query to the SqlDataSource as the Select Command. However, we have recently discovered a very bizarre SQL error that we haven’t seen before:
Errors :
"The variable name '#' has already been declared.
Variable names must be unique within a query batch or stored procedure."
We aren’t declaring any variables in our SQL. As stated above, the only input parameter comes from the Querystring, and we access this parameter using both QueryStringParameters in the ASP:SqlDataSource on the ASP side and “int.Parse(Request.QueryString["id"]).ToString()” on the C# side while constructing the SQL query.
After researching this error, I have yet to find an instance where the variable declaration is empty. Most people are getting errors similar to this when they have declared a variable such as '#email' or '#address' twice. We have no double declarations, and the fact that the variable in the error is not defined is causing a massive headache.
Has anyone seen anything like this before or have any suggestions on how to further debug?
I'll post some code if need be, but we are mostly interested to see if anyone has seen an error like this before.
Code:
string MainQueryStr = ResultsPages.SearchString(SearchVariables(), Request,
ProjectsSqlds, 0, "SELECT DISTINCT dbo.{0}.* FROM dbo.{0}(" + int.Parse(Request.QueryString["id"]).ToString() + ")",
"getXyzById", "AbcId");
StringBuilder SearchQueryStr = new StringBuilder();
SearchQueryStr.Append(MainQueryStr);
SearchQueryStr.Append(" ORDER BY AbcName");
ProjectsSqlds.SelectCommand = SearchQueryStr.ToString();
The search string function is a 500 line method that we can't post right now. It is used all over our solution and works as it should. It stitches together strings to create the query.
This is how the SearchString function appends the parameters:
l.Add(ResultsPages.NewSearchQueryString(ABCFiltersTxBx, SearchQueryStringVariableType.String,
"{1}.AbcID IN (" + ABCFiltersTxBx.Text + ")"));
Where the ABCFiltersTxBx is parsed into a comma separated string.
I should chime in as the supervisor in question here:
OK, so we figured out what was happening.
What we didn't realize was that the SQLDataSource was taking our appended WHERE clauses and using them as SelectParameters. Each parameter we wanted to add to the query that would ultimately feed the SQLDS was then being added as a SelectParameter without us realizing it, and because we hadn't made any explicit parameter declarations, the parameters were added with just "" as the name, leading to the error of "'#' has already been declared".
The most embarrassing part of this whole thing is that our API has already accounted for Parameter Names, but we had unwittingly excluded this part. Thank you all very much for reading and attempting to help. We thoroughly appreciate you taking your time to help us brainstorm our solution over here.
So I suppose the take-home of this whole error is in 2 parts:
Know your API. When you realize that you screwed it up on your own, graciously thank those that took the time to help you here on StackOverflow (or wherever you seek help), as their time is valuable as well.
"'#' is already declared" would indicate that you have parameters being declared without a name, so when debugging, look through the SQLDS you are using and find any parameters that haven't been explicitly named.
Again, thank you to all who read and offered to help. It's greatly appreciated.
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.
I have added a parameter to my report with the option "Allow Multiple Values" checked.
This is a status column (IE, Proposed, In Progress, Completed, Canceled), and I want the user to be able to select which (and how many) different OrderStatus to report on.
How I normally set parameters is:
report.SetParameterValue("#dtBegin", dtBegin.DateTime);
What I tried to do for the multiple values was something like this:
//pseudo loop
foreach(int intOrderStatus in intSelectedOrderStatuses)
{
report.Parameter_OrderStatus.CurrentValues.AddValue(intOrderStatus);
}
I have checked it does add the values to the OrderStatus parameter, but when the report runs, the CrystalReports dialog pops up and asks me to enter values for the OrderStatus parameter. So it seems as though the values aren't "commited" to the parameter. I have done a number of searches and can't figure out why it's not working.
Thanks,
Just set the parameter value with an array of ints.
report.SetParameterValue("#OrderStatus", new int[]{1,2,3});
in the select expert you would use the in operator.
{table.order_status_id} in {?#OrderStatus}
What you can do is, make a normal parameter field,i.e without multiple values, only discreet values true, all you need to pass is 1,2,3,4. "," is the delimiter for separation use what ever you think works for you, then in record selection formula simply put
{table.order_status_id} in split({#OrderStatus}, ",")
all you need to pass from you page is the string 1,2,3,4 and it should work
Have you set the parameter to Hidden in the Crystal Reports parameter options?
I haven't tried this, but I think that you should be able to add intOrderStatus to either a ParameterDiscreteValue or ParameterRangeValue and pass that into Parameter_OrderStatus.CurrentValues instead of intOrderStatus.
Well i have same issue. The work around is very simple. Don't add data source after parameters. e.g
report.SetParameterValue("#dtBegin", dtBegin.DateTime);
report.SetParameterValue("#dtBegin2", dtBegin.DateTime1);
//Note datasource is assigned after parameters
report.SetDatasource(dataset);
The crystal report will refresh parameters before applying data source to report.
The below is the not popup discrete dialog box
//Note Datasource is applied before parameters
report.SetDatasource(dataset);
report.SetParameterValue("#dtBegin", dtBegin.DateTime);
report.SetParameterValue("#dtBegin2", dtBegin.DateTime1);
Following is tested in Crystal Reports version 13.0.20:
1) In Parameter Fields section add new parameter as follow:
Name: ParamMultipleOrderStatus
Type: Number
Value Options:
Allow multiple values: true
2) Choose the Select Expert Record ... in Crystal Reports and code may like this (use = operator):
{Orders.OrderStatus} = {?ParamMultipleOrderStatus}
3) Use following code:
foreach (int intOrderStatus in intSelectedOrderStatuses)
{
report.ParameterFields["ParamMultipleOrderStatus"].CurrentValues.AddValue(intOrderStatus);
}