为什么 csc 可运行的 C# 程序在 Visual Studio 2022 中报错?
结论
两次执行面向的运行时不同。
在 Developer Command Prompt 中直接调用 csc.exe,很可能生成的是面向 .NET Framework 的程序。.NET Framework 可以从安装目录或 GAC 中找到 System.Security.Permissions。Visual Studio 项目明确以 net8.0 为目标,使用现代 .NET 运行时,默认不包含旧式 Code Access Security 组件。
问题通常出在手动引用的 MySql.Data.dll 与项目目标框架不兼容,或者该 DLL 的传递依赖没有随项目一起提供,与 Visual Studio 本身无关。
建议删除手动添加的 DLL 引用,改用 NuGet 安装兼容 net8.0 的 MySql.Data 包。NuGet 会选择合适的程序集并处理依赖项。
为什么直接使用 csc.exe 可以运行
Visual Studio Developer Command Prompt 中的 csc.exe 通常来自 .NET Framework 工具链。下面的命令虽然只明确引用了一个 DLL:
csc program.cs /r:MySql.Data.dll
编译器仍会自动使用当前工具链的默认框架引用。生成的 program.exe 随后由 .NET Framework CLR 运行,而非 .NET 8 的 CoreCLR。
因此,使用 csc.exe 编译成功,并不能说明程序运行在 .NET 8 上。csc 只是编译器,编译器版本与目标运行时是两个概念。
可以先检查实际调用的编译器:
where csc
如果路径类似下面这样,通常说明使用的是 .NET Framework 编译器:
...\Microsoft.NET\Framework64\v4.0.30319\csc.exe
在这种环境中,旧版或面向 .NET Framework 构建的 MySql.Data.dll 可以依赖 System.Security.Permissions。运行时通常能够提供这个程序集,因此程序可以正常启动。
为什么 net8.0 项目会报错
Visual Studio 项目的目标框架由项目文件指定:
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
.NET 8 不会将 .NET Framework 的完整程序集集合纳入共享框架。System.Security.Permissions 对应的 Code Access Security 模型也不属于现代 .NET 的常规安全机制。
异常出现在:
MySql.Data.MySqlClient.MySqlConnection.AssertPermissions()
这表明当前加载的 MySql.Data.dll 正在尝试访问 System.Security.Permissions。通常有以下两种原因:
- 手动选择了 Connector/NET 安装目录中面向 .NET Framework 的
MySql.Data.dll。 - 编译器可以引用这个 DLL,但它依赖的程序集没有复制到
bin输出目录。
手动添加程序集引用时,Visual Studio 只会引用指定文件,不会像 NuGet 那样根据包的目标框架分组选择资产并恢复完整的传递依赖。
异常中的俄语:
Не удается найти указанный файл.
意思是“找不到指定文件”。它与源代码目录中的西里尔字符或空格没有直接关系。
推荐解决方法:通过 NuGet 安装 Connector/NET
先在 Solution Explorer 中删除手动添加的 MySql.Data.dll 引用,再通过 NuGet 安装对应的软件包。
在 Visual Studio 中按以下步骤操作:
- 右键单击项目。
- 选择 Manage NuGet Packages。
- 搜索
MySql.Data。 - 选择与项目目标框架兼容的版本并安装。
- 确认项目中没有保留旧的文件引用。
也可以在项目目录中运行:
dotnet add package MySql.Data --version 9.5.0
dotnet restore
dotnet build
dotnet run
项目文件中应出现类似配置:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MySql.Data" Version="9.5.0" />
</ItemGroup>
</Project>
不要同时保留指向本地 MySql.Data.dll 的 <Reference>,否则 MSBuild 仍有可能选中手动引用的旧程序集。
重新生成前,检查项目的 Dependencies > Packages,确认 MySql.Data 显示为 NuGet 包,而非 Dependencies > Assemblies 下的文件引用。
如果仍然加载了错误的 DLL
可以临时输出程序集的位置和目标框架,确认程序实际加载的是哪个 MySql.Data.dll:
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.Versioning;
using MySql.Data.MySqlClient;
var assembly = typeof(MySqlConnection).Assembly;
Console.WriteLine(assembly.FullName);
Console.WriteLine(assembly.Location);
var targetFramework = assembly
.GetCustomAttributes<TargetFrameworkAttribute>()
.FirstOrDefault();
Console.WriteLine(targetFramework?.FrameworkName ?? "Unknown target framework");
如果输出路径指向 Connector/NET 的手动安装目录,而非项目的 NuGet 缓存或构建输出目录,说明旧引用还没有清除。
还要检查项目文件中是否残留类似配置:
<ItemGroup>
<Reference Include="MySql.Data">
<HintPath>...\MySql.Data.dll</HintPath>
</Reference>
</ItemGroup>
删除旧引用后重新执行:
dotnet restore
dotnet build
dotnet run
如有必要,可以关闭 Visual Studio,删除当前项目的 bin 和 obj 目录,然后重新恢复并生成。不要删除解决方案之外的共享目录或 NuGet 全局缓存。
能否直接安装 System.Security.Permissions
可以尝试通过 NuGet 添加兼容包:
dotnet add package System.Security.Permissions
这种做法更适合用于兼容性排查,不建议作为首选修复方案。它可能会消除当前的 FileNotFoundException,但无法保证旧程序集调用的所有 .NET Framework 安全 API 都能在 .NET 8 上正常工作。某些旧 API 在现代 .NET 中可能不起实际作用,也可能抛出 PlatformNotSupportedException。
应先逐项确认:
MySql.Data已通过 NuGet 安装;- NuGet 为
net8.0选择了正确的资产; - 项目没有同时引用旧的本地 DLL;
- 输出目录中没有残留旧版本程序集。
如果正确安装的包仍明确声明依赖 System.Security.Permissions,应由 NuGet 恢复该依赖,或者在确认兼容性后显式添加。
可使用的程序代码
依赖配置正确后,连接代码不需要特殊修改:
using System;
using MySql.Data.MySqlClient;
namespace ConsoleApp1
{
internal class Program
{
static void Main(string[] args)
{
string cs =
"server=localhost;userid=s;password=1234567;database=ilyadb";
using var con = new MySqlConnection(cs);
con.Open();
Console.WriteLine($"MySQL version : {con.ServerVersion}");
}
}
}
不建议将数据库密码直接写入源代码。实际项目应从用户机密、环境变量或受保护的配置中读取连接字符串。
csc.exe 示例之所以能够运行,很可能是因为它构建并运行了 .NET Framework 程序,而 Visual Studio 项目实际运行在 .NET 8 上。删除手动 DLL 引用并改用 NuGet PackageReference,通常可以解决目标框架选择错误和传递依赖缺失的问题。
备注:内容仅供参考。
