local.settings.json
から接続文字列を正しくプルするためにDbContext
を取得する際に問題が発生しました
環境:
System.Data.Entity.Internal.AppConfig
にありますlocal.settings.json
ファイルを持っていますが、これはドットネットコアではありません。 .net4.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
トークン値に移動する:同じエラーが発生するprovider
属性内のConnectionString
属性をEntityClient
に設定します:これは何もしませんでしたShipBob_DevEntities
を文字列値=からConnectionString
の値にする:これにより、次のような新しいエラーがスローされます。
キーワードメタデータはサポートされていません
code first
アプローチで接続文字列が正しくない場合に発生するように見えるdatabase first
例外をスローするADO接続文字列を使用してみました。
dotPeekを使用してEntityFramework.dll
を逆コンパイルする自由を取り、問題をSystem.Data.Entity.Internal.LazyInternalConnection.TryInitializeFromAppConfig
まで追跡しました。このメソッド内には、ConnectionStringSettings
値がnullに設定されているProviderName
オブジェクトを吐き出すLazyInternalConnection.FindConnectionInConfig
への呼び出しがあります。残念ながら、この値を生成するために使用していると思われるAppConfig.cs
クラスをデバッグできないため、スタックします。
これまで、これら2つの記事を参照してきました。そのうちの1つは、プロバイダー名を独自のトークンとして配置することを示しています。ただし、これは機能していません。
https://github.com/Azure/azure-functions-cli/issues/19
https://github.com/Azure/azure-functions-cli/issues/46
Entity Framework接続のlocal.settings.jsonで使用する正しい形式を知っている人はいますか?
したがって、解決策は簡単なものになりました。 local.settings.json
[〜#〜]で指定されたProviderName
属性は、キャメルケースである必要があります[〜#〜]。
元のgitハブの議論から:
https://github.com/Azure/azure-functions-cli/issues/46
プロバイダー名をパスカルケースとして表示します
https://github.com/Azure/azure-functions-cli/issues/19
プロバイダー名がキャメルケースであることが疑似コードで表示されます見逃しがちでしたが、構成セクションは次のとおりである必要があります
"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"
}
}
これらの点は重要です:
ProviderName
属性がキャメルケースであることを確認してくださいSystem.Data.EntityClient
であることを確認してください注:この回答は、DbContextのパラメーターなしのコンストラクターを使用しようとしていることを前提としています。新しいコードを作成している場合は、2番目の賛成の答えに従うことが簡単にできます
ポータル構成、つまりデプロイメントスロットの使用を維持しながら、プロバイダー名の問題を回避する方法を考え出しました。静的プロパティを使用してdbコンテキストのデフォルトの接続文字列を設定する必要があります
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ポータルに接続文字列を追加することも含まれます。それらmetadata情報を含み、プロバイダー名を含まない完全な接続文字列を使用してください!
最初にdbを使用している場合、このコードがオーバーライドされないように、自動生成された.ttファイルt4テンプレートを編集する必要があります。
T4構文に関するリンクは次のとおりです。 https://docs.Microsoft.com/en-us/visualstudio/modeling/writing-a-t4-text-template
EFT4テンプレートの説明は次のとおりです。 https://msdn.Microsoft.com/en-us/library/jj613116(v = vs.113).aspx#1159a805-1bcf-4700-9e99-86d182f143fe
私はここでいくつかの同様の質問と回答を経験しました。それらの多くは誤解を招くか、全員が同じレベルにあり、Azureの機能がどのように機能しているかを理解していると想定しています。私のような初心者には答えがありません。ここで、私のソリューションを段階的に要約したいと思います。自動生成されたedmxファイルを変更する必要があるため、提供された回答が最善の選択肢であるとは思いません。誤って上書きしたり、データベースからedmxを次に更新したりする可能性があります。また、ここでの最良のオプションは、私の意見では、アプリ設定の代わりに接続文字列を使用することです。
最も重要なことは、local.settings.jsonファイルを理解していることですIS Azure用ではありません。名前が明確に示しているように、ローカルでアプリを実行することです。したがって、解決策は何の関係もありません。このファイル。
App.ConfigまたはWeb.Configは、Azure関数の接続文字列では機能しません。データベースレイヤーライブラリがある場合、Asp.Netアプリケーションで行うように、これらのいずれかを使用して接続文字列を上書きすることはできません。
を使用するには、AzureポータルのAzure関数のApplication Settings
の下に接続文字列を定義する必要があります。接続文字列があります。そこで、DBContextの接続文字列をコピーする必要があります。 edmxの場合、以下のようになります。接続タイプがあり、SQlAzureを使用しますが、カスタム(カスタムでのみ機能すると主張する人)でテストしましたが、両方で機能します。
metadata = res:// / Models.myDB.csdl | res:///Models.myDB.ssdl | res:// */Models.myDB.msl; provider = System.Data.SqlClient ;プロバイダー接続文字列= 'データソース= [yourdbURL];初期カタログ= myDB;永続的なセキュリティ情報= True;ユーザーID = xxxx;パスワード= xxx; MultipleActiveResultSets = True; App = 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: }
これが私のために働く2つのアプローチです:
アプローチ1
メタデータ= res:/// xxx.csdl | res:/// xxx.ssdl | res:// */xxx.msl; provider = System.Data.SqlClient;プロバイダー接続文字列= 'データソース= xxx.database.windows.net;初期カタログ= xxx;ユーザーID = xxx;パスワード= xxx; MultipleActiveResultSets = True; App = EntityFramework' `
public partial class TestEntities: DbContext
{
public TestEntities(string connectionString)
: base(connectionString)
{
}
string connectionString = Environment.GetEnvironmentVariable("connectionStringAppSettings");
using (var dbContext = new TestEntities(connectionString))
{
// Do Something
}
アプローチ2
ここでの目標は、アプローチ1の問題を回避するために、クラス「TestEntities」をそのままにすることです。
アプローチ1のように、接続文字列をアプリ設定(それぞれlocal.settings.json)に追加します
TestEntitiesはそのままにします
public partial class TestEntities : DbContext
{
public TestEntities ()
: base("name=TestEntities")
{
}
public partial class TestEntities
{
public TestEntities(string connectionString)
: base(connectionString)
{
}
}
以前に同様の問題が発生しました。目的を達成するために次のアプローチを使用します。参照してください。
local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=brucchstorage;AccountKey=<AccountKey>",
"AzureWebJobsDashboard": "DefaultEndpointsProtocol=https;AccountName=brucchstorage;AccountKey=<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:
}
また、Azure Functionsについては、 ローカル設定ファイル を参照してください。