How to catch multiple sql exception? - asp.net

There are two unique fields in my database and it is possible the user will try to add a value which already exists in one (or both) of these columns via my webpage. Quite literally, there are 2 textboxes and these will refer to the 2 columns in SQL.
I would like the error caught and show the user which word (or words) was not allowed where a duplicate would be created.
SQL prevents me entering the duplicate, but, it will error on the first attempt. Meaning, if the user tried to enter 2 words and both were duplicates, SQL would error on the first textbox, meaning the user could update textBox1 value, try and again and then be told off about the second textbox. This is not good for the user as it's slow but I don't know what the best approach is.

In my opinion your last defence is the database! You should be preventing the query getting there!
For me, I'd query the database and retrieve the 2 values of all rows for just these 2 columns.
Then, when a user tries to submit, I'd check the list to see if it exists. This means no exception is thrown. I can then decide how to display this information to the screen.
Of course, this is great depending on how many rows you have, if you had millions maybe this isn't so good and you may want to ping the database first using a scalar variable to see if the value already exists!

SqlException are quite verbose and u will get a full stacktrace instead of a few particular fields what caused the exception.
Also sometimes SqlException wouldn't specify enough like in case of hitting a stored procedure which fails internally ..
The best idea would be to do all kinds of validations for the field values, FK constraints, not null checks, etc before hitting the DB.
Hitting the db and then letting the user know due to some exception is not at all advised as is a big performance bottleneck.

Related

Error handling for query string parameters -1%27, getting bombarded

I am not an expert, but not a rookie either. I'm using Asp.net webforms. I set up an error catching routine in global.asax to log the error info in an SQL table and redirect to a friendly error page. I began finding hundreds of exceptions per day with this in the query string "?id=-1%27". I use query strings for items and categories but only allow integers of 3 digits or less. Then I started geo-locating the IPs. The vast majority of them are from Russia and surrounding countries. So I started storing all of the IPs in a table. Is anyone else experiencing this and how best to handle it. I want to catch legitimate errors, but this is a major annoyance. Any input would be appreciated. I have Googled for 2 days and can't find anything related specifically to this issue.
The %27 is ASCII for the single quote (') and that is a red flag for someone trying to perform SQL injection via the query string to your application's data access layer logic.
I would be less concerned about where the attacks are coming from and more focused on techniques for protecting/processing your data before it is even attempted to be used by your data access layer and data storage (read: database).
Using parameterized SQL and data sanitation (read: white-listing allowable text for strings) is a great first step in combating these attacks.
UPDATE
It might be worth considering creating a custom exception for the invalid ID value being passed in as part of the query string. You can then test for the length being greater than three and throw that custom exception. Elsewhere you can catch/trap that custom exception type and do whatever you wish with that (read: potentially ignore that exception if it is becoming too large of annoyance). Please understand that I would never advocate ignoring exceptions (empty catch block), but merely stating that is possible to do such a "bad" thing.

NHibernate Session.Load or Session.Get

I have an idea of Session.Load and Session.Get but would like to know its real time implementation. Suppose there are Company and Location tables with n:1 relationship. In the Company edit page, user selects a location and submits the page. By using below code, it gets attached without hitting the db.
cust.Location = session.Load<Location>(selectedlocationid)
But meanwhile, if another user deletes the location during this period, exception might occur. This situation may even occur with ADO.NET/Entity framework since we just update the id's without checking existence.
I would like to know generally how to update for this simple scenario. Since web application has disconnected architecture, is it ok to just ignore such possibility and go-ahead with "Load" (or) hit the db using "Get" and check for nulls and proceed.
You cannot lock rows before deleting since there may be a lot of delay between viewing a row for delete and actually deleting the row.
Not locking the row is optimistic concurrency.
At the database level implement your foreign key relationships so that it would not allow relation to a deleted row. That way, your code would raise an exception if someone deleted the row.
You could catch that exception and alert the user accordingly.

About the GridView control in asp.net

I'm working on a web application, on one page I am inserting records in the database and I want to display the data in a GridView but on a diffrent page. How can I do this?
I know how to display records in a GridView, but I want to know if there are two web pages,
on one page provides the facility to insert the records and U want to display the records in the GridView bit on the second page.
While it is possible to retain the data being inserted without retrieving it from the database, I think it is better to save the data on the first page and retrieve it from the database on the second page.
You can do this by writing inline SQL or a stored procedure. One simple approach would be to pass the resultset into a DataTable and bind a GridView to that.
That does involve more work -- more code and more trips to the database. However, I think it is very useful when performing INSERTs that the web page is updated to display what actually got into the database. Sometimes, this is different from what the user thinks they entered, and they can see the problem immediately.
One question would be how to identify the data that has just been inserted. I can think of several ways to do that. One is to query for all records entered today by the person logged in (which is recorded in the CreatedBy and CreatedDate columns of the database tables). Sort the resultset in descending order of CreatedDate, so that the most recent entries appear at the top of the GridView. Another would be by assigning a batch number to the data entry and retrieving only the data in that batch.
If you really want to hang on to the data entry, you could put it into Session on the first page, and then retrieve it from Session for display on the second page.
Following along the lines of what DOK said, it's also a lot easier to validate data entered by your users in your business logic before you submit it to the database.
Secondly, users can change their minds about data on a webpage frequently. The data on the web could be in an partially-finished state or could have typos or errors in it. If someone else saw this data and believed that it needed to be completed, then you could end up with duplicated entries in the database that would then require reconciliation.
Honestly, your best bet is to use the Session object to hold temporary user data. The MSDN entry for the GridView RowEditing event contains some great source code for this approach. Whenever I have to use GridViews to handle data from the database, I mimic this.
In addition to handling problems with temporary data storage, you can compare the Session object to your database results to determine whether or not new rows have been inserted. This is somewhat costly as it involves overloading the Equals method (and GetHashCode as well, if you follow what Microsoft recommends) and using Equals to iterate over the two collections, comparing the properties of both objects, and determining which records are new based on records that don't exist in your Session object, but do exist in your database object.
It's also worth noting that this approach assumes that you don't delete data from your database, but set the status of a record in your database to "Deleted" -- if that's a boolean field or an sequence of codes you use to describe the state of rows in a table.

Primary keys on webforms (load initially or on save)?

This is just a general question irrespective of database architecture.
I am maintaining an ASP.NET web application. The structure is such that,
Say on 'Add a new employee' webform
The primary key (or the record id to
be saved with) is initially loaded on form
load event & displayed as a label
So when the form loads, the record id to save with is shown to the user
Positives:
End user already knows what the id/serial of the form is (even before he saves the form)
So on form save when he is directed
to gridview screen (with all entries)
he can search records easily
(although the most recent one is at
the top anyway)
Negatives:
If he does not save the form, say he
just cancels after loading the data entry form,
the id/key initially fetched is
wasted (in my case it is a sequence
field fetched on form load from database)
What do you guys do in these scenarios ? Which approach would you recommend for 'web applications'? And how to facilitate the user with a different approach ? Is our current approach recommended (To me,it wastes the ids/sequence from database)
I'd always recommend not presenting the identity field value for the record being created until the record has been created. The "create a temporary placeholder record first to obtain the identity field value ahead of time" approach can, as you mention, result in wasted IDs, unless you have a process in place to reclaim them.
You can always pop-up a message box when the user presses save that tells them the identity field value of the newly created record.
In this situation you could use a GUID created by the application itself. The database would then only have the PK set to be a Unique Identifier (GUID) and that it must not be null. In this situation you are not wasting any unique keys as each call to get a new GUID should be definition produce a (mathmatically) unique identifier. It is worth noting that if you use this method, it is best to make sure your PK is not set up to be clustered. The resulting index reorganisation upon insert could quickly result in an application that suffers performance hits.
For one: I wouldn't care so much about wasted id values. When you are in danger of running out of int32 values (and when has that happened to you last?), use int64. The user experience is way much more important than wasting a few id values.
Having said that, I would not want the primary key to be anything the user would want to type in. If you are having a primary key that users need to type in, chances are it then is (or will be requested to be) more than just an int32/64 value and carries (will carry) meaning in its composition and/or formatting. Primary keys should not have that. (Tons of reasons google for meaningless primary keys or other such terms).
If you need a meaningful key, make it a secondary index that is in no way related to the primary key. If a part of that is still a sequential number taken from some counter value in your database. Decide whether functionally it is a problem for gaps to appear in the sequence. (The tax people generally don't want gaps in invoice numbers). If functionally it is no problem, then certainly don't start worrying about it technically. If functionally it is a problem, then yes, you have no option but to wait for the save in order to show it to the user. But, please, when you do, don't do it in a popup. They are horribly intrusive as they have to be dismissed. Just put up an informative message on the screen where the user is sent after (s)he saves the new employee. Much like gmail is telling you about actions you have performed just above the list of messages.

Allowing nulls vs default values

I'm working on an ASP.NET project that replaces many existing paper forms. One of the requirements is that the user can save the form in any state, i.e. they could create a new blank form and immediately save it with no data or with partial data. I'm validating for data type on every save but validation for required fields does not occur until the user marks the form as completed.
I'm not sure what the best approach is to handle this requirement in the database and domain model. As I see it, I have two options:
Allow nulls for any field that may not have data. This feels like the "correct" approach but it requires that almost every database field allow nulls and I have to code around a lot of nullable types. Also, when the form is finalized none of the required fields are enforced in the database.
Populate my business objects with meaningful default values. In some cases, there are meaningful default values for many (but not all) fields that I could use. This approach verges on "magic numbers" which makes me uncomfortable.
Which approach is best? Or is there a third way? I'm not willing to go to extremes, such as splitting the tables.
Edited to add: I wanted to expand on this a bit since I accepted a response. The primary reason that I'm not interested in splitting the tables is that once a project is submitted, the data on the forms is used to generate data for another system that is the system of record. At that point the original form data is unlikely to be revised or used for reporting.
I don't understand why you don't want to split the tables. I don't know what domain you're in but in any I could imagine there are two classes of people:
people who have submitted the form
people who haven't
And as a business executive I don't care about the second. But the first I care deeply about, and they need to have all their data in correctly.
It also improves efficiency - most of your queries about aggregate data will be over the first table, not the second. The second table will only be used for index seeks.
If splitting the table(s) (are there more than one?) is not an option, I would consider creating single table to store serialisations of objects of incomplete forms, and only commit a form to the "real" tables when the form is fully submitted by the user.
If there isn't a sensible default, and you don't want to split the data, then nulls are almost certainly your best option. Re the db not being to verify that they are not null when completed... well, if you don't want to split the table there isn't much you can do (short of using a CHECK constraint, or an INSTEAD OF trigger to run validation). But the DB isn't the only place responsible for data validation. Your app logic can do that too.
You could use a temporary table with "allow nulls" on every column to store the form containing partial or no data and copy / move the data to the final table when the user marks the form as completed. This way, you do not depend on default values (which the user may forget to change), you can save in any state, and you still have the validation in the end.
This is a situation that cries out for split tables. I know you said you don't want to do that, and in a comment even said "this project doesn't warrant that level of effort". but it's really the best solution.
Set up preliminary table(s) with everything except your key nullable. When the user marks the form complete, and it passes validation, move it to the final table(s). not only is this The Right Thing To Do, but it's probably less effort than "coding around nullable values" when working with finished forms.
If you need to see all forms, finished or not, make a Union view.
I'd take the first option but add a column to the database tables so that when the form is completed this is flagged. Then for anything using the form data it merely needs to check that the form has been completed.
That's my suggestion for a way around this.
NULL values are not searchable by the indexes.
If you'll need to issue a query like "select first 10 forms with a certain field unfilled", this query will use a FULL TABLE SCAN which may be not efficient.
Oracle does not distinguish between NULL and empty string, but other databases do. You'll probably want to make an empty string to be the DEFAULT for unfilled fields and use it in a search.
If you don't need to search on unfilled fields, then just make them NULL.
NULL generally means "Don't Know" (in a database) whereas an empty string could actually represent an empty string.
I would tend to use NULL as the "Don't Know" value in your case. When you print out data you'll just have to assume that any NULL value means an empty string.
CHECK CONSTRAINT + VIEW
if you don't have a status field add one so you can tell that it is finished.
add a check constraint on that status field so it can't be marked finished if any of the columns are null.
When you write your queries on "finished" forms you can ignore checking for nulls everywhere if you do one of these two options:
just add Status="F"inished in the where clause
make a view of only finished ones
when using the "finished view" you don't have to do all the validation checks or worry about unfinished ones showing up in the results
I've had a similar situation, and while I haven't yet come up with a solution, I have been toying with the idea of just using simple XML serialization to store the temporary document data. If you generate simple classes that model the data in the objects (using nullable types where needed, perhaps), it would be easy to stuff data from the screen into those objects, serialize them to XML and then store them in a temporary "staging" table. When your users are done working and want to submit or finalize the document, then you perform all of your needed validation against the serialized data, eventually putting into the "real" table with the proper data structures and constraints.

Resources