4

エンティティを 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();
        }
    }
}

Windows Azure SDK for .NET 1.8 を使用した例。

4

1 に答える 1

6

EndSaveChanges の代わりに EndSaveChangesWithRetries を呼び出す必要があります。そうしないと、BeginSaveChangesWithRetries によって返される IAsyncResult オブジェクトを EndSaveChanges で使用できません。そこで、End メソッドの呼び出しを以下のように変更してみてはいかがでしょうか。

context.BeginSaveChangesWithRetries(SaveChangesOptions.Batch,
    (asyncResult => context.EndSaveChangesWithRetries(asyncResult)),
    null);

また、他の質問については、呼び出しごとに新しい TableServiceContext を作成することをお勧めします。DataServiceContext はステートレス ( MSDN ) ではなく、非同期呼び出しで TableStorageWriter.Write を実装した方法では同時操作が許可される可能性があるためです。実際、ストレージ クライアント ライブラリ 2.0 では、単一の TableServiceContext オブジェクトを使用する同時操作を明示的に禁止しました。さらに、TableServiceContext を作成しても、Azure Storage への要求は発生しません。

于 2012-12-07T21:33:21.377 に答える