Connecting to a MySQL database on the .NET Compact Framework

by Nicholas Piasecki on May 8th, 2009

Our mobile picking application at work runs on the .NET Compact Framework and typically connects to a SQL Server database. This is all nifty and supported with a vanilla install of NETCF and is as such uninteresting. But recently I’ve been tasked with an integration scenario where an alternative persistence implementation for the mobile picking application must communicate with a MySQL 5.1 database.

MySQL offers an ADO.NET driver called Connector/Net 6.0 at its Web site. Sweet. So you reference Mysql.Data.CF in your application and you’re good to go. But as soon as you call Open() on a MysqlConnection instance, you’ll get slammed with a System.IndexOutOfRangeException deep down in the innards of the of the Connector/Net library. If you take a look at the stack trace, you’ll see that it’s occurring in MemoryStream of all places. Apparently, upon calling Open(), the driver immediately issues a command to the database to get some metadata about its capabilities, and we blow up at trying to build that parameterized query.

Why is this broken?

The MySQL Connector/Net library is using the same code for the full framework as well as the compact framework, with little ifdefs for CF-specific or CF-omitted behavior sprinkled throughout the codebase. This isn’t a bad thing; in fact, it’s quite normal, and I do it for one of my common libraries that’s shared between our internal processing application and the mobile picker. The problem stems from an actual behavior difference between the MemoryStream implementations of the full and the compact frameworks. Here’s some sample code that demonstrates the problem:

MemoryStream ms = new MemoryStream();
ms.Position = 4;
ms.WriteByte((byte)0);
Console.WriteLine(ms.Capacity);
Console.ReadLine();

What we are doing is instancing a new MemoryStream via its default constructor; its internal byte[] buffer will be empty (capacity zero). We set its internal Position to somewhere and then try to write a byte.

In the full framework, the MemoryStream auto-expands the capacity by checking to see if the Position is greater than or equal to the Length. So after the above code executes, you end up with a MemoryStream instance whose internal byte[] buffer contains 5 bytes (all zeroes).

In the compact framework, the MemoryStream also auto-expands, but it only does it if the Position equals the Length–not if the Position is greater than the Length. So the above code results in a System.IndexOutOfRangeException. It’s not a documented exception for the WriteByte() method, so I would imagine it is an oversight in the compact framework. (Although the MySQL use case is a little strange; I would never use the MemoryStream class this way.)

The work around is to download the source distribution for Connector/Net 6.0 and edit the MySqlPacket.cs file. Around line 34, change

private MemoryStream buffer = new MemoryStream();

to

private MemoryStream buffer = new MemoryStream(5);

All we’re doing is starting the internal byte[] buffer with a capacity of 5, since the MySqlPacket.cs constructor sets the Position to 4. It shouldn’t affect actual behavior of the MySqlPacket since we’re only adding capacity and not length to the MemoryStream instance that it uses.

Other unrelated problems

If you’re upgrading the Connector/Net 6.0 source to NETCF v35 (just right-click the project in Visual Studio 2008 and choose “Upgrade Project,” you’ll need to delete the CompilerGeneratedAttribute.cs file. NETCF v35 already has one, but NETCF v20 didn’t; I guess that’s why the MySQL guys had created their own.

Finally, you may be getting a “Missing Manifest Exception” whenever Connector/Net 6.0 attempts to access its Resources object for error messages. That’s because they’re trying to share the same Resources.designer.cs file for the CF assembly that was created for the desktop assembly. The problem is that in line 42 of the generated Resources.designer.cs file, it’s trying to load the embedded resx file from the assembly–but it’s searching for “MySql.Data.MySqlClient.Properties.Resources”, which is the namespace for the desktop DLL. So it doesn’t find it in the NETCF assembly on your device and tosses the missing manifest error. The solution is to either fix up the name by editing it directly (e.g., “MySql.Data.CF.Properties.Resources”) or by deleting the file and letting Visual Studio regenerate it properly on the next recompile.

Conclusions and delusions

I’ve filed two bugs, one with MySQL and one on Connect, who knows what will happen with them:

The CF version of Connector/Net seems pretty alpha, but it’s what we’ve got to work with. Good luck!

Update 7/6/2009: Download my custom version of the file.

7 Comments
  1. Rodrigo permalink

    Hello Nicholas,

    Thanks for the information. Would you mind sending me an email with the updated “MySql.Data.CF.dll” file? I downloaded the source files from MySQL website (http://dev.mysql.com/downloads/connector/net/6.0.html) but got many errors while trying to open the “MySQLClient.sln” on VS2008.

    Thanks!

  2. Chris permalink

    Hello you,

    i’m from Germany and have also the Problem.

    Would you sending me an email with the “MySQl.Data.CF.dll” too?

    I spend so many Time on this d*mn Problem..

    Thank you!

  3. zandro permalink

    Hi Nicholas,
    Great help. Thanks! Another favor… Your compiled file worked when I was using “Server=127.0.0.1″ , if I specify another location it gives me an error
    “MySql.Data.MySqlXlient.MySqlException: Unable to connect to any of the specified hosts.”

    Connection String is: conn = new MySql.Data.MySqlClient.MySqlConnection(“Server=192.168.1.102;Uid=genuser;Pwd=password;Database=utils;”);

    I have added that ip as part of the host for genuser (which I believe should already be able to connect with any host). Any ideas on why I can only connect through “127.0.0.1″ and not using a different IP where my MySQL server is located at???

    Also, I downloaded the source for the 6.1.3 mysql .net connector but I was unable to compile it. Kept getting a “The imported project “C:\Program Files\Visual Studio 2005 SDK\2007.02\VisualStudioIntegration\Tools\Build\Microsoft.VsSDK.targets” was not found” error. Kindly guide me on how compile the project.

    Any help is appreciated. Thanks.

  4. jfs permalink

    Thanks for the information, I’ve downloaded de latest version of the Connector/Net, 6.1.3. The 1st error, that raises an IndexOutOfRangeException is fixed but the Resoruce file error keeps alive.
    I fix it adding de Mysql.Data.CF project to my solution, where i have the device application project.

    After adding this project, i had to comment the last line of the AssemblyInfo,
    [assembly: AssemblyKeyName("ConnectorNet")].
    if you keep this line uncommented, the project not buids. :(

    Doing this, i can connect to mysql server!

    Zandro, i think you have a network problem, i’ve the same problem using de VS2005 emulator, until i read that it is necessary to conect it through Microsoft ActiveSync. If you don’t connect it, the emulator is not connected with de MySQLl server, because ther is no connection between both Operating systems (emulator and server)

    I hope this help.

  5. Thanx guys, you helped me a lot. I did the same as JFS and it works.

    But note, that if you try the same wit connector 6.2.2 then you will get the problem “Timeouts are not supported on this stream”. This is most likely bug of 6.2.* releases (up to 6.2.2 so far). When I downgraded to 6.1.3 connection was opened fine and I could read the data. I will keep you posted if there is a fix available with new release of .NET connector.

  6. Peter permalink

    Hi, problem described in my previous note (Timeouts are not supported …) is already solved on mySQL side, here is the bug report http://bugs.mysql.com/50321 with the solution provided. It is part of 6.2.3 changelog.

  7. Try effiproz-cf database for compact framework. effiproz is written entirely in C#. http://www.effiproz.com/product_cf.aspx

Leave a Reply

Note: XHTML is allowed. Your email address will never be published.

Subscribe to this comment feed via RSS