We have a pretty basic requirement for printing cards, envelopes, brochures, etc. We want to take requests in for donations and then allow for printing in batches of these orders.
The PrintDocument is the main class in .NET for printing. The sample code shown looks like this:
Private Sub pd_PrintPage(sender As Object, ev As PrintPageEventArgs)
Dim linesPerPage As Single = 0
Dim yPos As Single = 0
Dim count As Integer = 0
Dim leftMargin As Single = ev.MarginBounds.Left
Dim topMargin As Single = ev.MarginBounds.Top
Dim line As String = Nothing
' Calculate the number of lines per page.
linesPerPage = ev.MarginBounds.Height / printFont.GetHeight(ev.Graphics)
' Print each line of the file.
While count < linesPerPage line = streamToPrint.ReadLine() If line Is Nothing Then Exit While End If yPos = topMargin + count * printFont.GetHeight(ev.Graphics) ev.Graphics.DrawString(line, printFont, Brushes.Black, leftMargin, yPos, New StringFormat()) count += 1 End While ' If more lines exist, print another page. If Not (line Is Nothing) Then ev.HasMorePages = True Else ev.HasMorePages = False End If End Sub
However, this requires you to manually print by drawing through the graphics context. This is not a great solution for something like envelopes, cards, etc. because hard coding a bunch of strings is not really a scalable solution.
What we need is a template engine - something to define a template that can be filled with data and then printed, all through .NET code. In addition, I would like the ability to print the same document to an image file so that I can show the user a print preview through the web.
So what should we use for a template engine? The options we came up with were:
1. Word - using the supplied primary interop assemblies, we could load up a word document, fill out some form fields or do a mail merge programmatically. However, this isn't recommended to be done by server based applications because each time you load up an instance of Word to do the processing.
2. Custom template - we could define our template layout. Given the amount of data we have, it wouldn't be that difficult to define a template that contains a basic background, some text fields with X,Y locations, etc. I'm not exactly a fan of this type of solution because it doesn't scale in terms of functionality - what happens when the user wants rich font support, margins, tables, embedded bitmaps, paragraph formatting, etc. Surely, we shouldn't have to re-invent the wheel here.
3. Printing existing controls. See this article on a basic explanation. This would allow you use a windows form as a template and the print it. This is better than custom coding a template engine, but its not exactly a great solution either - who wants to build a windows form to represent an envelope?
After exploring a few other ideas, we came up with a basic idea - use SQL Server 2005 Reporting Services. After thinking about it, it provides us all the pieces we need in a nice package:
1. Template engine based on XML that can be generated by a relatively non-technical user.
2. Automatic data binding to the data source - simply create a report that represents a card, an envelope, etc.
3. Page sizing and pagination support - we would need this for envelopes and odd sized cards.
4. Rendering to image format - we can use this for preview.
5. Programming model through web services and ability to grab rendered output through web services. So for our preview feature, we can simply call the web service and stream out a rendered image. Alternatively, we can simply point the URL that will supply a rendered image of your report.
So we think we can use SQL Server 2005 Reporting Services as a template engine and embed it into our web application to enable server side printing.
One drawback on this approach - I haven't found anything in the web services API that allows me to render the report directly to the printer. I can see the ReportExecutionService.Render method that can give me back a stream in any format, but then I would need to figure out how send that stream to the printer. The simplest format to handle would be an image - simply then drawing on the graphics object and printing it would then be possible. There is a good post on this type of idea here...
Showing posts with label SQL Server. Show all posts
Showing posts with label SQL Server. Show all posts
Friday, May 18, 2007
Friday, April 6, 2007
SSIS and Visual Studio 2005 are very slow...
We've been using the Business Intelligence Studio as part of Visual Studio 2005. In general, we find its a well designed ETL tool, but for one problem - its too SLOW!
From what I can see, there are two basic problems: 1) the need to repeatedly validate packages against the database; and 2) the assumption that each package gets its own connection to the database.
Problem #1: Validation
The basic problem with the speed issue seems to be its constant need to validate against the underlying database. For example by default:
I have a project where we're doing replication of tables from a SYBASE database to a SQL Server 2005 database. For each table, we've created a package. We now have 50-60 packages.
Every time you open up the project, it re-validates each package against both the SYBASE database and the SQL database. Each build re-validates. Each execute in Debug mode re-validates. Each run in production re-validates. All this validation on a slow database connection makes basic development tasks very slow.
The same thing happens when running the package in DTExec or through the SQL Agent - it pre-validates every package. This is both good and bad - its good in that it means it will fail your package before trying to execute some bad SQL or badly mapped columns, but given that you're going to run the same package over and over again without a change, there should be a way to turn off this step for packages that haven't changed.
I've looked around and haven't seen any method to change this behaviour - it would be great to have some more lazy validation, e.g. once I have validated it once, don't re validate unless I actually make a change to the package.
Problem #2: Data Sources
In an SSIS Project, there are data sources that you can define once as a common data source. However, there seems to be two problems with the data source model:
1. You cannot store an ADO.NET data source configuration as a shared data source - these have to be re-created in each package. Given how common these of connections are, this seems to me to be a big oversight.
2. Each package when its loaded creates its own connection to the database. Its very slow to create a connection and then tear it down especially with either a slow network or a slow database (e.g. an old legacy connection).
This causes problems for us with so many packages. When I open my project, Visual Studio opens each package and validates it. This causes a connection to created to every database in the package in parallel! With our old SYBASE database, it simply gets overwhelmed when Studio tries to validate 50 packages all in parallel.
My only solution so far is to consolidate packages together - I've been taking 20-30 packages and combining them into a single monster package. This reduces the connections created and speeds up validation. However, this strikes me as unreasonable from a re-usability perspective as it reduces package modularity.
I've done a bit of searching around these settings and I haven't found any way to configure the way that packages are validated - if anyone knows of a way, put a comment up so I can be corrected!
From what I can see, there are two basic problems: 1) the need to repeatedly validate packages against the database; and 2) the assumption that each package gets its own connection to the database.
Problem #1: Validation
The basic problem with the speed issue seems to be its constant need to validate against the underlying database. For example by default:
I have a project where we're doing replication of tables from a SYBASE database to a SQL Server 2005 database. For each table, we've created a package. We now have 50-60 packages.
Every time you open up the project, it re-validates each package against both the SYBASE database and the SQL database. Each build re-validates. Each execute in Debug mode re-validates. Each run in production re-validates. All this validation on a slow database connection makes basic development tasks very slow.
The same thing happens when running the package in DTExec or through the SQL Agent - it pre-validates every package. This is both good and bad - its good in that it means it will fail your package before trying to execute some bad SQL or badly mapped columns, but given that you're going to run the same package over and over again without a change, there should be a way to turn off this step for packages that haven't changed.
I've looked around and haven't seen any method to change this behaviour - it would be great to have some more lazy validation, e.g. once I have validated it once, don't re validate unless I actually make a change to the package.
Problem #2: Data Sources
In an SSIS Project, there are data sources that you can define once as a common data source. However, there seems to be two problems with the data source model:
1. You cannot store an ADO.NET data source configuration as a shared data source - these have to be re-created in each package. Given how common these of connections are, this seems to me to be a big oversight.
2. Each package when its loaded creates its own connection to the database. Its very slow to create a connection and then tear it down especially with either a slow network or a slow database (e.g. an old legacy connection).
This causes problems for us with so many packages. When I open my project, Visual Studio opens each package and validates it. This causes a connection to created to every database in the package in parallel! With our old SYBASE database, it simply gets overwhelmed when Studio tries to validate 50 packages all in parallel.
My only solution so far is to consolidate packages together - I've been taking 20-30 packages and combining them into a single monster package. This reduces the connections created and speeds up validation. However, this strikes me as unreasonable from a re-usability perspective as it reduces package modularity.
I've done a bit of searching around these settings and I haven't found any way to configure the way that packages are validated - if anyone knows of a way, put a comment up so I can be corrected!