Site cover image

kohei-matsunobu-tech-blog

クラウド・プログラミング関連などのちょっとした気づきを書いてます!Notionでメモしていることを公開してます。このブログはスモールスタートしたばかりなので、UI/UXなどは定期的に改善予定です。

Post title iconSalesforceのSOAP APIを使用してVB.NETと連携する方法

SalesforceのSOAP APIを使ってVB.NETでSalesforce組織のレコードを参照・更新・削除したりする方法を説明します。Enterprise WSDLを使います。

1. SalesforceからWSDLを取得する

Salesforceにログインし、画面右上の歯車マークから[設定]を開く

Image in a image block

設定画面左側の[クイック検索]から[api]を検索し、赤枠のリンクを押下する
※[設定]-[インテグレーション]-[API]

Image in a image block

API画面の[Enterprise WSDLの生成]リンクを押下する

Image in a image block

Enterprise WSDLの作成画面の[Generate]ボタンを押下する

Image in a image block

ブラウザの別タブにXMLファイルが展開表示されるので、URLを控えておく

Image in a image block

2. VB.NETプロジェクトを作成する

Visual Studioを起動し、新規プロジェクトを作成する
※今回はコンソールアプリ(.NET Framework)を選択していますが、デスクトップアプリを作成したい場合は、Windowsフォームアプリ(.NET Framework)を選択してください

Image in a image block

任意のプロジェクト名を入力し、[作成]ボタンからプロジェクトを作成する
※今回は、.NET Framework4.8を使用

Image in a image block

正常にプロジェクトが作成されると、右図のような画面に切り替わる

Image in a image block

3. Salesforceから取得したWSDLをVB.NETプロジェクトに設定する

メニューから、[プロジェクト]-[サービス参照の追加]を開く

Image in a image block

サービス参照の追加画面下部にある[詳細設定]ボタンを押下する

Image in a image block

サービス参照設定画面下部の[Web参照の追加]ボタンを押下する

Image in a image block

Web参照の追加画面のURL欄に「1. SalesforceからWSDLを取得する」で取得したWSDLリンクを入力し、URL欄右側の[→]を押下する

Image in a image block

正常に動作した場合は、Salesforceへのログイン画面が表示されるので、認証を行う

Image in a image block

Salesforceへの認証に成功した場合、WSDLを参照可能な状態になるので、[Web参照名]に任意の名前を入力し、[参照の追加]ボタンを押下する

Image in a image block

4. WSDLファイルのプロパティを設定する

メニューから、[プロジェクト]-[(プロジェクト名)のプロパティ]を選択する

Image in a image block

プロパティ画面の[参照設定]を開く

Image in a image block

[インポートされた名前空間]にインポートしたいファイルが選択されていない場合、チェックを入れて保存をすることでビルド参照ができるようになる

Image in a image block

チェックを入れたものが上記の参照確認ボックスにあることを確認する

Image in a image block

5.Reference.vbのエラーを修正する

WSDLを取り込むと、Reference.vbというクラスやプロパティを定義しているファイルをVisual Studioが生成します。

この生成されたファイルがビルド時に一部エラーとなるので、修正する必要があります。

  1. エラー箇所を修正する
Image in a image block

  • 属性’〇〇’を複数回適用することはできません。

    こちらのエラーでは該当属性が複数定義されているため、いずれかを残すように修正すればOKです。今回は、該当箇所をコメントアウトしました。

    Image in a image block

  • class’〇〇’に同じ名前のメンバーが多種類存在するため、’△△’があいまいです。

    こちらも〇〇が該当箇所のコードで複数定義されているため、いずれかを残すように修正すればOKです。今回も同様、該当箇所をコメントアウトしました。

    Image in a image block

  • ‘〇〇’は、このclassで’△△’として既に宣言されています。

    こちらも〇〇が該当箇所のコードで複数定義されているため、いずれかを残すように修正すればOKです。今回も同様、該当箇所をコメントアウトしました。

    Image in a image block

  • ‘()’が二重になっている変数がある(ListViewRecordColumn型)

    下記のように2か所が()()というように()が重複しています。()()は構文エラーなので一つ消せばOKです。2枚目の画像は修正後になります。

    Image in a image block
    Image in a image block

6. プロジェクトをビルドする

「5.Reference.vbのエラーを修正する」で修正した内容をもとにビルドに成功するか確認します。

メニューから、[プロジェクト]-[(プロジェクト名)のプロパティ]を選択する

Image in a image block

プロパティ画面の[コンパイル]を開き、[XMLドキュメントファイルを生成する]をオフにする

Image in a image block

プロパティ画面の[詳細コンパイルオプション]ボタンを押下する

Image in a image block

コンパイラの詳細設定画面の[シリアル化アセンブリの生成]をオンに設定し、[OK]ボタンを押下する

Image in a image block

メニューから、[ビルド]-[ソリューションのビルド]を押下し、ビルドしてみる

Image in a image block

下記のように出力結果でビルドに成功していることを確認する

Image in a image block

ビルドに成功した場合は、プロジェクトフォルダ>bin>DebugにSalesforceSampleApp.exeが生成されます。(Releaseビルドの場合は、プロジェクトフォルダ>bin>Releaseに実行ファイルが生成される)まだ、処理を実装していないのでexeファイルを実行しても何も起きません。

6.Salesforceユーザのシークレットキーを取得する

SalesforceへSOAP APIを使用してアクセスする際に、該当ユーザのシークレットキーが必要になるので取得しておきます。

Salesforce画面右上のユーザアイコンを押下し、[設定]リンクを開く

Image in a image block

[私のセキュリティトークンのリセット]画面の[セキュリティトークンのリセット]ボタンを押下する

Image in a image block

Salesforceへログインしているユーザに設定されているメールアドレスにセキュリティトークンが記載されたメールが届く

Image in a image block

メール本文に記載されているセキュリティトークンを控えておく(第三者に漏れないように)

Image in a image block

7. VB.NETでSOAPクライアントを使う

以下は、SalesforceのSOAP APIを使ってオブジェクトレコードを参照・更新・削除したりするVB.NETの基本的なコードです。認証情報はハードコーディングを避けるため、App.Config(設定ファイル)に記述しています。

ブログ執筆用に非常に簡素なコード(かつ非効率)になっているため、こちらのコードを参考に実際の環境に合わせて適切に変えてビルドしてください。

1. まずVB.NET全体のコード
Imports SalesforceSampleApp.sforce
Imports System.Web.Services.Description
Imports System.Web.Services.Protocols

''' <summary>
''' SalesfroceとVB.NET連携
''' </summary>

Module Module1

    ' SFに接続するためのインスタンス
    Dim SFDCBinding As New SforceService()

    ''' <summary>
    ''' メインコントローラ
    ''' </summary>
    Sub Main()
        SFDCBinding.Timeout = 30000

        Dim loginResult As Boolean = Login()

        If loginResult Then
            ' 取引先情報取得
            getAccounts()

            ' 取引先作成
            createAccounts()
            getAccounts()

            ' 取引先名更新
            updateAccountByName("取引先001", "取引先(変更001)")
            getAccounts()

            ' 取引先削除
            deleteAccount("取引先(変更001)")
            getAccounts()

            ' ログアウト
            Logout()

            Console.ReadLine()
        End If
    End Sub

    ''' <summary>
    ''' Salesfroceへログイン
    ''' </summary>
    ''' <returns>ログイン成功=True/ログイン失敗=False</returns>
    Function Login() As Boolean

        Console.WriteLine("=== Salesforceへログイン[開始] ===")

        ' SFのユーザ名
        Dim userName As String = My.Settings.Salesforce_UserName

        ' SFのパスワード
        Dim password As String = My.Settings.Salesforce_Password
        Dim loginResult

        Try
            ' ログイン
            loginResult = SFDCBinding.login(userName, password)
        Catch e As SoapException
            Console.WriteLine("ログイン失敗")
            Return False
        End Try

        ' パスワード失効している場合
        If loginResult.passwordExpired Then
            ' SFDCBinding.setPassword(userId, newPassword) で更新が必要
            Return False
        End If

        ' エンドポイント更新
        Dim authEndPoint As String = SFDCBinding.Url
        SFDCBinding.Url = loginResult.serverUrl

        ' セッションヘッダ追加
        SFDCBinding.SessionHeaderValue = New SessionHeader()
        SFDCBinding.SessionHeaderValue.sessionId = loginResult.sessionId

        ' 結果表示
        Dim userInfo As GetUserInfoResult = loginResult.userInfo
        Dim msg As String = ""
        msg += "UserID: " & userInfo.userId & vbCrLf
        msg += "User Full Name: " & userInfo.userFullName & vbCrLf
        msg += "User Email: " & userInfo.userEmail & vbCrLf
        msg += vbCrLf
        msg += "SessionID: " & loginResult.sessionId & vbCrLf
        msg += "Auth End Point: " & authEndPoint & vbCrLf
        msg += "Service End Point: " & loginResult.serverUrl & vbCrLf

        Console.WriteLine(msg)
        Console.WriteLine("=== Salesforceへログイン[終了] ===")
        Return True
    End Function

    ''' <summary>
    ''' Salesfroceからログアウト
    ''' </summary>
    Sub Logout()
        SFDCBinding.logout()
    End Sub

    ''' <summary>
    ''' Salesfroceから取引先情報を取得
    ''' </summary>
    Sub getAccounts()
        Console.WriteLine("=== 取引先情報取得[開始] ===")

        ' 取引先レコードを取得
        Dim soql As String = "SELECT Id, Name FROM Account"

        Try
            ' SOQL実行
            Dim qr As QueryResult = SFDCBinding.query(soql)
            Dim msg As String = ""

            ' レコードの数分処理を繰り返す
            While True
                Dim records As sObject() = qr.records
                For i As Integer = 0 To records.Length - 1
                    ' 取引先レコード取得結果をmsgへ格納
                    Dim acc As Account = CType(records(i), Account)
                    msg += "ID: " & acc.Id & ", Name: " + acc.Name & vbCrLf
                Next

                If qr.done Then
                    ' レコード数分全て処理ができた場合、処理終了
                    Exit While
                Else
                    ' レコード数分全処理が全て処理できていない場合、処理を繰り返す
                    qr = SFDCBinding.queryMore(qr.queryLocator)
                End If
            End While

            ' コンソールに取得したレコード情報を表示する
            Console.WriteLine(msg)
            Console.WriteLine("=== 取引先情報取得[終了] ===")
        Catch ex As Exception
            Console.WriteLine(ex.Message)
        End Try
    End Sub

    ''' <summary>
    ''' Salesfroceから取引先レコードを作成
    ''' </summary>
    Sub createAccounts()
        Console.WriteLine("=== 取引先レコード作成[開始] ===")
        Dim result As String() = New String(1) {}

        Dim account1 As Account = New Account()
        account1.Name = "取引先001"
        account1.BillingStreet = "403 McAdoo St"
        account1.BillingCity = "Truth or Consequences"
        account1.BillingState = "NM"
        account1.BillingCountry = "US"
        Dim accounts As Account() = {account1}

        Try
            Dim saveResults As SaveResult() = SFDCBinding.create(accounts)
            For i As Integer = 0 To saveResults.Length - 1

                If saveResults(i).success Then
                    Console.WriteLine("Successfully created Account ID: " & saveResults(i).id)
                    result(i) = saveResults(i).id
                Else
                    Console.WriteLine("Error: could not create Account " & "for array element " & i & ".")
                    Console.WriteLine("   The error reported was: " & saveResults(i).errors(0).message & vbLf)
                    result(i) = saveResults(i).id
                End If
            Next
        Catch e As SoapException
            Console.WriteLine("An unexpected error has occurred: " & e.Message & vbLf + e.StackTrace)
        End Try

        Console.WriteLine("=== 取引先レコード作成[終了] ===")
    End Sub

    ''' <summary>
    ''' Salesfroceから取引先レコードを更新
    ''' </summary>
    Sub updateAccountByName(oldAccName As String, newAccName As String)
        Console.WriteLine("=== 取引先レコード更新[開始] ===")

        Try
            ' 取引先1件取得(汎用性は持たせていない)
            Dim soql As String = "SELECT Id, Name FROM Account WHERE Name = '" & oldAccName & "' LIMIT 1"
            Dim qr As QueryResult = SFDCBinding.query(soql)
            Dim acc As New Account

            While True
                Dim records As sObject() = qr.records

                ' 取引先レコード取得
                acc = CType(records(0), Account)

                If qr.done Then
                    ' レコード数分全て処理ができた場合、処理終了
                    Exit While
                Else
                    ' レコード数分全処理が全て処理できていない場合、処理を繰り返す
                    qr = SFDCBinding.queryMore(qr.queryLocator)
                End If
            End While

            ' 取引先名更新
            acc.Name = newAccName
            Dim updateAcc As Account() = {acc}

            Dim saveResults As SaveResult() = SFDCBinding.update(updateAcc)

            For Each saveResult As SaveResult In saveResults

                If saveResult.success Then
                    Console.WriteLine("Successfully updated Account ID: " & saveResult.id)
                Else
                    Dim errors As [Error]() = saveResult.errors

                    If errors.Length > 0 Then
                        Console.WriteLine("Error: could not update " & "Account ID " & saveResult.id & ".")
                        Console.WriteLine(vbTab & "The error reported was: (" & errors(0).statusCode & ") " + errors(0).message & ".")
                    End If
                End If
            Next

        Catch ex As SoapException
            Console.WriteLine("An unexpected error has occurred: " & ex.Message & vbLf + ex.StackTrace)
        End Try

        Console.WriteLine("=== 取引先レコード更新[終了] ===")
    End Sub

    ''' <summary>
    ''' Salesfroceから取引先レコードを削除
    ''' </summary>
    Sub deleteAccount(accName As String)
        Console.WriteLine("=== 取引先レコード削除[開始] ===")

        Try
            ' 取引先1件取得(汎用性は持たせていない)
            Dim soql As String = "SELECT Id, Name FROM Account WHERE Name = '" & accName & "' LIMIT 1"
            Dim qr As QueryResult = SFDCBinding.query(soql)
            Dim acc As New Account

            While True
                Dim records As sObject() = qr.records

                ' 取引先レコード取得
                acc = CType(records(0), Account)

                If qr.done Then
                    ' レコード数分全て処理ができた場合、処理終了
                    Exit While
                Else
                    ' レコード数分全処理が全て処理できていない場合、処理を繰り返す
                    qr = SFDCBinding.queryMore(qr.queryLocator)
                End If
            End While

            ' 取引先を削除処理
            Dim accId As String = acc.Id
            Dim ids As String() = {accId}
            Dim deleteResults As DeleteResult() = SFDCBinding.delete(ids)

            Dim msg As String = ""

            For Each result As DeleteResult In deleteResults
                If result.success Then
                    msg += "Delete Successfull! Deleted Record ID: " & result.id & vbCrLf
                Else
                    Console.WriteLine("Error!: " & result.errors(0).message)
                End If
            Next

            Console.WriteLine(msg)

        Catch ex As SoapException
            Console.WriteLine("An unexpected error has occurred: " & ex.Message & vbLf + ex.StackTrace)
        End Try

        Console.WriteLine("=== 取引先レコード削除[終了] ===")
    End Sub
End Module

2. Salesforceへログイン

Login()の部分です。実行結果は以下のようになるはずです。

Image in a image block

3. Salesforceの取引先情報の取得

getAccounts()の部分です。実行結果は以下のようになるはずです。

Image in a image block
Image in a image block

4. Salesforceの取引先情報の作成

createAccounts()の部分です。実行結果は以下のようになるはずです。

Image in a image block
Image in a image block
Image in a image block

5. Salesforceの取引先情報の更新

updateAccountByName()の部分です。実行結果は以下のようになるはずです。

Image in a image block
Image in a image block
Image in a image block

6. Salesforceの取引先情報の削除

deleteAccount()の部分です。実行結果は以下のようになるはずです。

Image in a image block
Image in a image block
Image in a image block

以上です。少しでもお役に立てれば