我正在尝试将一些webjob代码移植到新的Azure Functions。到目前为止,我已成功导入我的DLL并成功引用它们,但是当我在代码中使用连接字符串时,我收到一条错误消息,说我必须添加ProviderName:
应用程序中的连接字符串'ConnectionString' 配置文件不包含必需的providerName 属性“。
这通常不是问题,因为在webjob(或Web应用程序)中,这将在App或Web.config中,并且连接字符串将被我在Azure中输入的任何内容覆盖。
使用Azure Functions,我没有web.config(虽然我尝试添加一个无效),所以自然缺少providername。
如何指定?
修改 经过一些游戏以及下面的人们提供的一些有用的提示后,我已经几乎设法让它发挥作用。
我现在做的是以下内容:
var connString = **MY CONN STRING FROM CONFIG**; // Constring without metadata etc.
EntityConnectionStringBuilder b = new EntityConnectionStringBuilder();
b.Metadata = "res://*/Entities.MyDB.csdl|res://*/Entities.MyDB.ssdl|res://*/Entities.MyDB.msl";
b.ProviderConnectionString = connString.ConnectionString;
b.Provider = "System.Data.SqlClient";
return new MyDB(b.ConnectionString);
这给了我调用数据库所需的内容。我在局部类中使用静态方法来获取运行上述代码的数据库实例,并使用[DbConfigurationType(typeof(MyDbConfiguration))]
我将该配置定义为:
public class MyDBConfiguration: DbConfiguration
{
public MyDBConfiguration()
{
SetProviderFactory("System.Data.EntityClient", EntityProviderFactory.Instance);
}
}
当我想要实际使用EF实体时,问题仍然存在。在这里,它将尝试使用原始配置初始化数据库类型,再次给我原始错误。根据这个堆栈跟踪:
at Void Initialize()
at System.Data.Entity.Internal.EntitySetTypePair GetEntitySetAndBaseTypeForType(System.Type)
at Void InitializeContext()
at System.Data.Entity.Core.Objects.ObjectContext CreateObjectContextFromConnectionModel()
at Void Initialize()
at Boolean TryInitializeFromAppConfig(System.String, System.Data.Entity.Internal.AppConfig)
at Void InitializeFromConnectionStringSetting(System.Configuration.ConnectionStringSettings)
所以我该如何避免这种情况?我想我需要一种方法来连接所有内容并运行我的自定义setter ..
答案 0 :(得分:6)
最后,斯蒂芬·莱恩德尔把我推向正确的方向;实体框架的基于代码的配置。
[DbConfigurationType(typeof(MyDBConfiguration))]
public partial class MyDB
{
public static MyDB GetDB()
{
var connString = **MY CONN STRING FROM SOMEWHERE**; // Constring without metadata etc.
EntityConnectionStringBuilder b = new EntityConnectionStringBuilder();
b.Metadata = "res://*/Entities.MyDB.csdl|res://*/Entities.MyDB.ssdl|res://*/Entities.MyDB.msl";
b.ProviderConnectionString = connString.ConnectionString;
b.Provider = "System.Data.SqlClient";
return new MyDB(b.ConnectionString);
}
public MyDB(string connectionString) : base(connectionString)
{
}
}
使用MyDbConfiguration:
public class MyDBConfiguration: DbConfiguration
{
public MyDBConfiguration()
{
SetProviderServices("System.Data.SqlClient", SqlProviderServices.Instance);
SetDefaultConnectionFactory(new SqlConnectionFactory());
}
}
使用上面的代码,EF从不要求与AppConfig相关的配置文件。但是记住,如果您的配置文件中有EF条目,将尝试使用它们,所以请确保它们已经消失。
就azure函数而言,这意味着我使用azure中的Azure Functions配置面板来插入没有Metadata和providername的ConnectionString,然后将其加载到GetDB中。
编辑:根据请求,以下是上述的一些解释性文字: 您无法在Azure Functions中添加有关连接的EF元数据,因为它们不使用app.config来指定它。这不是连接字符串的一部分,而是关于连接的元数据,除了EF用于映射到特定C#类和SQL提供程序等的连接字符串之外。为避免这种情况,您可以使用上面的示例对其进行硬编码。您可以通过创建一个继承自DBConfiguration的类来实现,并使用该标记(使用部分类的属性)标记您的EF数据库类。
此DBConfiguration包含一种实例化新数据库对象的不同方式,其中此元数据是硬编码的,但是连接字符串是从Azure中的应用程序设置中检索的。在这个例子中我只使用了静态方法,但我想它也可能是一个新的构造函数。
一旦你有了这个静态方法,就可以使用它来获取数据库代码中的新数据库,如下所示:
using (var db = MyDB.GetDB()) {
// db code here.
}
这允许您在没有APP.Config的情况下使用EntityFramework,您仍然可以使用Azure Functions APP设置更改连接字符串。
希望有所帮助
答案 1 :(得分:2)
使用this question,您可以在打开连接之前设置默认工厂,方法是使用个人DbConfiguration
课程(请参阅this link也可以使用):
public class MyDbConfiguration : DbConfiguration
{
public MyDbConfiguration()
{
SetDefaultConnectionFactory(new SqlConnectionFactory());
}
}
现在您需要告诉您的DbContext
使用新配置。由于无法使用web.config或app.config,您可以使用属性添加配置:
[DbConfigurationType(typeof(MyDbConfiguration))]
public class MyContextContext : DbContext
{
}
现在使用DbContext
上的连接字符串将默认使用SQL提供程序。
答案 2 :(得分:2)
提供的答案是完美的,它帮助了我很多,但它不是动态的,因为我不想硬编码我的连接字符串。如果你正在使用天蓝色功能的插槽。我正在寻找一个可以使用多个连接字符串的解决方案。对于遇到这个问题的其他人来说,这是我一步一步的替代方法。
最重要的是我们了解local.settings.json文件 不是为了AZURE。它是在本地运行您的应用程序名称 清楚地说。所以解决方案与此文件无关。
App.Config或Web.Config不适用于Azure功能连接字符串。如果您有数据库层库,则无法像使用Asp.Net应用程序那样使用其中任何一个覆盖连接字符串。
为了使用,您需要在Azure功能的Application Settings
下的Azure文档中定义连接字符串。有
连接字符串。你应该复制你的DBContext的连接字符串。如果它是edmx,它将如下所示。有连接类型,我使用它SQlAzure但我用Custom测试(有人声称只适用于自定义)适用于两者。
元数据= RES:// /Models.myDB.csdl|res:// /Models.myDB.ssdl|res://*/Models.myDB.msl;provider=System。 Data.SqlClient提供方 连接字符串='数据源= [yourdbURL];初始 catalog = myDB; persist security info = True;用户 ID = XXXX;密码= XXX; MultipleActiveResultSets = TRUE;应用=的EntityFramework
这是自动生成的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());
}
}
}
var connString = ConfigurationManager.ConnectionStrings["myDBEntities"].ConnectionString; using (var dbContext = new myDBEntities(connString)) { //TODO: }
答案 3 :(得分:1)
如果您无法简单地更改实例化DbContext
的方式,请添加答案。如果您正在调用使用无参数构造函数实例化DbContexts的代码,则会发生这种情况。
它涉及使用静态构造函数从azure门户中的appsettings读取连接字符串并将其传递给DbContext基础构造函数。这使您可以避免使用providerName
,并且还允许您保留对门户配置的使用,而无需对任何内容进行硬编码。
请在此处参阅我接受的答案:Missing ProviderName when debugging AzureFunction as well as deploying azure function
答案 4 :(得分:1)
在Azure函数内部偶然发现并解决了这个问题。
public static class MyFunction
{
// Putting this in more than one place in your project will cause an exception,
// if doing it after the DbConfiguration has been loaded.
static MyFunction() =>
DbConfiguration.Loaded += (_, d) =>
d.AddDefaultResolver(new global::MySql.Data.Entity.MySqlDependencyResolver());
// The rest of your function...
//[FunctionName("MyFunction")]
//public static async Task Run() {}
}
答案 5 :(得分:0)
您可以访问门户网站,点击Function app settings
然后点击Configure app settings
来访问网站的应用设置。这将打开一个刀片,允许您为功能应用程序设置所有应用程序设置。只需使用与web.config相同的密钥和值。