.NET ObjectDataSource ignores culture information when inserting and updating
It’s been ages since I last updated my blog and I’m feeling super guilty.
So I thought I’d get stuck into it again and start with a whinge – a whinge about something that had me stumped for way too long this morning.
I have to say that I hardly ever use the out-of-the-box ASP.NET server controls (like asp:DropDownList, asp:TextBox, asp:DataGrid, etc etc) because I prefer to use standard HTML controls, stick runat=”server” tags on them and handle them manually. Call me old-fashioned, tell me I’m doing it the “hard” way… I don’t care. It works and I know how to do it quickly. I always find that when I use the more complete and complex server controls, I get 95% of the work done quickly and then spend hours trying to get the last 5% to work. I don’t like that very much.
Anyway, sometimes I end up having to use a variety of these server controls and today was one such day. Everything was going swimmingly until I tried to insert / update a DateTime property on the type that I had bound my ListView control to, using an ObjectDataSource. I’m in the UK and here, we do not use US-formatted dates. For some reason, no matter where I put localization code to set the locale to “en-GB”, when I hit my “Save” button, my code would throw an exception because it could not convert the string representation of the date into a DateTime object. That’s because it was trying to convert it to an American date. Grr!!!
After a lot of Googling, I came across this article. And there was the answer I was looking for.
Turns out that this is a known bug since ASP.NET 2.0 that Microsoft have decided they “won’t fix”. WTF. They’ve decided not to fix it because ”... the potential fix is relatively dangerous and the workaround is relatively simple…”.
The bug occurs because behind the scenes, .NET is calling ConvertFromInvariantString on all the new values – which is the “en-US” culture. This is clearly a massive assumption on their part but alas, it seems it is “too risky” to fix this.
The “simple workaround” they suggest is to handle the OnItemInserting and OnItemUpdating or OnRowUpdating events and in those handlers, extract the date values from the EventArgs, parse them from strings into DateTime objects and save them back. The following is an example of how one might do this:
1 2 3 4 5 6 7 8 9 10 11 | private static void MyList_ItemInserting(object sender, ListViewInsertEventArgs e) { var myDate = e.Values["MyDate"].ToString(); e.Values["MyDate"] = DateTime.Parse(myDate); } private static void MyList_ItemUpdating(object sender, ListViewUpdateEventArgs e) { var myDate = e.Values["MyDate"].ToString(); e.Values["MyDate"] = DateTime.Parse(myDate); } |
I realize this is not a hard fix – but the annoying part was figuring out why it was happening in the first place!!
Anyway, I hope this whinge helps someone else solve this problem… :)
Read MoreHow to make a text string fit your labels in .NET
In my chosen career, I solve problems everyday. Sometimes the problems I’m given are small and simple to solve, and sometimes they are most definitely not. That, I can deal with. What annoys me is when a problem seems like it should only take five or so minutes to solve and yet somehow, it takes you all day. It’s not that you’re bad at what you do, it’s just that the thing you’re trying to do wasn’t quite as simple as you or anyone else had thought it would be. Or perhaps the framework you’re working with has some nasty little quirks that you weren’t aware of. Or perhaps the thing you’re trying to do just hasn’t been done before, or at least hasn’t been well documented. Whatever the reason, spending all day on a “simple problem” isn’t good for your sanity and makes you feel like you ought to be doing COMP101 all over again.
One such problem that I’ve come across more than once in the last few weeks is how to make a text string fit inside a label or other similar control. If the string is too long to fit, the end should be truncated and replaced by an ellipsis. Sounds pretty straightforward eh? Nope, think again.
After coming up with a few complicated solutions including but not limited to iterating through every character in the string and measuring the length of the string (yes, highly inefficient, I know!), I finally found a solution which seems to do the trick. I feel this amazing solution needs to be shared with everyone so here it is:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | private string textToDraw = "Hello, how are you? Why does this string not fit in the label that I have drawn? Maybe it is because it is too long?"; public Form1() { InitializeComponent(); label1.Text = ShortenString(textToDraw, this.Width - 10, label1.Font); } public string ShortenString(string myString, int width, Font font) { string result = string.Copy(myString); TextRenderer.MeasureText(result, font, new Size(width, 0), TextFormatFlags.EndEllipsis | TextFormatFlags.ModifyString); return result; } private void Form1_ResizeEnd(object sender, EventArgs e) { // Set the width to something - I've just set it to the width of the form - 10 to allow for the ellipsis but // I guess this would need to depend on which control the label is to be displayed inside of int width = this.Width - 10; label1.Text = ShortenString(textToDraw, width, label1.Font); } |
The trick to solving this problem was to use the TextRenderer class and calling its MeasureText function. MeasureText doesn’t seem like the most obvious function to use but it seems to work.
Note that this example is for a C# winforms application. The same could be done for a web application although you’d have to use JavaScript to re-calculate the string when the browser or element is resized.
Has anyone else ever had to solve this particular problem? If so, I’m interested to hear how you did it!
Read MoreHow to populate a drop down list from an XML file in .NET
I know this is not rocket science but it’s actually something I’d never had to do until recently. Normally I populate my drop down lists (and repeaters, etc etc) using data from databases, not XML.
However, fear not. Using XML as a datasource in .NET is super easy. Here is one way to do it:
1 2 3 4 5 6 7 8 | XmlDataSource source = new XmlDataSource(); source.DataFile = Server.MapPath("Values.xml"); source.XPath = "ParentElement/ValueList/ValueItem"; myDropDownList.DataSource = source; myDropDownList.DataTextField = "Text"; myDropDownList.DataValueField = "Value"; myDropDownList.DataBind(); |
And your xml file, Values.xml, may look something like:
<?xml version="1.0" encoding="utf-8" standalone="yes" ?> <ParentElement> <ValueList> <ValueItem Text="Item 1" Value="1" /> <ValueItem Text="Item 2" Value="2" /> </ValueList> </ParentElement> |
Happy coding!
Read MoreHow to develop secure .NET applications using Server SSL Certificates and Client Certificates – PART 4
The following article is part 4 and therefore the last in a 4 part series of articles about developing .NET applications using SSL. Part 1 in this series can be found here, part 2 can be found here and part 3 can be found here.
How to set up a web application to automatically redirect to HTTPS if accessed via HTTP when SSL is required
SSL can be “required” at the site level, folder level or even file level.
If any file that has SSL set to “required” is requested via HTTP, HTTP Error 403;4 “Forbidden” will be returned automatically by IIS. As far as I can tell, there is no simply way to tell IIS to re-direct to the same page via HTTPS. This effect can be achieved in two different ways and if “defence in depth” is the preferred approach then both solutions can be implemented together. Note that both solutions require custom code to be written however.
Redirect with IIS and code:
- Create a new Web Form (aspx) in your Web Application called RedirectToSSL (or similar).
- In the Page_Load event handler, insert the following code:
1 2 3 4 5 6 7 8
string redirectUrl = HttpContext.Current.Request.Url.Query; redirectUrl = redirectUrl.Substring((redirectUrl.LastIndexOf(';')+1) , redirectUrl.Length - (redirectUrl.LastIndexOf(';')+1)); System.UriBuilder secureUrlBuilder = new System.UriBuilder(redirectUrl); secureUrlBuilder.Scheme = System.Uri.UriSchemeHttps; secureUrlBuilder.Port = -1; // Use default port HttpContext.Current.Response.Redirect(secureUrlBuilder.Uri.ToString(), true);
- The aspx needs to be at least 512 bytes, otherwise IIS won’t redirect to it. So make sure you don’t delete everything out of it, it should never get displayed anyway.
- In IIS, right-click your Web Site and go to Properties > Custom Errors.
- Select the “403;4” HTTP error in the list HTTP errors and click the Edit Properties button.
- Select “URL” from the Message type drop-down list and enter “/RedirectToSSL.aspx” into the URL textbox, as shown below.
- Press OK twice to close the dialogs down.
- Restart the website and/or reset IIS to ensure all settings have been applied.
- Open Internet Explorer and go to:
https://<servername>/<securedpage>and verify that you are automatically redirected to the https version of the same page.
Redirect with code alone:
- Insert the following code at the beginning of the Page_Load event handler of every page that needs to be secured:
1 2 3 4 5 6 7 8 9
// Make sure the request has come through SSL (ie that HTTPS has been used) if (!HttpContext.Current.Request.IsSecureConnection) { System.Uri currentUrl = HttpContext.Current.Request.Url; System.UriBuilder secureUrlBuilder = new System.UriBuilder(currentUrl); secureUrlBuilder.Scheme = System.Uri.UriSchemeHttps; secureUrlBuilder.Port = -1; HttpContext.Current.Response.Redirect(secureUrlBuilder.Uri.ToString(), true); }
How to develop secure .NET applications using Server SSL Certificates and Client Certificates – PART 3
The following article is part 3 in a 4 part series of articles about developing .NET applications using SSL. Part 1 in this series can be found here and part 2 can be found here.
Installing Certificates into the correct Certificate Stores
Applications depend heavily on server SSL and client certificates being installed in the correct certificate stores. Certificates may need to be copied and pasted or exported and imported into stores in order to get the systems correctly working together in a secure manner.
Client application (with client certificate):
- Local Computer > Trusted Root Authority store should contain the Root CA certificate of the Server SSL Certificate Issuer of the Web application.
- Current User > Personal store should contain the Client Certificate for the Client application.
- Current User > Trusted Root Authority store should contain the Root CA certificate of the Client Certificate Issuer of the Client application
Web application (with server SSL certificate):
- Local Computer > Personal store should contain the Server SSL Certificate for the Web application.
- Local Computer > Trusted Root Authority store should contain the Root CA certificate of the Server SSL Certificate Issuer of the Web application.
- Local Computer > Trusted Root Authority store should contain the Root CA certificate of the Client Certificate Issuer of the Client application.
- Current User > Trusted Root Authority store should contain the Root CA certificate of the Client Certificate Issuer of the Client application.
How to verify the above certificates are in the correct locations:
- From the Start menu, select Run, type “mmc” and click OK. This will open the Microsoft Management Console.
- Click on the File menu option then on “Add/Remove Snap-in”.
- In the Add/Remove Snap-in dialog, click the Add button.
- From the Add Standalone Snap-in dialog, select “Certificates” from the list of snap-ins, and click Add.
- Select the “Computer account” option and click Add. Select “Local computer” and click Finish.
- If you are logged in as the user that will be used to run the client application, add the “My user account” as well.
- Now you will be able to look through the Certificates that are installed in all the different stores.
How to develop secure .NET applications using Server SSL Certificates and Client Certificates – PART 2
The following article is part 2 in a 4 part series of articles about developing .NET applications using SSL. Part 1 in this series can be found here.
Setting Up Client Certificates
Client certificates can be used to authenticate the client connecting to a web application. The client can either be a browser or a custom written client application.
Requesting a client certificate:
- Open IE (Firefox didn’t work so well for me…) and type in:
http://<certauthservername>/certsrv/ - Click on the “Request a certificate” link.
- Click on the “Web Browser Certificate” link.
- Enter all required information into the form shown above click “Submit”
Issue the client certificate from your test Certification Authority:
- Log onto the Windows Server 2003 machine and open the Certification Authority dialog from Administrative Tools.
- Expand the root certification authority “Pending Requests” folder.
- The certificate you just requested should be in the “Pending Requests” folder. Right-click on this request and select All Tasks > Issue. The certificate request will be removed from the “Pending Requests” folder and appear in the “Issued Certificates”.
Retrieve the certificate and install it into the Current User > Personal Store:
- Go back to IE on your web server and type in
http://<certauthservername>/certsrv/again. - Click on the “View the status of a pending certificate request” link.
- Click on the certificate request you want to view.
- Click on the “Install this certificate” link.
- Click “Yes” on the dialog that opens to install the client certificate.
- Click “Yes” on the next dialog as well.
Requiring client certificates at web application with IIS:
Once a client certificate has been requested, issued and installed on a client machine, a web application can be set up to require client certificates. For extra security, client certificates can also be mapped to a windows account user.
- On the client machine, open a Microsoft Management Console with the Certificates snap-in. Export the client certificate without the private key. This will generate a .cer file. Copy this file over to the server hosting the web application.
- On the server hosting the web application, right-click the website in IIS and select “Properties”.
- Under Properties, go to the “Directory Security” tab.
- Under the Secure Communications section, click the “Edit” button.
- In the Secure Communications dialog, change the “Client Certificates” option to “Require client certificates” and check the “Enable client certificate mapping” checkbox.
- Click on the “Edit” button in the “Enable client certificate mapping” section.
- This will open up the Account Mappings dialog.
- Click the “Add” button.
- Select the client certificate .cer file recently exported from the server that hosts the client application or client browser.
- Give the mapping a relevant name and choose the windows user that the web application will be run under.
- Click OK.
- Click OK to close the Account Mappings dialog and Secure Communications dialogs.
- Remove all other authentication options in the IIS manager Directory Security setting by clicking on the “Edit” button under Anonymous access and authentication control in the Directory Security tab.
- Uncheck all authentication options and press OK.
- Open up a browser and verify that you cannot reach the web site unless you navigate to it from the machine that has the client certificate installed on it.





















