如何在Azure函数中指定EntityFramework ProviderName

时间:2016-10-07 12:11:34

标签: entity-framework function configuration azure-functions

我正在尝试将一些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))]

装饰我的MyDB Partial

我将该配置定义为:

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 ..

6 个答案:

答案 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)

提供的答案是完美的,它帮助了我很多,但它不是动态的,因为我不想硬编码我的连接字符串。如果你正在使用天蓝色功能的插槽。我正在寻找一个可以使用多个连接字符串的解决方案。对于遇到这个问题的其他人来说,这是我一步一步的替代方法。

  1. 最重要的是我们了解local.settings.json文件 不是为了AZURE。它是在本地运行您的应用程序名称 清楚地说。所以解决方案与此文件无关。

  2. App.Config或Web.Config不适用于Azure功能连接字符串。如果您有数据库层库,则无法像使用Asp.Net应用程序那样使用其中任何一个覆盖连接字符串。

  3. 为了使用,您需要在Azure功能的Application Settings下的Azure文档中定义连接字符串。有 连接字符串。你应该复制你的DBContext的连接字符串。如果它是edmx,它将如下所示。有连接类型,我使用它SQlAzure但我用Custom测试(有人声称只适用于自定义)适用于两者。

  4.   

    元数据= 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

    1. 设置完成后,您需要读取应用程序中的url并提供DBContext。 DbContext实现了一个带有连接字符串参数的构造函数。默认情况下,构造函数没有任何参数,但您可以扩展它。如果您使用的是POCO类,则可以简单地修改DbContext类。如果您使用像我这样的数据库生成的Edmx类,您不想触摸自动生成的edmx类,而不想在同一名称空间中创建部分类,并按如下所示扩展此类。
    2. 这是自动生成的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());
                  }
              }
          }
      
      1. 毕竟你可以使用下面的代码从Azure功能项目中获取azure设置的连接字符串并提供给你的DbContext myDBEntities是您在连接字符串的azure门户中提供的名称。
      2. 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相同的密钥和值。