ですが WCF の機能を利用する事により「それっぽい」形に仕上げる事はできます。
前回の記事でも利用したワークフローを WCF を利用し REST っぽい形式で公開するには WCF によるサービスの定義、実装が必要となります。サンプルとして Visual Web Developer にて新規に WCF サービスを作成する流れで説明します。
WCF サービスのインターフェースを定義します。このあたりは WCF で REST 形式を扱う場合の実装そのものです。WebGet 属性を利用して、引数を受け取るように記載します。続いてサービス部分の実ロジックです。1: <ServiceContract()>2: Public Interface IService13:4: <OperationContract()>5: <WebGet(UriTemplate:="/{Value}")>
6: Function ExecuteWorkflow(ByVal Value As String) As String7:8: End Interface
前回の記事で引数のやりとりについて書きましたが、その内容をそのまま利用しています。行っている処理としては、引数を指定してワークフローを実行しその結果を返却するというシンプルな形です。なお実行するワークフローの xaml ファイルはちゃんと App_Data フォルダを利用するようにしていたのですが、ここのフォルダ位置を取得するのに少し手間取りました。ASP.NET の場合と WCF の場合では微妙に手段を変えなければいけないという制約があり、上記ロジックのように HostEnvironment.ApplicationPhysicalPath にて物理パスを取得する、という方法まで辿り着くのが・・・。1: Imports System.Activities
2: Imports System.Activities.XamlIntegration
3: Imports System.Threading
4: Imports System.ServiceModel.Channels
5: Imports System.Web.Hosting
6:7: Public Class Service18: Implements IService1
9:10: Private Const WF_NAME As String = "workflow.xaml"11: Private Const INPUT_VARIABLE_NAME As String = "INARG"12: Private Const OUTPUT_VARIABLE_NAME As String = "OUTARG"13:14: Private wfResult As String = ""15: Private syncEvent As New AutoResetEvent(False)16:17: Public Function ExecuteWorkflow(Value As String) As String Implements IService1.ExecuteWorkflow18: 'App_Data フォルダのパスを取得
19: Dim targetPath = System.IO.Path.Combine(HostingEnvironment.ApplicationPhysicalPath, "App_Data", WF_NAME)20: Dim wfFile = ActivityXamlServices.Load(targetPath)
21:22: '入力引数の設定
23: Dim inArgs As New Dictionary(Of String, Object)24: inArgs.Add(INPUT_VARIABLE_NAME, Value)25:26: Dim wfApps As New WorkflowApplication(wfFile, inArgs)27: wfApps.Completed = AddressOf Completed
28:29: Dim resultValue As String = ""30: Try
31: wfApps.Run()32: syncEvent.WaitOne()33: resultValue = wfResult34: Catch ex As Exception35:36: End Try37: Return resultValue
38: End Function39:40: Private Sub Completed(ByVal e As WorkflowApplicationCompletedEventArgs)41:42: If Not ((e.CompletionState = ActivityInstanceState.Canceled) OrElse43: (e.CompletionState = ActivityInstanceState.Faulted)) Then
44: '正常終了時に結果を取得する
45: If e.Outputs.ContainsKey(OUTPUT_VARIABLE_NAME) Then46: wfResult = e.Outputs(OUTPUT_VARIABLE_NAME).ToString47: End If48: End If49:50: syncEvent.Set()
51: End Sub52:53: End Class
もうひとつREST形式で利用するために web.config ファイルを編集します。
WCF 既定の構成となる web.config に2か所記述を追加しています。一つは WCF サービスのエンドポイントの部分、もう一つはそのエンドポイントのベヘイビアの部分です。エンドポイントビヘイビアについては固定的にこういうもの、でいいかと思いますw1: <?xml version="1.0" encoding="utf-8"?>2: <configuration>3:4: <system.web>5: <compilation debug="true" strict="false" explicit="true" targetFramework="4.0" />6: </system.web>7: <system.serviceModel>8: <!-- 追加部分 -->
9: <services>10: <service name="RESTWFService.Service1">11: <endpoint behaviorConfiguration="webHttpBehavior" binding="webHttpBinding"12: bindingConfiguration="" contract="RESTWFService.IService1" />13: </service>14: </services>15:16: <behaviors>17: <!-- 追加部分 -->
18: <endpointBehaviors>19: <behavior name="webHttpBehavior">20: <webHttp />21: </behavior>22: </endpointBehaviors>23:24: <serviceBehaviors>25: <behavior>26: <!-- メタデータ情報の開示を避けるには、展開する前に、下の値を false に設定し、上のメタデータのエンドポイントを削除します -->
27: <serviceMetadata httpGetEnabled="true"/>28: <!-- デバッグ目的で障害発生時の例外の詳細を受け取るには、下の値を true に設定します。例外情報の開示を避けるには、展開する前に false に設定します -->
29: <serviceDebug includeExceptionDetailInFaults="false"/>30: </behavior>31: </serviceBehaviors>32: </behaviors>33: <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />34: </system.serviceModel>35: <system.webServer>36: <modules runAllManagedModulesForAllRequests="true"/>37: </system.webServer>38:39: </configuration>
サービスのエンドポイント部分は、サービス名を名前空間付きでサービスクラス名、エンドポイントのコントラクトを名前空間付きでインターフェース名を指定し、webHttpBinding を利用するように設定します。
このように WCF サービスを実装し実行すると、通常の REST サービスよろしくブラウザから普通にアクセスできるようになります。
本当の REST 形式とは異なり、あくまでもそれっぽい動作を行うだけですが、これを利用する事で通常の Web サービスとして公開する事も可能となります。
0 件のコメント:
コメントを投稿