Generating Resx Files For Globalization and Localization#

Using resource files (resx files) for globalization is a standard technicque.  ASP.NET allows you to create 1 resx file per page to help you manage your content.

But when it is time to convert those files into the correctly named localized version to send to the translator, you might find yourself doing a lot of copying and renaming.

So I wrote a little script that does this for you:

Imports System.IO
Module Module1

    Sub Main()
        Dim languages() As String = {"es", "pl", "de", "fr"}
        For Each filepath As String In Directory.GetFiles("C:\translationTest")
            If filepath.Contains("x.resx") Then
                For i As Integer = 0 To languages.Length - 1
                    File.Copy(filepath, filepath.Replace(".resx", "." & languages(i) & ".resx"))
                Next
            End If
        Next
    End Sub

End Module

This will generate all the files for you, and then all you need to do is send the off and wait for the translator to do the REAL work :).

Categories:  |  |  | 
Tuesday, July 22, 2008 2:13:50 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Where did my columns go?#

I just noticed this while working on a windows forms .net application.

I made some changes to the underlying business objects that I had bound to a datagridview.  Things looked like they should at runtime, but when I opened up the designer, several of my columns were missing!

After some testing around, I realized that any column that was bound to a property on the object, where I had changed the name of the property, was no longer showing.

I figured it would fail the databind or something, but at least let me change the column details to get things working right!

So I added in fake empty property definitions to the business objects and presto: back come the columns.

After that, I was able to update the databinding field and remove my bogus properties.

 

Categories:  |  |  | 
Wednesday, February 13, 2008 6:15:40 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

What could cause this casting error?#

Error:

Unable to cast object of type 'System.Collections.Generic.List`1[EditQuoteController+UnsavedQuoteItemInfo]' to type 'System.Collections.Generic.List`1[EditQuoteController+UnsavedQuoteItemInfo]'.

Yes, you read that right.  Unable to cast object of type X to type X.

I have seen this type of error once before and it was when there were multiple assemblies referencing different version of a common assembly, so even though their names were the same, their versions were different.

But in this instance there is nothing like this that could be having an impact.  All of the classes of consequence are in the same assembly.

Also, I don't get exception very often, only every now and then.

UPDATE:

I think maybe this is happening between builds on my development machine b/c I am storing some data in the session.  So the version in session was from the last build?  Doesn't sound like a great explanation, but it's the best I have at this point.

UPDATE 2:

I am pretty sure that what I wrote in the last update is what is actually happening. 

I used this code:

Try
    list = CType(view.Session.Item(Me.UnsavedKey), List(Of UnsavedQuoteItemInfo))
Catch ex As System.InvalidCastException
    Dim sError As String = "Unable to cast from type " & _
        view.Session.Item(Me.UnsavedKey).GetType.AssemblyQualifiedName & _
        " to type " & GetType(List(Of UnsavedQuoteItemInfo)).AssemblyQualifiedName & _
        ".  The session has been cleared."
    view.Session.Item(Me.UnsavedKey) = Nothing
    Throw New System.ApplicationException(sError)
End Try

Which producted the following 2 types:

System.Collections.Generic.List`1[[EditQuoteController+UnsavedQuoteItemInfo, App_Web_bp-bbqew, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]], mscorlib, Version=2.0.0.0, Culture=neutral PublicKeyToken=b77a5c561934e089

System.Collections.Generic.List`1[[EditQuoteController+UnsavedQuoteItemInfo, App_Web_ve7ziow-, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089. 

I am guessing this is a by product of using the web site project, instead of web application project.  There are some other reasons why we wanted to use web site instead of web app on this project, so you don't have to scold me: we made the right choice.

But it seems that every time I make a change to the project, it creates a new dynamically named assembly.  So even though the classes are really the same, they are globally different as far as asp.net is concerned.

 

Categories:  |  |  | 
Monday, January 14, 2008 3:14:02 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Using My.Settings on a referenced project#

I recently ran into some seemingly strange behavior as I was testing a couple windows services I had written.

In my case, I had a test harness program that was referencing the service (an exe) but this could also apply to references to dlls if you are using the projects application settings (My.Settings.Whatever in VB.Net).

After figuring it out, it all makes sense.

When you create an application setting by providing a value in the project's "Settings" tab, the value is written out into a special <applicationSettings> block in your config file.

But, in order to make those values accessible via a strongly typed/intellisense method, a class is created to wrap those values.  The class is in the Settings.vb file that is generated when you first add an application setting to your project.

But there is one more interesting thing to note:  If the settings class doesn't find the item it expects in the config file, it will return the last supplied value by default. 

So what this means is that if create an application setting for XYZ for the value "123" and then change the app.config file directly to change the "123" to "abc", then "abc" will be returned when you run the program.  However, if you were to then alter the config file to remove or rename the XYZ item, then your application would return "123" again when it ran.

Also, if you directly modify the config file, and then try to edit the projects applications settings, it will alert you to the fact that some values have changed, and ask if you want to use the updated values from the config file.  If you say yes, it will overwrite the Settings.vb file to use the new values that you had supplied in the config file.

So, I was referencing a project that used these settings, but when I would update the config file, those updated settings were not seen.  All I had to do was go into the project settings tab, allow it to refresh the Settings.vb file, and rebuild the project.

 

Categories:  |  |  | 
Wednesday, August 22, 2007 7:07:09 AM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Right aligning text when printing from a .net program#

In a program I am writing, I need to print directly to a couple of label printers.

My God these things are a pain in the ass to work with, but I will leave that rant to another post.

One thing I ran into was how to right align text when using the DrawString method of the System.Drawing.Graphics class off of the PrintPageEventArgs.

The solutions I was coming across seemed about as bad as I was expecting.

They involved measuring the width of the line of string using some System.Drawing.Graphics.MeasureString to figure out the length, and then dynamically position the text to make it appear right aligned.  So what that means is that for short text, X would be greater and for long text X would be less.

Fortunately, I came across the most simple solution:

Dim s As New StringFormat()
s.Alignment = StringAlignment.Far

e.Graphics.DrawString("por que?", New Font("Tahoma", 8), Brushes.Black, 50, 50, s)

Very simple.  But you have to wonder, why did MS pick "Far" as the alignment name instead of "Right", as you would expect.  Maybe "Far" is more of a graphics term for alignment?  Who knows.

 

Categories:  |  |  | 
Monday, August 06, 2007 1:44:24 AM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

The "Microsoft Crossroads"?#

Sam Gentile thinks that MS is at a crossroads in terms of web development.

He thinks with all the cool, free, cutting edgs stuff out there, like Ruby on Rails, MS may soon lose out on all the "alpha geeks", who move on to newer and better things while MS stays locked in the past.

I'm not ready to crown RoR the winner of anything yet.  True, MS is usually not on the cutting edge, but they usually do a pretty good job adopting good ideas.  There are only a handful of serious RoR sites out there.  If that number grows a ton, then it will mean something. 

Martin Fowler has some similar concerns though, so maybe this will come to fruition.

Categories:  |  | 
Thursday, May 31, 2007 8:15:46 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Software Development and TDD Anti-Patterns#

This is awesome!

Wikipedia has a whole list of programming anti-patterns, and James Carr lists some TDD anti-patterns.

Some of these are pretty funny:

Magic numbers: Including unexplained numbers in algorithms

Superboolean logic: unnecessary comparison or abstraction of boolean arithmetic

Boat anchor: Retaining a part of a system that no longer has any use

Categories:  |  | 
Tuesday, May 29, 2007 10:14:43 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Unit testing data access #

Roy Osherove blogs that he was mistaken when he suggesting using mocks for data access code.  With the improved Rollback attributes that he helped create, along with people like Justin Burtch who created a similar attribute for VSTS, they are now thinking that this is the way to go: rolling back database changes.

Roy is no fan of VSTS testing, finding a few bugs and some questionable design decisions.  Those don't seem like deal breakers for me, but we will see.

Categories:  |  |  |  | 
Tuesday, May 29, 2007 8:48:11 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

BindingListView#

The BindingList is very nice, but doens't support some things like sort and filter that a lot of people would like to have (see here for a short discussion on BindingList vs Datatable).

This project, in sourceforge, called BindingListView is supposed to allow you to get a sorted or filtered "view" of a bindinglist.

Might be worth checking out.

Categories:  |  | 
Tuesday, May 29, 2007 8:19:00 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Webservices Compression#
Categories:  |  |  |  | 
Wednesday, May 02, 2007 2:34:54 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

WCF One-Way Calls, Callbacks, And Events#

Here an article I was reading about some of the new (and from the looks of it... very useful) features of WCF.

One-Way calls, callbacks, and events.

Categories:  |  | 
Monday, April 30, 2007 1:03:06 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

ASP.NET Design Patterns#
Categories:  |  |  | 
Wednesday, April 11, 2007 9:17:54 AM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Controlling Programs Remotely#

It looks like from this article that the author is showing how to use remoting to interact with a windows form running on a server.

http://www.codeproject.com/csharp/RemoteWinControls.asp

Pretty interesting.

Categories:  |  | 
Tuesday, April 10, 2007 2:32:23 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

How to get the TOP X rows from a DataTable or DataView#

Here is a function I found that can trim down a datatable/dataview to a limited number of rows.  Basically, it's like doing a "TOP X".

''' <summary>
''' Will return a dataview with only the top "number" of rows.
''' </summary>
''' <param name="myDataView">dataview to "trim"</param>
''' <param name="number">the number of rows to return</param>
''' <returns></returns>
''' <remarks></remarks>
Public Shared Function GetTopDataViewRows(ByVal myDataView As DataView, ByVal number As Integer) As DataView
    Dim tableToClone As DataTable = myDataView.Table.Clone
    Dim i As Integer
    For i = 0 To number - 1
        If i >= myDataView.Count Then Exit For
        tableToClone.ImportRow(myDataView(i).Row)
    Next
    Return New DataView(tableToClone, myDataView.RowFilter, myDataView.Sort, myDataView.RowStateFilter)
End Function

I didn't write this, credit goes to this post.

Categories:  | 
Friday, February 23, 2007 3:06:17 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Gridview, DateFormatString, and HtmlEncoding#

Here is the original source of this tip.

"for some bizarre reason, you have to set HtmlEncode=false on a bound column in a gridview, to get the DataFormatString to work. "

Categories:  |  |  | 
Tuesday, February 20, 2007 11:59:55 AM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Dealing with WinForms Combobox and name/value items.#

I just read this article on aspalliance.com by Sandeep Archarya.

I think the article had 2 main points.  One was that databinding a combobox is not "bug free" because the act of manually databinding to a combobox causes the SelectedIndexChanged event to fire.  The second point was to show how to create a simple namevalue class to be added to the combobox items collection to get around the "problem" of combobox's taking an object as the item in it's list (as opposed to a name value pair).

I would point out the following:

First, I am not sure that I would call the SelectedIndexChanged event firing a bug.  When you manually databind a list, the first item become selected by default, and thus the selectedindex HAS changed, from -1 to 0.

Second, if you consider this a problem you can get around it a couple different ways.

1) Don't use manual databinding.

In the designer, select a datasource or create a new one.  I created a simple employee object and created an object datasource for this employee.  This creates a EmployeeBindingSource object that I bind my employee list to.  Using this method, I didn't experience the SelectedIndexChanged event firing on the databind.

Private list As New System.Collections.Generic.List(Of employee)
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    '*** create some fake employee objects
   For i As Integer = 70 To 80
      list.Add(New employee(i, Chr(i)))
   Next

    '*** this will populate our control (Combobox1)
   Me.EmployeeBindingSource.DataSource = list

End Sub

2) You can use manual databinding, and manually detach and attach the event handler for this event.

Private list As New System.Collections.Generic.List(Of employee)

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    
    '*** create some fake employee objects
   For i As Integer = 70 To 80
      list.Add(New employee(i, Chr(i)))
   Next

    '*** remove the handler
    RemoveHandler ComboBox1.SelectedIndexChanged, AddressOf ComboBox1_SelectedIndexChanged
    '*** databind
    Me.ComboBox1.ValueMember = "id"
    Me.ComboBox1.DisplayMember = "name"
    Me.ComboBox1.DataSource = list
    '*** add the handler back
    AddHandler ComboBox1.SelectedIndexChanged, AddressOf ComboBox1_SelectedIndexChanged
End Sub

 

Categories:  |  |  | 
Friday, November 10, 2006 4:32:43 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Convert RTF to HTML#

More than once I have looked into a way to convert RTF into HTML.  Mostly because there are RTF textboxes available for winforms, but you might want to save the page as HTML, and not RTF.

This article shows a way to do this that:

http://www.codeproject.com/vb/net/RTFToHTML.asp

Categories:  |  | 
Monday, November 06, 2006 4:33:56 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Make Use Of Culture in SQL Reporting Services Local Reports#

When using SQL Reporting services, you can format things such as dates and currency.

However, depending on the situation you might want to:

  1. Show a report with culture X on a computer running culture Y.
  2. Show a report using the same culture settings as the local computer.

To do (1), all you have to do is set the "Language" parameter of the local report in design time.

To get (2) to work, you need to set the Language parameter of the report as the expression "=User.Language".  This will set the report culture as the culture that the hosting program is running under.

If you have a program that you need to switch between different cultures, you can do so with the following line of code (which changes the culture to "English-Ireland")

System.Threading.Thread.CurrentThread.CurrentCulture = New Globalization.CultureInfo("en-IE", False)

More information can be found at: http://msdn2.microsoft.com/en-us/library/ms156493.aspx

Categories:  |  |  | 
Monday, October 09, 2006 12:43:24 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Performance of Web Services / Remoting / Enterprise Services#

I had previously read and heard in presentations by Rocky Lhotka that performance comparisons between Web Services and Remoting showed that they were basically the same, and that when talking about RPC protocols ES killed them both so badly (order of magnitude) that it wasn't worth fretting over the small diff between WS and remoting.

Rocky kinda explains this position in this post:
http://www.lhotka.net/weblog/RemotingVsWebServicesVsESCOMDCOM.aspx

However, I actually tracked down the white paper on Microsofts website:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwebsrv/html/asmxremotesperf.asp

Much to my suprise the giant performance improvement when using ES was only seen when calling empty functions.  In otherwords, it was basically a test of the transport.  Some "real world" tests showed ES performing faster than most other methods, but sometimes something like Remoting TCP Binary would outperform it as well.

In the tests that actually did something, the performance across the board was usually fairly comperable.  I guess this makes sense.  If you liken the round trip of an RPC call to a person going on a business trip, the speed of the airplane is less important that the time it takes the person to do the job at the end of the trip.  So even if your plane takes 3 hours instead of 2 hours, if your going to be staying for a week then that 1 hour isn't a big deal.

The major conclusion is to not pass datasets.  Datasets are serialized as XML even if you are using the binary serializer.  I have posted some stuff on this topic as well on my blog so you can search for it if you want.