UiPath Studioで使用するカスタムアクティビティの作成方法


# 目次

**2019/07/03 目次を追記**
記事が多数になってしまったので、他記事へのリンクを追加しました。

- [カスタムアクティビティの作成方法](https://qiita.com/masatomix/items/1f63513e80313a99faeb) 今回の記事
- [カスタムアクティビティの作成方法(GUI構築)](https://qiita.com/masatomix/items/e75598f73b0e019044ac) 
- [カスタムアクティビティのnupkgの作り方](https://qiita.com/masatomix/items/d62683a158da6d35f24d)
- [カスタムアクティビティ開発で、外部ライブラリを使用する](https://qiita.com/masatomix/items/61024a6b9294a1707d23)
- [カスタムアクティビティの配置場所について](https://qiita.com/masatomix/items/b8988fcc2bd7046825f2)
- [カスタムアクティビティ開発で、見た目のカスタマイズを行う](https://qiita.com/masatomix/items/f3c5a36755860dba63ca)
- [カスタムアクティビティ開発で、リソースの外部化とローカライズを行う](https://qiita.com/masatomix/items/96d997608c02ca37a0d9)
- [カスタムアクティビティ開発で、リソースの外部化とローカライズを行う(XAML版)](https://qiita.com/masatomix/items/b747d1532529f9a2977d)



# UiPathのアクティビティを自作したい

[UiPath Studio 2018.3 Early access - Beta release をさわってみた2 (カスタムアクティビティ)](https://qiita.com/masatomix/items/ae619eed7699e677338d) にて、2018.3版から導入される新しいカスタムアクティビティの作成方法をしらべました。そうしたら「既存のアクティビティを呼び出す、アクティビティ」などは簡単に作成できるのですが、たとえば

![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/ccdad017-fa1c-5bbd-3a92-fd04ec70f6ad.png)

このような、GUIをもつようなアクティビティはどうやら作成することが出来ないことがわかりました。ってなわけでやっぱり、2018.2までの既存のカスタムアクティビティの作り方は知っておく必要がありそう、となりましたので、整理しておきます。。


ただ、先人の知恵には感謝です。
[【UiPath】カスタムアクティビティの作成（事前準備と実践初級）](https://qiita.com/UmegayaRollcake/items/c9ff9a01b101ba9193fc)  このページに、かなりの情報が整理されていました！！いつも参考にさせていただいています。感謝します！


# 事前のインストールなど
## Visual Studio IDE
https://visualstudio.microsoft.com/ja/vs/ より Visual Studio Community をインストール。2018/10/02現在2017版が最新ぽい。 次へ次へでインストールできますが、「個別のコンポーネント」タブで Windows Workflow Foundation を選択することを忘れずに。。


![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/af3bf7bb-053b-0534-ed49-22d7a15d6083.png)

## nuget.exe
いわゆる *.nupkg を作成するコマンドラインツール。コレを使って自作アクティビティが入ったDLLをnupkgに格納します。
https://www.nuget.org/downloads よりダウンロードして、任意の場所に解凍しておきましょう。


# やってみる
UiPathの出している [Creating a Custom Activity](https://activities.uipath.com/docs/creating-a-custom-activity) コレを追っかけつつ「stringの配列を渡したらWindowsのパスを生成して返してくれる」ようなアクティビティを作ってみます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/ccdad017-fa1c-5bbd-3a92-fd04ec70f6ad.png)

こんな感じにWindowsのパスを返してくれます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/4eb1ca70-5860-1d6a-1f9c-ee992d8fa939.png)


## Visual Studio 側での作業
### Visual Studioでプロジェクトの作成

Visual Studioを起動し、ファイル >> 新規作成 >> プロジェクト を選択
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/e18753a6-1923-64aa-b414-e35718240843.png)


Visual C# >> クラスライブラリ(.NET Framework)を選択
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/9f95b5a4-1320-79bb-8229-a1e538f41526.png)

||値|
|-----------------|------------------|
| 名前             |            Path |
| 場所             |           適当で |
| ソリューション名  |            Path |


としました。Gitで管理したい人は適宜「新しいGitリポジトリの作成」を選択します。


###ライブラリの追加
つづいて、アクティビティ作成のためのライブラリの参照を追加します。メニューより、 プロジェクト >> 参照の追加 を選択し
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/362c3678-bdaa-9fac-508b-7ed034cfd989.png)


下記の通り、

|名前|
|-----------------|
| System.Activities  |  
| System.ComponentModel.Composition  |  


にチェックを入れてOKをクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/834c916c-ccad-0179-78b0-5eb915347774.png)



### アクティビティの追加
さて、アクティビティを追加していきます。ソリューションエクスプローラの「Path」ってなってるアイコンを右クリックして、 追加 >> 新しい項目 を選択

![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/ddfe8939-66d6-177b-2a19-2bfe54f20814.png)

Workflow >> コードアクティビティを選択。クラス名は「**Combine.cs**」としました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/f7a2f62f-c901-639d-a8d1-c1b796294141.png)

C#のソースコードが追加されたと思います。追加したソースは、初期状態は、こんな感じになっています。

```C#:Combine.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;

namespace Path
{

    public sealed class Combine : CodeActivity
    {
        // 文字列型のアクティビティ入力引数を定義します
        public InArgument<string> Text { get; set; }

        // アクティビティが値を返す場合は、CodeActivity<TResult> から派生して、
        // Execute メソッドから値を返します。
        protected override void Execute(CodeActivityContext context)
        {
            // テキスト型の入力引数のランタイム値を取得します
            string text = context.GetValue(this.Text);
        }
    }
}
```

InArgument はこのアクティビティの引数、Execute メソッドはこのアクティビティが実行されたときの処理を記述するメソッドです。

あとでもうすこし整理しますが、とりあえず下記の通り、 OutArgument なプロパティを一つ定義しました。このOutArgument なプロパティは、Executeの実行結果を格納するためのプロパティです。Executeでは InArgumentの値にHello Worldを追記して、OutArgumentにSetしています。


```C#
    public sealed class Combine : CodeActivity
    {
        // 文字列型のアクティビティ入力引数を定義します
        public InArgument<string> Text { get; set; }

        public OutArgument<String> result { get; set; }  // 追記

        // アクティビティが値を返す場合は、CodeActivity<TResult> から派生して、
        // Execute メソッドから値を返します。
        protected override void Execute(CodeActivityContext context)
        {
            // テキスト型の入力引数のランタイム値を取得します
            string text = context.GetValue(this.Text);
            result.Set(context, text + " Hello world.");  // 追記

        }
    }
```

つづいて、GUIクラスを追加します。さきほど同様、ソリューションエクスプローラを右クリックして、 追加 >> 新しい項目 を選択し、次は、 Workflow >> アクティビティデザイナー を選択します。クラス名は「**CombineDesigner.xaml**」としました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/b6a2f487-3633-8366-76db-4bea8299b530.png)


下記のようなGUIエディタが起動すると思います。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/b60cb907-c639-283b-059e-7e22cc3487b7.png)


先ほどのC#のソース Combine.cs に、このXAMLファイルとの紐付けなどをおこなったり、このエディタでUIを構築したりしていきますが、いったんそれらは後回しにして先に進みます。


### nupkgに反映されるデータの作成
つづいて、アクティビティが格納されるnupkgの元になる情報を作成していきます。

ソリューションエクスプローラを右クリックして プロパティを選択
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/9d1359e8-1934-85b9-0eed-0bdb8137c06b.png)


表示される画面で一番うえの「アプリケーション」を選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/a15830aa-6d2b-9c63-ea76-b54243eeff9a.png)
アセンブリ名: ActivitiesPathUtils とします。ちなみに  [Creating a Custom Activity](https://activities.uipath.com/docs/creating-a-custom-activity) ここに

>Important!
>The NuGet Package Id field must contain the keyword “Activities” to appear in the Manage Packages window, in Studio.

と書いてあるとおり、アセンブリ名は 「Activities」という文字列を含んでいる必要があるようです。

**2018/10/18追記**

上記の通り ActivitiesPathUtils にしたアセンブリ名ですが、https://www.nuget.org/packages/UiPath.Platform.Activities/ にあるライブラリを見た感じだと、ネーミングは `kino.UiPath.Utils.Activities`
とかのほうが、それっぽいですね。。

**2018/10/18追記 ここまで**

また アセンブリ情報 のボタンをクリックし、
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/093bb6e5-1642-cf3b-55f6-59605e11f050.png)


| 項目       |       値 |
|:-----------------|------------------|
| タイトル            | Path Utilities | 
| 説明                |Path Utilities は、ファイルパスの連結などを行うUtility群です |    
| アセンブリバージョン     | 0.0.1.0 |      

などと入力しておきます。タイトルとか説明は、まあなんでも結構です。





### いったんビルド

ここまでで一度ビルドします。ツールバーの Debug をReleaseへ変更し、
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/8ea58ac3-29f4-9dd0-0bc5-c9e76c9c0d7f.png)

ビルド>>ソリューションのビルド を選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/d924d0d7-cf15-556f-3024-8e66deefcbdf.png)
**出力(コンソール)のところに、下記のようなActivitiesPathUtils.dll が出力された、的な文言**が表示されていればOK。

```
1>------ すべてのリビルド開始: プロジェクト:Path, 構成: Release Any CPU ------
1>  Path -> Z:\git\Path\Path\bin\Release\ActivitiesPathUtils.dll
========== すべてリビルド: 1 正常終了、0 失敗、0 スキップ ==========
```

そのバスに実際にDLLが出力されていることを確認しましょう。

### nupkgの設定ファイルnuspecの生成
ソースコードを含んだDLLが作成できたので、そのファイルをnupkgにパッケージングしていきますが、そのための設定ファイルをnuget.exeを使って作成します。

具体的には下記の通り、

```
Z:\git\Path\Path>dir
2018/10/04  18:12    <DIR>          .
2018/10/02  14:46    <DIR>          ..
2018/10/02  14:13               597 CombineDesigner.xaml.cs
2018/10/02  13:58    <DIR>          obj
2018/10/04  16:47    <DIR>          bin
2018/10/02  15:01             1,156 Combine.cs
2018/10/02  15:12             1,473 CombineDesigner.xaml
2018/10/04  17:41    <DIR>          Properties
2018/10/04  17:27             3,525 Path.csproj   ←コレ
2018/10/02  09:49               187 Class1.cs
Z:\git\Path\Path>
```

.Netのプロジェクトファイル Path.csprojがあるディレクトリに移動して、下記コマンドを実行します。

あ、nuget.exeにはパスを通しておくか、事前準備で配置した場所をフルパス指定してください。

```
Z:\git\Path\Path> nuget.exe spec Path.csproj
'Path.nuspec' は正常に作成されました。
```

というメッセージが表示され、下記のようなxmlファイル(Path.nuspec)が作成できたと思います。

```xml
<?xml version="1.0"?>
<package >
  <metadata>
    <id>$id$</id>
    <version>$version$</version>
    <title>$title$</title>
    <authors>$author$</authors>
    <owners>$author$</owners>
    <licenseUrl>http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE</licenseUrl>
    <projectUrl>http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE</projectUrl>
    <iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>$description$</description>
    <releaseNotes>Summary of changes made in this release of the package.</releaseNotes>
    <copyright>Copyright 2018</copyright>
    <tags>Tag1 Tag2</tags>
  </metadata>
</package>
```

コレを書き換えていきますが、結論いうと下記の通り書き換えればOKです。version など、さっき記載したアセンブリ情報のプレースホルダになってる箇所はそのままにしつつ、authorsはプレースホルダがないっぽいので固定的に。xxx_URL_HERE_OR_DELETE_THIS_LINEの箇所はとりあえず行削除。


```xml

<?xml version="1.0"?>
<package >
  <metadata>
    <id>$id$</id>
    <version>$version$</version>
    <title>$title$</title>
    <authors>m-kino</authors>   ←固定的に書かないとエラーになるっぽい
    <owners>m-kino</owners>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>$description$</description>
    <releaseNotes>Summary of changes made in this release of the package.</releaseNotes>
    <copyright>Copyright 2018</copyright>
  </metadata>
  <files>
    <file src="bin\Release\*.dll" target="lib" />
  </files>
</package>
```

このうち、

```xml
<files>
  <file src="bin\Release\*.dll" target="lib" />
</files>
```

については、DLLファイルをlibディレクトリ直下に配置せよっていう指示ですが、コレを書かないとUiPath Studioでは参照されない箇所(lib¥net461 っていうディレクトリ配下)にDLLが置かれるっぽく、その対応のためのおまじないです。

正しい対策方法があればしりたいのですが、今回はコレで行きます。ちなみに上記のディレクトリ階層(lib¥net461)は、.Netのバージョン毎にDLLを置くための配慮みたいですね。。


**2018/10/18追記**
他のヒトの nupkgを見てて、こうやればよさそうってのが分かってきたので整理しました。ちょっと分量があったので、[UiPathのカスタムアクティビティのnupkgの作り方(元記事の訂正)](https://qiita.com/masatomix/items/d62683a158da6d35f24d) にまとめました。
**2018/10/18追記 ここまで**


### nupkg作成
ようやくnupkgを作成します。先ほどのディレクトリで、下記の通りコマンドを実行します。

```
Z:\git\Path\Path> nuget.exe pack Path.csproj -Prop Configuration=Release
'Path.csproj' からパッケージをビルドしています。
MSBuild auto-detection: using msbuild version '15.8.169.51996' from 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\bin'.
'Z:\git\Path\Path\bin\Release' のファイルをパックしています。
メタデータに 'Path.nuspec' を使用しています。
Successfully created package 'Z:\git\Path\Path\ActivitiesPathUtils.0.0.1.nupkg'.
警告: NU5101: The assembly 'lib\ActivitiesPathUtils.dll' is placed directly under 'lib' folder. It is recommended that assemblies be placed inside a framework-specific folder. Move it into a framework-specific folder.
警告: NU5102: The value "Summary of changes made in this release of the package." for ReleaseNotes is a sample value and should be removed. Replace it with an appropriate value or remove it and rebuild your package.

Z:\git\Path\Path>
```

なんか色々と怒られてますが、Path.nuspec と Path.csproj などに記載している情報を元に、ActivitiesPathUtils.0.0.1.nupkg を作成することが出来たと思います。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/18e39de3-c1a8-79b7-d8dd-6ffcc5e1bdb0.png)


遭遇したトラブルとしては、**一度ビルドをしないとDLLが見つからないっていうエラー**が出る、**ソースを修正したあとは、ビルド >> ソリューションのクリーン、と、ビルドをしないと旧DLL**がパッケージされちゃう、**-Prop Configuration=Release オプションをつけないと、Debugの方のDLLも入れようとしてエラー**になっちゃう、などがありましたのでご注意。



**2018/10/18追記**

ソースを修正したらソリューションのクリーンとビルドをしないと旧DLLがパッケージされちゃう件は**「ソリューションのリビルド」**でもよさそうです。

**2018/10/18追記 ここまで**




### パッケージマネージャのローカルリポジトリの追加
最後に、このnupkgが置かれる場所(今回は Z:\git\Path\Path ってなってます)を、Visual Studioのパッケージマネージャ配置場所として指定します。

このVisual Studioのパッケージマネージャの設定は、Visual Studioに追加機能としてインストールするモジュール達の配布場所を設定する箇所で、URLやローカルのパスを指定することが出来ます。で、この指定はどうやらUiPath Studioと共通になってるぽく、ここに設定するとUiPath Studio側にも追加されます。なのでどっちのStudioでやってもイイのですが、今回はVisual Studio側でやります。


ツール >> NuGet パッケージマネージャ >> パッケージマネージャ設定 を選択
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/fa0efaf2-f0d9-218f-79c0-6670c2040bf5.png)

パッケージソースを選択、右上のプラスアイコンで、パッケージソースを追加
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/5b7b6df1-37c2-cd7b-79b8-62fcd7a5d431.png)


名前とソース(ファイルパス)を設定します。名前は何でもよく、ソースは、先ほどのnupkgが置かれた場所(Z:\git\Path\Path) を指定しました。で更新をクリックすると
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/b5e7962e-1ce9-08f0-7b6a-a1fe379bbbae.png)

下記の通り、利用可能なパッケージソース に追加されたので、OKをクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/6752a1e9-748a-ce40-e385-ac886923fdca.png)


パッケージソースの場所は今回  Z:\git\Path\Path っていう中途半端な場所になりましたが、実運用を考えたパッケージソースの場所は、ちゃんと検討が必要になりそうですね。



以上で、Visual Studioでの作業は完了です。

やったことを整理すると、

- Visual Studioでプロジェクトを作成
- ソースを作成しビルドしてDLLを生成
- DLLをnupkgに入れるための設定ファイルを作成し、nuget.exeで nupkgファイルを作成
- nupkgファイルを UiPath Studioへ配布するためのリポジトリの設定

などになります。ソースコードの修正はこの次のサイクルでやるとして、つぎはこのnupkgをUiPath Studioへ配布・インストールしてみます。


## UiPath Studio側での作業

### UiPath Studioでのnupkgのインストール

UiPath Studioでプロジェクトを開始後、Activities ペインの段ボールっぽいアイコン(Manage Packagesて書いてある)のをクリック。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/79aacf28-c35c-e96d-b6c0-177165dd7cc8.png)


表示されるダイアログの、Available >> ALL をクリックします。先ほどの nupkgが表示されればOKです。ときおりナゼか表示されないこともあって、上部の検索ボックス(Search in Available)をいじると出てきたり、微妙に不安定な気がしますorz。。

まあ、表示されたら Install をクリックしてnupkgをインストールします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/fc1f64ad-efe0-9a32-4e7d-8187fa7836f4.png)

インストールがうまくいったら、Installed >> ALLをクリックして、下記の通りインストール済みであることを確認してください。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/fbf147d0-51b0-fa12-3f35-a9b5424bcf73.png)

### アクティビティの配置
StudioのActivityペインに、インストールしたアクティビティが表示されていると思いますので、ドラッグアンドドロップしてみましょう。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/193f55f2-9407-bd06-f9f1-baf75dc0ea0c.png)


先ほど作成したアクティビティのソースと見くらべてみると、Combine.csで定義したプロパティ:

```C#
public OutArgument<String> result { get; set; }
public InArgument<string> Text { get; set; }
```

が、Studio上のPropertiesに対応しています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/d3437b71-d36f-eaff-3fae-4dbae0e582a3.png)






Textに定義された「"こんにちは"」がExecute で

```C#
 result.Set(context, text + " Hello world.");
```
と処理されてresultへセットされ、Studio上でresult 変数に格納され、それをつぎのアクティビティ Write lineでコンソール出力しています。

実行してみると、
![image.png](https://qiita-image-store.s3.amazonaws.com/0/73777/035a5481-36bc-58ee-5630-dac1b5e9c325.png)


うごきましたねーー。。。


## いったんまとめ
ひきつづき

- C#のコード側でXAMLを指定して、アクティビティとGUIの紐付け
- そのGUIをXAMLで構築
- パスを連結する実際のロジック作成
- バージョンをインクリメントしてnupkgの再パッケージング

などをやりたいのですが、とても長くなったのでまずはここまで。本丸は[次回](https://qiita.com/masatomix/items/e75598f73b0e019044ac)です。。

## ソースコード
https://github.com/masatomix/UiPath_Path/tree/0.0.1
に配置しました。

## 関連リンク
- [【UiPath】カスタムアクティビティの作成（事前準備と実践初級）](https://qiita.com/UmegayaRollcake/items/c9ff9a01b101ba9193fc)  いつも参考にさせていただいています。感謝します！
- [プライベートなnugetパッケージを作る](https://qiita.com/Temarin/items/f8847bf787c161e874e6)
- [UiPath Studio 2018.3 Early access - Beta release をさわってみた2 (カスタムアクティビティ)](https://qiita.com/masatomix/items/ae619eed7699e677338d)
- [UiPath Studio 2018.3 Early access - Beta release をさわってみた1](https://qiita.com/masatomix/items/5e56c31d1ef3b400da6f)
- [Windows Workflow Foundation × UiPath カスタムアクティビティ × 自分的作成時の注意点](https://www.kinakomotitti.net/entry/2018/07/19/201340)


## 記事目次
- [UiPath Studioで使用するカスタムアクティビティの作成方法](https://qiita.com/masatomix/items/1f63513e80313a99faeb)  今回の記事
- [UiPath Studioで使用するカスタムアクティビティの作成方法 つづき(GUI構築)](https://qiita.com/masatomix/items/e75598f73b0e019044ac) 次回の記事
- [UiPathのカスタムアクティビティの配布について(Orchestrator接続なし版)](https://qiita.com/masatomix/items/9206873c2959451ac01e)
- [UiPathのカスタムアクティビティの配布について(Orchestrator接続あり版)](https://qiita.com/masatomix/items/af71fa799d53d3cbc08a)
-  [UiPathのカスタムアクティビティの配置場所について(アクティビティ開発者・UiPath開発者・Robot向け)](https://qiita.com/masatomix/items/b8988fcc2bd7046825f2)
- https://github.com/masatomix/UiPath_Path ソースのMaster Branch