AzureCosmosFactory.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. using Azure.Core.Serialization;
  2. using Microsoft.Azure.Cosmos;
  3. using Microsoft.Extensions.Logging;
  4. using Microsoft.Extensions.Options;
  5. using System;
  6. using System.Collections.Concurrent;
  7. using System.Text.Json;
  8. using System.Text.Json.Serialization;
  9. using System.IO;
  10. using System.Threading.Tasks;
  11. namespace TEAMModelOS.SDK.DI
  12. {
  13. public class AzureCosmosFactory
  14. {
  15. private readonly IServiceProvider _services;
  16. private readonly IOptionsMonitor<AzureCosmosFactoryOptions> _optionsMonitor;
  17. private readonly ILogger _logger;
  18. //private Option _option;
  19. private ConcurrentDictionary<string, CosmosClient> CosmosClients { get; } = new ConcurrentDictionary<string, CosmosClient>();
  20. // private CosmosDatabase database { get; set; }
  21. public AzureCosmosFactory(IServiceProvider services, IOptionsMonitor<AzureCosmosFactoryOptions> optionsMonitor, ILogger<AzureCosmosFactory> logger)
  22. {
  23. if (services == null) throw new ArgumentNullException(nameof(services));
  24. if (optionsMonitor == null) throw new ArgumentNullException(nameof(optionsMonitor));
  25. _services = services;
  26. _optionsMonitor = optionsMonitor;
  27. _logger = logger;
  28. }
  29. /// <summary>
  30. /// 取得CosmosClient,支持安全執行緒
  31. /// </summary>
  32. /// <param name="name"></param>
  33. /// <param name="region">可以使用Regions.{區域}設置,指定此屬性後,SDK會首選該區域來執行操作。此外,SDK會自動選擇後備的地理複製區域以實現高可用性。如果未指定此屬性,則SDK會將寫區域用作所有操作的首選區域</param>
  34. /// <returns></returns>
  35. public CosmosClient GetCosmosClient(string? region = null, string name = "Default")
  36. {
  37. try
  38. {
  39. //CosmosClientOptions 的 SerializerOptions = new CosmosSerializationOptions() { PropertyNamingPolicy = CosmosPropertyNamingPolicy.CamelCase }
  40. //需等待官方修正
  41. JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions()
  42. {
  43. // DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
  44. };
  45. var cm = CosmosClients.GetOrAdd(name, x => new CosmosClient(_optionsMonitor.Get(name).CosmosConnectionString, new CosmosClientOptions()
  46. {
  47. Serializer= new CosmosSystemTextJsonSerializer(jsonSerializerOptions),
  48. ApplicationRegion = region
  49. }));
  50. return cm;
  51. }
  52. catch (Exception e)
  53. {
  54. _logger?.LogWarning(e, e.Message);
  55. throw;
  56. }
  57. }
  58. }
  59. /// <summary>
  60. /// Uses <see cref="Azure.Core.Serialization.JsonObjectSerializer"/> which leverages System.Text.Json providing a simple API to interact with on the Azure SDKs.
  61. /// </summary>
  62. // <SystemTextJsonSerializer>
  63. public class CosmosSystemTextJsonSerializer : CosmosSerializer
  64. {
  65. private readonly JsonSerializerOptions _serializerOptions;
  66. public CosmosSystemTextJsonSerializer(JsonSerializerOptions jsonSerializerOptions)
  67. {
  68. this._serializerOptions = jsonSerializerOptions;
  69. }
  70. public override T FromStream<T>(Stream stream)
  71. {
  72. using (stream)
  73. {
  74. if (typeof(Stream).IsAssignableFrom(typeof(T)))
  75. {
  76. return (T)(object)stream;
  77. }
  78. return JsonSerializer.Deserialize<T>(stream, _serializerOptions);
  79. }
  80. }
  81. public override Stream ToStream<T>(T input)
  82. {
  83. var outputStream = new MemoryStream();
  84. JsonSerializer.Serialize<T>(outputStream, input, _serializerOptions);
  85. // A BREAKPOINT HERE AND A LOOK INSIDE 'outputStream' shows that ALL the fields have been serialized EXCEPT 'Id' or 'id.
  86. outputStream.Position = 0;
  87. return outputStream;
  88. }
  89. }
  90. // </SystemTextJsonSerializer>
  91. }