2011年5月31日火曜日

Azure Blob ストレージへ REST API にてアップロードするアクティビティ(仮)

ストレージ関係の REST API を暇を見つけながらちろちろやっている最中ですが、とりあえずアップロード(ただし条件付き)ができるところまではできましたので、恒例のアクティビティ化をしてみました。
条件付き、というのは本来ストレージへアップロードを行う場合には何点か考慮しなくてはいけないポイントがあり、現時点ではその考慮点の一部にしか対応できていないためです。何を考える必要があるかと言うと、次の点になります。

  • アップロードするファイルの容量

Windows Azure のストレージには大きくわけて 2 つの方式が提供されています。一つは BlockBlob と呼ばれる種類で、これは 64MB までの一つのファイル、または 4MB 単位に分割したファイル群という形でアップロードが可能です。分割するメリットは同時に複数セッションを利用してアップロード速度を向上させたり、エラー発生時のリトライ処理量を減らすなどがあたります。もう一つは PageBlob と呼ばれる種類でこちらは 1TB までのファイルを扱う事が可能な点と、バイト単位(イメージとしてはHDD等のセクタ)にて読み書きの処理が行える点がポイントとなります。現在ベータ版として提供されている Azure Drive (ストレージを通常の NTFS ドライブに見せかけて利用できる)は PageBlob をベースに作成されていると思われます。

2011年5月26日木曜日

Azure Storage REST API サンプル ~コンテナ関係~

Windows Azure Storage Services REST API という形で提供されている、REST 形式にて利用するストレージ関係のAPIの中で、コンテナ周りの API をアクティビティ化してみました。その際に色々分かったところもあるので、メモとして残しておきます。

コンテナ関係のAPI

List Containers 現在のコンテナ一覧を取得する
Create Container コンテナを新規に作成する
Delete Container コンテナを削除する
Get Container Properties コンテナの情報を取得する
Get Container ACL コンテナのアクセス制限を設定する
Set Container ACL コンテナのアクセス制限を取得する
Get Container Metadata コンテナにメタデータを取得する
Set Container Metadata コンテナにメタデータを設定する

カテゴライズした場合、もう一つ List Blobs という API もあるのですが、個人的にこれはBlob操作系と思っているので別の機会にします。

2011年5月25日水曜日

Azure Storage REST API の Authorization ヘッダ・改訂版

前回の記事で Auzre の Storage REST API で必須となる Authorization ヘッダの SharedKey 値の算出ロジックを記載しましたが、その後色々やっていくにつれ若干の修正が必要な事がわかりました。
変更点は今のところ1か所のみです。

2011年5月20日金曜日

Azure Storage 関係の REST API で利用する Authorization ヘッダ

現在 Azure のストレージ関係で利用する REST API を色々試行錯誤しながら試しているところですが、これら ストレージ用 REST API を利用するにあたり、真面目にやると物凄くよくわからない部分が Authorization ヘッダの SharedKey 値ではないでしょうか。
MSDN にある程度記述があるのですが、読んでいてもいまいちピンとこないというかさっぱりわかりませんw 色々と web 上の資料やサンプルコードを探しているうちに、海外サイトで丁度良いサンプルソースがあったのでこれを VB 用に移植したものを紹介します。

2011年5月19日木曜日

SQL Azure ファイアウォール管理 REST API のアクティビティ化

基本的に前回とほぼ同一ですが、SQL Azure のファイアウォール制御作成列挙削除)もアクティビティ化してみました。ファイアウォール制御 API 自体は特に難しいものでもなく、非常に簡単な形式となっています。メッセージ生成が必要なのも新規作成の際のみです。
前回同様ベースとなるクラスから。

2011年5月18日水曜日

SQL Azure Management REST API をアクティビティ化

SQL Azure には管理用の REST API が多数提供されています。
今回はサーバー管理用の REST API をアクティビティ化してみました。REST API 利用ですので、SDK 等の導入は一切必要ありません。
殆ど似た形になるので今回はベースクラスを作成し、各アクティビティはそれを継承する形にしています。まずはベースとなるアクティビティクラスから。

2011年5月17日火曜日

Windows Azure のサブスクリプション操作履歴を取得するアクティビティ

提供されている REST API の中にはサブスクリプションの操作履歴を取得するものがあります。それほど詳しく使ってはいないのですが今のところ管理ポータルからは見る事の出来ない情報になっています。
今回もいきなりソースを。

2011年5月16日月曜日

Windows Azure Management REST API でホスティング一覧を取得するアクティビティ

Code RecipeMSDN でサンプルが紹介されていたのでアクティビティにしてみました。
Windows Azure 管理ポータルで目視できる内容ですが、定期的に監視などする事を考えるとスクリプトまたはプログラム化する必要が高くなります。また SDK でマネージド DLL 等も配布されていますが、端末にそれを入れるのも億劫ですw
そのような場合は、REST API が提供されているのでこれを利用した監視等々を行う事になるかと思います。実際に REST API を利用するには一つだけ事前準備が必要です。
  • 管理用証明書を作成、設定する

当然と言えば当然ですが、アクセス制限を行うために Windows Azure ではクライアント証明書を利用します。証明書自体は正規のものを購入する、makecert ユーティリティで作成するなど方法があります。今回は makecert ユーティリティで作成しました。その際 MSDNSE の雑記 さんのところを参考にさせてもらいました。ありがとうございます。
できあがった証明書は自分の環境にインストール(作成した cer ファイルをダブルクリック等で実行するとインポートができます)、Windows Azure 管理ポータルからもインポートします。
AzurePortal
インポートすると管理ポータルでこのように確認ができます。ここで表示されている値で、ThumbPrint と書かれている値が後々必要になりますのでメモしておきます。
これでアクティビティの実装を行います。

Workflow に引数を設定して実行

以前、デザイナに「引数」タブがなかったので表示するようにしてみた記事を書きましたが、実際にそれを利用する場合は、次のようなロジックになります。なお Workflow では実行時に渡すものも引数と呼び、終了時に受け取るものも引数と呼びます。
1: '入力引数の設定
2: Dim inArgs As New Dictionary(Of String, Object)
3: inArgs.Add([引数名], Value)
4: 
5: Dim wfApps As New WorkflowApplication(wfFile, inArgs)
引数を渡す場合は、このような形で Dictionary を作成し WorkflowApplication や WorkflowInvoker に引き渡します。詳しく調査していないのですが、恐らく WorkflowApplication.HostEnvironment を通しても同様にアクセスできるのではないかな、と思っていますが試していませんw
反対に結果を受け取る場合のロジックは次のようになります。

2011年5月13日金曜日

REST っぽい Workflow サービスの公開

実際には Workflow サービスにおいて REST 形式での公開は行えません。というのも、MSDN に記載されている通り、メッセージング関係のアクティビティでは定型的な推測のみ行うように用意されており、WebGet 属性や WebInvoke 属性等を付与する事ができないためです。
ですが WCF の機能を利用する事により「それっぽい」形に仕上げる事はできます。
Arguments

2011年5月11日水曜日

IActivityTemplateFactory による カスタムアクティビティの統合

純粋に一つの処理を行うカスタムアクティビティは今までにも何度か作成したように非常に簡単です。ですが実際に利用する側となると、単一処理なアクティビティばかりでは、何度もデザイナ上に配置する必要が生じてしまい使いにくいものとなります。
そのような場面では IActivityTemplateFactory インターフェースを継承したクラスを用意し、デザイナにドロップした際に複数アクティビティを自動で展開させる事が可能です。

2011年5月10日火曜日

Workflow サービスを Windows Azure 上で公開する

Windows Azure でもWorkflowサービスはサポートされていますので、デプロイするだけで利用可能です。そこまでの流れとデバッグについてまとめておきます。
Express のみの環境で Windows Azure を利用するには Visual Web Developer が絶対必要です。デバッグを行うのであれば管理者権限で起動する必要もあります。
Workflow サービス自体は WCF の仕組みで動作していますので、プロジェクトの種類は WCF Service Web Role を選択します。
CreateNewSolution
選択しOKボタンクリックで新規にソリューションが作成され、このように表示されます。

2011年5月9日月曜日

Workflow 上の Receive アクティビティと WCF での実装

Workflow 上で Receive アクティビティ等を利用し送受信を行うサービスを構築できるのは以前の記事などで書いた通りです。それをWCFでロジックを組んだ場合にどうなるか、というのを比較してみると各プロパティでの設定がなんとなくでも見えてくるかと思います。

1: <ServiceContract()>
2: Public Interface IService1
3: 
4:     <OperationContract()>
5:     Function GetData(ByVal value As Integer) As String
6: 
7: End Interface

このソースが Receive アクティビティを利用した場合をWCFにて表したソースとなります。アクティビティ上で OperationName プロパティで指定した名称はそのまま Function 名となり、WorkflowService の Name プロパティで指定したものがインターフェース名(≒クラス名)となります。Receive アクティビティの Content で指定したものは、Function の引数として定義、または DataContract 属性を付与したクラスとなります。

このような事を自動で行っているために、WCF ではできている事が Workflow 上ではできていない点もあります。一つが Function に対しての属性付加 ( WebGet とか ) で、これができないので REST サービスとしての Workflow が行えていません。

ただ上記のようなロジックを組み、コード上で Workflow を利用する形式であればRESTであろうと行えるので、やりようはあるのですが Workflow 単体では残念ながらまだ手段がわかっていません。

2011年5月6日金曜日

IIS Express での Workflow サービスホスティング

IIS で Workflow サービスのホスティングを行う場合の操作について以前の記事で書きました。この方法は IIS Express でも当然有効ですが、一点だけハマった部分があるので書き残しておきます。

  • Windows Server AppFabric をインストールしている
  • AppFabric ランタイム機能のホスティングサービスを有効にしている
  • AppFabric ホスティングサービスにて永続化構成を設定していない

ネックとなったのは Windows Server AppFabric です。これは Windows Vista 以降の IIS で利用できるものなので、自分の Windows7 クライアントにもインストールはしていたのですが、何も設定を行っていなかったため、今回の現象に遭遇しました。厄介なのは、これが IIS 利用時には発生せずに IIS Express 利用時のみに発生する現象だった、という点です。

AppFabric1

これが Windows Server AppFabric の「機能の追加/削除」の GUI です。添付したイメージではホスティングサービスの機能が無効になっています。この状態であれば今回の現象は発生しません。

AppFabric2

こちらが「Configure AppFabric」のGUIです。このように「未設定」の場合に問題が発生します。

この状態で、IIS Express にて Workflow サービスをホスティングし呼び出してみると永続化のエラーが発生します。AppFabricPersistenceDB にログインできません、というエラーです。永続化の設定など、全く行っていなかったので最初は分かりませんでした。例外の情報からAppFabric関連というのは分かるのですが、設定を何も行っていなかったのもあり最初はお手上げでした。色々と試行錯誤の末、AppFabric のホスティングサービス自体を無効にしておけば回避できました。

ここさえ回避してあれば、IIS Express でも簡単に Workflow サービスが利用できます。必要なのは xamlx と web.config の 2 ファイルだけです。IIS Express は XP 環境でも動作しますので、XP 上で Workflow サービスを構成することもできます。

TrackingRecord によるトラッキング

WF の仕組みとして TrackingRecord によるトラッキングの仕組みが用意されています。これはワークフローが、またはアクティビティが何か動作をするたびに通知されるレコードで、全部で 13 種類の状態が通知されます。各トラッキングレコードが何を伝えてくれるかは MSDN を参照してください。

TrackingRecord : WorkflowInstanceRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 0, EventTime = 2011/05/02 9:59:55, ActivityDefinitionId = Sequence, State = Started }
TrackingRecord : ActivityStateRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 1, EventTime = 2011/05/02 9:59:55, Activity { Name=Sequence, ActivityId = 1, ActivityInstanceId = 1, TypeName=System.Activities.Statements.Sequence }, State = Executing }
TrackingRecord : ActivityStateRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 2, EventTime = 2011/05/02 9:59:56, Activity { Name=Assign, ActivityId = 7, ActivityInstanceId = 2, TypeName=System.Activities.Statements.Assign }, State = Executing }
TrackingRecord : ActivityStateRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 3, EventTime = 2011/05/02 9:59:56, Activity { Name=Assign, ActivityId = 7, ActivityInstanceId = 2, TypeName=System.Activities.Statements.Assign }, State = Closed }
TrackingRecord : ActivityStateRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 4, EventTime = 2011/05/02 9:59:56, Activity { Name=Delay, ActivityId = 5, ActivityInstanceId = 3, TypeName=System.Activities.Statements.Delay }, State = Executing }
TrackingRecord : WorkflowInstanceRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 5, EventTime = 2011/05/02 9:59:56, ActivityDefinitionId = Sequence, State = Idle }
TrackingRecord : ActivityStateRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 6, EventTime = 2011/05/02 9:59:57, Activity { Name=Delay, ActivityId = 5, ActivityInstanceId = 3, TypeName=System.Activities.Statements.Delay }, State = Closed }
TrackingRecord : ActivityStateRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 7, EventTime = 2011/05/02 9:59:57, Activity { Name=メッセージを表示, ActivityId = 2, ActivityInstanceId = 4, TypeName=Workflow4.Command.DisplayActivity }, State = Executing }
TrackingRecord : ActivityStateRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 8, EventTime = 2011/05/02 9:59:58, Activity { Name=メッセージを表示, ActivityId = 2, ActivityInstanceId = 4, TypeName=Workflow4.Command.DisplayActivity }, State = Closed }
TrackingRecord : ActivityStateRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 9, EventTime = 2011/05/02 9:59:58, Activity { Name=Sequence, ActivityId = 1, ActivityInstanceId = 1, TypeName=System.Activities.Statements.Sequence }, State = Closed }
TrackingRecord : WorkflowInstanceRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 10, EventTime = 2011/05/02 9:59:58, ActivityDefinitionId = Sequence, State = Completed }

実際にトラッキングを行った際には、上記のようなレコードが通知されます。この内容は前回の記事で実際に実行した際の内容です。デザイナ上でトラッキング内容に基づいて表示を行うのですが、その前に追跡用のプロファイルを作成する必要があります。これは「何をトラッキングし通知するか」を設定するものです。

1: 'トラッキングプロファイルの生成
2: customTracker = New VisualTrackingParticipant '独自に用意したトラッキング用クラス
3: Dim trcProfile As New TrackingProfile With {.Name = "CustomTrackingProfile"}
4: 'トラッキングが必要なアクティビティの名前を設定
5: Dim ctQuery As New CustomTrackingQuery With {.Name = "*", .ActivityName = "*"}
6: trcProfile.Queries.Add(ctQuery)
7: 'トラッキングが必要なステータスを設定
8: Dim wfiQuery As New WorkflowInstanceQuery
9: wfiQuery.States.Add(WorkflowInstanceStates.Started)
10: wfiQuery.States.Add(WorkflowInstanceStates.Aborted)
11: wfiQuery.States.Add(WorkflowInstanceStates.Canceled)
12: wfiQuery.States.Add(WorkflowInstanceStates.Completed)
13: wfiQuery.States.Add(WorkflowInstanceStates.Idle)
14: wfiQuery.States.Add(WorkflowInstanceStates.Persisted)
15: wfiQuery.States.Add(WorkflowInstanceStates.Resumed)
16: wfiQuery.States.Add(WorkflowInstanceStates.Suspended)
17: wfiQuery.States.Add(WorkflowInstanceStates.Terminated)
18: wfiQuery.States.Add(WorkflowInstanceStates.UnhandledException)
19: wfiQuery.States.Add(WorkflowInstanceStates.Unloaded)
20: wfiQuery.States.Add(WorkflowInstanceStates.Unsuspended)
21: trcProfile.Queries.Add(wfiQuery)
22: 'ステータスのトラッキングが必要なアクティビティの名前を設定
23: Dim asQuery As New ActivityStateQuery With {.ActivityName = "*"}
24: asQuery.States.Add("*")
25: asQuery.Variables.Add("*")
26: trcProfile.Queries.Add(asQuery)
27: 
28: customTracker.TrackingProfile = trcProfile
29: _wfApps.Extensions.Add(customTracker)

トラッキングプロファイルを設定するのはこのようなロジックとなります。作成したプロファイルを、WorkflowApplication の Extensions として追加していますが、これは WorkflowInvoker も同様です。

1: Imports System.Activities
2: Imports System.Activities.Tracking
3: Imports System.Collections.Generic
4: 
5: Public Class VisualTrackingParticipant
6:     Inherits Tracking.TrackingParticipant
7: 
8:     Public Event TrackingRecordReceived As EventHandler(Of TrackingEventArgs)
9: 
10:     Public Property ActivityIdToWorkflowElementMap As Dictionary(Of Integer, activity)
11:     Public Property ActivityElementMap As Dictionary(Of Object, Debugger.SourceLocation)
12: 
13:     Protected Overrides Sub Track(ByVal record As System.Activities.Tracking.TrackingRecord, ByVal timeout As System.TimeSpan)
14:         OnTrackingRecordReceived(record, timeout)
15:     End Sub
16: 
17:     Protected Sub OnTrackingRecordReceived(ByVal record As TrackingRecord, ByVal timeout As TimeSpan)
18: 
19:         Dim resultArgs As New TrackingEventArgs With {.Record = record, .Timeout = timeout}
20:         Select Case True
21:             Case TypeOf record Is WorkflowInstanceRecord '100
22:             Case TypeOf record Is WorkflowInstanceUnhandledExceptionRecord '101
23:             Case TypeOf record Is WorkflowInstanceAbortedRecord '102
24: 
25:             Case TypeOf record Is ActivityStateRecord '103
26:                 If ActivityIdToWorkflowElementMap.ContainsKey(DirectCast(record, ActivityStateRecord).Activity.Id) Then
27:                     resultArgs.Activity = ActivityIdToWorkflowElementMap.Item(DirectCast(record, ActivityStateRecord).Activity.Id)
28:                 End If
29:             Case TypeOf record Is ActivityScheduledRecord '104
30:                 If ActivityIdToWorkflowElementMap.ContainsKey(DirectCast(record, ActivityScheduledRecord).Activity.Id) Then
31:                     resultArgs.Activity = ActivityIdToWorkflowElementMap.Item(DirectCast(record, ActivityScheduledRecord).Activity.Id)
32:                 End If
33:             Case TypeOf record Is FaultPropagationRecord '105
34:             Case TypeOf record Is CancelRequestedRecord '106
35:             Case TypeOf record Is BookmarkResumptionRecord '107
36:             Case TypeOf record Is CustomTrackingRecord '108,110,111
37: 
38:             Case TypeOf record Is WorkflowInstanceSuspendedRecord '112
39:             Case TypeOf record Is WorkflowInstanceTerminatedRecord '113
40: 
41:         End Select
42:         RaiseEvent TrackingRecordReceived(Me, resultArgs)
43: 
44:     End Sub
45: End Class
46: 

独自に用意したトラッキング用クラスはこのようなロジックで行っています。内容としては対象アクティビティが関連する ActivityStateRecord や ActivityScheduledRecord が通知された際に、TrackingRecord の内容から対象アクティビティを確定させてイベントに通知させることを行っています。イベント受け取り側ではこの内容を元に、WorkflowDesigner.DevugManagerView.CurrentLocation にその時点でのアクティビティを設定する事で、デザイナ上に黄色い枠線で囲まれて表示が行われるようになります。

2011年5月3日火曜日

リホスティングデザイナにて引数を設定

今までのリホスティングしたデザイナのスクリーンショットでは引数の設定ができていませんでした。調べてみるとちょっと一手間加えてあげる必要がある、と海外 MSDN フォーラムにて問い合わせされていたのでそれを試してみました。

   1:  Dim wfFile As Object = New Sequence
   2:   
   3:  Dim activityBuilderType As New ActivityBuilder
   4:  activityBuilderType.Name = "ActivityBuilder"
   5:  activityBuilderType.Implementation = wfFile
   6:  designer.Load(activityBuilderType)



このような形で ActivityBuilder にてアクティビティをラップするようにし、それをデザイナ上でロードすることで引数の設定ができるようになります。


image


ただし今の時点で自分が調べ切れていないのですが、以前に書いた WorkflowService の場合はこの方法が利用できない様子です。まぁサービスで引数はない(パラメータなどを利用するため)ので影響はないですが。

2011年5月2日月曜日

ワークフローのトラッキング

デザイナをリホスティングしている環境でも、ワークフローの実行トラッキングを行う事ができます。やること自体は非常に簡単で、

  1. 実行情報の出力
  2. 出力されたトラッキング情報を元にデバッガの位置を設定

この二つを行えばデザイナ上でのトラッキングが可能です。実際のロジックは次回以降にて掲載する予定ですので、今回はトラッキングを行った際の挙動を貼り付けておきます。


このような感じでトラッキングを行う事ができます。