SQLDataSource parameter insertion: Sanitisation and formatting - asp.net

I am building a Web application and I want to allow users to insert records into a database. The method that I came across is to take the information from text boxes and run this code:
SqlDataSource1.InsertParameters["ProductCode"].DefaultValue = txtProductCode.Text;
SqlDataSource1.InsertParameters["Name"].DefaultValue = txtName.Text;
SqlDataSource1.InsertParameters["Version"].DefaultValue = txtVersion.Text;
SqlDataSource1.InsertParameters["ReleaseDate"].DefaultValue = txtReleaseDate.Text;
try
{
SQLDataSource1.Insert();
}
...
If I try to inject some SQL I get the error message:
Message: String or binary data would be truncated. The statement has been terminated.
Does this method sanitise the parameters? I am having a hard time finding this information because I am not sure if there is still a way to get around this error. If it does not how should I go about sanitising the inputs?
Additionally, the ReleaseDate parameter seems to be currently reading as dd/MM/yyyy but is there a way to lock this so that the same code on a different system doesn't behave differently. I am worried that if the code is run on a system with different regional settings it will use a different format.

One of your field in the table is not long enough to insert the value. You need to check each of ProductionCode, name, Version and ReleaseDate for their length and increase them accordingly.
http://msdn.microsoft.com/en-us/library/aa196741(v=sql.80).aspx

Related

Datetime.Now method in ASP.NET

I am using ASP.NET to provide some variables for the data that has to be added to a SQL database.
Code I am using:
I am using DateTime.Now to select the current time.
How I use it:
I have two pages, one is a page to insert the posts of the users. Other page is used for ajax purpose, to add some text comments to the posts.
In both page I use the same code.
But the code is executing different values. You can have a look here:
In the post the time is saved as "9/1/2013" which means 1st September, 2013! In comment it is saved as Sep 1 2013, which means the same.
My question: how does the code know that the request is an ajax one or the post one. The post page code is wrapped in if(IsPost) { however the comment is an ajax call.
What is the reason behind this?
I found what the issue was.
I had set the column DataType to nvarchar(50) in the database table. After editing it to DataType DateTime I was able to get the same result. So the issue was not the Culture or DateTime. It was the DataType of the column in SQL Server Database.
Assuming that your AJAX call is not changing the format string of your DateTimes, I would assume the threads which process those 2 different requests are operating under different cultures, which would explain why they're being displayed differently (not sure why though, check your settings perhaps). Try the following and you'll see how culture can effect DateTime output:
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
Console.WriteLine (DateTime.Now.ToString());
Thread.CurrentThread.CurrentCulture = new CultureInfo("gu-IN");
Console.WriteLine (DateTime.Now.ToString());
Here's some additional information on CultureInfo.
Code knows from Current thread's Culture information. You should use DateTime.Now.ToString("yyyy-MMM-dd") or any other formate according to your needs to be sure of output.

SqlDataSource erroring when retrieving NVARCHAR(max) column

I'm writing a small ASP .Net application in order to retrieve data from a SQL database. The application uses drop downs in order to select what the next drop down should contain and when a page is selected, it should retrieve the HTML from the database. Everything is working until it gets to the retrival of the HTML data. When I try to retrieve the data, I get:
Microsoft JScript runtime error:
Sys.WebForms.PageRequestManagerServerErrorException:
An unknown error occurred while
processing the request on the server.
The status code returned from the
server was: 500
The HTML column is a defined as NVARCHAR(MAX), but I can't see this causing a problem. The application works if I set the DataValueField to another column. Has one else come across a problem like this? Maybe someone could shine some light on this?
One thing I noted when dealing with varchar(max) columns is that the framework still commonly expects to have a size associated with it. What I ended up having to do was specify the length as -1 to get it to accept a varchar(max) field. Your error message doesn't indicate that this is the problem, but you might try experimenting with it rather than turning off the validation, which could possibly have other repercussions.
Figured it out. Just needed to set ValidateRequest to false at the Page level.

dates behaving differently on different dbs?

I have an asp.net webpage, with a jQuery datepicker on it.
I am in the UK, so when I enter 28/02/2010, I expect it to resolve to 28th Feb 2010.
This is working as expected on my local dev env - but not on our QA or prod-like envs - or one of the other dev machines. In these cases it seems to attempt to resolve it to American date format - and fails validation as it is out of range.
The jQuery seems to generate the correct date each time - which leads me to think it may be a database issue.
I am using SQL Server 2005, my collation is Latin1_General_CI_AS, my colleagues are using collation SQL_Latin1_General_CP1_CI_AS, and a Chinese one.
Given that we don't have control over the prod SQL Server installation (just our db), what is the best way to make this work in a standard way? Change the db settings, or the code that uses it?
Thanks in advance!
- L
[EDIT to add code info]
This is my view code to call the datepicker:
<%=Html.TextBox("DateOfBirth", Model.DateOfBirth.ToShortDateString(), new { #class = "datepicker" })%>
Here is the js for the datepicker:
DatePickerSettings = {
setup: function () {
$(".datepicker").datepicker({
dateFormat: 'dd/mm/yy',
changeMonth: true,
changeYear: true
});
}
};
And this is how I specify the date in the model:
[Required]
[DisplayName("Date of Birth")]
public virtual DateTime DateOfBirth { get; set; }
The date appears correct inthe controller and repository... until it hits the db.
Thanks :)
I was hoping to wait until you'd updated the question with some more information, but as I've seen some answers suggesting that you change the string format you use to talk to the database...
Don't send dates as raw text in SQL queries.
Use a parameterized query, which means you don't need to worry about formatting the value at all. Then you've just got to make sure that you can get the date format correct between the browser and ASP.NET.
Aside from anything else, if you're including user data in SQL queries directly, you'll generally be opening yourself up to SQL injection attacks. Always use parameterized queries (unless your web app is really a "run this SQL" test tool...)
If you're already using parameterized queries, then the problem is likely to be between the browser and ASP.NET, and the database part is irrelevant. Divide and conquer the problem: chase the data as it passes through different layers (browser, jQuery, ASP.NET etc) until you find out where it's gone wrong. Don't even think about a fix until you know where it's gone wrong.
Is your page Culture aware?
You can determine UI Cutlure information for different browsers(locales) and have your ASP.NET Culture constant.
The Culture value determines the results of culture-dependent functions, such as the date, number, and currency formatting, and so on. The UICulture value determines which resources are loaded for the page
Check out this MSDN link:
How to: Set the Culture and UI Culture for ASP.NET Web Page Globalization
http://msdn.microsoft.com/en-us/library/bz9tc508(v=VS.85).aspx
Use CONVERT to change the date format to a standard that is accepted across all environments.
CAST and CONVERT
I'd have to see the code that interprets the dates to know for sure, but a likely suspect is the Region and Language settings on the machines where the code is running. Make sure it is set appropriately for your region.
However, if you can't change settings on the servers, you should probably explicitly use CAST or CONVERT in SQL Server to force it to parse it in the region specific way you expect the data will be entered.
You also need to check your ASP.Net layer, and see what it is running in.
Check the machine configuration and check they are set to run in the same date/time/region.
Change your code to use yyyymmdd format.
As far as i know it works in all the DBs
Just to add another opinion here, I find dd/mmm/yyyy the best date format to send to databases as it's completely unambiguous across cultures.

Customize elmah.axd output fields

ELMAH shows host, code, type, error, user, date and time by default on its error log web page. Is there any way to configure it and show other fields like IP or REFERER?
(source: googlecode.com)
You could write your own error page. Bind a datagrid to ErrorLog.GetErrors() and use whatever columns you want:
List<ErrorLogEntry> entries = new List<ErrorLogEntry>();
ErrorLog.GetDefault(HttpContext.Current).GetErrors(0, 50, entries);
string ip = entries[0].Error.ServerVariables["REMOTE_ADDR"];
string referrer = entries[0].Error.ServerVariables["HTTP_REFERER"];
ELMAH is open-source. You can download the source and make any modifications you like (within the terms of the license, of course.)
You should be able to trap any data made available by the HttpConext.Request object. You'd have to modify the code that grabs and stores the data, and the database to make columns for that new data.

Downloading >10,000 rows from database table in asp.net

How should I go about providing download functionality on an asp.net page to download a series of rows from a database table represented as a linq2sql class that only has primitive types for members (ideally into a format that can be easily read by Excel)?
E.g.
public class Customer
{
public int CustomerID;
public string FirstName;
public string LastName;
}
What I have tried so far.
Initially I created a DataTable, added all the Customer data to this table and bound it to a DataGrid, then had a download button that called DataGrid1.RenderControl to an HtmlTextWriter that was then written to the response (with content type "application/vnd.ms-excel") and that worked fine for a small number of customers.
However, now the number of rows in this table is >10,000 and is expected to reach upwards of 100,000, so it is becoming prohibitive to display all this data on the page before the user can click the download button.
So the question is, how can I provide the ability to download all this data without having to display it all on a DataGrid first?
After the user requests the download, you could write the data to a file (.CSV, Excel, XML, etc.) on the server, then send a redirect to the file URL.
I have used the following method on Matt Berseth blog for large record sets.
Export GridView to Excel
If you have issues with the request timing out try increasing the http request time in the web.config
Besides the reasonable suggestion to save the data on server first to a file in one of the answers here, I would like to also point out that there is no reason to use a DataGrid (it’s one of you questions as well). DataGrid is overkill for almost anything. You can just iterate over the records, and save them directly using HtmlTextWriter, TextWriter (or just Response.Write or similar) to the server file or to a client output stream. It seems to me like an obvious answer, so I must be missing something.
Given the number of records, you may run into a number of problems. If you write directly to the client output stream, and buffer all data on server first, it may be a strain on the server. But maybe not; it depends on the amount of memory on the serer, the actual data size and how often people will be downloading the data. This method has the advantage of not blocking a database connection for too long. Alternatively, you can write directly to the client output stream as you iterate. This may block the database connection for too long as it depends on the download speed of the client. But again; it your application is of a small or medium size (in audience) then anything is fine.
You should definitely check out the FileHelpers library. It's a freeware, excellent utility set of classes to handle just this situation - import and export of data, from text files; either delimited (like CSV), or fixed width.
It offer a gazillion of options and ways of doing things, and it's FREE, and it works really well in various projects that I'm using it in. You can export a DataSet, an array, a list of objects - whatever it is you have.
It even has import/export for Excel files, too - so you really get a bunch of choices.
Just start using FileHelpers - it'll save you so much boring typing and stuff, you won't believe it :-)
Marc
Just a word of warning, Excel has a limitation on the number of rows of data - ~65k. CSV will be fine, but if your customers are importing the file into Excel they will encounter that limitation.
Why not allow them to page through the data, perhaps sorting it before paging, and then give them a button to just get everything as a cvs file.
This seems like something that DLinq would do well, both the paging, and writing it out, as it can just fetch one row at a time, so you don't read in all 100k rows before processing them.
So, for cvs, you just need to use a different LINQ query to get all of the rows, then start to save them, separating each cell by a separator, generally a comma or tab. That could be something picked by the user, perhaps.
OK, I think you are talking too many rows to do a DataReader and then loop thru to create the cvs file. The only workable way will be to run:
SQLCMD -S MyInstance -E -d MyDB -i MySelect.sql -o MyOutput.csv -s
For how to run this from ASP.Net code see here. Then once that is done, your ASP.Net page will continue with:
string fileName = "MyOutput.csv";
string filePath = Server.MapPath("~/"+fileName);
Response.Clear();
Response.AppendHeader("content-disposition",
"attachment; filename=" + fileName);
Response.ContentType = "application/octet-stream";
Response.WriteFile(filePath);
Response.Flush();
Response.End();
This will give the user the popup to save the file. If you think more than one of these will happen at a time you will have to adjust this.
So after a bit of research, the solution I ended up trying first was to use a slightly modified version of the code sample from http://www.asp.net/learn/videos/video-449.aspx and format each row value in my DataTable for CSV using the following code to try to avoid potentially problematic text:
private static string FormatForCsv(object value)
{
var stringValue = value == null ? string.Empty : value.ToString();
if (stringValue.Contains("\"")) { stringValue = stringValue.Replace("\"", "\"\""); }
return "\"" + stringValue + "\"";
}
For anyone who is curious about the above, I'm basically surrounding each value in quotes and also escaping any existing quotes by making them double quotes. I.e.
My Dog => "My Dog"
My "Happy" Dog => "My ""Happy"" Dog"
This appears to be doing the trick for now for small numbers of records. I will try it soon with the >10,000 records and see how it goes.
Edit: This solution has worked well in production for thousands of records.

Resources