I need to create reports in a C# .NET Windows app. I've got an SQL Server 2005 database, Visual Studio 2005 and am quite OK with creating stored procedures and datasets.
Can someone please point me in the right direction for creating reports? I just can't seem work it out. Some examples would be a good start, or a simple How-to tutorial... anything really that is a bit better explained than the MSDN docs.
I'm using the CrystalDecisions.Windows.Forms.CrystalReportViewer control to display the reports, I presume this is correct.
If I'm about to embark on a long and complex journey, what's the simplest way to create and display reports that can also be printed?
I have managed to make this work now.
Brief Overview
It works by having a 'data class' which is just a regular C# class containing variables and no code. This is then instantiated and filled with data and then placed inside an ArrayList. The ArrayList is bound to the report viewer, along with the name of the report to load. In the report designer '.Net Objects' are used, rather than communicating with the database.
Explanation
I created a class to hold the data for my report. This class is manually filled by me by manually retrieving data from the database. How you do this doesn't matter, but here's an example:
DataSet ds = GeneratePickingNoteDataSet(id);
foreach (DataRow row in ds.Tables[0].Rows) {
CPickingNoteData pickingNoteData = new CPickingNoteData();
pickingNoteData.delivery_date = (DateTime)row["delivery_date"];
pickingNoteData.cust_po = (int)row["CustomerPONumber"];
pickingNoteData.address = row["CustomerAddress"].ToString();
// ... and so on ...
rptData.Add(pickingNoteData);
}
The class is then put inside an ArrayList. Each element in the arraylist corresponds to one 'row' in the finished report.
The first element in the list can also hold the report header data, and the last element in the list can hold the report footer data. And because this is an ArrayList, normal Array access can be used to get at them:
((CPickingNoteData)rptData[0]).header_date = DateTime.Now;
((CPickingNoteData)rptData[rptData.Count-1]).footer_serial = GenerateSerialNumber();
Once you have an arraylist full of data, bind it to your report viewer like this, where 'rptData' is of type 'ArrayList'
ReportDocument reportDoc = new ReportDocument();
reportDoc.Load(reportPath);
reportDoc.SetDataSource(rptData);
crystalReportViewer.ReportSource = reportDoc;
Now you will need to bind your data class to the report itself. You do this inside the designer:
Open the Field Explorer tab (which might be under the 'View' menu), and right-click "Database Fields"
Click on 'Project Data'
Click on '.NET Objects'
Scroll down the list to find your
data class (if it isn't there,
compile your application)
Press '>>' and then OK
You can now drag the class members
onto the report and arrange them as
you want.
Crystal is one possible option for creating reports. It has been around a long time and a lot of people seem to like it.
You might want to take a look at SQL reporting services. I have used both but my preferance is SQL reporting services. Its pretty well integrated into studio and works similar to the other microsoft projects. Its also free with the sql express etc.
This is a good article on beginning reporting services:
http://www.simple-talk.com/sql/learn-sql-server/beginning-sql-server-2005-reporting-services-part-1/
You can use the report viewer with client side reporting built into vs.net (ReportBuilder/ReportViewer control). You can create reports the same way as you do for sql reporting services, except you dont need sql server(nor asp.net). Plus you have complete control over them(how you present, how you collect data, what layer they are generated in, what you do with them after generating, such as mailing them, sending to ftp, etc). You can also export as PDF and excel.
And in your case building up a report from data and user input, this may work great as you can build up your own datasource and data as you go along. Once your data is ready to be reported on, bind it to your report.
The reports can easily be built in Visual Studio 2005 (Add a report to your project), and be shown in a Winforms app using the ReportViewer control.
Here is a great book i recommend to everyone to look at if interested in client side reports. It gives a lot of great info and many different scenarios and ways to use client side reporting.
http://www.apress.com/book/view/9781590598542
I second alex's recommendation to look at sql reporting services - if you have a sql developer license, then you probably already have reporting services
i don't like crystal reports, too much tedium in the designer (editing expressions all the time) too many server-deployment issues (check those license files!)
I use Crystal. I will outline my method briefly, but be aware that I'm a one man shop and it may not translate to your environment.
First, create a form with a CR Viewer. Then:
1) Figure out what data you need, and create a view that retrieves the desired columns.
2) Create a new Crystal report using the wizard giving your view as the source of the data.
3) Drag, drop, insert, delete, and whatever to rough your report into shape. Yes, it's tedious.
4) Create the necessary button click or whatever, and create the function in which to generate the report.
5) Retrieve the data to a DataTable (probably in a DataSet). You do not have to use the view.
6) Create the report object. Set the DataTable to be the DataSource. Assign the report object to the CR Viewer. This is one part for which there are examples.
Comments:
If you lose the window with the database fields, etc (Field Explorer), go to View/Document Outline. (It's my fantasy to have Bill Gates on a stage and ask him to find it.)
The reason for setting up the view is that if you want to add a column, you revise the view, and the Field Explorer will update automatically. I've had all sorts of trouble doing it other ways. This method also is a work-around for a bug that requires scanning through all the tables resetting which table they point to. You want to hand Crystal a single table. You do not want to try to get Crystal to join tables, etc. I don't say it doesn't work; I say it's harder.
There is (or was) documentation for the VS implementation of Crystal on the Business Objects web site, but I believe that it has disappeared behind a register/login screen. (I could stand more info on that myself.)
I've had trouble getting Crystal to page break when I want, and not page break when I don't want, etc. It's far from the best report writer I've ever used and I do not understand why it seems to have put so many others out of business. In addition, their licensing policies are very difficult to deal with in a small, fluid organization.
Edited to add example:
AcctStatement oRpt = new AcctStatement() ;
oRpt.Database.Tables[0].SetDataSource(dsRpt.Tables[0]);
oRpt.SetParameterValue("plan_title",sPlanName) ;
crViewer.ReportSource = oRpt ;
I found the following websites solved my problems. Included here for future reference.
CrystalReportViewer Object Model Tutorials for the tutorial on how to make the whole thing work. And also Setting up a project to use Crystal Reports
and specifically preparing the form and adding the control
i think this may help you out
http://infynet.wordpress.com/2010/10/06/crystal-report-in-c/
I strongly recommend trying an alternative reporting solution - I have a lot of experience with Crystal, and have managed to do some funky things with it in .Net, but quite honestly the integration of Crystal and .Net is an absolute pig for anything but the simplest cases.
I have tried RS. I am converting from RS back to Crystal. RS is just too heavy and slow (or something). There is no reason to have to wait 30 seconds for a report to render is RS when Crystal does it in under a second.
Related
I am currently working on a college C# project where I am required to apply N-Tier Architecture with 5 Layers:
Data Access
SQL Layer
Business Layer
Desktop Front End
Web Front End
One of the requirements of the project is to display reports.
I chose to use ReportViewer and RDLC reports to accomplish this. My choice has been working fine until I reached the final iteration of the project.
Before this iteration, I only had to generate reports from the Desktop application and the RDLC report was inside my Desktop application project. Now I need to generate the report on a ASP.Net WebForm.
Since the report needs to be accessed by 2 different projects, I thought all I had to do was move the RDLC report up a layer, to my Business Layer (probably should have been there anyways, oops). Of course, I ran into problems. It's never that easy, is it?
After some searching I found 2 particular useful posts:
Reportviewer and report are in different projects in the same solution. How do I attach the report to the viewer
https://forum.inductiveautomation.com/t/displaying-a-report-over-multiple-projects/12825
The first post told me all that I would need to do is set the Copy to Output Directory of my RDLC file to Copy always and then set the ReportViewer.LocalReport.ReportPath to the rdlc's file name with the extension ("example.rdlc").
Unfortunately, this answer never worked for both me and the OP. Why it didn't work was explained in the second post:
A report viewer cannot view a report from another project, although this may make a good feature request. - adam.morales
I then tried something a little different. Instead of accessing the report with ReportPath from a different project, why don't I create a property in my business layer that will return a LocalReport that already has the report definition?
Unfortunately, ReportViewer.LocalReport is read only. Even if it was writable, I would not be surprised if it didn't solve the issue; because, ReportPath is a string and the issue probably occurs when the LocalReport attempts to render.
This poses a very big problem for me. There is not enough time to completely redo the Reports and I don't want to have to resort to have 2 different RDLC files, 1 for each front end project; because, that's bad design.
To be completely clear on my needs:
I need to be able to access a RDLC report from 2 different projects
I must follow N-Tier Architecture and keep code reusable
So, that's why I ask, what kind of work-around could I possibly try to remedy this problem?
Well, the best I could find is embedding a PDF into the WinForms. This seems to require third-party DLLs, something I've been trying to avoid; because, it's a college project.
While this is not tested yet...
The LocalReport.Render method can generate a PDF (among a variety of things) as an Byte[]. If I use the Render method inside my Business Layer; then, I would expect it work since LocalReport would do its own thing while in the same project as the RDLC file and therefor work.
After that I should be able to simply return the generated report and use it where ever I want.
Unfortunately, I don't want to go through the complexity of adding third-party dlls to the college project so I'm going to simply duplicate the RDLC files... Hate the solution; but, it is what it is.
I am currently working on a program in C# that allows our users to run, view and export a batch of Crystal Reports. The reports were made using the Crystal Reports 2008 GUI. One of the main reasons for doing this is to allow us to preserve hyperlinks when the Crystal Report is exported to PDF. My program does this by exporting to rtf, then converting the rtf to a pdf. If anyone knows of a less convoluted method of preserving hyperlinks when converting to PDf I'd love to hear it, but that's not my current question.
I have done a lot of tests on how to optimize my program to make the export take as little time as possible. From what I've seen, having the application query for the data, then binding the resultset to the Crystal Report is by far the fastest method. My problem is that I can't hard-code the queries into the program, they need to be retreived from the Crystal Report itself.
In Crystal Reports 2008, there is an option called "Show SQL Query" under the Database menu. This brings up a window with the SQL query used for the given report. This is exactly what I need to get my hands on from within my application. I've loaded a crystal report and, while debugging, traversed the ReportDocument object trying to find the query, but no luck.
So, my question is; is there any method available that would allow me to pull out the query used by a given Crystal Report?
I realize this is a very old question, but thought I would offer an alternative for those who stumble across this but need a framework target of 3.5 (dynamic is not available in 3.5).
You will need the following references for this solution to work.
using CrystalDecisions.ReportAppServer.DataDefModel;
using CrystalDecisions.CrystalReports.Engine;
Then just access the ClientDoc interface with the following and return a list of Command Text strings.
private static List<string> GetCommandText(CrystalDecisions.CrystalReports.Engine.ReportDocument report)
{
var rptClientDoc = report.ReportClientDocument;
return rptClientDoc.DatabaseController.Database.Tables.OfType<CommandTable>()
.Select(cmdTbl => cmdTbl.CommandText).ToList();
}
Alright, so dotjoe gave me all of the hints that I needed to work this out. The following code can be used to pull the command text from a crystal report.
public string getCommandText(ReportDocument rd)
{
if (!rd.IsLoaded)
throw new ArgumentException("Please ensure that the reportDocument has been loaded before being passed to getCommandText");
PropertyInfo pi = rd.Database.Tables.GetType().GetProperty("RasTables", BindingFlags.NonPublic | BindingFlags.Instance);
return ((dynamic)pi.GetValue(rd.Database.Tables, pi.GetIndexParameters()))[0].CommandText;
}
It looks a bit messy, but it makes some sort of sense when you start wading through it. Basically, it uses reflection to get the value of the CommandText property, with a little dynamics thrown in to get past the dynamic properties in the ReportDocument.
This is pulling the command text for me, but I have had no time to do any tests on the code. I'm sure I'll be making some tweaks once I've had the time to work with this. I have no clue what happens with reports that do not use "SQL Commands". I'll post a comment once I've tested this further.
Scott
P.S. This requires that you reference the standard reflection/dynamic libraries, as well as the following Crystal Report libraries:
crystaldecisions.reportappserver.datadefmodel
crystaldecisions.crystalreports.engine
crystaldecisions.shared
I faced wuth task of creating system that will generate various medical papers for patients based on DB data. There is a lot of 3d party companies that will use this product therefore this product will be web-based. The main purpose of this product is printing this papers I have described above. Users already has prepared paper blank on which personal information will be imprinted. All users has various printers and the main issue I need to solve is that every printer prints in own maner and imprinted characters losts their positions.
The possible way I can solve this is to provide reports designer embedded in system, that allow every user "adjust" report to get printer prints properly.
By the way, we has all necessary documents reports storing in .fr3 files. It's 'cause we use same reports in another desktop application and we use fast report engine in that application. So the only one web reports designer I have found is Stimul soft reports web designer. But it's big, awkward and seems too heavy for this small project. Could you guys advice me some lightweight web reports designer/engine that can solve my issue?
P.S.: sorry for my English. I will use ASP .NET MVC3 (C#) for implementing this project.
The key question is do you need report design via the browser, do you merely need printer positioning, or can the report design be performed on the user's computer and it's just report generation that must be on the browser.
If you need report design in the browser then you are limited to products like Stimulsoft which as you said tend to be ackward and limited.
What you may be facing, based on your question, is that you need to position the report on the printer as all printers set the upper left of the generated report in a slightly different place on the paper. The best way to handle this issue is to make your report work fine regardless of the upper left of the printing on the page as the differences are small. But if that won't work, just prompt the user for the adjustment values.
Finally, if you want a system where it is very easy for non programmers to design reports, and the designer can be on their computer, please take a look at Windward Reports (disclaimer - I'm the CTO at Windward. With Windward you design your reports in Microsoft Word, Excel, or PowerPoint so it is both very easy and very powerful.
I does not understand what your problem is with position. A normal reporting solution print identical on different printers (not valid for old 9 dot printer).
Do you want print in a form (blank)? i-net Clear Reports has a page option for form print and an Online Designer. You find the form print option in the page setup dialog. If you enable the form print option the left and right margin will not change and the print will not scale.
Or do you search a simple designer in a browser? Then you can take a look in the ad-hoc reporting.
Use SQL-Server reporting services (2008 R2 in it's latest and most bug-corrected version).
It can render to HTML, and export to PDF, XLS, CSV and to Word (Word only with a commercial custom extension).
It also has a COM-object, which allows the report to run standalone, without SSRS installed.
SSRS also supports OracleProvider, apart from SQL server.
If a MS-SQL dependency is an overkill, you could take a look at Eclipse BIRT, which is a Java SSRS clone, which has a web viewer and JDBC database connectivity (however, the report format is not compatible).
The bad thing about it is, that it requires the version of Visual Studio that came with the SQL server version (so no designing of SSRS 2008 R1/R2 reports in Visual Studio 2010, you need Visual Studio 2008).
take a look into List & Label. It has a Webserveredition for generating output on web-applications and if you need to modify them there is an ActiveX available. We've done some successful projects with this stuff. Just try it out!
Take a look at Izenda AdHoc
.
In-browser Designer, In-browser Viewes, highly customizable but very simple API, exports feature, multiple databases types support.
You could even change reports looking using CSS styles.
Of course, compatible with MVC.
We've created a Crystal Report viewer application to house all of our company reports. It's built in such a way that any time we add, modify or delete a report, the viewer application itself does not need to change. The viewer app is completely driven by an XML configure file that tells it what reports are available, where they are, connection information etc. We want to keep it this way too. When we add a new report, we don't want to have to update everyone's viewer application.
The problem is that Crystal talks to our DB directly and we would prefer it didn't. Therefore, for each report, the viewer needs to query the database to retrieve the data each report needs. The problem is that many of our reports allow the user to enter a large number of filter criteria. Ideally, what we would like to be able to do is to have Crystal prompt the user to enter their filter criteria, like it currently does, and then be able to somehow get the SQL statement it would send on to the DB, pass it on to the DB ourselves, and tell Crystal not to. the viewer would then supply the report with data.
Does anyone know if this can be done? An alternative we've considered is to have the viewer prompt the user for the filter criteria, and then build the SQL statement. However, then each report becomes a C# coding project with an update to the viewer. We're trying to avoid that.
Thanks.
Interesting approach. I have only ever done the opposite.
Normally people like to build their own reports using a Crystal client. The report connects to a datasource specified in the report itself.
Using .NET to query the reports needs, set parameters and formulas then view the report is a piece of cake.
Anyway, there are only two methods that I know of called "pull" and "push". Pull is what I just described above. Push is what you described as a solution that you considered but it would involve coding for each report.
I'm afraid what you are trying to do has never been done before. However, I would recommend the "pull" method. It has worked very well for me with a client with dozens of users and hundreds of reports.
I'm writing a Winforms application and I've been writing these awful HTML reports where I have templates set up and use String.Replace to get my variables into the templates, then output the results to a WebBrowser control. I really don't like this set up.
I'd love to be able to use ASP.NET for my reports, but my clients don't want to have to run IIS on all the machines this is getting installed on, so that's not really an option.
Have you tried the reportviewer control? Your customers will be happy with the fancy new reports. It is template based and can include data from database or from code data, you can use parameters, images, and the result can be exported to Excel or to PDF.
Plus the control has some basic functionality like paging, zooming, printing, finding...
Why do you need ASP.NET? I don't see, what difference it can make. Maybe you can render your HTML more easily, but it's still not "real" reporting.
Like was said earlier, use the report viewer with client side reporting. You can create reports the same way as you do for sql reporting services, except you dont need sql server(nor asp.net). Plus you have complete control over them(how you present, how you collect data, what layer they are generated in, etc). You can also export as PDF and excel.
Here is a great book i recommend to everyone to look at if interested in client side reports. It gives a lot of great info and many different scenarios and ways to use client side reporting.
http://www.apress.com/book/view/9781590598542
While I haven't used it, I hear a lot of podcast ads for Telerik reporting. Might be worth looking at. Looks pretty sweet.
You can use the version of Crystal Reports included in Visual Studio and save the output to a .PDF file which wouldn't be too clumsy to read from a browser. (That's what I did on my last contract)
Why not using xsl to generate html reports? Much nicer than doing string replace.
You might look into Cassini -- a free ASP.NET web server component that you can embed directly in your WinForms application. The UltiDev version (linked) is based on the code that Microsoft released back in .NET 1.0, which was also used for the Visual Studio 2005+ Development Web Server.
For an advanced reporting solution that goes beyond the dataset only reportviewer in VS, you should consider Data Dynamics Reports
It offers all that is in SSRS and adds Master Reports, Themes, Calendar data region, Data Visualization (Databar, Sparkline, Iconset, ColorScale, ...), complete object model for maximum programming flexibility, royalty free end user report designer, barcode report item, excel template export and data merging, and much more. You can download a trial from Data Dynamics (now GrapeCity) and try it with few reports, you will not be disappointed.