Azure CloudBlobStream序列化(使用Json.NET)



我有一个小问题。我的环境是.NET Core 2.1中的控制台应用程序。

看看这个代码:

private static void Main(string[] args)
{
try
{
Console.WriteLine($"Test starts: {DateTime.Now.ToString("o")}");
string connectionString = "[My connection string]";
string containerName = "mycontainer";
CloudStorageAccount account = CloudStorageAccount.Parse(connectionString);
CloudBlobClient serviceClient = account.CreateCloudBlobClient();
CloudBlobContainer container = serviceClient.GetContainerReference(containerName);
container.CreateIfNotExistsAsync().Wait();
CloudBlockBlob cloudBlockBlob = container.GetBlockBlobReference($"{containerName}/Test.txt");
CloudBlobStream cloudBlobStream = cloudBlockBlob.OpenWriteAsync().Result;
string json = JsonConvert.SerializeObject(cloudBlobStream);
Console.WriteLine($"Test ends: {DateTime.Now.ToString("o")}");
}
catch (Exception e)
{
string stackTrace = e.StackTrace;
while(e != null)
{
Console.WriteLine(e.Message);
e = e.InnerException;
}
Console.WriteLine(stackTrace);
}
Console.Write("Press any key to exit...");
Console.ReadKey();
}

当我尝试用命令string json = JsonConvert.SerializeObject(cloudBlobStream);序列化CloudBlobStream对象时,我得到以下异常:

从"Microsoft.WindowsAzure.Storage.Blob.BlobWriteStream"上的"Length"获取值时出错。不支持指定的方法。位于Newtonsoft.Json.Serialization.ExpressionValueProvider.GetValue(对象目标(位于Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues位于Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter编写器,对象值,JsonObjectContract约定,JsonProperty成员,JsonContainerContract集合contract,JsonPropertycontainerProperty(位于Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter JsonWriter,Object value,Type objectType(位于Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter JsonWriter,Object value,Type objectType(位于Newtonsoft.Json.JsonConvert.SerializeObjectInternal(对象值,类型类型,JsonSerializer-JsonSerializer(位于C:\Projects\AzureBlobStreamSerializationTest\AzureBlobStream序列化测试\Program.cs:line 28

知道如何解决这个问题吗?

谨致问候,Attilio

在您的代码中,看起来您实际上是在试图将Stream对象序列化为数据。这是行不通的。发生异常是因为序列化程序正在尝试从Stream对象读取所有公共属性。其中一个属性是Length,当打开流进行写入时,它是不可读的。

我认为您误解了如何使用Json.Net和Azure存储Blob的流。JsonConvert类实际上只是一个门面,不幸的是,它的SerializeObject()方法没有支持流的重载。要使用Json.Net处理流,如果要序列化到流,则需要使用JsonSerializer实例以及StreamWriterJsonTextWriter;如果要从流反序列化,则需要同时使用StreamReaderJsonTextReader

这里有几个扩展方法,你可能会发现它们很有帮助和指导意义:

public static class BlobExtensions
{
public static async Task SerializeObjectToBlobAsync(this CloudBlockBlob blob, object obj)
{
using (Stream stream = await blob.OpenWriteAsync())
using (StreamWriter sw = new StreamWriter(stream))
using (JsonTextWriter jtw = new JsonTextWriter(sw))
{
JsonSerializer ser = new JsonSerializer();
ser.Serialize(jtw, obj);
}
}
public static async Task<T> DeserializeObjectFromBlobAsync<T>(this CloudBlockBlob blob)
{
using (Stream stream = await blob.OpenReadAsync())
using (StreamReader sr = new StreamReader(stream))
using (JsonTextReader jtr = new JsonTextReader(sr))
{
JsonSerializer ser = new JsonSerializer();
return ser.Deserialize<T>(jtr);
}
}
}

现在假设您有一个类Item,它表示一些数据,您希望将这些数据序列化为JSON并存储到Azure blob:中

class Item 
{
public int Id { get; set; }
public string Name { get; set; }
public double Price { get; set; }
}

以下是如何使用第一种扩展方法:

...
var item = new Item { Id = 1, Name = "Widget", Price = 2.5 };
cloudBlockBlob.SerializeObjectToBlobAsync(item).Wait();

相反,如果您想从blob中检索JSON并将其反序列化为Item,则可以使用其他扩展方法:

var item = cloudBlockBlob.DeserializeObjectFromBlobAsync<Item>().Result;

注意:如果在async方法中使用这些方法,则应使用await语法,而不是分别使用Wait().Result

await cloudBlockBlob.SerializeObjectToBlobAsync(item);
...
var item = await cloudBlockBlob.DeserializeObjectFromBlobAsync<Item>();

CloudBlobContainer.GetBlockBlobReference的参数应该是blob名称。

请从代码中删除containerName。

CloudBlockBlob cloudBlockBlob = container.GetBlockBlobReference("Test.txt"); //remove the container name from original code

根据错误执行,这表明JsonConvert.SerializeObject不支持CloudBlobStream作为参数。

知道如何解决这个问题吗?

如果要获取文本字符串,可以使用cloudBlockBlob.DownloadTextAsync()。因此,请将您的代码更改为以下

container.CreateIfNotExistsAsync().Wait();
CloudBlockBlob cloudBlockBlob = container.GetBlockBlobReference("Test.txt"); //make sure that blob is existing
var json = cloudBlockBlob.DownloadTextAsync().Result;

最新更新