Wednesday, April 29, 2009

Something has happened!

Neopets alum will appreciate the title, everyone else, not so much. Anyway, let's just say you want to alert someone of some thing, some event or happening. It could happen within Page_Init, Page_Load, or some custom function you wrote, such as MyFatButton_Click(). This is all asp.net, in case there was any doubt.

In my situation, I'm working in an order entry system where people first add items, and later in the process, add payments of check, credit card, etc. There is nothing that prevents them from going back several steps and removing items after payments are applied (but not submitted yet). This results in a negative order balance which is generally undesirable, as we do not want to owe people money or have to refund money.

The fix was to simply remove payments on a negative order balance. This was regarded as acceptable by the client, and if it's good with them, it's good with me. But they also wanted to let the user know that something has happened, e.g., their payment was removed. Here's the code for that:

(inside page_init, page_load would have worked fine as well, as far as I know):

System.Web.UI.ScriptManager.RegisterStartupScript(this, this.GetType(), "alertPaymentRemoved", string.Format("alert ('The payment(s) for this order have been removed.');"), true);

Some explanation might be helpful here. The ScriptManager allows you to inject some javascript at the time where it is useful to do so. The first argument, this, is a reference to the aspx page. Let me know if you have any questions.

Friday, April 24, 2009

Confirm alert box the e-z way

on your button or linkbutton, add the OnClientClick attribute with the following value:

OnClientClick="return confirm('Are you sure you want to delete this?');"
... />

Pretty easy, commonly requested, useful. There you go.

Thursday, April 23, 2009

Oh mother tell your children not to do what I have done

Don't do this: Have a panel that uses an ajax CollapsiblePanel from the Ajax Control Toolkit, hide it by default, and then put a textbox inside the panel, and then put a requiredfieldvalidator on the textbox, and Then: expect any of your buttons to work! The result is that when the page loads, none of your buttons will work because the validator's validatin', which is good, but you can't see the validator's error message because it's in your collapsed panel, which is bad.

Here's a little search engine fodder: Datalist linkbutton button not posting back.

Handy SQL script when creating sprocs

If you don't want to fuss with changing your stored procedure (sproc) script, specifically changing Create to Alter after the sproc has been created, use this handy snippet:


If exists(Select * from information_Schema.routines where specific_name = 'mySproc')
BEGIN
Drop proc [mySproc]
END
--(Create sproc script below)
--...


Change "mySproc" to the name of your sproc
This is especially nice when you've got a change script that just keeps growing and growing, and you don't want any interruptions when it comes time to run the script on a live environment.

Tuesday, April 21, 2009

What to do with a recently-migrated Access table that is now in your SQL database

The table in this case was a user info table called UserInfo, appropriately. I am using asp.net Membership, as well as a new table analogous to the UserInfo table, but with improvements (atomic storage of data, constraints, etc.) so I needed to create an entry in membership using the old table's email and password, and then create a corresponding entry in my user table using pretty much everything from the old table.

First, I needed to remove all of the superfluous duplicates, as email was to become a unique identifier in my new table (and act as the username in my Membership tables). These guys helped me out. They look like some good blokes. Anyway, I just wanted to delete the top 1 record in all the instances where there were 2 or more records containing the same email. My script looked like this:

DELETE TOP (1) FROM USERS
WHERE EMAIL IN
(
SELECT EMAIL FROM USERINFO
GROUP BY EMAIL
HAVING COUNT(EMAIL) > 1
)

The good thing about this script is also its flaw. It will only delete one record at a time where the email exists more than once, ensuring that you don't delete both of the records (you want to keep one!). Fortunately, there were only about 120 duplicates, and my simple and farily quick and effective solution was to just press "f5" 120 times. Done! I didn't want to mess with cursors when I can just monkey-push the button like I'm playing Track-n-Field at the local nickel arcade.

How would you have done this more elegantly?

Next, how to move data from one table to another table the E-Z way (or not).

How to migrate an MS Access table into a SQL Server 2005 database

With a little help from Google, I found a free tool that Microsoft makes and for my purposes, it worked ok. It is the SQL Server Migration Assistant 2005 for Access V4.0. Note that this requires you to get a "license". It's free also and I'm not sure why they do this, but so be it.

I had hoped this tool would move the data from an access table directly into a corresponding table in SQL Server. It did not do this. This is probably a simple case of user ignorance and I'm sure this tool is far more powerful than I understand. What this tool did instead is just copy the access table directly into the SQL database as a new table. Well, this certainly makes the table easier to work with if it's in the same database, so I was very happy to achieve this step, and so easily! I understand that Access has a migration tool, but I wasn't having a whole lot of luck with it.

Once the table was in my SQL database, that's when the fun began. What I did there is worthy of its own post.

Thursday, April 16, 2009

Bug #1234

In our web-based system, customers are not allowed to use post office boxes. We would check this with our "bulletproof" regular expression. Bulletproof means we haven't had any complaints. Until we did. Something along the lines of "Incident XXXX: Customer who lives on Post Office Road can't update her address information".

We ended up doing a special code-behind check specifically for this customer's address. Elegant? Nah. Hackish? The very essence of what a hack is. Did it work? Great! No problems reported since, and it's been months since this was implemented.

Tuesday, March 10, 2009

High-level structure of a well-designed web application in Visual Studio

I work in a .NET environment, using MS SQL databases and MS development tools. It's a fantastic environment to work in, but that's another topic for later. There is a pattern I have observed in web projects that are well-designed. They look something like this:

- Solution 'MySolution'
>>> MyLibraryProject.Web
>>> MyLibraryProject.Objects
>>>>>> Business (folder)
>>>>>> Data (folder)
>>> MyWebProject
>>>>>> (all the stuff contained in a web project, aspx and code-behind files, designer files, sitemap files, style sheets, images, etc.)

The gist is that there is a Web library for user controls and such, an Objects library containing a Business folder for business objects, and a Data folder for data adapters that map roughly one-to-one to the business objects (e.g., Customer.cs as the business object, and CustomerAdapter.cs as the data adapter for Customer.cs). Then you have the web project that's going to actually use the libraries in some fashion.

The data adapter is generally simply a call to a stored procedure and the addition of whatever parameters are required.

From testing to development

I have moved from testing to development in a very official manner, due to restructuring in our company. I've jumped from one platform to the next, and the previous one has disintegrated. There's no going back. This decision was made in September of last year, and so far, so good. My goal was development, and I used my testing position and my insistence on getting involved in actual coding, and the help of a series of fortunate (for me) events, to achieve my goal.

Now I just have to get excellent fast. No problem.