Quantcast
Channel: てすとぶろぐ
Viewing all 208 articles
Browse latest View live

Randomize なんてものがあって

$
0
0

これは Visual Basic Advent Calendar 2012の記事です。

VisualBasic 固有というよりも、旧来の Basic より脈々と受け継がれてきた命令の一つに Randomize があります。乱数を利用する際に初期化を行う命令なのですが、.NETでの一般的な乱数発生命令と微妙に使い方が違ったりしています。


   1:  Sub Main()
   2:   
   3:          Randomize()
   4:          Console.WriteLine("乱数:" + Rnd.ToString)
   5:   
   6:  Dim r = New Random()
   7:          Console.WriteLine("乱数2:" + r.Next.ToString)
   8:   
   9:          Console.ReadLine()
  10:   
  11:  End Sub

こんな感じで利用します。ロジックだけみると書き方が異なるだけで同じように動きそうなものですが・・・。

乱数

実際に動作させると上記のように結果が異なるのがわかると思います。

RandomizeとRndを利用した乱数は Single 型の小数値ですが、Random クラスと Next メソッドを利用した場合は整数にて取得が行えます。

昔の Basic では発生した乱数に 100 をかけてうんぬん、とやられた方もいらっしゃるかも知れませんね。懐かしい話です。

だからどうした、という話ですがw

追記:2012/12/13 @yaju さんの指摘で 少数→小数 と訂正しました


DynamicValue アクティビティで JSON データを扱う

$
0
0

Workflow Manager 1.0 によって大幅追加されたアクティビティのうち、DynamicValue 関係のアクティビティがあります。名前通り動的な値を扱うためのアクティビティなのですが、具体的にいうと JSON データに対しての操作が可能になるアクティビティ群です。

今回はそれらの中から、JSON 値を生成する BuildDynamicValueアクティビティと、JSON 値から指定したものの値を取得する GetDynamicValuePropertiesを利用してみます。

サンプルの JSON データとしてFacebook 上で作成されている CLR/H のサイトデータを利用します。Facebook の情報にアクセスするために Graph API を利用してアクセスします。

   1: https://graph.facebook.com/144924185576953

このようにアクセスすることで次のように情報が取得できます。

   1: {
   2:"about": "CLR/H \u306f\u3001\u5317\u6d77\u9053\u3067 IT\u95a2\u9023\u3001\u7279\u306b\u958b\u767a\u7cfb\u6280\u8853\u306b\u95a2\u3059\u308b\u5b66\u7fd2\u3068\u7814\u7a76\u3092\u76ee\u7684\u3068\u3057\u305f\u30b3\u30df\u30e5\u30cb\u30c6\u30a3\u3067\u3059\u3002\n",
   3:"general_info": "\u672d\u5e4c\u3067\u6d3b\u52d5\u3057\u3066\u3044\u308b.NET\u3084MS\u30c6\u30af\u30ce\u30ed\u30b8\u4e2d\u5fc3\u306b\u52c9\u5f37\u4f1a\u3092\u958b\u50ac\u3057\u3066\u3044\u308b\u56e3\u4f53\u3067\u3059\u3002\n",
   4:"is_published": true,
   5:"talking_about_count": 18,
   6:"website": "http://clr-h.jp/",
   7:"were_here_count": 0,
   8:"category": "Non-profit organization",
   9:"id": "144924185576953",
  10:"name": "CLR/H",
  11:"link": "https://www.facebook.com/pages/CLRH/144924185576953",
  12:"likes": 51,
  13:"cover": {
  14:"cover_id": 421089204627115,
  15:"source": "http://sphotos-d.ak.fbcdn.net/hphotos-ak-ash4/s720x720/255021_421089204627115_2066584892_n.jpg",
  16:"offset_y": 20
  17:    }
  18: }

今回はここから指定した値を抽出するワークフローを作成してみます。

   1:Sub Main()
   2:Dim result AsNew Variable(Of String)
   3:Dim response AsNew Variable(Of DynamicValue)
   4:Dim picaddress AsNew Variable(Of String)
   5:  
   6:'メインのワークフローの作成
   7:Dim seq AsNew Sequence
   8:     seq.Variables.Add(response)
   9:     seq.Variables.Add(result)
  10:     seq.Variables.Add(picaddress)
  11:  
  12:'BuildDynamicValue アクティビティで JSON 値の作成
  13:Dim dvBuild AsNew BuildDynamicValue With {.Result = response}
  14:'JSON の Dictionary を作成
  15:Dim jsDic AsNew Dictionary(Of String, InArgument)
  16:     jsDic.Add("about", New InArgument(Of String)("CLR/H \u306f\u3001\u5317\u6d77\u9053\u3067 IT\u95a2\u9023\u3001\u7279\u306b\u958b\u767a\u7cfb\u6280\u8853\u306b\u95a2\u3059\u308b\u5b66\u7fd2\u3068\u7814\u7a76\u3092\u76ee\u7684\u3068\u3057\u305f\u30b3\u30df\u30e5\u30cb\u30c6\u30a3\u3067\u3059\u3002\n"))
  17:     jsDic.Add("general_info", New InArgument(Of String)("\u672d\u5e4c\u3067\u6d3b\u52d5\u3057\u3066\u3044\u308b.NET\u3084MS\u30c6\u30af\u30ce\u30ed\u30b8\u4e2d\u5fc3\u306b\u52c9\u5f37\u4f1a\u3092\u958b\u50ac\u3057\u3066\u3044\u308b\u56e3\u4f53\u3067\u3059\u3002\n"))
  18:     jsDic.Add("is_published", New InArgument(Of String)("true"))
  19:     jsDic.Add("talking_about_count", New InArgument(Of String)("18"))
  20:     jsDic.Add("website", New InArgument(Of String)("http://clr-h.jp/"))
  21:     jsDic.Add("were_here_count", New InArgument(Of String)("0"))
  22:     jsDic.Add("category", New InArgument(Of String)("Non-profit organization"))
  23:     jsDic.Add("id", New InArgument(Of String)("144924185576953"))
  24:     jsDic.Add("name", New InArgument(Of String)("CLR/H"))
  25:     jsDic.Add("link", New InArgument(Of String)("https://www.facebook.com/pages/CLRH/144924185576953"))
  26:     jsDic.Add("likes", New InArgument(Of String)("51"))
  27:     dvBuild.Properties = jsDic
  28:     dvBuild.Result = response
  29:  
  30:'GetDynamicValueProperties アクティビティで JSON 値から取得
  31:Dim dv AsNew GetDynamicValueProperties With {
  32:         .Source = response
  33:     }
  34:     dv.Properties.Add("link", New OutArgument(Of String)(picAddress))
  35:  
  36:'結果を標準出力に出力
  37:Dim wl AsNew WriteLine With {.Text = picaddress}
  38:  
  39:     seq.Activities.Add(dvBuild)
  40:     seq.Activities.Add(dv)
  41:     seq.Activities.Add(wl)
  42:  
  43:     WorkflowInvoker.Invoke(seq)
  44:     Console.ReadLine()
  45:  
  46:End Sub

JSON 値の作成部分が長いロジックになりますが、これはワークフロー中で作成しようとしているからであって、普通は Web サービスから取得した結果をそのまま用いたりするのではないかと思います。

もちろんコードで行わなくとも・・・と、言いたかったのですがデザイナで利用しようとするとアクティビティのプロパティが一部表示されていない状態になってしまったので、現時点では利用できるかどうかはっきりしていません。今回、私が検証した環境が Windows 8 + Visual Studio 2010 Pro という環境で無理やりやりくりしたせいもあり、本当はプロパティも問題なくデザイナにも表示されるのかもしれませんが、まだ調べきれていません。

ただ仮にできるとした場合は次のようなワークフローになるかと思います。

DYnamicValueWF

Windows 8 になってからの数少ない不満が、ワークフローデザイナーの配色です・・・。

実行結果としては次のようになります。

DYnamicValueWF_Exec

このように非常に簡単に JSON 値を扱えるようになりますので、外部 Web サービスとの連携も今まで以上に行いやすくなるのではないでしょうか。

Visual Studio Express エディションで開けないプロジェクトを開けるようにするには

$
0
0

Express エディションの Visual Studio は、無償版であり一部機能が限定されています。そのため、有償版の Visual Studio で作成したプロジェクトが開けない事も多々あります。ですが、実際には全てが全て扱うことができないのではなく、一部のプロジェクトは Express エディションでも利用する事が可能です。

個人的には当然といいますか、Workflow Foundation 回りで関連してくるのですが、Workflow Foundation 関係のプロジェクトとして「ワークフローコンソールプロジェクト」があります。WF4 のワークフローを扱うコンソールプロジェクトなのですが、ワークフローデザイナーの部分を除けば、他のコンソールプロジェクトと同様の構成であったりします。

ですが、Express エディションでプロジェクトを開こうとすると
「このエディションでは対応していない機能です」
と言われてしまい、読み込んではくれません。

「デザイナーが使えないのは百も承知だ。いいからだまってプロジェクトくらい読み込みやがれ」と憤ってしまうのですが、実は読み込ませることは手段があったりします。

Visual Studio でプロジェクトの種類、必要な拡張機能についてを決めているのは proj ファイルに記載されているとある値です。

   1:  <?xml version="1.0" encoding="utf-8"?>
   2:  <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   3:  <PropertyGroup>
   4:  <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
   5:  <Platform Condition="'$(Platform)' == ''">x86</Platform>
   6:  <ProductVersion>10.0</ProductVersion>
   7:  <SchemaVersion>2.0</SchemaVersion>
   8:  <ProjectGuid>{6192E5B9-93A2-4632-9A90-A31096374EBA}</ProjectGuid>
   9:  <ProjectTypeGuids>{32f31d43-81cc-4c15-9de6-3fc5453562b6};{F184B08F-C81C-45F6-A57F-5ABD9991F28F}</ProjectTypeGuids>
  10:  <OutputType>Exe</OutputType>
  11:  <StartupObject>Sub Main</StartupObject>
  12:  <RootNamespace>Sample1</RootNamespace>
  13:  <AssemblyName>Sample1</AssemblyName>

上記は Visual Studio 2010 Professional エディションで作成した、ワークフローコンソールプロジェクトの vbproj ファイルです。この中で 9 行目の projectTypeGuids がそれにあたります。ここに記載されている guid にて利用される機能やプロジェクトの種類が決められています。

言い換えるとこの部分を別なものに書き換えてあげれば読み込ませることは可能になります。ただしデータベースプロジェクトなど、完全に機能依存しているようなプロジェクトはできませんが、ワークフローコンソールプロジェクトのように部分的に影響しているものであれば、読み込ませ(場合によっては実行・ビルドも)ることができるようになります。

ネット上のサンプルとしては結構 Express エディション非対応なものが見受けられますが、今回の方法を使うと利用できるものもありますので、一度試してみるといいかもしれません。

・・・と、実はこんな感じでできたのは Visual Studio 2010 Express エディションまでで、Visualo Studio 2012 Express ではこの方法が使えませんでした・・・。

今のところ Visual Studio 2012 Express で同様のことをやるには、同じようなプロジェクトを自前でつくって各種ファイルを取り込んであげるくらいしかなさそうです・・・。
悔しいのでもう少し調べてみようと思います。

VB の Select Case と C# の Switch

$
0
0

MSDN 上での記載では、VB の Select Case と C# の Switch が同等の命令として扱われています。実際にはどちらも条件多分岐命令としては同じなのですが、実際に利用すると VB の Select Case の方が色々と融通が利いて便利な命令であったりします。

例えば C# では Switch 命令で利用できるのは静的な(メソッドやプロパティではない)値である必要があります。ですが VB の Select Case ではメソッドだろうとプロパティだろうと、どのようなものでも記載できます。

   1:  SelectCaseTrue
   2:  Case (A = B): Console.WrilteLine("OK")
   3:  Case (B = C): Console.WrilteLine("これもOK")
   4:  CaseElse
   5:  End Select

VB ではこのように非常に何でもありで思った通りに記載が可能です。

   1:  Switch (true) {
   2:  case (A == B):
   3:         Console.WriteLine("C#では書けない");
   4:  default
   5:  }

C# では上記のようなロジックはコンパイルエラーとなります。

このように VB には便利で書きやすい命令もありますので、一概に C# が良いとは言い切れない面もありますので、両方の言語を比べてみるとまた面白い発見があるのではないでしょうか。

PowerShell 3.0 の ForEach –parallel はマルチスレッドではない

$
0
0

PowerShell Advent Calendar 2012用記事です。

PowerShell 3.0 で追加された PowerShell Workflow の紹介には、かなりの確率で ForEach による並列動作についての記事が掲載されます。ぱっと見ていると、PowerShell でマルチスレッド動作しそうにも思えますが、実際にはどうなのかを検証してみました。


まずはサンプルとして下記のようなスクリプトを作成してみました。

   1:  workflow Test-ParallelWf {
   2:      $numlist = 1..10
   3:      ForEach -parallel ($num in $numlist) {
   4:          $tid = [threading.thread]::CurrentThread.ManagedThreadId
   5:  "Number:{0}  ThreadId:{1}" -f $num, $tid
   6:          Start-Sleep -s 10
   7:  "Complete {0} " -f $num
   8:      }
   9:  "Complete PS-Workflow..."
  10:  }

ForEach で繰り返される処理が、どのスレッドで動作しているか、を取得して表示するスクリプトです。これを実行すると次のような結果になります。

PSWF_1

この通り、実行結果には同一のスレッドIDが出力されているのが見えると思います。これはどういうことなのでしょうか。

   1:  <ns1:PowerShellValuex:TypeArguments="ns3:PSDataCollection(ns3:PSObject)"Expression="$numlist"Result="[ForeachCondition_54385d5b2a13440c87c104e8557c9e39]"/>
   2:  <ParallelForEachx:TypeArguments="x:Object">
   3:  <ParallelForEach.Values>
   4:  <InArgumentx:TypeArguments="ns5:IEnumerable(ns0:Object)">
   5:  <ns1:PowerShellValuex:TypeArguments

先ほどの PowerShell Workflow にて実際に作成される WF4 Workflow の内容を一部抽出したものが上記 xaml です。ParallelForEach アクティビティが利用されているのが見えると思います。ここで思い出してもらいたいのは、Workflow Foundation 4 では Parallel 関係のアクティビティは非同期に動作しない、という点です。挙動としては、シングルスレッド上で Parallel で定義された処理をスケジューリングしておき、Sleep や他の何らかの理由で処理が停滞するタイミングで、継続する処理へとスイッチされるように動作します。ですので一見すると非同期でバシバシ動いてくれそうなのですが、その実まったく非同期ではなくシングルタスク的な動作になってしまいます。

なお、この ParallelForEach アクティビティで処理が切り替わる条件として、MSDNには次のように記載されています。

ただし、スケジュール済みのアクティビティ自体が非同期でない場合 (メッセージング アクティビティ、InvokeMethodAsyncCodeActivityから派生するアクティビティなど) を除き、別々のスレッドでは実行されません。

このあたりを踏まえると、PowerShell Workflow においてもむやみやたらに –parallel させるのではなく、メッセージに関する操作や非同期としてあらかじめ提供されている処理を行うケースなどに限定して利用するのが、効果をあげるポイントになるのではないかと思います。スクリプトを実行しているホスト側の処理をマルチスレッドで動作させよう~、といった場合は特に注意が必要です。今回のサンプルは内部で Start-Sleep を行ったタイミングで処理が切り替わっている、という事になりますので、そういった処理を意図的に切り替えるようなものを仕込んでおくのもいいかも知れません。

そして PowerShell Workflow 全般に関係しているかはわかりませんが、このスケジューリングさせる数にも注意が必要と思われます。MSDN上では

-MaxSessionsPerWorkflow<Int32>

Specifies the maximum number of session that can be created to support each workflow. The default value is 5.

と書かれており、デフォルトの最大セッション数を 5 としています。実行環境にも左右されるとは思いますが、それ以上スケジューリングさせて動作させるのは、どうやら非効率になる可能性が存在しているようです。

Visual Basic 特有の XML 記載で遊んでみる

$
0
0

これは Visual Basic Advent Calendar 2012用の記事です。

Visual Basic 固有の機能の一つとして、XML の扱い方があります。扱い方、といっても処理方法が云々というわけではなく、定義としてそのまま記載できるですとか、処理を埋め込むことができるといったちょっt面白い記述が可能になりますので、今回はそのあたりを遊んでみました。


まず XML データを Visual Basic では直接定義することができます。

'サンプルデータ
Private xmlValue As XElement = <list>
<person twitter="@Masayuki_Ozawa" skill="お絵かき">ムッシュ</person>
<person twitter="@kamebuchi" skill="Azure">抱かれたい男No1</person>
<person skill="Sharepoint">シマえもん</person>
<person twitter="@mentaro" skill="XNA">社長</person>
</list>

また Import のもう一つの使い方として、XML データの名前空間を定義することもできます。

   1:  Imports<xmlns="http://kumaanija.jp/">

この xmlValue で定義したデータをそのまま Console.WriteLine すると次のようになります。

VB1

このように Imports で指定した名前空間が、XML データに適用されているのが見えると思います。しかし Visual Basic による XML 操作は他にも色々なことが可能です。

   1:  Console.WriteLine("Part 1:")
   2:  '普通に LINQ して抽出
   3:  Dim al1 = xmlValue.Elements().Where(Function(elm) elm.Attribute("twitter") IsNot Nothing)
   4:  Console.WriteLine("<ついったらー>")
   5:  ForEach elm In al1
   6:      Console.WriteLine(elm.ToString)
   7:  Next
   8:  Console.WriteLine("</ついったらー>")

まずはそのままシンプルに LINQ to XML で抽出してみます。このあたりは別に Visual Basic だからということでもなく、他言語でもできるところです。実行結果は次の通りです。

VB2

次に埋め込み式と呼ばれる方法を用いて同じ事を行います。

   1:  '埋め込み式を利用
   2:  Dim al2 = <ついったらー>
   3:  <%= xmlValue.Elements.Where(Function(elm) elm.Attribute("twitter") IsNot Nothing) %>
   4:  </ついったらー>
   5:  Console.WriteLine(al2)

なんと先ほどの LINQ to XML で記載していた部分がまるまる埋め込むことができます。実行結果は次の通りです。

VB3

先ほどの結果と微妙に異なっているのがわかるでしょうか。Imports で指定した名前空間の適用がルートノードに対して行われているかどうかの違いがあります。サンプル1では直接出力していた部分は当然適用されていませんが、サンプル2では変数に値が設定されるタイミングで名前空間も適用されています。

さらに埋め込み式では自作のメソッドを呼び出すことも可能です。

   1:  '埋め込み式も利用して xml を変換
   2:  Dim cnvXml AsNew XElement("list")
   3:  ForEach elm In xmlValue.Elements().Where(Function(el) el.Attribute("skill") <> "XNA")
   4:  Dim person = <person twitter=<%= ExtractTwitter(elm.Attribute("twitter")) %>>
   5:  <%= ConvertElement(elm.Value) %>
   6:  </person>
   7:      cnvXml.Add(person)
   8:  Next
   9:  Console.WriteLine(cnvXml)
  10:   
  11:  PrivateFunction ExtractTwitter(value AsString) AsString
  12:  If value IsNot NothingThen
  13:  Return value
  14:  Else
  15:  Return""
  16:  EndIf
  17:  EndFunction
  18:   
  19:  PrivateFunction ConvertElement(value AsString) AsString
  20:  Return value + "様"
  21:  EndFunction

属性 twitter の部分と、person エレメントの値の部分でそれぞれ自作メソッドを呼び出しています。これを実行すると次のようになります。

VB4

呼び出されたメソッドがちゃんと動作して、出力される結果が編集されているのが見えると思います。ここでさらに LINQ の記述を利用してまとめてしまうと、次のように書くこともできます。

   1:  'LINQ と埋め込み式を利用
   2:  Dim al4 = <list>
   3:  <%= xmlValue.Elements().Where(Function(el) el.Attribute("skill") <> "XNA") _
   4:                    .Select(Function(el)
   5:  Dim res = el
   6:                                el.Value += "様"
   7:  Return el
   8:  EndFunction) %>
   9:  </list>
  10:  Console.WriteLine(al4)

LINQ の Select メソッドを利用して自作メソッドで行っていた文字列編集も盛り込んでみました。これを実行した結果が次のようになります。

VB5

このように Visual Basic では XML に関する記載や処理が、他言語と比べて面白く書くことができます。埋め込み式と LINQ を混ぜ合わせることで非常にシンプルに XML に対する処理を記述することができますので、色々と試してみると面白いのではないでしょうか。

Workflow Manager Tool for VS2012 を使ったデバッグの方法

$
0
0

Workflow Manager 1.0 はサーバー用アプリなので、Windows 7 等のクライアント OS にはインストールできず、そのためそのままでは Workflow Manager 1.0 のアクティビティを利用したワークフローのデバッグなどができない状態です。

ですがそれを行うためのツールとして、Workflow Manager Tools for VS2012 が提供されています。実際にこれを用いてどのようにデバッグするのかをまとめてみました。


基本的な流れは MSDNの記述に従った形になりますが、そこに至るまで色々とあります。まず、このツールですが名前が表す通り VS2012 Professional 以上が必要です。VS2012 環境が用意できたら MSDN上に記載されているリンク先より Workflow Manager Tool をインストールします。

このツールは、Windows 7 等 Workflow Manager 1.0 が導入できない環境で開発を行う際に必須となるもので、Workflow Manager のテスト用エミュレータが付属しています。実際にデバッグを行う場合は、このエミュレータに対してワークフローのデプロイ・実行を行って確認していくことになります。

デバッグを行う前に初期設定が必要です。Program Files \ Workflow Manager Tools \ 1.0 とフォルダを下ると、Microsoft.Workflow.VisualStudio.Configuration.exe があり、これを実行することで開発用の環境設定が行われます。これを行わなければエミュレータはだまりこくった状態になってしまいます(エラーが出てくれないのは不親切です・・・)

初期設定を行った後で、実際のデバッグを行います。今回はサンプルとして HttpActivity を用いたサンプルがありましたのでこれを利用してみます。このサンプルで利用されている HttpSend アクティビティは Workflow Manager 1.0 で提供される新規アクティビティで、Http を利用したデータの取得やデータの送信ができる非常に使いでのあるアクティビティです。ですが、内部で隠された Extension を利用しており Workflow Manager 環境以外では利用できない形になっています。

Program Files \ Workflow Manager Tools \ 1.0 フォルダにある Microsoft.Workflow.TestServiceHost.exe が開発用エミュレータで、起動には管理者権限が必要です。

WMT1

起動すると Workflow Manager の設定が読み込まれますので、少し待ちます。

WMT2

上記のようにインスタンスまで読み込まれれば準備完了です。この状態になってからでなければサンプルコードが起動できません。なお、サンプルを動作させるには上記エミュレータで利用しているアドレスを使うように、ソースを修正する必要があります。

WMT3 

サンプルソースにて上記のようにアドレスを記載している箇所があります。スクリーンショット中にて「エミュレータアドレス」とコメントを記載している箇所がそれにあたりますので、そこのアドレスをエミュレータで利用しているアドレスに書き換える必要があります。サンプルソースは https ですが、エミュレータは http ですので注意してください。

WMT4

このようにすることで Workflow Manager を利用したワークフローのデバッグが行えるようになります。

DynamicValue 関係でサポートされる型

$
0
0

今回の Workflow Manager によって追加されるアクティビティの中で、結構嬉しかったものの一つに DynamicValue アクティビティ群による動的な値のサポートがあります。

しかし色々試している内に制約が結構痛かったので、ここに調査結果を書いておきます。


DynamicValue 関係は内部で Microsoft.Activities.Dynamic 名前空間に属するクラスを利用しています。ここに用意されているクラスは全て Friend 扱いで外部からの利用ができなくなっています。そのため、現状ではここのクラスでサポートされていないものはどうやっても扱うことができません。

今回発生した現象は、以前のサンプルと同様のことをワークフロー上でやってみようとしたのが発端で、Facebook から値を取得してみようとしていました。ところが取得した結果を DynamicValue に変換しようとしたタイミングで次のようなエラーが発生することがあります。

エラー

このようなエラーが発生した原因は、取得した JSON 値にあります。

取得した値を変換しようとして、サポートされている型と判断できる場合は良いのですが、双でなかった場合に上記のようなエラーが発生します。現在サポートされている型についてごにょごにょして見てみたところ、次のように定義されていました。

サポート

String、Int、Bool、DateTime、Double、Guid、TimeSpan がサポートされており、それ以外の型は全てエラーとなります。かなりなんてこったいな気分です。


Workflow Manager 1.0 CU1 がリリースされました

$
0
0

気が付くと 2 月末のあたりで Workflow Manager 1.0 の CU1 がリリースされていました・・・。

Web Platform Installer または直接ダウンロードして適用できます。

今回のアップデートで改善される点は次の通りです。

  • ワークフロー インスタンスの中断、および再開のサポート
  • コンテナーが指定されていない場合は、構成ウィザードがクラッシュします。
  • 長整数 (Int64) 型のサポート
  • クライアント アセンブリが CLS 準拠
  • パフォーマンスの修正と強化されたデバッグ トレース

個人的に気になったのは Int64 のサポートですね。以前の DynamicValue アクティビティで Int64 が未サポートであったために、Facebook から情報取得できなかった件がありますので、今回の CU1 で改善されていればいいなぁ・・・。

.NET 4.5 導入後の WF 標準アクティビティアイコンのリソース変更について

$
0
0

以前に .NET 4.5 をインストールすると標準アクティビティのアイコンが Metro チックに変更される、という記事を書きました。この記事を書いた時は、正式版ではなかったのですが、その後正式版をインストールしてみたところ、アクティビティのアイコンは変化しませんでした。ただし、自作ツールの方では変化があり、ツールボックスのアイコンが表示されなくなってしまっていました。この点について調べてみたところアイコンを保持していたリソースファイルに変更が入っていたことがわかりました。

今まで利用していたリソースは System.Activities.Presentation.dll に含まれている icon.xaml というファイル名でした。これが .NET 4.5 インストールにより次のように変更されます。

image

ILSpy による解析ですので xaml はコンパイルされた baml になっていますが、大体わかると思います。今までの icon.xaml はファイルとして存在していますが、その中にアクティビティのアイコンリソースはありませんでした。これが自作ツールでアクティビティのアイコンが表示されなくなった原因でした。

では.NET 4.5 におけるアクティビティアイコンはどこに、となりますが icon.xaml に似たファイル名として icon.default.xaml と icon.windowsapp.xaml という2つのがファイルが含まれているのが見えると思います。このファイルが.NET 4.5 における標準アクティビティアイコンが含まれているリソースになります。

icon.default.xaml を利用すると通常のアイコンが、icon.windowsapp.xaml を利用すると Metro チックなアイコンを利用できるようになります。

image

ですがスクリーンショットを見ていただくとわかりますが、ワークフローデザイナー上のアクティビティアイコンが通常時のものとなっています。ここを変更する方法についてはこれから調査しようと思います。

.NET 4.5 導入後の WF 標準アクティビティアイコンのリソース変更について(2)

$
0
0

前回の記事で、ツールボックスに表示するアイコンを Metro スタイルに変更する方法についてまとめてみました。その時に宿題として残っていた、ワークフローデザイナー上でのアイコン切り替えについて方法が判明したので記載しておきます。

調べてみると非常に簡単な方法が用意されていました。

.NET 4.5 導入にて WorkflowDesignerIcons クラスが追加されており、そこには UseWindowsStoreAppStyleIcons メソッドが用意されています。これを呼び出すだけで表示されるアイコンは切り替わります。

   1:PrivateSub Window_Loaded(sender AsObject, e As RoutedEventArgs)
   2:Dim wd = New WorkflowDesigner
   3:     WorkflowDesignerIcons.UseWindowsStoreAppStyleIcons()
   4:     Grd.Children.Add(wd.View)
   5:Dim sq AsNew Sequence With {.DisplayName = "アイコンサンプル"}
   6:  
   7:     wd.Load(sq)
   8:End Sub

このような形で本当に呼び出すだけです・・・。


image


わかってみると非常に簡単でした。

WF 4.5 で追加されたアウトラインビューを利用する

$
0
0

WF4.5 でワークフロー中の構造を表示するアウトラインビューが提供されることは知っていたのですが、てっきり Visual Studio 上だけの話だとばかり思っていて華麗にスルーしていたところ、これはリホスティング環境でも普通に使えるシロモノだというのが判明したので実際に使ってみました。

ワークフローデザイナーを利用するのと同じく非常に簡単です。

   1:<Windowx:Class="MainWindow"
   2:xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:Title="MainWindow"Height="350"Width="525"Loaded="Window_Loaded">
   5:<Grid>
   6:<Grid.ColumnDefinitions>
   7:<ColumnDefinitionWidth="109*"/>
   8:<ColumnDefinitionWidth="408*"/>
   9:</Grid.ColumnDefinitions>
  10:  
  11:<GridName="Grd"Grid.Column="1"></Grid>
  12:<GridName="doc"Grid.Column="0"></Grid>
  13:  
  14:</Grid>
  15:</Window>

こんな xaml でメイン画面を用意したとして。


   1:Imports System.Activities
   2:Imports System.Activities.Presentation
   3:Imports System.Activities.Statements
   4:Imports System.Activities.Core.Presentation
   5:  
   6:Class MainWindow
   7:  
   8:PrivateSub Window_Loaded(sender AsObject, e As RoutedEventArgs)
   9:Dim metadata AsNew DesignerMetadata
  10:         metadata.Register()
  11:  
  12:Dim wd = New WorkflowDesigner
  13:         WorkflowDesignerIcons.UseWindowsStoreAppStyleIcons()
  14:         Grd.Children.Add(wd.View)
  15:  
  16:Dim sq AsNew Sequence With {.DisplayName = "アイコンサンプル"}
  17:Dim wl1 AsNew WriteLine With {.DisplayName = "出力する", .Text = "クマー"}
  18:Dim wl2 AsNew WriteLine With {.DisplayName = "出力する", .Text = "ムッシュ"}
  19:Dim wl3 AsNew WriteLine With {.DisplayName = "出力する", .Text = "名言"}
  20:         sq.Activities.Add(wl1)
  21:         sq.Activities.Add(wl2)
  22:         sq.Activities.Add(wl3)
  23:  
  24:         doc.Children.Add(wd.OutlineView)
  25:  
  26:         wd.Load(sq)
  27:  
  28:EndSub
  29:End Class

こんな感じにソースを書きます。WorkflowDesigner クラスで OutlineView プロパティが新たに追加され、これを特に何も考えずに表示させればそのまま連動した形で表示されます。

image

非常に簡単で、大きいワークフローを操作する際には有用ですので必須機能ですね。

ウイルスバスターを導入している環境では Hyper-V に新規 VM を作成しようとするとエラーになる

$
0
0

調べてみると Windows 2008 Server とかの世代から脈々と受け継がれている仕様のようですが、今後も食らう可能性が高いので残しておきます。

ウイルスバスターを導入している環境では、新規 VM の作成時にエラーとなるのは前述したとおりです。エラーとなる箇所は様々で、メモリが設定できませんとかストレージを設定できませんとか色々出てきますが、原因は全てウイルスバスターです。

MS からも公式に KBが出されていますので、そちらも参照してください。トレンドマイクロから出されている KB では、設定が必要な情報が不足しておりダメでした。

ウイルスバスターの管理コンソールが利用できるのであればそちらからスキャンの除外設定を行えますが、自分の環境ではそれが許されておりませんでしたので、レジストリに直接設定を行います。

Hyper-Vウイルスバスター

ExcludeExt は除外する拡張子の設定で、今回は vhd ファイルを全般除外させました。ExcludeFile は除外するファイルの設定で個別に指定する必要がある場合に行います。今回は Hyper-V で利用される Vmms と Vmwp 二つを指定する必要があるとの事です。

ExclideFolder は除外するフォルダの設定で、ここには Hyper-V で利用するデータフォルダ(設定が保存されているフォルダや VHD ファイルのフォルダ)を指定する必要があります。

ここまでの設定を行うことで、Hyper-V での新規 VM 作成が阻害されずに行うことができるようになります。

Workflow Manager CU1 による DynamicValue アクティビティのサポート型追加

$
0
0

以前の記事で Workflow Manager 1.0 CU1 がリリースされたことを書きました。その際、アップデートされた内容の中に、Int64 型のサポートという記述があったので、以前試して失敗していた DynamicValue アクティビティのサンプルを再度確認してみました。


今回もソースからの実行ではなく、ワークフローデザイナーにて作成したワークフローで確認しています。

DynamicValueデザイナー

上記のワークフローを WorkflowManager 上で実行させてみました。具体的には CLR/H の Facebook ページ情報を取得して、JSON で渡されるその結果から特定の項目を取得してみようというものです。

以前は JSON データの中に Int32 ではオーバーフローしてしまう値が含まれていたために、Workflow Manager 上でエラーとなっていたものですが、今回は・・・。

DynamicValue実行結果

途中で value = 61 と表示されているのが見えているように、無事実行ができました!

これで心おきなく DynamicValue アクティビティを利用して JSON データも気楽に扱えるようになるというものです。
ひとつ気になっている点が実はあり、このアップデートの適用ですが Workflow Manager 1.0 CU1 が行ったのか、Workflow Manager Tools for Visual Studio 2012 または Visual Studio 2012 Update 2 が行ったものなのかがつかめていません。今のところ、Workflow Manager Tools の最新版適用でも更新されるのではないかな、という見解です。

WF についての本を書きました

$
0
0

最近かなりご無沙汰になってしまっていました(汗
この Blog ではここまで色々と WF について書いていましたが、それがようやく一つの形になることができました。

1116045_527174247349857_1681146161_o

今回、工学社の編集者様からお声をかけていただいて動いたこの企画ですが、実際に提案されたのは1年前で、そのころ腐っていたり多忙にやられていたのもあって、こんなに時間がかかってしまいました。ここまで色々ご指導いただいた方々含め感謝しています。

なお、本のターゲットとしては「非開発者」を想定していて、コーディングでバリバリ書くよ!、という層にはあまり向いておりません。WF ってどういうもので、どんな感じに利用できるのか、という入口に絞って広く浅くに扱った内容となっています。

よろしければぜひ購入していだけると非常に嬉しい限りです。


Workflow Manager 1.0 CU1 開発環境の構築

$
0
0

以前に Workflow Manager 1.0 環境のインストールについて書きましたが、開発のみであれば Workflow Manager 1.0 本体の導入は不要です。最近再構築を行いましたので、ここで改めて開発環境の構築についてまとめておきます。

必要環境

Visual Studio 2012 の Professional 版以降が必要です。今の時点では残念ながら Express のみの環境で開発環境を構築する方法は見つかっておりません。ですが環境さえ構築すれば、後は Express 環境でも開発は可能と思われます。

インストールには Web Platform Installer を利用します。

スクリーンショット (1)

WebPI 上では Workflow Manager Tools 1.0 for Visual Studio 2012 として、ツールのカテゴリ最下層に用意されていますので、これを選択しインストールを行います。上記画面のように Tools のインストールと同時に Workflow Manager のコンポーネントもインストールが行われますが、実行するには他にも必須コンポーネントが必要なのは、以前に書いた際と同様です。ここでは開発に必要なもののインストールのみ行われます。

Workflow Manager 向け開発では Microsoft.Activities.Dll と Microsoft.Activities.Design.Dll が重要コンポーネントとなるのですが、この開発ツールをインストールしなければ Microsoft.Activities.Design.Dll がインストールされないため、Express 版のみの環境では開発が行えないというのが実態です。この Dll で提供されている機能の中で、Workflow Manager 向けにワークフローを変換する、という機能があるのですがこれが利用できないのです。ここ以外の機能については Microsoft.Activities.Dll で提供されているのでワークフローのデプロイや実行は指示できるのですが、デプロイ時の変換だけができないという非常にぐぬぬな状況です。

そのため有償版を保有していない人が Workflow Manager 向け開発を行うためには、評価版の Visual Studio 2012 をインストールした上で開発ツールのインストールを行う必要があります。そのようにすることで、Professional 版以上を保有していない人でも開発は可能ですので、是非試してみてください。

なお、Visual Studio 2013 で同様にいけるかどうかはまだ未検証です・・・。

WF における xaml について簡単な説明をしてみる

$
0
0

Workflow Foundation も xaml を利用しているので XAML Advent Calendar 2013に参加してみました。他の方々に比べると異様な感じを醸し出しているのですが、まあ諦めてください。

まず Workflow Foundation での xaml ですが、2つの使われる場面があります。一つは、アクティビティデザイナーで利用するデザイナーの定義。もう一つはワークフロー自体の定義になります。

アクティビティデザイナーは WPF を利用しているので、WPF アプリケーションで利用している方法が全てそのまま利用可能です。

   1:<sap:ActivityDesignerx:Class="Speak1"
   2:xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:xmlns:s="clr-namespace:System;assembly=mscorlib"
   4:xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   5:xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
   6:xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"
   7:xmlns:sapc="clr-namespace:System.Activities.Presentation.Converters;assembly=System.Activities.Presentation">
   8:  
   9:<sap:ActivityDesigner.Resources>
  10:<sapc:ArgumentToExpressionConverterx:Key="ArgumentToExpressionConverter"/>
  11:  
  12:<DataTemplatex:Key="ExpandedActivityViewTemplate">
  13:<BorderBorderThickness="1">
  14:<Grid>
  15:<Grid.ColumnDefinitions>
  16:<ColumnDefinitionWidth="Auto"/>
  17:<ColumnDefinitionWidth="*"/>
  18:</Grid.ColumnDefinitions>
  19:<LabelGrid.Column="0"Grid.Row="1"Content="ワード"/>
  20:<sapv:ExpressionTextBoxGrid.Column="1"
  21:Width="200"
  22:Expression="{Binding ModelItem.Text, Mode=TwoWay, 
  23:                                                                  Converter={StaticResource ArgumentToExpressionConverter}, ConverterParameter=In}"
  24:ExpressionType="s:String"
  25:OwnerActivity="{Binding Path=ModelItem}"
  26:UseLocationExpression="False"/>
  27:</Grid>
  28:</Border>
  29:</DataTemplate>
  30:  
  31:<DataTemplatex:Key="CollapsedActivityViewTemplate">
  32:<LabelPadding="0,0,0,0"FontStyle="Italic"
  33:Foreground="{x:Static SystemColors.GrayTextBrush}"HorizontalAlignment="Center"
  34:VerticalAlignment="Center"Content="ダブルクリックで展開します"></Label>
  35:</DataTemplate>
  36:  
  37:<Stylex:Key="ConnectionSettingsStyle"TargetType="{x:Type ContentPresenter}">
  38:<SetterProperty="ContentTemplate"Value="{DynamicResource CollapsedActivityViewTemplate}"/>
  39:<Style.Triggers>
  40:<DataTriggerBinding="{Binding Path=ShowExpanded}"Value="true">
  41:<SetterProperty="ContentTemplate"Value="{DynamicResource ExpandedActivityViewTemplate}"/>
  42:</DataTrigger>
  43:</Style.Triggers>
  44:</Style>
  45:  
  46:</sap:ActivityDesigner.Resources>
  47:  
  48:<ContentPresenterStyle="{DynamicResource ConnectionSettingsStyle}"Content="{Binding}"/>
  49:  
  50:</sap:ActivityDesigner>

これはとある勉強会で利用したアクティビティデザイナーのソースです。WF 特有のコントロールを利用している箇所はありますが、それ以外の点では WPF アプリそのものというのが見てわかると思います。アクティビティデザイナーの特徴として Visual Studio やリホスティングデザイナー上で直接触れることができるのが、少々感覚的にも異なるところではないでしょうか。


なお上記のアクティビティをワークフローデザイナー上で見ると次のような感じになります。


image

もう一つの xaml を利用する箇所としてはワークフローになりますが、こちらは xaml と言っても完全に独自のものです。WPF で利用されている xaml とは形は同一でもその内容は別物となります。

   1:<Activitymc:Ignorable="sads sap"x:Class="Workflow1"sap:VirtualizedContainerService.HintSize="315,490"mva:VisualBasic.Settings="Assembly references and imported namespaces for internal implementation"
   2:xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities"
   3:xmlns:local="clr-namespace:NAWASAMI_ACIVITY"
   4:xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   5:xmlns:mv="clr-namespace:Microsoft.VisualBasic;assembly=System"
   6:xmlns:mva="clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities"
   7:xmlns:s="clr-namespace:System;assembly=mscorlib"
   8:xmlns:s1="clr-namespace:System;assembly=System"
   9:xmlns:s2="clr-namespace:System;assembly=System.Xml"
  10:xmlns:s3="clr-namespace:System;assembly=System.Core"
  11:xmlns:s4="clr-namespace:System;assembly=System.ServiceModel"
  12:xmlns:sa="clr-namespace:System.Activities;assembly=System.Activities"
  13:xmlns:sad="clr-namespace:System.Activities.Debugger;assembly=System.Activities"
  14:xmlns:sads="http://schemas.microsoft.com/netfx/2010/xaml/activities/debugger"
  15:xmlns:sap="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation"
  16:xmlns:scg="clr-namespace:System.Collections.Generic;assembly=System"
  17:xmlns:scg1="clr-namespace:System.Collections.Generic;assembly=System.ServiceModel"
  18:xmlns:scg2="clr-namespace:System.Collections.Generic;assembly=System.Core"
  19:xmlns:scg3="clr-namespace:System.Collections.Generic;assembly=mscorlib"
  20:xmlns:sd="clr-namespace:System.Data;assembly=System.Data"
  21:xmlns:sl="clr-namespace:System.Linq;assembly=System.Core"
  22:xmlns:st="clr-namespace:System.Text;assembly=mscorlib"
  23:xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  24:<Sequencesad:XamlDebuggerXmlReader.FileName="C:\Users\DemoUser\Desktop\NawaTech20131123\NAWASAMI_ACIVITY\NAWASAMI_ACIVITY\Workflow1.xaml"sap:VirtualizedContainerService.HintSize="275,450">
  25:<Sequence.Variables>
  26:<Variablex:TypeArguments="x:String"Name="tekitou"/>
  27:</Sequence.Variables>
  28:<sap:WorkflowViewStateService.ViewState>
  29:<scg3:Dictionaryx:TypeArguments="x:String, x:Object">
  30:<x:Booleanx:Key="IsExpanded">True</x:Boolean>
  31:</scg3:Dictionary>
  32:</sap:WorkflowViewStateService.ViewState>
  33:<local:Speak1ActivityText="{x:Null}"DisplayName="魂のシャウト"sap:VirtualizedContainerService.HintSize="253,63"/>
  34:<Assignsap:VirtualizedContainerService.HintSize="253,60">
  35:<Assign.To>
  36:<OutArgumentx:TypeArguments="x:String">[tekitou]</OutArgument>
  37:</Assign.To>
  38:<Assign.Value>
  39:<InArgumentx:TypeArguments="x:String">ムッシュがひどい</InArgument>
  40:</Assign.Value>
  41:</Assign>
  42:<WriteLinesap:VirtualizedContainerService.HintSize="253,61"Text="[tekitou]"/>
  43:<DelayDuration="00:00:10"sap:VirtualizedContainerService.HintSize="253,22"/>
  44:</Sequence>
  45:</Activity>

この xaml をワークフローデザイナー上で見ると次のようなものになります。

image

シーケンシャル型のワークフローでは、処理の順番と xaml 上の記述が一致するのがわかると思います。ですので、ワークフローデザイナーがない環境であったとしても、xaml を直接編集して処理を入れ替えるとか行うのはまだ可能です。

それではもう一つのフローチャート型の場合を見てみます。

image

このワークフローの xaml は次のように記述されています。

   1:<Activitymc:Ignorable="sap sads"x:Class="FlowSample"sap:VirtualizedContainerService.HintSize="696,676"mva:VisualBasic.Settings="Assembly references and imported namespaces for internal implementation"
   2:xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities"
   3:xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   4:xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   5:xmlns:mv="clr-namespace:Microsoft.VisualBasic;assembly=System"
   6:xmlns:mva="clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities"
   7:xmlns:s="clr-namespace:System;assembly=mscorlib"
   8:xmlns:s1="clr-namespace:System;assembly=System"
   9:xmlns:s2="clr-namespace:System;assembly=System.Xml"
  10:xmlns:s3="clr-namespace:System;assembly=System.Core"
  11:xmlns:sad="clr-namespace:System.Activities.Debugger;assembly=System.Activities"
  12:xmlns:sads="http://schemas.microsoft.com/netfx/2010/xaml/activities/debugger"
  13:xmlns:sap="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation"
  14:xmlns:scg="clr-namespace:System.Collections.Generic;assembly=System"
  15:xmlns:scg1="clr-namespace:System.Collections.Generic;assembly=System.ServiceModel"
  16:xmlns:scg2="clr-namespace:System.Collections.Generic;assembly=System.Core"
  17:xmlns:scg3="clr-namespace:System.Collections.Generic;assembly=mscorlib"
  18:xmlns:sd="clr-namespace:System.Data;assembly=System.Data"
  19:xmlns:sl="clr-namespace:System.Linq;assembly=System.Core"
  20:xmlns:st="clr-namespace:System.Text;assembly=mscorlib"
  21:xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  22:<Flowchartsad:XamlDebuggerXmlReader.FileName="C:\Users\DemoUser\Desktop\NawaTech20131123\NAWASAMI_ACIVITY\NAWASAMI_ACIVITY\FlowSample.xaml"sap:VirtualizedContainerService.HintSize="656,636">
  23:<sap:WorkflowViewStateService.ViewState>
  24:<scg3:Dictionaryx:TypeArguments="x:String, x:Object">
  25:<x:Booleanx:Key="IsExpanded">False</x:Boolean>
  26:<av:Pointx:Key="ShapeLocation">270,2.5</av:Point>
  27:<av:Sizex:Key="ShapeSize">60,75</av:Size>
  28:<av:PointCollectionx:Key="ConnectorLocation">300,77.5 300,107.5 310,107.5 310,126.5</av:PointCollection>
  29:<x:Doublex:Key="Width">642</x:Double>
  30:</scg3:Dictionary>
  31:</sap:WorkflowViewStateService.ViewState>
  32:<Flowchart.StartNode>
  33:<x:Reference>__ReferenceID0</x:Reference>
  34:</Flowchart.StartNode>
  35:<FlowDecisionx:Name="__ReferenceID0"sap:VirtualizedContainerService.HintSize="70,87">
  36:<sap:WorkflowViewStateService.ViewState>
  37:<scg3:Dictionaryx:TypeArguments="x:String, x:Object">
  38:<x:Booleanx:Key="IsExpanded">True</x:Boolean>
  39:<av:Pointx:Key="ShapeLocation">275,126.5</av:Point>
  40:<av:Sizex:Key="ShapeSize">70,87</av:Size>
  41:<av:PointCollectionx:Key="FalseConnector">345,170 375,170 375,243.5 345,243.5 345,360 368,360</av:PointCollection>
  42:<av:PointCollectionx:Key="TrueConnector">275,170 190,170 190,240</av:PointCollection>
  43:</scg3:Dictionary>
  44:</sap:WorkflowViewStateService.ViewState>
  45:<FlowDecision.True>
  46:<FlowStepx:Name="__ReferenceID2">
  47:<sap:WorkflowViewStateService.ViewState>
  48:<scg3:Dictionaryx:TypeArguments="x:String, x:Object">
  49:<av:Pointx:Key="ShapeLocation">68,240</av:Point>
  50:<av:Sizex:Key="ShapeSize">244,60</av:Size>
  51:<av:PointCollectionx:Key="ConnectorLocation">190,300 190,330 52.5,330 52.5,96.5 292.5,96.5 292.5,126.5</av:PointCollection>
  52:</scg3:Dictionary>
  53:</sap:WorkflowViewStateService.ViewState>
  54:<Assignsap:VirtualizedContainerService.HintSize="244,60">
  55:<sap:WorkflowViewStateService.ViewState>
  56:<scg3:Dictionaryx:TypeArguments="x:String, x:Object">
  57:<x:Booleanx:Key="IsExpanded">True</x:Boolean>
  58:</scg3:Dictionary>
  59:</sap:WorkflowViewStateService.ViewState>
  60:</Assign>
  61:<FlowStep.Next>
  62:<x:Reference>__ReferenceID0</x:Reference>
  63:</FlowStep.Next>
  64:</FlowStep>
  65:</FlowDecision.True>
  66:<FlowDecision.False>
  67:<FlowStepx:Name="__ReferenceID1">
  68:<sap:WorkflowViewStateService.ViewState>
  69:<scg3:Dictionaryx:TypeArguments="x:String, x:Object">
  70:<av:Pointx:Key="ShapeLocation">368,330</av:Point>
  71:<av:Sizex:Key="ShapeSize">244,60</av:Size>
  72:</scg3:Dictionary>
  73:</sap:WorkflowViewStateService.ViewState>
  74:<Assignsap:VirtualizedContainerService.HintSize="244,60">
  75:<sap:WorkflowViewStateService.ViewState>
  76:<scg3:Dictionaryx:TypeArguments="x:String, x:Object">
  77:<x:Booleanx:Key="IsExpanded">True</x:Boolean>
  78:</scg3:Dictionary>
  79:</sap:WorkflowViewStateService.ViewState>
  80:</Assign>
  81:</FlowStep>
  82:</FlowDecision.False>
  83:</FlowDecision>
  84:<x:Reference>__ReferenceID1</x:Reference>
  85:<x:Reference>__ReferenceID2</x:Reference>
  86:</Flowchart>
  87:</Activity>

急に記載されている量が増えています。これはフローチャート型ワークフローの特徴である、アクティビティの自由な配置が関連しており、デザイナー上で好きに配置されたアクティビティの座標や、アクティビティ間を接続する線(フローノードと呼ばれるアクティビティ)の座標など、非常に多くの情報が必要になるためです。

また、処理の遷移を自由に行えるのもフローチャート型の特徴ですので、サンプルのように処理の遷移を戻した場合は「次に進むアクティビティ」を xaml 上の一つの要素として記述されることになり、シーケンシャルのように先頭から読み進めていくことが非常に難しくなっています。

このように Workflow Foundation でも xaml を利用していますが、アクティビティデザイナーのように WPF アプリケーションとして記述する部分と、ワークフローのように WF 独自の記述を行うもの二つが存在しています。xaml と言われると WPF などに言われるグラフィカルな世界をイメージされることが多いですが、WF のような処理を表す用途にも使われています。

ただ、WF3 で利用されていた xoml のように、気が付けば xaml じゃなくなる可能性はなきにしもあらずで・・・。

Visual Basic のラムダ式を改めて考える

$
0
0

ごめんなさい。ごめんなさい。ごめんなさい。

すっかり忘れていたのですが VB Advent Calendar向けの投稿です。

Visual Basic で悪評高い構文の一つがラムダ式の記述だと思います。

実際 C# と VB、両方使ってみてわかるのですが C# ではさくっと記述できるラムダ式も VB ではFunction ~ End Function や Sub ~ End Sub といった記述のために、中括弧だけでコードブロックを記載できる C# と比較するとどうしても冗長的で読みにくいと感じる人は多いのではないでしょうか。

勿論 VB でも、ワンライナーで記載することは可能ですが、その場合も

   1:Dim res = hogeList.Where(Function(x) x.IsHoge)

というように

   1: var res = hogeList.Where(x => x.IsHoge());

C# と比較するとやはり冗長に思えます。ですが、個人的にはこの冗長さこそが VB の特徴というかメリットなのではないか、と最近は思えるようになりました。

   1:Dim res = hogeList.Select(
   2:Function(vl, idx)
   3:ReturnNewWith {vl, idx}
   4:EndFunction).OrderBy(Function(x) x.idx)

上記のサンプルではワンライナーで記載することができるものですが、意図的にコードブロックとしてみました。この場合、Select で行っていることが 値(Vl)とインデックス(idx)を返却しているのが、Return を記述できているためにパッと見で理解しやすい記述にできています。

OrderBy の方では Return が記述されていないために、慣れた人でなければ配列のインデックス(idx)の値でソートを行っているというのが、つかみにくい記述となっています。このあたりは感覚的なところが大きいので、私が思っているのとは違う意見を持たれる方も多いでしょうが・・・。

とかく LINQ などを利用すると~.~.~・・・と、どんどんメソッドをつなげて記述していってしまい、結果非常に長いロジックを作成しやすくなってしまいます。C# の世界ではフリーフォーマットという特色がありますので、それでも見やすいところで適宜改行を挟むことが可能ですが、VB の場合は改行を行える位置にかなりの規制があります。先ほどの例を書き換えてみると

   1:Dim res = hogeList.
   2:Select(
   3:Function(vl, idx)
   4:ReturnNewWith {vl, idx}
   5:EndFunction).
   6:             OrderBy(Function(x) x.idx)

このような形で、行末がドットの位置で改行をすることになります。これはこれでなれればよいのかもしれませんが、今までの改行文字(_)を利用しているのとさほど違いがありません。一つ前の行末に文字があるかないかで、この行は単独の処理なのかどうかを目で判断するのは良い記述とは言えません。

VB の場合は、短くすることにあまりこだわらず見た目にわかりやすい方向性でコードを書くことが行いやすいのではないでしょうか。もともとの言語構文的特色もあり、C# よりも会話言語的な記述を行うのが VB の特色の一つです。コードの短さにこだわるよりも、文章としての読みやすさを求めるのが VB を利用する場合には大事なのではないでしょうか。

言語はシンプルに短いものがベストと言われる考え方もあり、それは反対するところではありませんが、VB という言語においてはシンプルで「読みやすい」ものがベストなのではないか、と私は思います。コードの短さを追求するのではなく、あくまでも文章的に。そうすることが他の言語にはない VB らしさを生み出せるのではないでしょうか。

ASP.NET で Bootstrap を使った思い出

$
0
0

これは One ASP.NET Advent Calendar 18 日目の記事となります。

ぶっちゃけクラサバサイドに属している自分として、ASP.NET についてテクニカルな話を出すのはなかなか難しいのもあって、今回は実際に ASP.NET を利用して開発した実例の紹介を。

今の会社に転職するまでは、.NET Framework 3.5 での ASP.NET WebForms でパッケージソフト的な何かを作っていたりしていました。その会社の中では .NET を使ってどうこうできるのが、自分と自分と一緒に仕事してくれたメンバーだけだったというのもあり、VB6 が最大勢力という社内の中ではちょっと異色なポジションでのお仕事でした。

そして今の会社に転職して最初に手掛けたのが、ASP.NET MVC3 を利用したとあるシステムの管理サイト的な何かの作成でした。その時はまだこの会社の空気を理解しておらず、プロジェクトの方々に聞いても特に制限はないとのことだったので、

VB で ASP.NET MVC3

サクサクっとやってしまったのですね。実際に動くものが出来上がるまでの時間は、それまでのこの社内では考えられないくらいだったと言われて嬉しかったのですが、後々

「VB を案件で利用したことほとんどないんだよねー、それに VB 書きにくいし」

という実態を聞いてしまい非常にごめんなさいごめんなさいという気持ちになったことを覚えています。Model や Controler はまだしも View は VB 使いから見ても見づらいですよねごめんなさいごめんなさい。

またこの時は、UI デザインも任されていたのですがもともとその方面の実力がなかったのもあり、Bootstrap(当時は Twitter Bootstrap)を使って作成したのも非常にごめんなさいごめんなさいでした。

ですが Bootstrap はやはり非常に楽にさせてもらうありがたいツールで、

   1:<thclass="th-width2">担当者の氏名 </th>

こんな感じの属性をつけるだけで、レイアウトをしっかり整えてくれるのは大変便利でした。


その後色々あって再度 ASP.NET を利用した開発を行うことになったのですが、この時は「実行環境が客先保有でどういう環境になるか全然情報もらえてないから…」という理由で、


VB で ASP.NET WebForms(かろうじて .NET Framework 3.5)


を用いて、これまた管理サイト的な何かを作ることになりました。最終的に判明した実機環境は .NET Framework 4.0 まではインストールされていたのですが、そのころにはほとんど組み上がっていたのもあり MVC の利用はできなかったのです。なお、この時は管理サイトと Web サービスの構築が案件上必要で、私が管理サイトを作成し他の方がサービスを作成したのですが、私は VB で他の方は C# と、「仕事としてこれでいいのか」的な状態にしてしまったという・・・。一つのソリューションで VB と C# が同居しているのは、この会社では多分この案件だけです(w)


そしてこの時もデザイン能力の不足を訴え Bootstrap を利用。おかげで UI レイアウトを固めるのだけはサクサクできました。


WebForms でも次のような感じで利用できます。



   1:<divclass="row">
   2:  
   3:<divclass="col-xs-2 col-sm-2 col-md-2 col-lg-2">
   4:<p>
   5:<asp:LabelID="lblUploadTitle"runat="server"Text="マスタのUpload"CssClass="control-label"></asp:Label>
   6:</p>
   7:</div>
   8:  
   9:<divclass="col-xs-4 col-sm-4 col-md-4 col-lg-4">
  10:<divclass="input-group">
  11:<asp:FileUploadID="updFile"runat="server"CssClass="btn btn-default"/>
  12:</div>
  13:</div>
  14:  
  15:<divclass="col-xs-2 col-sm-2 col-md-2 col-lg-2">
  16:<asp:ButtonID="btnUpload"runat="server"Text="アップロード"CssClass="btn btn-default"/>
  17:</div>
  18:  
  19:</div>

WebForms であっても CssClass 属性に Bootstrap のクラスを記載するだけで利用できますので、非常に簡単です。これだけで解像度の違いを殆ど気にすることなくデザインを統一することができるのは大きなメリットでした。


実際に案件として Bootstrap を利用したのはこの会社では私が最初らしいというのを後で聞いたのですが、利用してみた感想としては


「プログラマが UI 画面をデザインするなら、レイアウトをある程度取りやすいツールの導入」


は非常に効果が高かったと思います。本職の方や、デザイン能力の高い方がいるのであれば迷うことなくお願いするのですが、案件の規模やその時に加わってもらえる要員の都合によっては設計者や開発者がそのままデザインも担当することになるケースは多々あるかと思います。


そのような場合、頑張って UI を考えたとしてもかなりの確率で


いかにも開発者が考えました感が満載の UI


を生み出してしまい、使いやすいシステムを構築するのが難しくなってしまいます。ですが Bootstrap に代表されるレイアウトツールを導入することで、デザインルールが簡単に統一でき見栄えからも使い心地からも安定した UI を素早く提供することができるのだと思います。
(難しい事を言われたとしても、今回利用しているコイツだとそういうレイアウト取れないんですよーアハハハハー、と逃げる手段にもなりますし(!))


ASP.NET MVC と ASP.NET WebForms 両方で Bootstrap を利用したのですが、ASP.NET からこのようなツールを利用するのは非常に簡単に行えるように出来上がっているというのを強く感じてます。時間のない時、予算のない時はこういったツールをできるだけ導入するのが、無事に案件をこなすためには有効なのではないでしょうか。



他の方とはかなり毛色の違う内容となりましたが、たまにはこういう内容もいいですかね?

CLR/H in TOKYO で話してきました

$
0
0

またも久々の更新となってしまいましたが、3/1 に行った CLR/H の東京公演にて WF について話してきました。今回は気持ちを改めて WF で構築する日本型ワークフローシステム、というテーマで話してみましたが、自分で作っていて「あれ、これでなんかシステム作って公開すれば結構いけるんでね?」と思った次第だったりします。

セッション時の資料はこちら


サンプルソースはご希望あれば公開しますが、WF ですのでほとんどがデザイナー上で事足りています。日本型ワークフローであれば、経路設定とか色々悩ましいところがあるのですが、そこを WF で構築することで非常にメンテナンス性も高く使いやすいものが非常に簡単につくる事ができるのが感じ取れてもらえれば嬉しいです。

Viewing all 208 articles
Browse latest View live