VisualStudio2017でガルーンAPIを使ってメッセージを送ってみる

#VisualStudio2017でガルーンAPIを使ってメッセージを送ってみる

##開発環境
・Visual Studio 2017 (C#)
・サイボウズ　ガルーン(クラウド版)

##ガルーンAPIの説明
リンク
[メッセージAPIについて](https://cybozudev.zendesk.com/hc/ja/articles/202487080)

にメッセージAPIの説明があります。

##WSDLの取得
リンク
[Garoon SOAP APIの共通仕様について](https://cybozudev.zendesk.com/hc/ja/articles/202228464)

で以下のように説明があります。

>Garoon SOAP APIでは、SOAPを使用してガルーンと他システムの連携を行います。Garoon SOAP APIの定義は、WSDL（Web Service Definition Language）によって記述されています。ガルーンが既定のディレクトリにインストールされている場合、下記のURLで確認できます。

>>
```WSDL:
Garoon on cybozu： https://（サブドメイン名）.cybozu.com/g/index.csp?WSDL
パッケージ版 Windows 環境：http://（インストールしたサーバーの IP アドレスまたはホスト名）/scripts/（インストール識別子）/grn.exe?WSDL
パッケージ版 Linux 環境：http://（インストールしたサーバーの IP アドレスまたはホスト名）/cgi-bin/（インストール識別子）/grn.cgi?WSDL
```


## Web参照の追加
- ソリューションエクスプローラーを右クリック > サービス参照の追加 > 詳細設定 > Web参照の追加
![WS000691.JPG](https://qiita-image-store.s3.amazonaws.com/0/90597/dc25b4d3-1f01-ef8d-6e83-299f3d0e37af.jpeg)

- Web参照名は、「GaroonService」としました。

今回は、Garoon on Cybozuを使用します。
ガルーンのクラウド版が30日間無料で登録できるので、そちらを利用しています。
リンク
[Garoon on cybozu.com](https://garoon.cybozu.co.jp/lp/?utm_source=google&utm_medium=list&utm_content=lp&utm_campaign=garoon)


## Reference.csの修正
- SOAPヘッダーを追加
Reference.csの先頭の方へ追記開始から追記終了部分を追加する。

```csharp:Reference.cs

namespace GaroonMessageAPI.GaroonService
{
using System;
using System.Web.Services;
using System.Diagnostics;
using System.Web.Services.Protocols;
using System.Xml.Serialization;
using System.ComponentModel;

/*追記開始*/
[System.Xml.Serialization.XmlRootAttribute(ElementName = "Action")]
public partial class ActionElement : SoapHeader
{
    [System.Xml.Serialization.XmlText()]
    public string actionValue;
}

[System.Xml.Serialization.XmlRootAttribute(ElementName = "Security")]
public class SecurityElement : SoapHeader
{
    [System.Xml.Serialization.XmlElement("UsernameToken")]
    public UsernameTokenElement usernameToken;
}

public class UsernameTokenElement
{
    public string Username;
    public string Password;
}

[System.Xml.Serialization.XmlRootAttribute(ElementName = "Timestamp")]
public class TimestampElement : SoapHeader
{
    public DateTime Created;
    public DateTime Expires;
}
/*追記終了*/

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.6.1586.0")]
```

- MessageBindigに追加したSOAPヘッダーを追記

```csharp:Reference.cs
public partial class MessageBinding : System.Web.Services.Protocols.SoapHttpClientProtocol {
    /* 追記開始 */
    public ActionElement action;
    public SecurityElement security;
    public TimestampElement timeStamp;
    /* 追記終了 */

    private System.Threading.SendOrPostCallback MessageGetFolderVersionsOperationCompleted;
```

- MessageCreateThreadsに追加したSOAPヘッダーを追記

以下のように修正
`/// <remarks/>`と`[System.Web.Services.Protocols.SoapRpcMethodAttribute("MessageSaveCreateThreads"`の間に追記する。

```csharp:Reference.cs
/// <remarks/>
[System.Web.Services.Protocols.SoapHeaderAttribute("action", Direction = SoapHeaderDirection.InOut)]
[System.Web.Services.Protocols.SoapHeaderAttribute("security", Direction = SoapHeaderDirection.InOut)]
[System.Web.Services.Protocols.SoapHeaderAttribute("timeStamp", Direction = SoapHeaderDirection.InOut)]
[System.Web.Services.Protocols.SoapRpcMethodAttribute("MessageSaveCreateThreads", RequestNamespace="http://wsdl.cybozu.co.jp/message/2008", ResponseNamespace="http://wsdl.cybozu.co.jp/message/2008", Use=System.Web.Services.Description.SoapBindingUse.Literal)]
[return: System.Xml.Serialization.XmlArrayAttribute("returns")]
[return: System.Xml.Serialization.XmlArrayItemAttribute("thread", Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)]
public ThreadType[] MessageCreateThreads(MessageCreateThreadsRequestType parameters) {
    object[] results = this.Invoke("MessageCreateThreads", new object[] {
                parameters});
    return ((ThreadType[])(results[0]));
}
```

- WSDLの不備？修正

なぜか
`private AceType[][] aclField;`
というように[]**[]**となっているところがあるので、[]をひとつに修正
※2か所あります

```csharp:Reference.cs
private AceType[] aclField;
```


```csharp:Reference.cs
public AceType[] acl
{
中略
}
```


- これでWSDLの取得した準備は、完了 

## フォームの作成
今回は、さくっとWPFで作成、Prismとか使用しないで単純に作成
項目は、以下
1. ログインアカウント
2. ログインパスワード
3. タイトル
4. 本文
5. 宛先のガルーンID
![WS000695.JPG](https://qiita-image-store.s3.amazonaws.com/0/90597/30773dfa-0494-d166-9a3d-aa48c536507e.jpeg)

XAMLだとこんな感じ

```MainWindow.xaml:
<Window x:Class="GaroonMessageAPI.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:GaroonMessageAPI"
        mc:Ignorable="d"
        Title="MainWindow" Height="500" Width="500">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <StackPanel Grid.Row="0" Grid.Column="0" Orientation="Vertical" Margin="10">
            <Label>ログインID</Label>
            <TextBox Name="Account"></TextBox>
        </StackPanel>
        <StackPanel Grid.Row="0" Grid.Column="1" Orientation="Vertical" Margin="10">
            <Label>パスワード</Label>
            <TextBox Name="Password"></TextBox>
        </StackPanel>
        <StackPanel Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Vertical" Margin="10">
            <Label>標題</Label>
            <TextBox Name="Subject">APIテスト</TextBox>
        </StackPanel>
        <StackPanel Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Vertical" Margin="10">
            <Label>本文</Label>
            <TextBox Name="Content" Height="60px">これは、APIテスト</TextBox>
        </StackPanel>
        <StackPanel Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Vertical" Margin="10">
            <Label>宛先</Label>
            <TextBox Name="UserId" >1</TextBox>
        </StackPanel>
        <Grid Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" Margin="10">
            <Button Name="Submit" Click="Submit_Click">送信</Button>
        </Grid>
    </Grid>
</Window>

```

## メッセージ送信処理の作成
今回は、MVVMモデルは使用しないので、XAML.csへ直接ボタンイベントの作成

```csharp:MainWindow.xaml.cs
private void Submit_Click(object sender, RoutedEventArgs e)
{
    try
    {
        MessageBinding messageAPI = new MessageBinding();
        ActionElement actionElement = new ActionElement();
        SecurityElement securityElement = new SecurityElement();
        UsernameTokenElement userNameTokenElement = new UsernameTokenElement();
        TimestampElement timeStampElement = new TimestampElement();

        var threadType = new ThreadType();
        var threadTypeAddressee = new ThreadTypeAddressee();
        var content1 = new content();
        var threadTypeFolder = new ThreadTypeFolder();
        var threadTypeFollow = new ThreadTypeFollow();
        var messageThreadType = new MessageCreateThreadType();
        var messageThreadsRequestType = new MessageCreateThreadsRequestType();

        actionElement.actionValue = "MessageCreateThreads";
        timeStampElement.Created = DateTime.UtcNow;
        timeStampElement.Expires = timeStampElement.Created.AddDays(8);

        // 送信者
        userNameTokenElement.Username = this.Account.Text.ToString(); //送信者のﾕｰｻﾞｰｱｶｳﾝﾄ;
        userNameTokenElement.Password = this.Password.Text.ToString(); //送信者のﾕｰｻﾞｰﾊﾟｽﾜｰﾄ;
        securityElement.usernameToken = userNameTokenElement;

        // Soapヘッダー
        messageAPI.action = actionElement;
        messageAPI.security = securityElement;
        messageAPI.timeStamp = timeStampElement;

        // ダミー情報
        threadType.id = "dummy";
        threadType.version = "dummy";

        // フォルダー
        threadTypeFolder.id = "dummy";
        threadType.folder = new ThreadTypeFolder[1];
        threadType.folder[0] = threadTypeFolder;

        // コメント
        threadTypeFollow.id = "dummy";
        threadType.follow = new ThreadTypeFollow[1];
        threadType.follow[0] = threadTypeFollow;

        // 標題
        threadType.subject = this.Subject.Text.ToString();//標題

        // 本文
        content1.body = this.Content.Text.ToString();//本文
        threadType.content = content1;

        // 確認フラグ
        threadType.confirm = false;

        // 宛先
        int i = 0;
        var ids = this.UserId.Text.Split(',');
        threadType.addressee = new ThreadTypeAddressee[ids.Length];
        foreach (var id in ids)
        {
            threadTypeAddressee = new ThreadTypeAddressee();
            threadTypeAddressee.user_id = id;
            threadTypeAddressee.name = "dummy";
            threadType.addressee[i] = threadTypeAddressee;
            i += 1;
        }

        // メッセージの送信
        messageThreadType.thread = threadType;
        messageThreadsRequestType.create_thread = new MessageCreateThreadType[1];
        messageThreadsRequestType.create_thread[0] = messageThreadType;

        ThreadType[] res = messageAPI.MessageCreateThreads(messageThreadsRequestType);

        if (res.Any())
        {
            MessageBox.Show(res[0].id.ToString() + "のメッセージIDが作成されました。");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);

    }
}
```

※dummyとしているのは、特に理由はないです。

実行結果をブラウザで確認。
![WS000697.JPG](https://qiita-image-store.s3.amazonaws.com/0/90597/0b1f99a8-75fd-c14e-0801-74fe9c711601.jpeg)


正しく、メッセージが作成されたことが確認できました。

残念ながら、VisualStudioを使ったAPIの説明やサンプルがサイボウズ社のサイトにもないので、今後はそこら辺の情報も充実していただきたいところです。
「cybozu developer network」には、「Garoon API フォーラム」というコミュニティサイトがありますが、動きが無いようです。
こちらも念のためのリンクをおいておきます。
 リンク
[Garoon API フォーラム](https://cybozudev.zendesk.com/hc/ja/community/topics/200674863-Garoon-API-%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A9%E3%83%A0)