【发布时间】:2012-12-10 06:21:28
【问题描述】:
如何将实体异步保存到 Windows Azure 表服务?
下面的代码同步工作,但在尝试异步保存时引发异常。
此声明:
context.BeginSaveChangesWithRetries(SaveChangesOptions.Batch,
(asyncResult => context.EndSaveChanges(asyncResult)), null);
System.ArgumentException 中的结果:“当前对象并非源自异步结果。参数名称:asyncResult”。
此外,异步保存时创建服务上下文的正确模式是什么?我应该为每个写操作创建一个单独的上下文吗?是不是太贵了(例如需要通过网络拨打电话)?
TableStorageWriter.cs:
using System;
using System.Data.Services.Client;
using System.Diagnostics;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
namespace WorkerRole1
{
public class TableStorageWriter
{
private const string _tableName = "StorageTest";
private readonly CloudStorageAccount _storageAccount;
private CloudTableClient _tableClient;
public TableStorageWriter()
{
_storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
_tableClient = _storageAccount.CreateCloudTableClient();
_tableClient.CreateTableIfNotExist(_tableName);
}
public void Write(string message)
{
try
{
DateTime now = DateTime.UtcNow;
var entity = new StorageTestEntity
{
Message = message,
PartitionKey = string.Format("{0:yyyy-MM-dd}", now),
RowKey = string.Format("{0:HH:mm:ss.fff}-{1}", now, Guid.NewGuid())
};
// Should I get this context before each write? It is efficient?
TableServiceContext context = _tableClient.GetDataServiceContext();
context.AddObject(_tableName, entity);
// This statement works but it's synchronous
context.SaveChangesWithRetries();
// This attempt at saving asynchronously results in System.ArgumentException:
// The current object did not originate the async result. Parameter name: asyncResult
// context.BeginSaveChangesWithRetries(SaveChangesOptions.Batch,
// (asyncResult => context.EndSaveChanges(asyncResult)), null);
}
catch (StorageClientException e)
{
Debug.WriteLine("Error: {0}", e.Message);
Debug.WriteLine("Extended error info: {0} : {1}",
e.ExtendedErrorInformation.ErrorCode,
e.ExtendedErrorInformation.ErrorMessage);
}
}
}
internal class StorageTestEntity : TableServiceEntity
{
public string Message { get; set; }
}
}
从 WorkerRole.cs 调用:
using System.Net;
using System.Threading;
using Microsoft.WindowsAzure.ServiceRuntime;
using log4net;
namespace WorkerRole1
{
public class WorkerRole : RoleEntryPoint
{
public override void Run()
{
var storageWriter = new TableStorageWriter();
while (true)
{
Thread.Sleep(10000);
storageWriter.Write("Working...");
}
}
public override bool OnStart()
{
ServicePointManager.DefaultConnectionLimit = 12;
return base.OnStart();
}
}
}
使用适用于 .NET 1.8 的 Windows Azure SDK 的示例。
【问题讨论】:
-
对于异步问题,上下文的范围是什么?我想知道上下文是否存在关闭问题。关于何时创建上下文,循环中的睡眠时间为 10000,我认为创建表服务上下文的性能不会成为问题。但是,我通常倾向于为每次调用创建它,除非您要大量且不断地使用它
-
请看一下上面Write()中被注释掉的代码。上下文的范围是本地的。我的尝试涉及关闭,但我可能做错了什么。事实上,我正在寻找一个如何做到这一点的例子。关于性能,假设 Write() 将被大量使用;我正在寻找最快、最安全的异步插入方式。
-
您是否尝试过将上下文范围向上移动?让它成为班级成员?
-
如果上下文是在构造函数中初始化的私有类成员,则与gist.github.com/4235952中相同的错误
标签: c# asynchronous azure azure-table-storage