DataProtection 1.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. commit 7520ffa0efd04c18630c2612855cb590a94cc69a
  2. Author: Nate McMaster <[email protected]>
  3. Date: Wed Aug 29 14:33:57 2018 -0700
  4. Fix up service scoping in the EF Core xml repository and update package version to 2.2
  5. diff --git a/DataProtection.sln b/DataProtection.sln
  6. index 7b22058b828..7fb7eb0592c 100644
  7. --- a/DataProtection.sln
  8. +++ b/DataProtection.sln
  9. @@ -79,10 +79,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.DataPr
  10. EndProject
  11. Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test", "test\Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test\Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test.csproj", "{06728BF2-C5EB-44C7-9F30-14FAA5649E14}"
  12. EndProject
  13. -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EntityFrameworkCore", "samples\EntityFrameworkCore\EntityFrameworkCore.csproj", "{E837A2E3-FC93-494C-8689-5AF9C6802AD7}"
  14. -EndProject
  15. Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.DataProtection.EntityFrameworkCore", "src\Microsoft.AspNetCore.DataProtection.EntityFrameworkCore\Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.csproj", "{3E4CA7FE-741B-4C78-A775-220E0E3C1B03}"
  16. EndProject
  17. +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EntityFrameworkCoreSample", "samples\EntityFrameworkCoreSample\EntityFrameworkCoreSample.csproj", "{22BA4EAB-641E-42B2-BB37-9C3BCFD99F76}"
  18. +EndProject
  19. Global
  20. GlobalSection(SolutionConfigurationPlatforms) = preSolution
  21. Debug|Any CPU = Debug|Any CPU
  22. @@ -279,14 +279,6 @@ Global
  23. {06728BF2-C5EB-44C7-9F30-14FAA5649E14}.Release|Any CPU.Build.0 = Release|Any CPU
  24. {06728BF2-C5EB-44C7-9F30-14FAA5649E14}.Release|x86.ActiveCfg = Release|Any CPU
  25. {06728BF2-C5EB-44C7-9F30-14FAA5649E14}.Release|x86.Build.0 = Release|Any CPU
  26. - {E837A2E3-FC93-494C-8689-5AF9C6802AD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
  27. - {E837A2E3-FC93-494C-8689-5AF9C6802AD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
  28. - {E837A2E3-FC93-494C-8689-5AF9C6802AD7}.Debug|x86.ActiveCfg = Debug|Any CPU
  29. - {E837A2E3-FC93-494C-8689-5AF9C6802AD7}.Debug|x86.Build.0 = Debug|Any CPU
  30. - {E837A2E3-FC93-494C-8689-5AF9C6802AD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
  31. - {E837A2E3-FC93-494C-8689-5AF9C6802AD7}.Release|Any CPU.Build.0 = Release|Any CPU
  32. - {E837A2E3-FC93-494C-8689-5AF9C6802AD7}.Release|x86.ActiveCfg = Release|Any CPU
  33. - {E837A2E3-FC93-494C-8689-5AF9C6802AD7}.Release|x86.Build.0 = Release|Any CPU
  34. {3E4CA7FE-741B-4C78-A775-220E0E3C1B03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
  35. {3E4CA7FE-741B-4C78-A775-220E0E3C1B03}.Debug|Any CPU.Build.0 = Debug|Any CPU
  36. {3E4CA7FE-741B-4C78-A775-220E0E3C1B03}.Debug|x86.ActiveCfg = Debug|Any CPU
  37. @@ -295,6 +287,14 @@ Global
  38. {3E4CA7FE-741B-4C78-A775-220E0E3C1B03}.Release|Any CPU.Build.0 = Release|Any CPU
  39. {3E4CA7FE-741B-4C78-A775-220E0E3C1B03}.Release|x86.ActiveCfg = Release|Any CPU
  40. {3E4CA7FE-741B-4C78-A775-220E0E3C1B03}.Release|x86.Build.0 = Release|Any CPU
  41. + {22BA4EAB-641E-42B2-BB37-9C3BCFD99F76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
  42. + {22BA4EAB-641E-42B2-BB37-9C3BCFD99F76}.Debug|Any CPU.Build.0 = Debug|Any CPU
  43. + {22BA4EAB-641E-42B2-BB37-9C3BCFD99F76}.Debug|x86.ActiveCfg = Debug|Any CPU
  44. + {22BA4EAB-641E-42B2-BB37-9C3BCFD99F76}.Debug|x86.Build.0 = Debug|Any CPU
  45. + {22BA4EAB-641E-42B2-BB37-9C3BCFD99F76}.Release|Any CPU.ActiveCfg = Release|Any CPU
  46. + {22BA4EAB-641E-42B2-BB37-9C3BCFD99F76}.Release|Any CPU.Build.0 = Release|Any CPU
  47. + {22BA4EAB-641E-42B2-BB37-9C3BCFD99F76}.Release|x86.ActiveCfg = Release|Any CPU
  48. + {22BA4EAB-641E-42B2-BB37-9C3BCFD99F76}.Release|x86.Build.0 = Release|Any CPU
  49. EndGlobalSection
  50. GlobalSection(SolutionProperties) = preSolution
  51. HideSolutionNode = FALSE
  52. @@ -324,8 +324,8 @@ Global
  53. {295E8539-5450-4764-B3F5-51F968628022} = {5A3A5DE3-49AD-431C-971D-B01B62D94AE2}
  54. {C85ED942-8121-453F-8308-9DB730843B63} = {60336AB3-948D-4D15-A5FB-F32A2B91E814}
  55. {06728BF2-C5EB-44C7-9F30-14FAA5649E14} = {60336AB3-948D-4D15-A5FB-F32A2B91E814}
  56. - {E837A2E3-FC93-494C-8689-5AF9C6802AD7} = {5A3A5DE3-49AD-431C-971D-B01B62D94AE2}
  57. {3E4CA7FE-741B-4C78-A775-220E0E3C1B03} = {5FCB2DA3-5395-47F5-BCEE-E0EA319448EA}
  58. + {22BA4EAB-641E-42B2-BB37-9C3BCFD99F76} = {5A3A5DE3-49AD-431C-971D-B01B62D94AE2}
  59. EndGlobalSection
  60. GlobalSection(ExtensibilityGlobals) = postSolution
  61. SolutionGuid = {DD305D75-BD1B-43AE-BF04-869DA6A0858F}
  62. diff --git a/samples/EntityFrameworkCore/DataProtectionKeyContext.cs b/samples/EntityFrameworkCore/DataProtectionKeyContext.cs
  63. deleted file mode 100644
  64. index a84031ae50b..00000000000
  65. --- a/samples/EntityFrameworkCore/DataProtectionKeyContext.cs
  66. +++ /dev/null
  67. @@ -1,21 +0,0 @@
  68. -// Copyright (c) .NET Foundation. All rights reserved.
  69. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  70. -
  71. -using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
  72. -using Microsoft.EntityFrameworkCore;
  73. -
  74. -namespace EntityFrameworkCore
  75. -{
  76. - class DataProtectionKeyContext : DbContext, IDataProtectionKeyContext
  77. - {
  78. - public DataProtectionKeyContext(DbContextOptions<DataProtectionKeyContext> options) : base(options) { }
  79. - public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
  80. - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
  81. - {
  82. - base.OnConfiguring(optionsBuilder);
  83. - optionsBuilder.UseInMemoryDatabase("DataProtection_EntityFrameworkCore");
  84. - optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
  85. - optionsBuilder.EnableSensitiveDataLogging();
  86. - }
  87. - }
  88. -}
  89. diff --git a/samples/EntityFrameworkCore/EntityFrameworkCore.csproj b/samples/EntityFrameworkCoreSample/EntityFrameworkCoreSample.csproj
  90. similarity index 100%
  91. rename from samples/EntityFrameworkCore/EntityFrameworkCore.csproj
  92. rename to samples/EntityFrameworkCoreSample/EntityFrameworkCoreSample.csproj
  93. diff --git a/samples/EntityFrameworkCore/Program.cs b/samples/EntityFrameworkCoreSample/Program.cs
  94. similarity index 56%
  95. rename from samples/EntityFrameworkCore/Program.cs
  96. rename to samples/EntityFrameworkCoreSample/Program.cs
  97. index 9e8a0d5ee1a..d4e978a7b85 100644
  98. --- a/samples/EntityFrameworkCore/Program.cs
  99. +++ b/samples/EntityFrameworkCoreSample/Program.cs
  100. @@ -1,27 +1,35 @@
  101. // Copyright (c) .NET Foundation. All rights reserved.
  102. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  103. +using System;
  104. using Microsoft.AspNetCore.DataProtection;
  105. using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
  106. +using Microsoft.EntityFrameworkCore;
  107. using Microsoft.Extensions.DependencyInjection;
  108. using Microsoft.Extensions.Logging;
  109. -using System;
  110. -namespace EntityFrameworkCore
  111. +namespace EntityFrameworkCoreSample
  112. {
  113. class Program
  114. {
  115. static void Main(string[] args)
  116. {
  117. // Configure
  118. - using (var services = new ServiceCollection()
  119. + var services = new ServiceCollection()
  120. .AddLogging(o => o.AddConsole().SetMinimumLevel(LogLevel.Debug))
  121. - .AddDbContext<DataProtectionKeyContext>()
  122. + .AddDbContext<DataProtectionKeyContext>(o =>
  123. + {
  124. + o.UseInMemoryDatabase("DataProtection_EntityFrameworkCore");
  125. + o.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
  126. + o.EnableSensitiveDataLogging();
  127. + })
  128. .AddDataProtection()
  129. .PersistKeysToDbContext<DataProtectionKeyContext>()
  130. .SetDefaultKeyLifetime(TimeSpan.FromDays(7))
  131. .Services
  132. - .BuildServiceProvider(validateScopes: true))
  133. + .BuildServiceProvider(validateScopes: true);
  134. +
  135. + using(services)
  136. {
  137. // Run a sample payload
  138. var protector = services.GetDataProtector("sample-purpose");
  139. @@ -30,4 +38,11 @@ namespace EntityFrameworkCore
  140. }
  141. }
  142. }
  143. +
  144. + class DataProtectionKeyContext : DbContext, IDataProtectionKeyContext
  145. + {
  146. + public DataProtectionKeyContext(DbContextOptions<DataProtectionKeyContext> options) : base(options) { }
  147. +
  148. + public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
  149. + }
  150. }
  151. diff --git a/samples/Redis/Program.cs b/samples/Redis/Program.cs
  152. index f8f213cfad4..aa1cdf5164c 100644
  153. --- a/samples/Redis/Program.cs
  154. +++ b/samples/Redis/Program.cs
  155. @@ -7,7 +7,7 @@ using Microsoft.Extensions.DependencyInjection;
  156. using Microsoft.Extensions.Logging;
  157. using StackExchange.Redis;
  158. -namespace Redis
  159. +namespace RedisSample
  160. {
  161. public class Program
  162. {
  163. diff --git a/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/ConfigureKeyManagementOptions.cs b/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/ConfigureKeyManagementOptions.cs
  164. deleted file mode 100644
  165. index 246aa3c1e53..00000000000
  166. --- a/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/ConfigureKeyManagementOptions.cs
  167. +++ /dev/null
  168. @@ -1,22 +0,0 @@
  169. -// Copyright (c) .NET Foundation. All rights reserved.
  170. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  171. -
  172. -using Microsoft.AspNetCore.DataProtection.KeyManagement;
  173. -using Microsoft.AspNetCore.DataProtection.Repositories;
  174. -using Microsoft.Extensions.DependencyInjection;
  175. -using Microsoft.Extensions.Options;
  176. -using System;
  177. -
  178. -namespace Microsoft.AspNetCore.DataProtection.EntityFrameworkCore
  179. -{
  180. - internal class ConfigureKeyManagementOptions : IConfigureOptions<KeyManagementOptions>
  181. - {
  182. - private readonly IServiceProvider _serviceProvider;
  183. -
  184. - public ConfigureKeyManagementOptions(IServiceProvider serviceProvider)
  185. - => _serviceProvider = serviceProvider;
  186. -
  187. - public void Configure(KeyManagementOptions options)
  188. - => options.XmlRepository = _serviceProvider.CreateScope().ServiceProvider.GetRequiredService<IXmlRepository>();
  189. - }
  190. -}
  191. \ No newline at end of file
  192. diff --git a/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/DataProtectionKey.cs b/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/DataProtectionKey.cs
  193. index b13a9fbd603..c236d5cb893 100644
  194. --- a/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/DataProtectionKey.cs
  195. +++ b/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/DataProtectionKey.cs
  196. @@ -1,9 +1,6 @@
  197. // Copyright (c) .NET Foundation. All rights reserved.
  198. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  199. -using System.ComponentModel.DataAnnotations;
  200. -using System.ComponentModel.DataAnnotations.Schema;
  201. -
  202. namespace Microsoft.AspNetCore.DataProtection.EntityFrameworkCore
  203. {
  204. /// <summary>
  205. @@ -14,8 +11,6 @@ namespace Microsoft.AspNetCore.DataProtection.EntityFrameworkCore
  206. /// <summary>
  207. /// The entity identifier of the <see cref="DataProtectionKey"/>.
  208. /// </summary>
  209. - [Key]
  210. - [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
  211. public int Id { get; set; }
  212. /// <summary>
  213. diff --git a/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/EntityFrameworkCoreDataProtectionExtensions.cs b/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/EntityFrameworkCoreDataProtectionExtensions.cs
  214. index a3577f0e6d6..ff24b58eb9d 100644
  215. --- a/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/EntityFrameworkCoreDataProtectionExtensions.cs
  216. +++ b/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/EntityFrameworkCoreDataProtectionExtensions.cs
  217. @@ -1,15 +1,15 @@
  218. // Copyright (c) .NET Foundation. All rights reserved.
  219. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  220. +using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
  221. using Microsoft.AspNetCore.DataProtection.KeyManagement;
  222. -using Microsoft.AspNetCore.DataProtection.Repositories;
  223. using Microsoft.EntityFrameworkCore;
  224. using Microsoft.Extensions.DependencyInjection;
  225. using Microsoft.Extensions.Logging;
  226. +using Microsoft.Extensions.Logging.Abstractions;
  227. using Microsoft.Extensions.Options;
  228. -using System;
  229. -namespace Microsoft.AspNetCore.DataProtection.EntityFrameworkCore
  230. +namespace Microsoft.AspNetCore.DataProtection
  231. {
  232. /// <summary>
  233. /// Extension method class for configuring instances of <see cref="EntityFrameworkCoreXmlRepository{TContext}"/>
  234. @@ -24,22 +24,15 @@ namespace Microsoft.AspNetCore.DataProtection.EntityFrameworkCore
  235. public static IDataProtectionBuilder PersistKeysToDbContext<TContext>(this IDataProtectionBuilder builder)
  236. where TContext : DbContext, IDataProtectionKeyContext
  237. {
  238. - var services = builder.Services;
  239. -
  240. - services.AddScoped<Func<TContext>>(
  241. - provider => new Func<TContext>(
  242. - () => provider.CreateScope().ServiceProvider.GetService<TContext>()));
  243. -
  244. - services.AddScoped<IXmlRepository>(provider =>
  245. + builder.Services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(services =>
  246. {
  247. - var scope = provider.CreateScope();
  248. - return new EntityFrameworkCoreXmlRepository<TContext>(
  249. - contextFactory: scope.ServiceProvider.GetRequiredService<Func<TContext>>(),
  250. - loggerFactory: scope.ServiceProvider.GetService<ILoggerFactory>());
  251. + var loggerFactory = services.GetService<ILoggerFactory>() ?? NullLoggerFactory.Instance;
  252. + return new ConfigureOptions<KeyManagementOptions>(options =>
  253. + {
  254. + options.XmlRepository = new EntityFrameworkCoreXmlRepository<TContext>(services, loggerFactory);
  255. + });
  256. });
  257. - services.AddTransient<IConfigureOptions<KeyManagementOptions>, ConfigureKeyManagementOptions>();
  258. -
  259. return builder;
  260. }
  261. }
  262. diff --git a/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/EntityFrameworkCoreXmlRepository.cs b/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/EntityFrameworkCoreXmlRepository.cs
  263. index 6720c400b8a..62250cf3efb 100644
  264. --- a/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/EntityFrameworkCoreXmlRepository.cs
  265. +++ b/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/EntityFrameworkCoreXmlRepository.cs
  266. @@ -1,13 +1,14 @@
  267. // Copyright (c) .NET Foundation. All rights reserved.
  268. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  269. -using Microsoft.AspNetCore.DataProtection.Repositories;
  270. -using Microsoft.EntityFrameworkCore;
  271. -using Microsoft.Extensions.Logging;
  272. using System;
  273. using System.Collections.Generic;
  274. using System.Linq;
  275. using System.Xml.Linq;
  276. +using Microsoft.AspNetCore.DataProtection.Repositories;
  277. +using Microsoft.EntityFrameworkCore;
  278. +using Microsoft.Extensions.DependencyInjection;
  279. +using Microsoft.Extensions.Logging;
  280. namespace Microsoft.AspNetCore.DataProtection.EntityFrameworkCore
  281. {
  282. @@ -17,40 +18,51 @@ namespace Microsoft.AspNetCore.DataProtection.EntityFrameworkCore
  283. public class EntityFrameworkCoreXmlRepository<TContext> : IXmlRepository
  284. where TContext : DbContext, IDataProtectionKeyContext
  285. {
  286. - private readonly ILoggerFactory _loggerFactory;
  287. - private readonly Func<TContext> _contextFactory;
  288. -
  289. - private ILogger<EntityFrameworkCoreXmlRepository<TContext>> _logger => _loggerFactory?.CreateLogger<EntityFrameworkCoreXmlRepository<TContext>>();
  290. -
  291. - private TContext _context => _contextFactory?.Invoke();
  292. + private readonly IServiceProvider _services;
  293. + private readonly ILogger _logger;
  294. /// <summary>
  295. /// Creates a new instance of the <see cref="EntityFrameworkCoreXmlRepository{TContext}"/>.
  296. /// </summary>
  297. - /// <param name="contextFactory">The factory method that creates a context to store instances of <see cref="DataProtectionKey"/></param>
  298. + /// <param name="services"></param>
  299. /// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
  300. - public EntityFrameworkCoreXmlRepository(Func<TContext> contextFactory, ILoggerFactory loggerFactory = null)
  301. + public EntityFrameworkCoreXmlRepository(IServiceProvider services, ILoggerFactory loggerFactory)
  302. {
  303. - _contextFactory = contextFactory ?? throw new ArgumentNullException(nameof(contextFactory));
  304. - _loggerFactory = loggerFactory;
  305. + if (loggerFactory == null)
  306. + {
  307. + throw new ArgumentNullException(nameof(loggerFactory));
  308. + }
  309. +
  310. + _logger = loggerFactory.CreateLogger<EntityFrameworkCoreXmlRepository<TContext>>();
  311. + _services = services ?? throw new ArgumentNullException(nameof(services));
  312. }
  313. /// <inheritdoc />
  314. public virtual IReadOnlyCollection<XElement> GetAllElements()
  315. - => _context?.Set<DataProtectionKey>()?.AsNoTracking().Select(key => TryParseKeyXml(key.Xml)).ToList().AsReadOnly();
  316. + {
  317. + using (var scope = _services.CreateScope())
  318. + {
  319. + var context = scope.ServiceProvider.GetRequiredService<TContext>();
  320. + return context.DataProtectionKeys.AsNoTracking().Select(key => TryParseKeyXml(key.Xml)).ToList().AsReadOnly();
  321. + }
  322. + }
  323. /// <inheritdoc />
  324. public void StoreElement(XElement element, string friendlyName)
  325. {
  326. - var newKey = new DataProtectionKey()
  327. + using (var scope = _services.CreateScope())
  328. {
  329. - FriendlyName = friendlyName,
  330. - Xml = element.ToString(SaveOptions.DisableFormatting)
  331. - };
  332. - var context = _context;
  333. - context?.Set<DataProtectionKey>()?.Add(newKey);
  334. - _logger?.LogSavingKeyToDbContext(friendlyName, typeof(TContext).Name);
  335. - context?.SaveChanges();
  336. + var context = scope.ServiceProvider.GetRequiredService<TContext>();
  337. + var newKey = new DataProtectionKey()
  338. + {
  339. + FriendlyName = friendlyName,
  340. + Xml = element.ToString(SaveOptions.DisableFormatting)
  341. + };
  342. +
  343. + context.DataProtectionKeys.Add(newKey);
  344. + _logger.LogSavingKeyToDbContext(friendlyName, typeof(TContext).Name);
  345. + context.SaveChanges();
  346. + }
  347. }
  348. private XElement TryParseKeyXml(string xml)
  349. diff --git a/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.csproj b/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.csproj
  350. index 966b1bfc78e..e1715d94f2e 100644
  351. --- a/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.csproj
  352. +++ b/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.csproj
  353. @@ -1,16 +1,11 @@
  354. <Project Sdk="Microsoft.NET.Sdk">
  355. <PropertyGroup>
  356. - <Description>EntityFramworkCore storage support as key store.</Description>
  357. - <VersionPrefix Condition="'$(ExperimentalVersionPrefix)' != ''">$(ExperimentalVersionPrefix)</VersionPrefix>
  358. - <VersionSuffix Condition="'$(ExperimentalVersionSuffix)' != ''">$(ExperimentalVersionSuffix)</VersionSuffix>
  359. - <VerifyVersion Condition="'$(ExperimentalVersionPrefix)' != ''">false</VerifyVersion>
  360. - <PackageVersion>$(ExperimentalPackageVersion)</PackageVersion>
  361. + <Description>Support for storing keys using Entity Framework Core.</Description>
  362. <TargetFramework>netstandard2.0</TargetFramework>
  363. <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  364. <GenerateDocumentationFile>true</GenerateDocumentationFile>
  365. <PackageTags>aspnetcore;dataprotection;entityframeworkcore</PackageTags>
  366. - <EnableApiCheck>false</EnableApiCheck>
  367. </PropertyGroup>
  368. <ItemGroup>
  369. @@ -21,4 +16,8 @@
  370. <PackageReference Include="Microsoft.EntityFrameworkCore" Version="$(MicrosoftEntityFrameworkCorePackageVersion)" />
  371. </ItemGroup>
  372. + <ItemGroup>
  373. + <Folder Include="Properties\" />
  374. + </ItemGroup>
  375. +
  376. </Project>
  377. diff --git a/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/baseline.netcore.json b/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/baseline.netcore.json
  378. new file mode 100644
  379. index 00000000000..9a9a7ebc1c0
  380. --- /dev/null
  381. +++ b/src/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore/baseline.netcore.json
  382. @@ -0,0 +1,203 @@
  383. +{
  384. + "AssemblyIdentity": "Microsoft.AspNetCore.DataProtection.EntityFrameworkCore, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
  385. + "Types": [
  386. + {
  387. + "Name": "Microsoft.AspNetCore.DataProtection.EntityFrameworkCoreDataProtectionExtensions",
  388. + "Visibility": "Public",
  389. + "Kind": "Class",
  390. + "Abstract": true,
  391. + "Static": true,
  392. + "Sealed": true,
  393. + "ImplementedInterfaces": [],
  394. + "Members": [
  395. + {
  396. + "Kind": "Method",
  397. + "Name": "PersistKeysToDbContext<T0>",
  398. + "Parameters": [
  399. + {
  400. + "Name": "builder",
  401. + "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionBuilder"
  402. + }
  403. + ],
  404. + "ReturnType": "Microsoft.AspNetCore.DataProtection.IDataProtectionBuilder",
  405. + "Static": true,
  406. + "Extension": true,
  407. + "Visibility": "Public",
  408. + "GenericParameter": [
  409. + {
  410. + "ParameterName": "TContext",
  411. + "ParameterPosition": 0,
  412. + "BaseTypeOrInterfaces": [
  413. + "Microsoft.EntityFrameworkCore.DbContext",
  414. + "Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.IDataProtectionKeyContext"
  415. + ]
  416. + }
  417. + ]
  418. + }
  419. + ],
  420. + "GenericParameters": []
  421. + },
  422. + {
  423. + "Name": "Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey",
  424. + "Visibility": "Public",
  425. + "Kind": "Class",
  426. + "ImplementedInterfaces": [],
  427. + "Members": [
  428. + {
  429. + "Kind": "Method",
  430. + "Name": "get_Id",
  431. + "Parameters": [],
  432. + "ReturnType": "System.Int32",
  433. + "Visibility": "Public",
  434. + "GenericParameter": []
  435. + },
  436. + {
  437. + "Kind": "Method",
  438. + "Name": "set_Id",
  439. + "Parameters": [
  440. + {
  441. + "Name": "value",
  442. + "Type": "System.Int32"
  443. + }
  444. + ],
  445. + "ReturnType": "System.Void",
  446. + "Visibility": "Public",
  447. + "GenericParameter": []
  448. + },
  449. + {
  450. + "Kind": "Method",
  451. + "Name": "get_FriendlyName",
  452. + "Parameters": [],
  453. + "ReturnType": "System.String",
  454. + "Visibility": "Public",
  455. + "GenericParameter": []
  456. + },
  457. + {
  458. + "Kind": "Method",
  459. + "Name": "set_FriendlyName",
  460. + "Parameters": [
  461. + {
  462. + "Name": "value",
  463. + "Type": "System.String"
  464. + }
  465. + ],
  466. + "ReturnType": "System.Void",
  467. + "Visibility": "Public",
  468. + "GenericParameter": []
  469. + },
  470. + {
  471. + "Kind": "Method",
  472. + "Name": "get_Xml",
  473. + "Parameters": [],
  474. + "ReturnType": "System.String",
  475. + "Visibility": "Public",
  476. + "GenericParameter": []
  477. + },
  478. + {
  479. + "Kind": "Method",
  480. + "Name": "set_Xml",
  481. + "Parameters": [
  482. + {
  483. + "Name": "value",
  484. + "Type": "System.String"
  485. + }
  486. + ],
  487. + "ReturnType": "System.Void",
  488. + "Visibility": "Public",
  489. + "GenericParameter": []
  490. + },
  491. + {
  492. + "Kind": "Constructor",
  493. + "Name": ".ctor",
  494. + "Parameters": [],
  495. + "Visibility": "Public",
  496. + "GenericParameter": []
  497. + }
  498. + ],
  499. + "GenericParameters": []
  500. + },
  501. + {
  502. + "Name": "Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.EntityFrameworkCoreXmlRepository<T0>",
  503. + "Visibility": "Public",
  504. + "Kind": "Class",
  505. + "ImplementedInterfaces": [
  506. + "Microsoft.AspNetCore.DataProtection.Repositories.IXmlRepository"
  507. + ],
  508. + "Members": [
  509. + {
  510. + "Kind": "Method",
  511. + "Name": "GetAllElements",
  512. + "Parameters": [],
  513. + "ReturnType": "System.Collections.Generic.IReadOnlyCollection<System.Xml.Linq.XElement>",
  514. + "Virtual": true,
  515. + "ImplementedInterface": "Microsoft.AspNetCore.DataProtection.Repositories.IXmlRepository",
  516. + "Visibility": "Public",
  517. + "GenericParameter": []
  518. + },
  519. + {
  520. + "Kind": "Method",
  521. + "Name": "StoreElement",
  522. + "Parameters": [
  523. + {
  524. + "Name": "element",
  525. + "Type": "System.Xml.Linq.XElement"
  526. + },
  527. + {
  528. + "Name": "friendlyName",
  529. + "Type": "System.String"
  530. + }
  531. + ],
  532. + "ReturnType": "System.Void",
  533. + "Sealed": true,
  534. + "Virtual": true,
  535. + "ImplementedInterface": "Microsoft.AspNetCore.DataProtection.Repositories.IXmlRepository",
  536. + "Visibility": "Public",
  537. + "GenericParameter": []
  538. + },
  539. + {
  540. + "Kind": "Constructor",
  541. + "Name": ".ctor",
  542. + "Parameters": [
  543. + {
  544. + "Name": "services",
  545. + "Type": "System.IServiceProvider"
  546. + },
  547. + {
  548. + "Name": "loggerFactory",
  549. + "Type": "Microsoft.Extensions.Logging.ILoggerFactory"
  550. + }
  551. + ],
  552. + "Visibility": "Public",
  553. + "GenericParameter": []
  554. + }
  555. + ],
  556. + "GenericParameters": [
  557. + {
  558. + "ParameterName": "TContext",
  559. + "ParameterPosition": 0,
  560. + "BaseTypeOrInterfaces": [
  561. + "Microsoft.EntityFrameworkCore.DbContext",
  562. + "Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.IDataProtectionKeyContext"
  563. + ]
  564. + }
  565. + ]
  566. + },
  567. + {
  568. + "Name": "Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.IDataProtectionKeyContext",
  569. + "Visibility": "Public",
  570. + "Kind": "Interface",
  571. + "Abstract": true,
  572. + "ImplementedInterfaces": [],
  573. + "Members": [
  574. + {
  575. + "Kind": "Method",
  576. + "Name": "get_DataProtectionKeys",
  577. + "Parameters": [],
  578. + "ReturnType": "Microsoft.EntityFrameworkCore.DbSet<Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey>",
  579. + "GenericParameter": []
  580. + }
  581. + ],
  582. + "GenericParameters": []
  583. + }
  584. + ]
  585. +}
  586. \ No newline at end of file
  587. diff --git a/test/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test/DataProtectionEntityFrameworkTests.cs b/test/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test/DataProtectionEntityFrameworkTests.cs
  588. index 31034c7f4cf..c298d8e64f2 100644
  589. --- a/test/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test/DataProtectionEntityFrameworkTests.cs
  590. +++ b/test/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test/DataProtectionEntityFrameworkTests.cs
  591. @@ -1,12 +1,14 @@
  592. // Copyright (c) .NET Foundation. All rights reserved.
  593. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  594. -using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
  595. -using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test;
  596. -using Microsoft.EntityFrameworkCore;
  597. using System;
  598. using System.Linq;
  599. using System.Xml.Linq;
  600. +using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
  601. +using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test;
  602. +using Microsoft.EntityFrameworkCore;
  603. +using Microsoft.Extensions.DependencyInjection;
  604. +using Microsoft.Extensions.Logging.Abstractions;
  605. using Xunit;
  606. namespace Microsoft.AspNetCore.DataProtection
  607. @@ -16,7 +18,7 @@ namespace Microsoft.AspNetCore.DataProtection
  608. [Fact]
  609. public void CreateRepository_ThrowsIf_ContextIsNull()
  610. {
  611. - Assert.Throws<ArgumentNullException>(() => new EntityFrameworkCoreXmlRepository<DataProtectionKeyContext>(null));
  612. + Assert.Throws<ArgumentNullException>(() => new EntityFrameworkCoreXmlRepository<DataProtectionKeyContext>(null, null));
  613. }
  614. [Fact]
  615. @@ -25,13 +27,13 @@ namespace Microsoft.AspNetCore.DataProtection
  616. var element = XElement.Parse("<Element1/>");
  617. var friendlyName = "Element1";
  618. var key = new DataProtectionKey() { FriendlyName = friendlyName, Xml = element.ToString() };
  619. - using (var context = BuildDataProtectionKeyContext(nameof(StoreElement_PersistsData)))
  620. - {
  621. - var service = new EntityFrameworkCoreXmlRepository<DataProtectionKeyContext>(() => context);
  622. +
  623. + var services = GetServices(nameof(StoreElement_PersistsData));
  624. + var service = new EntityFrameworkCoreXmlRepository<DataProtectionKeyContext>(services, NullLoggerFactory.Instance);
  625. service.StoreElement(element, friendlyName);
  626. - }
  627. +
  628. // Use a separate instance of the context to verify correct data was saved to database
  629. - using (var context = BuildDataProtectionKeyContext(nameof(StoreElement_PersistsData)))
  630. + using (var context = services.CreateScope().ServiceProvider.GetRequiredService< DataProtectionKeyContext>())
  631. {
  632. Assert.Equal(1, context.DataProtectionKeys.Count());
  633. Assert.Equal(key.FriendlyName, context.DataProtectionKeys.Single()?.FriendlyName);
  634. @@ -44,25 +46,24 @@ namespace Microsoft.AspNetCore.DataProtection
  635. {
  636. var element1 = XElement.Parse("<Element1/>");
  637. var element2 = XElement.Parse("<Element2/>");
  638. - using (var context = BuildDataProtectionKeyContext(nameof(GetAllElements_ReturnsAllElements)))
  639. - {
  640. - var service = new EntityFrameworkCoreXmlRepository<DataProtectionKeyContext>(() => context);
  641. - service.StoreElement(element1, "element1");
  642. - service.StoreElement(element2, "element2");
  643. - }
  644. +
  645. + var services = GetServices(nameof(GetAllElements_ReturnsAllElements));
  646. + var service1 = CreateRepo(services);
  647. + service1.StoreElement(element1, "element1");
  648. + service1.StoreElement(element2, "element2");
  649. +
  650. // Use a separate instance of the context to verify correct data was saved to database
  651. - using (var context = BuildDataProtectionKeyContext(nameof(GetAllElements_ReturnsAllElements)))
  652. - {
  653. - var service = new EntityFrameworkCoreXmlRepository<DataProtectionKeyContext>(() => context);
  654. - var elements = service.GetAllElements();
  655. - Assert.Equal(2, elements.Count);
  656. - }
  657. + var service2 = CreateRepo(services);
  658. + var elements = service2.GetAllElements();
  659. + Assert.Equal(2, elements.Count);
  660. }
  661. - private DbContextOptions<DataProtectionKeyContext> BuildDbContextOptions(string databaseName)
  662. - => new DbContextOptionsBuilder<DataProtectionKeyContext>().UseInMemoryDatabase(databaseName: databaseName).Options;
  663. + private EntityFrameworkCoreXmlRepository<DataProtectionKeyContext> CreateRepo(IServiceProvider services)
  664. + => new EntityFrameworkCoreXmlRepository<DataProtectionKeyContext>(services, NullLoggerFactory.Instance);
  665. - private DataProtectionKeyContext BuildDataProtectionKeyContext(string databaseName)
  666. - => new DataProtectionKeyContext(BuildDbContextOptions(databaseName));
  667. + private IServiceProvider GetServices(string dbName)
  668. + => new ServiceCollection()
  669. + .AddDbContext<DataProtectionKeyContext>(o => o.UseInMemoryDatabase(dbName))
  670. + .BuildServiceProvider(validateScopes: true);
  671. }
  672. }
  673. diff --git a/test/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test/EntityFrameworkCoreDataProtectionBuilderExtensionsTests.cs b/test/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test/EntityFrameworkCoreDataProtectionBuilderExtensionsTests.cs
  674. index d04ccdde88d..55b67d98e38 100644
  675. --- a/test/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test/EntityFrameworkCoreDataProtectionBuilderExtensionsTests.cs
  676. +++ b/test/Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test/EntityFrameworkCoreDataProtectionBuilderExtensionsTests.cs
  677. @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.Test
  678. .AddDbContext<DataProtectionKeyContext>()
  679. .AddDataProtection()
  680. .PersistKeysToDbContext<DataProtectionKeyContext>();
  681. - var serviceProvider = serviceCollection.BuildServiceProvider();
  682. + var serviceProvider = serviceCollection.BuildServiceProvider(validateScopes: true);
  683. var keyManagementOptions = serviceProvider.GetRequiredService<IOptions<KeyManagementOptions>>();
  684. Assert.IsType<EntityFrameworkCoreXmlRepository<DataProtectionKeyContext>>(keyManagementOptions.Value.XmlRepository);
  685. }