在使用Entity Framework开发数据业务系统时,使用了MySQL数据库,ADO.NET driver for MySQL使用官网http://www.mysql.com/downloads/connector/net/中下载的提供程序,在开发环境中安装该提供程序后,该安装程序将修改系统配置文件“C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config”,修改后的文件段如下:
<system.data>
<DbProviderFactories>
<add name="Odbc Data Provider" invariant="System.Data.Odbc" description=".Net Framework Data Provider for Odbc" type="System.Data.Odbc.OdbcFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<add name="OleDb Data Provider" invariant="System.Data.OleDb" description=".Net Framework Data Provider for OleDb" type="System.Data.OleDb.OleDbFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<add name="OracleClient Data Provider" invariant="System.Data.OracleClient" description=".Net Framework Data Provider for Oracle" type="System.Data.OracleClient.OracleClientFactory, System.Data.OracleClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<add name="SqlClient Data Provider" invariant="System.Data.SqlClient" description=".Net Framework Data Provider for SqlServer" type="System.Data.SqlClient.SqlClientFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.2.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</DbProviderFactories>
</system.data>
配置节”<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient"…”是安装程序添加的,默认主机环境中没有该配置节。
当发布程序到目标主机时,没有该配置节时,应用程序将弹出异常,所以我们需要想办法修改目标主机上的配置将上面的配置节添加进去,可行的办法有一下几种:
1、在可执行程序的配置文件中添加该配置段。
此方法带来的后果是,在开发主机上调试程序变得非常不方便,因为该配置信息在系统中只能出现一次,如果配置文件加载配置是发现有两个相同段的配置(一个位于上文提到的machine.config中,一个位于你要调试的程序demo.exe.config中),程序将发生异常无法调试,有解决方法就是在调试时将该该配置段暂时注释,发布时取消注释,但是这样的反复操作太令人痛苦了,所以此方法建议不采用。
2、程序启动时修改“machine.config”配置文件,添加配置段。
此方法经验证部分可行,因为程序要修改该的配置文件存在于系统路径下,有文件保护,需要有授权才能访问并修改该文件,而授权又是相当繁琐的过程。所以此方法建议不采用。
3、在安装程序中自定义安装过程,在该过程中修改“machine.config”配置文件。
此方法屏蔽了方法2的授权过程,因为安装程序自身有权限修改任何文件,所以此方法为最佳方法。实现步骤如下,在主输出项目中添加一个继承自“Installer”类的子类,重载方法“ public override void Commit(IDictionary savedState)”,在该方法体内实现将配置节添加到“machine.config”配置文件中,然后在安装项目中自定义安装过程。
自定义安装类:
using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using System.Diagnostics;
using System.Windows.Forms;
namespace Freemansoft.Csm
{
/// <summary>
/// 自定义安装。
/// </summary>
[RunInstaller(true)]
public partial class CsmInstaller : Installer
{
/// <summary>
/// 构造方法。
/// </summary>
public CsmInstaller()
{
InitializeComponent();
}
/// <summary>
/// 重载提交。
/// </summary>
public override void Commit(IDictionary savedState)
{
base.Commit(savedState);
CreateUnInstallBat();
CreateMySQLProviderSection();
}
/// <summary>
/// 创建“MySQL数据库”数据提供程序配置段。
/// </summary>
private static void CreateMySQLProviderSection()
{
string invarientValue = "MySql.Data.MySqlClient";
string machineCfgFileName = @"C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config";
string name = "MySQL Data Provider";
string description = ".Net Framework Data Provider for MySQL";
string type = "MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.2.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d";
XDocument document = XDocument.Load(machineCfgFileName);
if (document != null)
{
XElement element = document.Root.Element("system.data");
if (element != null)
{
element = element.Element("DbProviderFactories");
if (element != null)
{
if (element.Elements().FirstOrDefault(a =>
a.Attribute("invariant").Value == invarientValue) == null)
{
element.Add(new XElement("add",
new XAttribute("name", name),
new XAttribute("invariant", invarientValue),
new XAttribute("description", description),
new XAttribute("type", type)));
document.Save(machineCfgFileName);
Logging.Logger.Inform("Add the mysql data provider configuration to the " + machineCfgFileName);
}
}
}
}
}
/// <summary>
/// 创建卸载批处理文件。
/// </summary>
protected void CreateUnInstallBat()
{
string dir = GetTargetDirectory();
FileStream fs = new FileStream(dir + "UnInstall.bat", FileMode.Create);
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine("@echo off");
sw.WriteLine(@"C:\Windows\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe -u " + Path.Combine(GetTargetDirectory(), "DbSynchronization.exe"));
sw.WriteLine(string.Format("start /normal %windir%\\system32\\msiexec /x {0}", base.Context.Parameters["productCode"].ToString()));
sw.WriteLine("exit");
sw.Flush();
sw.Close();
fs.Close();
}
/// <summary>
/// 获取安装目标目录。
/// </summary>
protected string GetTargetDirectory()
{
string directory = Path.GetDirectoryName(base.Context.Parameters["assemblypath"].ToString());
if (directory[directory.Length - 1] != Path.DirectorySeparatorChar)
{
directory += Path.DirectorySeparatorChar;
}
return directory;
}
}
}
安装项目自定义过程: