使用 Visual Studio Express for Web 从 ASP.NET MVC 连接到 MySQL






4.50/5 (7投票s)
本文介绍在使用 Visual Studio Express 2013 进行 ASP.NET MVC 开发时,如何在不使用 ORM 的情况下连接到 MySQL。
目标
本文旨在演示如何在 Microsoft Visual Studio Express for Web 中使用 ASP.NET MVC,并且不使用 Nhibernate 或 EntityFramework 等 ORM 来使用 MySQL 数据库。示例将包括读取图像。
示例起源
该示例源于我正在开发的一个桌面票务系统,该系统将仅有限地在线访问其部分功能。该系统拥有 30 个专用表处理程序集。在线界面将仅限于乘客注册、机票购买、支付和乘客查询。
由于我使用的是 Express 版本产品,初步研究表明无法连接到 MySQL。Nelson LeQuet 在 Udemy 或 3DBuzz 上提供的相关课程。Nelson 在他的网站中使用了 Nhibernate / FlusentMigrator 的组合,我强烈推荐这套技术用于新的开发。Nelson 没有直接给我答案,而是教我如何自己解决,于是我开始了一个新的 ASP.NET MVC 项目,添加了我在桌面开发中使用的同一个 MySQL.Data 库,引入了相同的命名空间,像在桌面模式下一样进行调用,结果就出来了——从 Microsoft Visual Studio Express 编写的 ASP.NET MVC 站点成功连接到了 MySQL。
此外,它们都没有展示如何使用 Test Explorer 来设置测试项目,而且所有项目都局限于测试单个表单的示例,其中显示的表单与调用的进程相关联。在我的示例中,与我将调用的进程关联的表单出现在第三个位置!
我的这份贡献很大程度上源于这些出色的资料,它们对我入门至关重要。
- [LEQUET] - Udemy 上的 Nelson LeQuet 的“Comprehensive ASP.NET MVC”
- [FREEMAN] - Apress 上的 Adam Freeman 的“Pro ASP.NET”
[FREEMAN] 的书让我入门了,但他的例子使用了 Entity Framework 和 SqlSever。我无法弄清楚如何跳过 EF 部分,也无法从中学到成功连接 MySQL。尽管如此,这仍然是我最喜欢的关于这个主题的书。
[LEQUET] 提供了 EntityFramework 的替代方案 Nhibernate,他的示例布局方式可以清楚地看到如何在不使用任何 ORM 的情况下进行操作。在该课程中,还可以接触到其他出色的资源,如 FluentMigrator、Bcrypt、Bootstrap、Elmah、Git 和 WebDeploy。
接下来的文字将演示如何在基本的 ASP.NET MVC 页面上实现该连接。
介绍示例应用程序。
示例应用程序是一个简单的网页,它从名为 PersonMaster 的表中读取 ID、姓名、地址和图像。您可以在运行它时用您数据库中的任何列/表组合替换它们。
| 包含的源代码 | 
|---|
| 我包含了我在其中成功建立连接的 ASP.NET MVC 项目。它无法“开箱即用”,因为您本地没有相同的数据库。在 cPerson 类中使用现有数据库中的任何表,您应该就能成功运行。 | 
入门
打开 Microsoft Visual Studio Express for Web,创建一个新项目,选择 **ASP.NET MVC Web Application**,如下图所示。

接下来,选择空模板,将视图引擎保留为 Razor,并且不要选择创建测试项目。

选择您偏好的源代码控制(或不选择)
编码解决方案
打开项目的 Web.Config 文件,在 configuration/appsettings 之后、system.web 之前插入 ConnectionStrings。
    ?<connectionStrings?>
    ?<add name="MySQLConnection"
    connectionString="Server=localhost;
                      user id=root;
                      password=myrootpass;
                      persist security info=True;
                      database=mytestdb"
    providerName="System.Data.SqlClient" /?>
  ?</connectionStrings?>
由于我们选择了空模板,所以没有要渲染的页面。在 Solution Explorer 中,在 Views 文件夹下添加一个名为 Home 的文件夹。

右键单击新的 Home 文件夹,然后从弹出菜单中选择 Add,再选择 View。将新视图命名为 'Index',将引擎保留为 'Razor',并清除所有三个复选框,如下图所示。

这将创建一个名为 Index.cshtml 的新模块。将其中的自动生成代码替换为以下内容。
@model Razor.Models.cPerson
@{
    Layout = null;
}
?<!DOCTYPE html?>
?<html?>
?<head?>
    ?<meta name="viewport" content="width=device-width" /?>
    ?<title?>Index?</title?>
?</head?>
?<body?>
    ?<div?>
        ?<p?>Name: @Model.Name?</p?>
        ?<p?>Address 1: @Model.Address1?</p?>
        ?<p?>Address 2: @Model.Address2?</p?>
        @if (Model.Photo != null)
        {
            ?<div style="float:left;margin-right:20px"?>
               ?<img width="75" height="75" src="@Url.Action("GetImage", "Home")" /?>
            ?</div?>
        }
    ?</div?>
?</body?>
?</html?>
接下来,右键单击 Controller 文件夹,选择 Add,然后从弹出菜单中选择 Controller。将新的 Controller 命名为 'HomeController'。

这就是 'HomeController' 的样子。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Razor.Controllers
{
    public class HomeController : Controller
    {
        cPerson myPerson = new cPerson(12);
        public ActionResult Index()
        {
            return View(myPerson);
        }
        public FileContentResult GetImage()
        {
            if (myPerson.Photo != null)
            {
                return File(myPerson.Photo, "jpg");
            }
            else
            {
                return null;
            }
        }
    }
}
您会注意到 cPerson 类引用下方有一些红色下划线。所以我们需要在 model 中创建它——但首先我们需要添加一个对 MySQL.Data 的引用。使用您一直以来使用的那个——对我来说是这样的。

现在,右键单击 Models 并添加一个类,命名为 cPerson。

这就是 cPerson 的样子。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MySql.Data.MySqlClient;
using System.Configuration;
namespace Razor.Models
{
    public class cPerson
    {
        public int PersonID { get; set; }
        public string Name { get; set; }
        public string Address1 { get; set; }
        public string Address2 { get; set; }
        public byte[] Photo { get; set; }
        private bool connection_open;
        private MySqlConnection connection;
        public cPerson()
        {
        }
        public cPerson(int arg_id)
        {
            Get_Connection();
            PersonID = arg_id;
            //    m_Person = new CPersonMaster();
            //  List<CPersonMaster> PersonList = new List<CPersonMaster>();
            //PersonList = CComs_PM.Fetch_PersonMaster(connection, 4, arg_id);
            //if (PersonList.Count==0)
            //  return "";
            //m_Person = PersonList[0];
            //DB_Connect.CloseTheConnection(connection);
	try
	{
        
		MySqlCommand cmd = new MySqlCommand();
		cmd.Connection = connection;
		cmd.CommandText =
	string.Format("select concat (person_id, ') ', surname, ', ', forename) Person, Address1, Address2, photo, length(photo) from PersonMaster where Person_ID = '{0}'",
									  PersonID);
		MySqlDataReader reader = cmd.ExecuteReader();
		try
		{
			reader.Read();
			if (reader.IsDBNull(0) == false)
				Name = reader.GetString(0); 
			else
				Name = null;
            if (reader.IsDBNull(1) == false)
				Address1 = reader.GetString(1); 
			else
				Address1 = null;
            if (reader.IsDBNull(2) == false)
				Address2 = reader.GetString(2); 
			else
				Address2 = null;
			if (reader.IsDBNull(3) == false)
					{
						Photo = new byte[reader.GetInt32(4)];
                        reader.GetBytes(3, 0, Photo, 0, reader.GetInt32(4));
					}
					else
					{	
						Photo = null;
					}
            reader.Close();
		}
		catch (MySqlException e)
		{
			string  MessageString = "Read error occurred  / entry not found loading the Column details: "
				+ e.ErrorCode + " - " + e.Message + "; \n\nPlease Continue";
			//MessageBox.Show(MessageString, "SQL Read Error");
			reader.Close();
			Name= MessageString;
            Address1 = Address2 = null;
		}
	}
	catch (MySqlException e)
	{
			string  MessageString = "The following error occurred loading the Column details: "
				+ e.ErrorCode + " - " + e.Message;
			Name= MessageString;
            Address1 = Address2 = null;
		}
             
             
             
             
             connection.Close();
        }
        private void Get_Connection()
        {
            connection_open = false;
            connection = new MySqlConnection();
            //connection = DB_Connect.Make_Connnection(ConfigurationManager.ConnectionStrings["SQLConnection"].ConnectionString);
            connection.ConnectionString = ConfigurationManager.ConnectionStrings["MySQLConnection"].ConnectionString;
            //            if (db_manage_connnection.DB_Connect.OpenTheConnection(connection))
            if (Open_Local_Connection())
            {
                connection_open = true;
            }
            else
            {
                //					MessageBox::Show("No database connection connection made...\n Exiting now", "Database Connection Error");
                //					 Application::Exit();
            }
        }
        private bool Open_Local_Connection()
        {
            try
            {
                connection.Open();
                return true;
            }
            catch (Exception e)
            {
                return false;
            }
        }
    }
}
如果一切都连接正确,当您编译项目并启动网站时,您的输出将类似于此。

工作原理
所有关键操作都发生在 model 中,关键步骤如下:
- 包含 MySql.Data.MySqlClient命名空间的 using 语句。
- 声明并实例化一个 MySqlConnection 类型的属性来保存连接句柄。
- 将 Web.Config 中的连接字符串读入连接句柄的 ConnectionString 属性。
- 通过调用连接句柄的 Open 方法打开连接。
- 声明并实例化一个 MySqlCommand类型的属性。
- 将连接句柄传递给您的 MySqlCommand属性的 connection 属性。
- 将您的 SQL 语句放入您 MySqlCommand属性的 CommandText 属性中。
- 创建一个 MySqlDataReader属性,并通过调用您MySqlCommand属性的ExecuteReader方法来实例化它。
- 使用 MySqlDataReader 属性的 Read 方法来恢复您的数据。
- 使用连接句柄的 Close 方法关闭连接。
我在最终示例中留下了一些注释掉的代码。这些是我成功连接到我的一些 C++/CLI 程序集时的代码。我保留它们是为了参考。
结论
在撰写本文时,我比平时更贴近主题。这里唯一的“额外”内容是从图像列中检索数据。我只建议遵循此示例,除非您有非常特殊的要求,而 Nhibernate 或 Entity Framework 等无法满足。
最后,请始终在每次查询或事务后关闭您的连接。最初,我一直在寻找一种方法来建立一个预先连接,并将该句柄传播到我的整个站点,以消除重复连接的开销。虽然减少连接开销在桌面应用程序中可能是一个好习惯,但对于网站来说并非如此。这是因为保持连接打开到最后会通过耗尽所有可用数据库连接来为 DOS 或拒绝服务攻击铺平道路。即使您的网站从未受到攻击,过多的并发连接在正常情况下也会给您的合法用户在使用网站时带来问题,如果同时访问它的用户太多。
历史
2014-09-22 - V1.0 - 首次提交


