Replace huge Case statement in Classic ASP - asp-classic

I have a 200+ case statement in Classic ASP which is getting out of control. It sets 5 variables, based on which case is selected. Address, Phone, Name etc. Just sets the variables and nothing else in each case.
Databases or files are not an option for this application.
Coming from the Perl world I would use a hash to store this info.

Brian, the classic ASP equivalent of a Perl hash is the Scripting.Dictionary object.

Getting out of control? I think it's already out of control!
Can you not categorise the cases into 'x' general areas and split down into helper routines?

Depends on what you want for performance.
The case statement is ugly but does not consume memory that would need to be allocated.
However, you could create a class for your fields and load instances of them into a Dictionary. Perform this operation in the global.asp script so it only happens once. Store the dictionary in the global asp collection such that it is only allocated once but used with each page call.
My appologies for not getting too specific here... it's been a while.

A lot of people use VBScript for Classic ASP, but you can use JavaScript / JScript on the server as an alternative. As a matter of fact, this is my preferred way of doing Classic ASP before finally moving to .NET (except in some cases, you will have to mix in VBScript for special cases, i.e. Disconnected Recordset, ExecuteNoRecords, etc.). It will provide you with better OOP support vs VBScript. Maybe you can try refactor that to.some sort of Strategy pattern afterward. Worth looking into I guess for better maintenance in the long run.

The fact that you can't migrate this over to a database or a text file is a bit of an issue as they would be the best solution for this type of data. However, if you have to have it in the code you could always try putting it into a matrix that you predefine. Then you could provide a function that returns the data from a given row in the matrix.

Scripting dictionary is the best option IMHO.

This should be done with a database, but since you said that is not an option, nothing you will write will be any less complex than a switch statement, since it's all required to live in your code (according to your terms of no db and no files).
I mean, you could use an Excel Spreadsheet if the idea of a database is too complicated but technically that would be a file as well!

Related

Classic ASP - Detect line number and file from which a function is called?

Our application is made in good (?) ol' classic ASP. Not ideal but it works and it's pretty stable - has been for 10-15 years. It is not particularly well documented in places, such as where a 'translation' (client-controlled piece of text) appears. All we have against a translation is a clientid and translationid, neither of which are particularly helpful. I've tried searching the (10s of thousands of lines of) core code for gettrans(1) (translation 1) and can see that doing this for another 3100 is going to be a nightmare, not to mention inaccurate as there are many functions which are called with a transid passed into them, and then they call gettrans(transid).
My last thought on this matter is the possibility that we could maybe detect, from gettrans, where a function is called from - not just the line number but the file name of the include (thankfully the includes are named usefully so figuring out where a translation is used should not be too hard!). I highly doubt that it would be possible to get the include name on the basis that includes are processed before ASP, but I'll settle for the overall filename and then we can combine the includes to get to the line of code and log the include file name.
I very much doubt this is possible and can't find anything on SO or Google. Does anyone know of any way to achieve this, or have any pointers on what I might try? Thanks in advance.
Regards,
Richard
Most you can achieve is getting the currently executing script, which can be obtained by:
Dim currentPage
currentPage = Request.ServerVariables("SCRIPT_NAME")
When inside included page it will give you the "parent" page.
However getting "callee" information is not possible with classic ASP as far as I know, so you will have to add another parameter to the function being called then change all calls to pass the parameter in order to identify where it comes from. Looks like someone did something similar and called it ASP Profiler, use it at your own risk of course. (Never tried myself)

Is there a utility for finding SQL statements in multiple files and listing any referenced tables and stored procedures

I'm currently looking at a terrible legacy ColdFusion app written with very few stored procedures and lots of nasty inline SQL statements (it has a similarly bad database too).
Does anyone know of any app which could be used to search the files of the app picking out any SQL statements and listing the tables/stored procedures which are referenced?
Dreamweaver will allow you to search the code of the entire site. If the site is setup properly including the RDS password and provide a data source it can tell you a lot of information. I've only set it up once so I can't remember exactly what information it gives you, I think maybe just the DB structure. Application window > databases. Even if it isn't set up properly just searching for "cfquery" will quickly find all your queries.
You could also write a CF script using CFDirectory/CFFile to loop the .cfm files and parse everything between cfquery and /cfquery tags.
CFBuilder may have some features like that but I'm not to familiar with it yet.
edit I've heard that CFBuilder can't natively find all your cfqueries that don't have cfqueryparam but you can use CF to extend CFB to do so. I imagine you could find/write something for CFB to help you with your problem.
another edit
I know it isn't indexing the contents of the query, but you can use regex to search using the editor as well. searching for <cfquery.+(select|insert|update|delete) checking the regex box should find the queries that aren't using cfstoredProc (be sure to uncheck the match case option if there is one). I know Dreamweaver and Eclipse can both search for Regex.
HTH
As mentioned above I would try a grep with a regex looking for
"<cfquery*" "</cfquery>" and "<cfstoredproc*" "</cfstoredproc>"
In addition if you have tests that have good code coverage or even just feel like the app is fully exercised in production you could try turning on "Log Database Calls" in Admin - > Datasources or maybe even at the JDBC driver level, just monitor performance to make sure it does not slow the site down unacceptably.
In short: no. You'd have to do alot of tricky parsing to make sure you get all the SQL. And because you can glob SQL together from lots of strings, you'll almost always miss some of it.
The best you're likely to do will be a case insensitive grep for "SELECT|INSERT|UPDATE|DELETE" and then manually pulling out the table names.
Depending on how the code is structured, you might be able to get the table names by regexing the SQL from clause. But that's not foolproof. Alot of people use string concatenation to build SQL statements. This is bad because it can introduce SQL injection attacks, and it also make this particular problem harder.

Handle database look-up values in ASP.NET application

Almost all the applications I worked on involve some look-up values. For example, a lot of times a list of languages ( English, French, etc...) need to be displayed on the WebForm for user to choose.
The common data structure for such look up values include an integer Id and a string as name. Since these look-up values are used so frequently, and they are unlikely to be changed. Most of time, instead of grabbing them from database, I just define a global enum in C# like this
enum Language : int { English = 1, French = 2}
I've been handling look-up values like this for years now. I knew it may not be the best way to handle them. For example, every time a new language is added to the system, somebody needs to remember to update that enum.
I guess this is a very common scenario, just wondering how you guys handle this type of look-up values.
Thanks,
I usually put them int he database anyway, because you never know if and when they'll need to change. There have been times when - by design - I know that the list will not change, and for those, I will use enums instead. All other cases, I will use a database table.
Depending on the data requirements, I typically handle small lookups like that in a configuration file often loaded singularly to be applied as an application variable for all instances of the app. The data is looked up once when the application is started or recycled and then remains useful until it is dead.
Although, I have a lot of intermediate data of similar nature that requires regular maintenance. It is easier to put this into a database because at least then you can build a small maintenance application to handle it. If you put them in an enum, you have to recompile and redeploy.
I ran into a similar issue with resource files. Since resource files are compiled, they require another redeployment.
You may benefit from T4 Templates. I haven't used these yet because we haven't had a requirement to meet the need, but I'd like to use them eventually.
Here's a great article for generating enums from a database table (the code is hard to read on the page, there is a link to the source at the end of the article):
http://www.thecodejunkie.com/2008/11/generate-enums-from-database-using-text.html
Also, Scott Hanselman has a list of great T4 templates/articles on his blog.
T4 Templates on MSDN

How to write a database class that supports parameterized queries

I'm a former classic ASP programmer and sometimes PHP programmer writing my first ASP.NET application. I'm loving the much-improved ADO.NET functions, but I'm feeling the need to write a database class. Partly I want to consolidate the code that actually interacts with the database, and partly I want to reduce what feels like repetition.
A simple database class is not hard to do, but I'm using parameterized queries as one of my security measures. I'm struggling with how to incorporate this into a class. I wrote a function to return the datatype of a column in the database by passing in the table and column name, but I can't think of a robust way to obtain the table and column name from the SQL query.
My design for the class was to have a Query() function for selecting, and an Execute() function for insert/update/delete. (Not opposed to having more public functions, but didn't want to get ahead of myself.) Both functions take a SQL string and a SortedList for the parameters. It might be possible to get the column name by finding the parameter name in the SQL string and looking in front of the equal sign. Likewise, it should be fairly simple to get the table name when the query is insert, update, or delete, because you only work with one table at a time. The big concern is selecting, because there could be one or more joins, inner selects, etc.
Am I headed in the wrong direction? Anything I'm not thinking of that could make my life easier or more difficult? Anybody written a class for this in any language that could offer some advice?
Don't reinvent the wheel. Look into nHibernate or LINQToSQL (or LINQToEntities) for your ORM needs.
Would second the call to find a tried and tested wheel that works for you, especially if this is your first foray into aspnet... there will be plenty else to keep you busy.
Would add a suggestion for SubSonic, which is perhaps a little lighter than nHibernate, but it really depends on the nature of your project, they are both great tools, and both have saved me months of work over the last few years.
I think since this is your first experience in ASP.NET you would be well advised to look into Linq to SQL. Do some tutorials so you get a feel for how it works before you try to code any Linq queries.
The only reasons I can think of to NOT use Linq to SQL in your case would be if you are not using SQL Server (or need to support other DBs either now or in future), or you cannot use .NET 3.5 runtime for some reason.
Good luck
It sounds to me like your "simple database class" is hiding too many details from the classes that need to use it.
I've written classes that contain a SqlCeEngine and expose methods like "LookupDescription(String Code)" ... I think that kind of design is something you should be looking into. And, consider looking into LINQ. It has a lot to offer.

How do you use Excel server-side?

A client wants to "Web-enable" a spreadsheet calculation -- the user to specify the values of certain cells, then show them the resulting values in other cells.
(They do NOT want to show the user a "spreadsheet-like" interface. This is not a UI question.)
They have a huge spreadsheet with lots of calculations over many, many sheets. But, in the end, only two things matter -- (1) you put numbers in a couple cells on one sheet, and (2) you get corresponding numbers off a couple cells in another sheet. The rest of it is a black box.
I want to present a UI to the user to enter the numbers they want, then I'd like to programatically open the Excel file, set the numbers, tell it to re-calc, and read the result out.
Is this possible/advisable? Is there a commercial component that makes this easier? Are their pitfalls I'm not considering?
(I know I can use Office Automation to do this, but I know it's not recommended to do that server-side, since it tries to run in the context of a user, etc.)
A lot of people are saying I need to recreate the formulas in code. However, this would be staggeringly complex.
It is possible, but not advisable (and officially unsupported).
You can interact with Excel through COM or the .NET Primary Interop Assemblies, but this is meant to be a client-side process.
On the server side, no display or desktop is available and any unexpected dialog boxes (for example) will make your web app hang – your app will behave flaky.
Also, attaching an Excel process to each request isn't exactly a low-resource approach.
Working out the black box and re-implementing it in a proper programming language is clearly the better (as in "more reliable and faster") option.
Related reading: KB257757: Considerations for server-side Automation of Office
You definitely don't want to be using interop on the server side, it's bad enough using it as a kludge on the client side.
I can see two options:
Figure out the spreadsheet logic. This may benefit you in the long term by making the business logic a known quantity, and in the short term you may find that there are actually bugs in the spreadsheet (I have encountered tons of monster spreadsheets used for years that turn out to have simple bugs in them - everyone just assumed the answers must be right)
Evaluate SpreadSheetGear.NET, which is basically a replacement for interop that does it all without Excel (it replicates a huge chunk of Excel's non-visual logic and IO in .NET)
Although this is certainly possible using ASP.NET, it's very inadvisable. It's un-scalable and prone to concurrency errors.
Your best bet is to analyze the spreadsheet calculations and duplicate them. Now, granted, your business is not going to like the time it takes to do this, but it will (presumably) give them a more usable system.
Alternatively, you can simply serve up the spreadsheet to users from your website, in which case you do almost nothing.
Edit: If your stakeholders really insist on using Excel server-side, I suggest you take a good hard look at Excel Services as #John Saunders suggests. It may not get you everything you want, but it'll get you quite a bit, and should solve some of the issues you'll end up with trying to do it server-side with ASP.NET.
That's not to say that it's a panacea; your mileage will certainly vary. And Sharepoint isn't exactly cheap to buy or maintain. In fact, short-term costs could easily be dwarfed by long-term costs if you go the Sharepoint route--but it might the best option to fit a requirement.
I still suggest you push back in favor of coding all of your logic in a separate .NET module. That way you can use it both server-side and client-side. Excel can easily pass calculations to a COM object, and you can very easily publish your .NET library as COM objects. In the end, you'd have a much more maintainable and usable architecture.
Neglecting the discussion whether it makes sense to manipulate an excel sheet on the server-side, one way to perform this would probably look like adopting the
Microsoft.Office.Interop.Excel.dll
Using this library, you can tell Excel to open a Spreadsheet, change and read the contents from .NET. I have used the library in a WinForm application, and I guess that it can also be used from ASP.NET.
Still, consider the concurrency problems already mentioned... However, if the sheet is accessed unfrequently, why not...
The simplest way to do this might be to:
Upload the Excel workbook to Google Docs -- this is very clean, in my experience
Use the Google Spreadsheets Data API to update the data and return the numbers.
Here's a link to get you started on this, if you want to go that direction:
http://code.google.com/apis/spreadsheets/overview.html
Let me be more adamant than others have been: do not use Excel server-side. It is intended to be used as a desktop application, meaning it is not intended to be used from random different threads, possibly multiple threads at a time. You're better off writing your own spreadsheet than trying to use Excel (or any other Office desktop product) form a server.
This is one of the reasons that Excel Services exists. A quick search on MSDN turned up this link: http://blogs.msdn.com/excel/archive/category/11361.aspx. That's a category list, so contains a list of blog posts on the subject. See also Microsoft.Office.Excel.Server.WebServices Namespace.
It sounds like you're talking that the user has the spreadsheet open on their local system, and you want a web site to manipulate that local spreadsheet?
If that's the case, you can't really do that. Even Office automation won't help, unless you want to require them to upload the sheet to the server and download a new altered version.
What you can do is create a web service to do the calculations and add some vba or vsto code to the Excel sheet to talk to that service.

Resources