Main Points

On the last page, I was able to get an instance of MySQL up and running on my computer, and the GUI tools as well. My admittedly brief tests all seem to indicate the tools and the MySQL instance on my dev box are running beautifully. If you're interested in the details of MySQL installation and configuration, click here! I also have good indications that the .NET Connector for MySQL has installed successfully; it's a provider to automate a lot of data access and manipulation details like the SQL Server, Access, and Oracle providers that are built in to the .NET Framework. While there's no indication of any changes in Visual Web Developer Express (VWD), I've run across information in a couple places that implies Microsoft has disabled plugins in VWD, you have to buy Visual Studio to use them. That means I can still use the .NET Connector, I just have to configure the web.config manually.

The Web.config File

Everything I need to do for testing with the MySQL database instance has been done except actually programming against .NET. Everything I need to do to test the GUI tools has been done, at least for now. The .NET Connector however, I really haven't had a chance to test out. Further, my preferred method for programming against the database using ASP.NET is to employ the .NET Connector, so that's a prerequisite to going further with the database anyway. So working out the .NET Connector is my next step. Since VWD may not support Visual Studio plug-ins, I did a lot more research about alternative manual techniques for using the .NET Connector.

I don't want to run off the primary account, I need a user account for my ASP.NET application to use when accessing the MySQL database on my dev box. Therefore, I start MySQL Administrator, log in to the database and select "User Administration" in the menu pane on the top left. On the main panel, I type in the Username I want to use "AspNet" and select an appropriate password. Then I click "Apply Changes" to save the new user. By default, new users have no power, so I need to provide access to one of the existing databases for testing purposes. I select the "Schema Privileges" tab at top. In the Schemata column at left, I select the information\_schema database. From the Available Privileges column at right, I choose SELECT and click the arrow to add this power to the Assigned Privileges column in the middle. For now that's all I want to do, read only access so I don't mess anything up. Then I click Apply Changes to save the configuration. Next, I need to create a connection string that will use this access to create a connection.

<add name="MysqlInstanceConnectionString" connectionString="server=localhost; user id=AspNet; password=superSecretPassword; database=information_schema; pooling=false;"
providerName="MySql.Data.MySqlClient"/>

This is the part that the MySQL plug-in for Visual Studio is supposed to handle for you. Fortunately, in my research on the internet, I ran across a couple examples of what completed connection strings look like on the blogs and forums. They are fairly straightforward, so I'm hopeful that this will work.

First, I checked to see if a connection to one of the older databases worked. There's no reason it should not, but now I know I have a configuration that works for sure. Note, that I've cleaned up all testing references, so what you see below was the output, which I've now hard coded into the webpage so that you can see my testing results.

AreaId AreaName
1 Point Loma
2 Clairemont West
3 Clairemont
4 University City
5 La Jolla

Here's the code that produces it.

<asp:GridView ID="MysqlTestGridView" runat="server" AutoGenerateColumns="False" DataKeyNames="AreaId" DataSourceID="MysqlTestDataSource">
<Columns>
<asp:BoundField DataField="AreaId" HeaderText="AreaId" InsertVisible="False" ReadOnly="True"
SortExpression="AreaId" />
<asp:BoundField DataField="AreaName" HeaderText="AreaName" SortExpression="AreaName" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="MysqlTestDataSource" runat="server" ConnectionString="<%$ ConnectionStrings:girlScoutsConnectionString %>"
SelectCommand="SELECT [AreaId], [AreaName] FROM [Area]"></asp:SqlDataSource>

Next, I customized it to grab some character set data from the MySQL database. I inserted the new name for the MySQL database and swapped out the data table and column names for ones in the MySQL database. However, it continues to display the same information, despite the fact that the Girl Scout database references are removed from the page; something's obviously being cached somewhere, but after refreshing the page several times I get the GS data each time. So I opened the MySQL Query Analyzer and tried copying the format for a SELECT statement which MySQL likes. This finally resulted in an error.

Exception Details: System.Data.SqlClient.SqlException: An error has occurred while establishing a connection to the server. When connecting to SQL Server 2005, this failure may be caused by the fact that under the default settings SQL Server does not allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server)

This actually makes me feel better. It should be throwing an error. So while SqlClient will manage an Access database in addition to MS SQL Server, it won't handle MySQL. According to one of the books I'd read, SqlClient works with any database that uses SQL to execute commands. That sounded a little strange, but weirder things have happened; however, clearly that's wrong. So try running some code based on one of the .NET Connector demos.

Accessing the .NET Connector

The MySQL samples involve working up a complete C# code behind which suits me fine except I'd like a smaller faster way to confirm that the connector is at least working. However, it looks like the only way to test it is to mock up one of the complete examples and just troubleshoot. *sigh* I do not enjoy this part of working with a new piece of technology; I like taking small bytes of a project, not big ones.

My first step is to add the proper import to the code behind file. According to all the Microsoft documentation about installing 3rd party software and all the MySQL documentation about installing the .NET Connector, this should all be handled automatically behind the scenes during installation. However, every user who's blogged about the process says it's not that easy; they're right. I added using Mysql.Data.MySqlClient; to the using statements, and I now get this error message.

Compiler Error Message: CS0246: The type or namespace name 'Mysql' could not be found (are you missing a using directive or an assembly reference?)

However, all the blogs I've uncovered have said you simply need to drop a copy of the MySql.Data.dll into the bin folder for your application. However, I still get the same error message even after trying that. I rebooted the computer and had VWD compile from scratch. Still nothing. *sigh* And it takes an incredibly long time for this to compile, so I start a build, then go do something else, come back in 15 minutes to see... yeah, the same error message. *grrrrr* So let's start keeping track of all the silly things I have to do to keep get the connector working

  • Copy MySql.Data.dll to the bin folder: Has no effect, still can't find Mysql namespace.
  • Add an assembly reference to the Web.config file: Several guys said this worked beautifully, but had no effect for me. Here's the assembly reference I tried to add. <add assembly="MySql.Data, Version=6.1.2.0, Culture=neutral, PublicKeyToken=C5687FC88969C44D" /> The 0 at the end of the version is a guess, but using 6.1.2 (the portion listed) didn't work either. I also have no idea what the PublicKeyToken might be, so I used the one that everyone said worked. However, they were installing connector 5.0.7; if the token for mine is different, I've no idea where to find it.
  • Add wildcard, *, reference in the Web.config <assemblies> section: Contrary to everything else I've ever heard, one of the gurus on a .NET forum said you need this or .NET won't compile the assemblies in your bin folder. I'd been under the impression that it was done automatically. Maybe he's using 1.1 or something. Lacking other options I decide to give it a try. Now, I have one other .dll from a provider system I was using to run a friend's website. I never added a * reference and it worked fine. Now the reference may have been added automatically for me. And I may have cleaned the reference out of the Web.config since I'm not using it now. But it's a longshot. Instead of adding the specific assembly (and as you saw I don't know key pieces of information about it), you simply use the wildcard to add every assembly in the bin folder. <add assembly="*" /> Sadly, I get the namespace error.

    As an aside, MSDN says "The value of <add> is an assembly name, not a DLL path. ASP.NET looks up the assembly name to find its physical DLL location." This is ridiculous to me. You know the path to the DLL, whereas there's no way to determine the "fully qualified assembly name" based on the file you're dropping into the bin folder. This is completely backwards, IMO.

  • change using MySql.Data.MySqlClient; from "Mysql" to "MySql": Success!

VWD now has access to the MySql namespace and provides its objects and methods in Intellisense; equally importantly, the application now compiles. On a side note, while MySQL files are written "MySql", you have to have worked with MySql files for awhile to consider this; all marketing material is for "MySQL" and .NET naming conventions dictate that this should be "Mysql". If I hadn't had so many problems getting the MySQL server to install this would have taken a lot longer to figure out. After a couple experiments, the .dll file needs to be in the bin folder; I even included MySql.Web.dll which also inserts some objects, but none of the other files in the Assemblies folder of the connector appear to add anything accessible to the using statements. However, the <add assembly="*" /> does not appear to impact the application one way or the other. I have therefore dropped it. We are now connected and ready to hit the database!

Programming Against the .NET Connector

It's time. I'm throwing a grid view control below so I can output data from the new MySQL database; these are the character sets supported by the MySQL instance.

DESCRIPTIONMax. Byte Length
UTF-32 Unicode4
UTF-8 Unicode4
UTF-16 Unicode4
EUC-JP Japanese3
UTF-8 Unicode3
UJIS for Windows Japanese3
EUC-KR Korean2
GB2312 Simplified Chinese2
Big5 Traditional Chinese2
Shift-JIS Japanese2
GBK Simplified Chinese2
SJIS for Windows Japanese2
UCS-2 Unicode2
DOS Kamenicky Czech-Slovak1
Mac West European1
ISO 8859-8 Hebrew1
ISO 8859-13 Baltic1
Windows Cyrillic1
Windows Arabic1
Windows Central European1
DOS West European1
ISO 8859-9 Turkish1
KOI8-R Relcom Russian1
GEOSTD8 Georgian1
ISO 8859-2 Central European1
DOS Russian1
US ASCII1
Mac Central European1
DOS Central European1
TIS620 Thai1
KOI8-U Ukrainian1
ISO 8859-7 Greek1
DEC West European1
Windows Baltic1
HP West European1
Binary pseudo charset1
ARMSCII-8 Armenian1
cp1252 West European1
7bit Swedish1

The XHTML output is virtually identical to what's above and the gridview is literally...

<asp:GridView ID="htmlTableOfMysqlCharacterSetData" runat="server">
</asp:GridView>

so the only thing interesting is the C# programming in the code behind...

using System.Web.Configuration;
using MySql.Data.MySqlClient;

public partial class Database08MySqlDataRetrieval : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
.
.
.
}
}

This is pretty basic. I neglected the default namespaces, but I am showing you that I've added a couple required namespaces. System.Web.Configuration is needed to retrieve the connection string to the MySQL database; we've stored it in the Web.config file and an object that lives in that namespace, WebConfigurationManager, is how we'll get it out. Also, we need to access the MySQL classes built into the .NET Connector, which is the entire reason we were trying to install that in the first place; they're stored in MySql.Data.MySqlClient so we're importing that namespace as well.

There's also a standard ASP.NET class declaration for the page. public means anyone (including the server which needs it) can access it. partial means it's incomplete, and still has to be put together with the .aspx page, and class defines this as a class. Finally, the class is named Database08MySqlDataRetrieval, and the colon, :, indicates that it's implementing the base class System.Web.UI.Page which means we don't have to write a lot of basic webpage functionality, we get it just by including ": System.Web.UI.Page". The only thing we need to do is run one method to execute our database instructions when the page loads, ie the Page_Load event handler. The event handler is protected so that it can only be used in this code or in the .aspx page, and void means it's code that executes instructions but doesn't return any output object. Beyond that, we can get down to the real database stuff that happens inside.

// Create a connection to the new MySQL database
string mysqlConnectionString = WebConfigurationManager.ConnectionStrings["MysqlInstanceConnectionString"].ConnectionString;
MySqlConnection connectionToTheMysqlDatabase = new MySqlConnection(mysqlConnectionString);

//Create a command object to pass a SQL statement to the MySQL database
string sqlStatementForTheMysqlDatabase = "SELECT C.`DESCRIPTION`, C.`MAXLEN` AS 'Max. Byte Length' FROM CHARACTER_SETS C ORDER BY C.`MAXLEN` DESC";
MySqlCommand commandForTheMysqlDatabase = new MySqlCommand(sqlStatementForTheMysqlDatabase, connectionToTheMysqlDatabase);

DataTable dataForMysqlDatabaseCharacterSets = new DataTable();

The first thing we have to do is prepare the pieces necessary to connect to the database. I've created a string object, mysqlConnectionString, to store the connection string and then assigned it the value from the Web.config file. The connection string is named "MysqlInstanceConnectionString". Next I take advantage of that MySql.Data.MySqlClient namespace to create some MySQL objects. First, I create an instance of a MySqlConnection using the new connection string. I also need a SQL statement to tell the database what information I want. In this case, I'm selecting the DESCRIPTION and the MAXLEN fields from the C table. You'll note I'm using an AS keyword to change the cryptic name of MAXLEN into 'Max. Byte Length'. I'm selecting the information from the CHARACTER_SETS table; what's happening next was specified by one of my GUI tools, the Query Browser, so I'm not touching it. However, I believe what's happening is that an implicit AS is being used to rename the table from "CHARACTER_SETS" to "C" making the rest of the statement much shorter, ie C.'DESCRIPTION' instead of CHARACTER_SETS.'DESCRIPTION'. It would be better practice, however, to include the AS. I'm ordering the data by the MAXLEN field and putting the results in descending order (from largest to smallest). With the SQL stored in a variable, sqlStatementForTheMysqlDatabase, I can go back to MySql.Data.MySqlClient and create a MySqlCommand that uses the SQL statement and the connection object. That's all I need to query the database. In order to have some place to put the information it returns, I still need to create a DataTable which I name dataForMysqlDatabaseCharacterSets. Now I'm ready to hit the database.

try
{
commandForTheMysqlDatabase.Connection.Open();
dataForMysqlDatabaseCharacterSets.Load(commandForTheMysqlDatabase.ExecuteReader());
}
finally
{
commandForTheMysqlDatabase.Connection.Close();
}

htmlTableOfMysqlCharacterSetData.DataSource = dataForMysqlDatabaseCharacterSets.DefaultView;
htmlTableOfMysqlCharacterSetData.DataBind();

I wrap the call to the database in a try block for protection, and then open the connection specified by the MySqlCommand. Then I call the ExecuteReader method on the command which actually returns the data from the database. These results are loaded into the DataTable for storage. A second block, finally closes the connection so that even if something goes terribly wrong while trying to get the data, the connection will be closed. Next, I call the id of the GridView and set it's DataSource to the default view of the DataTable. This tells the GridView what data it should be working with, but I still need to call the DataBind() method on the GridView which actually inserts the data.

The results appear above; the data from the MySQL database is published as requested onscreen. This is not a hard coded test; the MySQL database now works on both my dev box and the production server, this is live information from the database. With some assistance from my webhost, I have a MySQL database up on this account in just a couple hours. Aaaaaaaah... so much easier than having to do it all myself on the dev box. Once that was taken care of, I reworked the connection string in the production server's Web.config file. When I settled in to see what happened, everything works first time. Brilliant! I love it! I'm also able to connect to the database remotely using MySQL's GUI tools, so I have access directly to the database as well as through the .NET application's webpages. That means I can work with the database at will. We have an enterprise-class database up live!