调试AzureFunction以及部署azure函数时缺少ProviderName
我有一个问题是让DbContext
正确地从我的local.settings.json
提取连接字符串
语境:
- 这是一个Azurefunction项目
- 主要问题代码在
System.Data.Entity.Internal.AppConfig
- 虽然我有一个
local.settings.json
文件,但这不是dotnet核心。 这是.net 4.6.1
错误信息:
‘应用程序配置文件中的连接字符串’ShipBob_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
标记值:相同的错误ocurrs - 将
ConnectionString
属性中的provider
属性设置为EntityClient
:这没有做任何事情 -
使
ShipBob_DevEntities
成为一个字符串值=ConnectionString
的值:这会引发新的错误,其中包括不支持关键字元数据
-
我尝试使用ADO连接字符串,它抛出
code first
exception,这似乎是在database first
一种方法中连接字符串不正确时发生的。
我冒昧地使用dotPeek反编译EntityFramework.dll
并将问题追溯到System.Data.Entity.Internal.LazyInternalConnection.TryInitializeFromAppConfig
。 在这个方法中,有一个对LazyInternalConnection.FindConnectionInConfig
的调用,它调出一个ConnectionStringSettings
对象,该对象的ProviderName
值设置为null。 不幸的是我无法调试它似乎用来生成这个值的AppConfig.cs
类,所以我被卡住了。
到目前为止,我已经查阅了这两篇文章。 其中一个规定将提供者名称作为自己的令牌; 但是,这不起作用。
https://github.com/Azure/azure-functions-cli/issues/193
https://github.com/Azure/azure-functions-cli/issues/46
有没有人知道在local.settings.json中使用的entity framework连接的正确格式?
所以解决方案最终变得微不足道。 local.settings.json
指定的ProviderName
属性必须是驼峰式的。
从原来的git hub讨论:
https://github.com/Azure/azure-functions-cli/issues/46
将提供程序名称显示为pascal大小写
https://github.com/Azure/azure-functions-cli/issues/193
在伪代码中显示提供者名称是camel case这很容易错过,但您的配置部分必须完全如下
"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配置中复制字符串,请确保使用unescape撇号
- 确保
ProviderName
属性是驼峰式的 - 确保提供程序名称为
System.Data.EntityClient
修复部署中缺少的providername
注意,这个答案假设您正在尝试使用DbContext的无参数构造函数。 如果您要创建新代码,您可以轻松地按照第二个提出的答案
我想出了一种绕过提供程序名称问题的方法,同时仍保留使用门户网站配置和部署插槽的方法。 它涉及使用静态属性设置db context的默认连接字符串
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应用程序等,仍然可以继续按预期运行。 这还涉及将连接字符串作为AppSetting添加到azure门户,而不是实际的连接字符串。 请使用完整的连接字符串,包括元数据信息,但没有提供者名称!
编辑
您需要编辑自动生成的.tt文件t4模板,以确保在首先使用db时不会覆盖此代码。
以下是T4语法的链接: https : //docs.microsoft.com/en-us/visualstudio/modeling/writing-a-t4-text-template
以下是对EF T4模板的解释: https : //msdn.microsoft.com/en-us/library/jj613116(v = vs133).aspx#1159a805-1bcf- 4700-9e99-86d182f143fe
我在这里经历了几个类似的问题和答案。 他们中的许多人要么误导,要么假设每个人都处于同一水平,并了解azure色function是如何运作的。 像我这样的新手没有答案。 我想在此总结一下我的解决方案。 我不认为提供答案是最佳选择,因为它会强制您更改自动生成的edmx文件,这些文件可能被错误覆盖或从数据库下次更新edmx。 此外,最好的选择是在我看来使用连接字符串而不是应用程序设置。
-
最重要的是我们了解local.settings.json文件不是为了AZURE。 它是在本地运行您的应用程序,因为名称显然是在说。 所以解决方案与此文件无关。
-
App.Config或Web.Config不适用于Azurefunction连接字符串。 如果您有数据库层库,则无法像使用Asp.Net应用程序那样使用其中任何一个覆盖连接字符串。
-
为了使用,您需要在Azurefunction中的“
Application Settings
下的azure门户上定义连接字符串。 有连接字符串。 你应该复制你的DBContext的连接字符串。 如果它是edmx,它将如下所示。 有连接类型,我使用它SQlAzure但我测试与自定义(有人声称只适用于自定义)适用于两者。
metadata = res:// /Models.myDB.csdl|res:// /Models.myDB.ssdl|res://*/Models.myDB.msl;provider=System.Data.SqlClient;provider connection string =’data source = [yourdbURL]; initial catalog = myDB; persist security info = True; user id = xxxx; password = xxx; MultipleActiveResultSets = True; App = EntityFramework
- 设置完成后,您需要读取应用程序中的url并提供DBContext。 DbContext实现了一个带有连接字符串参数的构造函数。 默认情况下,构造函数没有任何参数,但您可以扩展它。 如果您使用的是POCO类,则可以简单地修改DbContext类。 如果您使用像我这样的数据库生成的Edmx类,您不想触摸自动生成的edmx类,而不想在同一名称空间中创建分部类并扩展此类,如下所示。
这是自动生成的DbContext
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()); } } }
- 毕竟,您可以使用下面的代码在Azurefunction项目中从azure设置获取连接字符串,并提供给您的DbContext myDBEntities是您在连接字符串的azure门户中提供的名称。
var connString = ConfigurationManager.ConnectionStrings["myDBEntities"].ConnectionString; using (var dbContext = new myDBEntities(connString)) { //TODO: }
我之前遇到过类似的问题,我会用以下方法来实现我的目的,你可以参考它:
local.settings.json
{ "IsEncrypted": false, "Values": { "AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=brucchstorage;AccountKey=", "AzureWebJobsDashboard": "DefaultEndpointsProtocol=https;AccountName=brucchstorage;AccountKey= ", "sqldb-connectionstring": "Data Source=.\\sqlexpress;Initial Catalog=DefaultConnection;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False" }, "ConnectionStrings": { "Bruce_SQLConnectionString": "Data Source=.\\sqlexpress;Initial Catalog=DefaultConnection;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False" } }
用于检索连接字符串:
var connString = ConfigurationManager.AppSettings["sqldb-connectionstring"]; //or var connString = ConfigurationManager.ConnectionStrings["Bruce_SQLConnectionString"].ConnectionString; using (var dbContext = new BruceDbContext(connString)) { //TODO: }
或者你可以为你的DbContext
初始化你的无参数构造函数,如下所示:
public class BruceDbContext:DbContext { public BruceDbContext() : base("Bruce_SQLConnectionString") { } public BruceDbContext(string connectionString) : base(connectionString) { } }
然后,您可以为DbContext
创建实例,如下所示:
using (var dbContext = new BruceDbContext(connString)) { //TODO: }
此外,您可以参考Azurefunction的本地设置文件 。
- 使用未处理的Service Bus故障消息回收Azure辅助角色
- 如何使用Azure流畅的资源管理注册资源提供程序?
- 在Azure上的WebJob中使用connectionstring
- 无法从Azure AD获取承载令牌以与API App一起使用
- 发布时将连接字符串从开发更改为生产
- ASP.NET Web API和OpenID Connect:如何从授权代码获取访问令牌
- 强制EventProcessorHost将失败的Azure Event Hub eventData重新传递给IEventProcessor.ProcessEvents方法
- 图Api – 401未经授权
- Azure Redis缓存 – ConnectionMultiplexer对象池