C# 调试AzureFunction以及部署azure函数时缺少ProviderName
我在获取C# 调试AzureFunction以及部署azure函数时缺少ProviderName,c#,entity-framework,azure,azure-functions,C#,Entity Framework,Azure,Azure Functions,我在获取DbContext以正确地从我的local.settings.json中提取连接字符串时遇到问题 背景: 这是一个Azure功能项目 主要问题代码位于System.Data.Entity.Internal.AppConfig 虽然我有一个local.settings.json文件,但这不是dotnet核心。是.NET4.6.1 错误消息: '应用程序配置文件中的连接字符串'shippoB_DevEntities'不包含所需的providerName属性。“” Json配置: {
DbContext
以正确地从我的local.settings.json中提取连接字符串时遇到问题
背景:
- 这是一个Azure功能项目
- 主要问题代码位于
System.Data.Entity.Internal.AppConfig
- 虽然我有一个
local.settings.json
文件,但这不是dotnet核心。是.NET4.6.1
错误消息:
'应用程序配置文件中的连接字符串'shippoB_DevEntities'不包含所需的providerName属性。“”
Json配置:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"AzureWebJobsDashboard": ""
},
"ConnectionStrings": {
"ShipBob_DevEntities": {
"ConnectionString": "metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string='data source=***;initial catalog=***;persist security info=True;User Id=***;Password=***;;multipleactiveresultsets=True;application name=EntityFramework'",
"providerName": "System.Data.EntityClient"
}
}
}
已测试的配置版本:
- 将提供程序名称移动到实际的
ConnectionString
token值中:出现相同的错误
- 将
ConnectionString
属性中的provider
属性设置为EntityClient
:这没有任何作用
- 将
shippob\u DevEntities
的字符串值=设置为ConnectionString
的值:这会引发新的错误,如下所示:
不支持关键字元数据
- 我尝试使用一个ADO连接字符串,该字符串抛出一个
code-first
异常,这似乎是在数据库优先
方法中连接字符串不正确时发生的
我冒昧地使用dotPeek反编译了EntityFramework.dll
,并将问题追溯到System.Data.Entity.Internal.LazyInternalConnection.TryInitializeFromAppConfig
。在这个方法中有一个对LazyInternalConnection.FindConnectionInFig
的调用,它会抛出一个ConnectionStringSettings
对象的ProviderName
值设置为null。不幸的是,我无法调试它似乎用来生成此值的AppConfig.cs
类,因此我被卡住了
到目前为止,我已经查阅了这两篇文章,其中一篇文章指出将提供者名称作为它自己的令牌;但是,这不起作用
有人知道在local.settings.json中用于实体框架连接的正确格式吗?我以前遇到过类似的问题,我会使用以下方法来实现我的目的,您可以参考它:
local.settings.json
{
“IsEncrypted”:错误,
“价值观”:{
“AzureWebJobsStorage”:“DefaultEndpointsProtocol=https;AccountName=brucchstorage;AccountKey=for Azure函数。因此解决方案最终变得微不足道。在local.settings.json
中指定的ProviderName
属性必须是大小写
来自最初的git hub讨论:
将提供程序名称显示为pascal大小写
以伪代码的大小写显示提供程序名称
很容易错过,但您的配置部分必须完全如下所示
"ConnectionStrings": {
"ShipBob_DevEntities": {
"ConnectionString": "metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string='data source=***;initial catalog=***;persist security info=True;User Id=***;Password=***;;multipleactiveresultsets=True;application name=EntityFramework'",
"ProviderName": "System.Data.EntityClient"
}
}
以下几点很重要:
- 确保连接字符串包含元数据信息
- 如果从xml配置复制字符串,请确保取消勾选撇号
- 确保
ProviderName
属性为camel case
- 确保提供程序名称为
System.Data.EntityClient
修复了部署中缺少providername的问题
注意,这个答案假设您正在尝试使用DbContext的无参数构造函数。如果您正在创建新代码,您可以很容易地遵循第二个向上投票的答案
我找到了一种绕过提供者名称问题的方法,同时仍然保留门户配置的使用,从而保留部署槽
private static string _connectionString = "name=ShipBob_DevEntities";
static ShipBob_DevEntities()
{
if(!string.IsNullOrEmpty(System.Environment.GetEnvironmentVariable("AzureFunction")))
{
var connectionString = System.Environment.GetEnvironmentVariable("EntityFrameworkConnectionString");
if (!string.IsNullOrEmpty(connectionString))
{
_connectionString = connectionString;
}
}
}
public ShipBob_DevEntities()
: base(_connectionString)
{
this.Configuration.LazyLoadingEnabled = false;
}
这涉及开发人员在azure门户中创建应用程序设置作为标志。在我的情况下,它是AzureFunction。这确保我们的代码仅在azure函数中运行,并且此DbContext的所有其他客户端,无论是web应用程序、windows应用程序等,都可以继续按预期运行。这还涉及到添加正在将您到azure门户的连接字符串设置为应用设置,而不是实际的连接字符串。请使用完整的连接字符串,其中包含元数据信息,但不包含提供商名称
编辑
您需要编辑自动生成的.tt文件t4模板,以确保在首先使用db时不会覆盖此代码
以下是关于T4语法的链接:
这里有一个关于EF T4模板的解释:我在这里讨论了几个类似的问题和答案。其中许多问题和答案要么是误导性的,要么是假设每个人都处于同一水平,并且理解azure功能是如何工作的。像我这样的新手没有答案。我想在这里一步一步总结我的解决方案。我不知道我不认为提供的答案是最好的选择,因为它迫使您更改自动生成的edmx文件,这些文件可能会被错误覆盖,或者从数据库中更新您的edmx。在我看来,这里最好的选择是使用连接字符串,而不是应用程序设置
最重要的是我们理解local.settings.json文件
不适用于AZURE。它是以名称在本地运行您的应用程序
很明显。所以解决方案和这个文件无关
App.Config或Web.Config不适用于Azure函数连接字符串。如果您有数据库层库,则无法像在Asp.Net应用程序中那样使用其中任何一个来覆盖连接字符串
为了使用,您需要在azure功能的应用程序设置下的azure门户上定义连接字符串
连接字符串。在这里,您应该复制DBContext的连接字符串。如果是edmx,则如下所示
using (var dbContext = new BruceDbContext(connString))
{
//TODO:
}
"ConnectionStrings": {
"ShipBob_DevEntities": {
"ConnectionString": "metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string='data source=***;initial catalog=***;persist security info=True;User Id=***;Password=***;;multipleactiveresultsets=True;application name=EntityFramework'",
"ProviderName": "System.Data.EntityClient"
}
}
private static string _connectionString = "name=ShipBob_DevEntities";
static ShipBob_DevEntities()
{
if(!string.IsNullOrEmpty(System.Environment.GetEnvironmentVariable("AzureFunction")))
{
var connectionString = System.Environment.GetEnvironmentVariable("EntityFrameworkConnectionString");
if (!string.IsNullOrEmpty(connectionString))
{
_connectionString = connectionString;
}
}
}
public ShipBob_DevEntities()
: base(_connectionString)
{
this.Configuration.LazyLoadingEnabled = false;
}
namespace myApp.Data.Models
{
public partial class myDBEntities : DbContext
{
public myDBEntities()
: base("name=myDBEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
}
namespace myApp.Data.Models
{
[DbConfigurationType(typeof(myDBContextConfig))]
partial class myDBEntities
{
public myDBEntities(string connectionString) : base(connectionString)
{
}
}
public class myDBContextConfig : DbConfiguration
{
public myDBContextConfig()
{
SetProviderServices("System.Data.EntityClient",
SqlProviderServices.Instance);
SetDefaultConnectionFactory(new SqlConnectionFactory());
}
}
}
var connString = ConfigurationManager.ConnectionStrings["myDBEntities"].ConnectionString;
using (var dbContext = new myDBEntities(connString))
{
//TODO:
}
public partial class TestEntities: DbContext
{
public TestEntities(string connectionString)
: base(connectionString)
{
}
string connectionString = Environment.GetEnvironmentVariable("connectionStringAppSettings");
using (var dbContext = new TestEntities(connectionString))
{
// Do Something
}
public partial class TestEntities : DbContext
{
public TestEntities ()
: base("name=TestEntities")
{
}
public partial class TestEntities
{
public TestEntities(string connectionString)
: base(connectionString)
{
}
}