未成功,做个记录,SelfHost.HttpSelfHostServer 如何加载证书
System.Web.Http.SelfHost.HttpSelfHostServer 如何加载证书 Dim certificate = LoadCertificateFromFile(certPath, certPassword)
在 System.Web.Http.SelfHost.HttpSelfHostServer
中加载证书需要通过 HttpSelfHostConfiguration
类进行配置。以下是完整的实现方案:
步骤 1:修改证书加载方法
保持之前的证书加载方法不变:
Imports System.Security.Cryptography.X509Certificates' 从本地文件路径加载证书
Private Shared Function LoadCertificateFromFile(certPath As String, certPassword As String) As X509Certificate2TryDim certificate = New X509Certificate2(certPath,certPassword,X509KeyStorageFlags.MachineKeySet OrX509KeyStorageFlags.PersistKeySet OrX509KeyStorageFlags.Exportable)Return certificateCatch ex As ExceptionThrow New Exception("加载证书失败: " & ex.Message, ex)End Try
End Function
步骤 2:配置 HttpSelfHostConfiguration
使用证书
在 Main
方法中,创建配置并指定证书:
Imports System
Imports System.Net
Imports System.Web.Http
Imports System.Web.Http.SelfHost
Imports System.Security.Cryptography.X509CertificatesModule ProgramSub Main()' 证书路径和密码Dim certPath As String = "C:\Path\To\YourCertificate.pfx"Dim certPassword As String = "YourSecurePassword"' 服务基地址(HTTPS)Dim baseAddress As New Uri("https://localhost:44300/")' 从文件加载证书Dim certificate = LoadCertificateFromFile(certPath, certPassword)' 创建配置并指定证书Dim config As New HttpSelfHostConfiguration(baseAddress)' 配置路由config.Routes.MapHttpRoute(name:="DefaultApi",routeTemplate:="api/{controller}/{id}",defaults:=New With {.id = RouteParameter.Optional})' 临时信任所有证书(仅用于开发环境)ServicePointManager.ServerCertificateValidationCallback = Function(sender, cert, chain, errors) True' 创建服务器并启动Using server As New HttpSelfHostServer(config)' 添加 HTTPS 端点并指定证书Dim binding = New HttpBindingInfo(HttpScheme.Https,certificate)server.Configuration.Services.Replace(GetType(IHttpBindingInfoProvider),New CustomBindingInfoProvider(binding))server.OpenAsync().Wait()Console.WriteLine("服务已启动: " & baseAddress)Console.WriteLine("按 Enter 停止服务...")Console.ReadLine()End UsingEnd Sub
End Module
步骤 3:创建自定义绑定信息提供程序
需要创建一个辅助类来提供证书绑定信息:
Imports System.Web.Http.SelfHost.ServiceModel
Imports System.ServiceModel.ChannelsPublic Class CustomBindingInfoProviderImplements IHttpBindingInfoProviderPrivate ReadOnly _bindingInfo As HttpBindingInfoPublic Sub New(bindingInfo As HttpBindingInfo)_bindingInfo = bindingInfoEnd SubPublic Function GetBindingInfo() As HttpBindingInfo Implements IHttpBindingInfoProvider.GetBindingInfoReturn _bindingInfoEnd Function
End Class
关键点说明
-
证书绑定方式:
- 通过
HttpBindingInfo
类指定 HTTPS 协议和证书 - 使用
CustomBindingInfoProvider
替换默认的绑定信息提供程序
- 通过
-
端口权限:
- 确保应用程序有访问指定端口的权限
- 非管理员用户无法绑定 1-1023 之间的端口
-
安全注意事项:
- 生产环境必须使用受信任的证书
- 禁用
ServicePointManager.ServerCertificateValidationCallback
的临时信任代码
完整代码示例
将上述代码组合在一起:
Imports System
Imports System.Net
Imports System.Web.Http
Imports System.Web.Http.SelfHost
Imports System.Security.Cryptography.X509Certificates
Imports System.Web.Http.SelfHost.ServiceModel
Imports System.ServiceModel.ChannelsModule ProgramSub Main()' 证书路径和密码Dim certPath As String = "C:\Path\To\YourCertificate.pfx"Dim certPassword As String = "YourSecurePassword"' 服务基地址(HTTPS)Dim baseAddress As New Uri("https://localhost:44300/")' 从文件加载证书Dim certificate = LoadCertificateFromFile(certPath, certPassword)' 创建配置并指定证书Dim config As New HttpSelfHostConfiguration(baseAddress)' 配置路由config.Routes.MapHttpRoute(name:="DefaultApi",routeTemplate:="api/{controller}/{id}",defaults:=New With {.id = RouteParameter.Optional})' 临时信任所有证书(仅用于开发环境)ServicePointManager.ServerCertificateValidationCallback = Function(sender, cert, chain, errors) True' 创建服务器并启动Using server As New HttpSelfHostServer(config)' 添加 HTTPS 端点并指定证书Dim binding = New HttpBindingInfo(HttpScheme.Https,certificate)server.Configuration.Services.Replace(GetType(IHttpBindingInfoProvider),New CustomBindingInfoProvider(binding))server.OpenAsync().Wait()Console.WriteLine("服务已启动: " & baseAddress)Console.WriteLine("按 Enter 停止服务...")Console.ReadLine()End UsingEnd Sub' 从本地文件路径加载证书Private Shared Function LoadCertificateFromFile(certPath As String, certPassword As String) As X509Certificate2TryDim certificate = New X509Certificate2(certPath,certPassword,X509KeyStorageFlags.MachineKeySet OrX509KeyStorageFlags.PersistKeySet OrX509KeyStorageFlags.Exportable)Return certificateCatch ex As ExceptionThrow New Exception("加载证书失败: " & ex.Message, ex)End TryEnd Function
End Module' 自定义绑定信息提供程序
Public Class CustomBindingInfoProviderImplements IHttpBindingInfoProviderPrivate ReadOnly _bindingInfo As HttpBindingInfoPublic Sub New(bindingInfo As HttpBindingInfo)_bindingInfo = bindingInfoEnd SubPublic Function GetBindingInfo() As HttpBindingInfo Implements IHttpBindingInfoProvider.GetBindingInfoReturn _bindingInfoEnd Function
End Class
常见问题
-
证书加载失败:
System.Security.Cryptography.CryptographicException: 无法访问私钥
- 解决:确保证书文件存在且应用程序有读取权限,使用正确的密码。
-
端口被占用:
System.InvalidOperationException: 无法启动 HTTP 服务器,端口已被占用
- 解决:使用
netstat -ano | findstr :44300
检查并关闭占用端口的进程。
- 解决:使用
-
HTTPS 连接被拒绝:
- 解决:确认证书格式正确(PFX 且包含私钥),并通过
certificate.Verify()
验证证书有效性。
- 解决:确认证书格式正确(PFX 且包含私钥),并通过
通过这种方式,您可以在 HttpSelfHostServer
中成功加载并使用证书,实现安全的 HTTPS 通信。
严重性 代码 说明 项目 文件 行 禁止显示状态 错误(活动) BC30002 未定义类型“HttpBindingInfo”。IHttpBindingInfoProvider,CustomBindingInfoProvider
您遇到的错误是因为 HttpBindingInfo
和 IHttpBindingInfoProvider
类型在较新版本的 .NET 中已被弃用或移动到不同的命名空间。以下是针对 ASP.NET Web API 2 的兼容解决方案:
替代方案:使用自定义 HTTP 消息处理程序
通过自定义消息处理程序来配置 HTTPS 证书,这种方法不依赖于已弃用的 HttpBindingInfo
类:
Imports System
Imports System.Net
Imports System.Net.Http
Imports System.Security.Cryptography.X509Certificates
Imports System.ServiceModel
Imports System.ServiceModel.Channels
Imports System.Web.Http
Imports System.Web.Http.SelfHostModule ProgramSub Main()' 证书路径和密码Dim certPath As String = "C:\Path\To\YourCertificate.pfx"Dim certPassword As String = "YourSecurePassword"' 服务基地址(HTTPS)Dim baseAddress As New Uri("https://localhost:44300/")' 从文件加载证书Dim certificate = LoadCertificateFromFile(certPath, certPassword)' 创建配置Dim config As New HttpSelfHostConfiguration(baseAddress)' 配置路由config.Routes.MapHttpRoute(name:="DefaultApi",routeTemplate:="api/{controller}/{id}",defaults:=New With {.id = RouteParameter.Optional})' 临时信任所有证书(仅用于开发环境)ServicePointManager.ServerCertificateValidationCallback = Function(sender, cert, chain, errors) True' 配置 HTTPS 端点config.HostNameComparisonMode = HostNameComparisonMode.Exactconfig.MaxReceivedMessageSize = 2147483647 ' 增大消息大小限制' 创建服务器并启动Using server As New HttpSelfHostServer(config)' 启动服务器前绑定证书(通过自定义配置)BindHttpsCertificate(baseAddress.Port, certificate)server.OpenAsync().Wait()Console.WriteLine("服务已启动: " & baseAddress)Console.WriteLine("按 Enter 停止服务...")Console.ReadLine()End UsingEnd Sub' 从本地文件路径加载证书Private Shared Function LoadCertificateFromFile(certPath As String, certPassword As String) As X509Certificate2TryDim certificate = New X509Certificate2(certPath,certPassword,X509KeyStorageFlags.MachineKeySet OrX509KeyStorageFlags.PersistKeySet OrX509KeyStorageFlags.Exportable)Return certificateCatch ex As ExceptionThrow New Exception("加载证书失败: " & ex.Message, ex)End TryEnd Function' 绑定证书到指定端口(使用 netsh 命令)Private Shared Sub BindHttpsCertificate(port As Integer, certificate As X509Certificate2)' 获取证书指纹Dim thumbprint = certificate.Thumbprint' 创建 SSL 证书绑定(使用 Process 调用 netsh)Dim process As New System.Diagnostics.Process()process.StartInfo.FileName = "netsh"process.StartInfo.Arguments = String.Format("http add sslcert ipport=0.0.0.0:{0} certhash={1} appid=""{{{2}}}""",port,thumbprint,Guid.NewGuid().ToString())process.StartInfo.UseShellExecute = Falseprocess.StartInfo.RedirectStandardOutput = Trueprocess.StartInfo.RedirectStandardError = Trueprocess.Start()' 等待命令执行完成process.WaitForExit()' 检查是否有错误If process.ExitCode <> 0 ThenDim errorOutput = process.StandardError.ReadToEnd()Throw New Exception("绑定证书失败: " & errorOutput)End IfEnd Sub
End Module
关键点说明
-
证书绑定方式:
- 通过
netsh http add sslcert
命令将证书绑定到指定端口 - 使用
BindHttpsCertificate
方法执行此操作
- 通过
-
权限要求:
- 需要管理员权限才能执行
netsh
命令 - 建议以管理员身份运行应用程序
- 需要管理员权限才能执行
-
清理绑定:
- 应用程序停止时,证书绑定不会自动解除
- 可使用
netsh http delete sslcert ipport=0.0.0.0:44300
手动删除绑定
完整解决方案
如果上述方法仍有问题,可以尝试使用 OWIN 自托管 替代(更现代的方案):
vb
Imports Microsoft.Owin.Hosting
Imports Owin
Imports System.Web.Http
Imports System.Security.Cryptography.X509CertificatesPublic Class StartupPublic Sub Configuration(app As IAppBuilder)Dim config As New HttpConfiguration()config.Routes.MapHttpRoute(name:="DefaultApi",routeTemplate:="api/{controller}/{id}",defaults:=New With {.id = RouteParameter.Optional})app.UseWebApi(config)End Sub
End ClassModule ProgramSub Main()Dim certPath As String = "C:\Path\To\YourCertificate.pfx"Dim certPassword As String = "YourSecurePassword"Dim baseAddress As String = "https://localhost:44300/"Dim certificate = LoadCertificateFromFile(certPath, certPassword)' 临时信任所有证书(仅用于开发环境)System.Net.ServicePointManager.ServerCertificateValidationCallback = Function(sender, cert, chain, errors) True' 启动 OWIN 自托管服务Dim options As New StartOptions(baseAddress)options.Settings.Add("sslCertThumbprint", certificate.Thumbprint)Using webApp = WebApp.Start(Of Startup)(options)Console.WriteLine("服务已启动: " & baseAddress)Console.WriteLine("按 Enter 停止服务...")Console.ReadLine()End UsingEnd SubPrivate Shared Function LoadCertificateFromFile(certPath As String, certPassword As String) As X509Certificate2' 与前面的方法相同...End Function
End Module
选择建议
- 传统 Web API 自托管:使用第一个方案(通过
netsh
绑定证书) - 现代 OWIN 自托管:使用第二个方案(更简单且兼容性更好)
无论选择哪种方案,都需要确保:
- 证书格式正确(PFX 且包含私钥)
- 应用程序有访问证书的权限
- 端口未被其他应用占用
certhash={1} appid=""{{{2}}}""", 这2个参数什么意思
在netsh http add sslcert
命令中,certhash
和appid
是两个关键参数,它们的作用和含义如下:
1. certhash
参数(证书哈希值)
- 含义:指定要绑定到 HTTP 端口的 SSL 证书的指纹(Thumbprint),即证书的唯一标识符。
- 作用:
- 操作系统通过指纹定位到注册表中存储的具体证书。
- 确保绑定的是正确的证书,避免与其他证书混淆。
- 获取方式:
- 通过
X509Certificate2.Thumbprint
属性获取(如代码中的certificate.Thumbprint
)。 - 也可通过 Windows 证书管理器查看(运行
certmgr.msc
,找到证书后查看 “详细信息” 中的 “指纹”)。
- 通过
2. appid
参数(应用程序 ID)
- 含义:指定绑定证书的应用程序的唯一标识符(GUID)。
- 作用:
- 区分不同应用程序对同一端口的绑定(理论上一个端口只能绑定一个证书)。
- 当多个应用程序需要共享端口时,通过
appid
标识各自的证书绑定。
- 格式要求:
- 必须是符合 GUID 格式的字符串(例如
{12345678-ABCD-EFGH-IJKL-1234567890AB}
)。 - 代码中使用
Guid.NewGuid().ToString()
动态生成唯一 ID,避免冲突。
- 必须是符合 GUID 格式的字符串(例如
命令参数示例解析
vb
netsh http add sslcert ipport=0.0.0.0:44300 certhash={1} appid="{{{2}}}"
ipport=0.0.0.0:44300
:绑定到所有 IP 地址的 44300 端口。certhash={1}
:替换为实际证书的指纹(例如A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6Q7R8
)。appid="{{{2}}}"
:替换为生成的 GUID(例如{12345678-1234-1234-1234-123456789012}
)。
注意事项
- 权限要求:
- 必须以管理员权限运行
netsh
命令,否则会提示 “访问被拒绝”。
- 必须以管理员权限运行
- 证书匹配:
certhash
必须与证书存储中的指纹完全一致(区分大小写,且不带空格)。
- 端口冲突:
- 一个端口只能绑定一个证书,若端口已被其他应用绑定,需先删除原有绑定:
bash
netsh http delete sslcert ipport=0.0.0.0:44300
- 一个端口只能绑定一个证书,若端口已被其他应用绑定,需先删除原有绑定:
appid
的作用范围:- 若多个应用程序使用相同
appid
,它们可以共享同一个端口的证书绑定(但需谨慎使用)。
- 若多个应用程序使用相同