为 ECMA2Host 创作 SAP ECC 7.51 Web 服务连接器模板
本指南指导你完成为 Web 服务扩展性连接管理代理 (ECMA) 连接器创建模板以管理 SAP ECC 用户的过程。
限制和假设
此模板演示如何管理用户。 本指南未涵盖其他对象类型,如本地活动组、角色和配置文件,因为 ECMA2Host 当前不支持多值引用。 本指南也未涵盖密码操作。
本指南不包括在 SAP 中创建用于调用公开的 BAPI 函数的服务帐户。 它假定预先创建的演示帐户开发人员与配置文件 RFC_ALL 同时使用,以向本文中提到的 BAPI 授予权限。
默认情况下,Web 服务配置工具不支持 SAP 中公开的以下功能:WSP 策略和每个终结点的多个绑定。 它确实需要仅包含 SOAP 1.1 的 WSDL,即不使用策略的一体式文档样式绑定。
此模板中使用的 SAP ECC BAPI 函数:
- BAPI_USER_GETLIST - 获取连接到此系统的所有用户列表。
- BAPI_USER_GETDETAIL - 获取特定用户的详细信息。
- BAPI_USER_CREATE1 - 创建用户。
- BAPI_USER_DELETE - 删除用户。
- BAPI_USER_CHANGE - 更新用户。
本指南中的所有 SAP 用户属性都被视为单值属性。
使用的编程语言为 Visual Basic。
定义 Web Service 终结点并创建架构
设计导入和导出工作流之前,需要创建模板,并使用通过 SOAP 接口公开的 SAP BAPI 函数定义终结点。 然后创建 ECMA2 对象的架构,并且其属性在此模板中可用。
- 从“C:\Program Files\Microsoft ECMA2Host\Web Service Configuration Tool”文件夹中,启动 Web 服务配置工具 wsconfigTool.exe
- 在 File-New 菜单中,选择“创建新 SOAP 项目”
- 选择 SOAP 项目,然后选择“添加新的 Web 服务”。
- 将 Web 服务命名为 SAPECC,提供用于下载已发布 WSDL 的 URL,输入 SAPECC 作为命名空间。 Web 服务名称有助于将模板中的此 Web 服务与其他服务区分开来。 命名空间定义用于生成类的 Microsoft .NET 命名空间的名称。 除非 SAP 管理员另有指示,否则请选择基本身份验证模式。 选择“下一步”。
- 提供凭据以连接到 SAP ECC 终结点。 选择“下一步”。
- 在终结点和操作页上,确保显示 BAPI 并选择“完成”
注意
如果看到多个终结点,则表示同时启用了 SOAP 1.2 和 SOAP 1.1 绑定。 这会导致连接器失败。 在 SOAMANAGER 中修改绑定定义,只保留一个。 然后重新添加 Web 服务。
- 将项目保存到 C:\Program Files\Microsoft ECMA2Host\Service\ECMA 文件夹。
- 在“对象类型”选项卡上选择,然后选择添加用户对象类型。 选择“确定”。
- 展开“对象类型”选项卡并选择“用户类型定义”。
- 将以下属性添加到架构中,并选择 userName 作为定位点。
- 保存你的项目。
名称 | 类型 | 定位点 |
---|---|---|
city | string | |
company | string | |
department | string | |
电子邮件 | string | |
expirationTime | string | |
firstName | string | |
lastName | string | |
middleName | string | |
telephoneNumber | string | |
jobTitle | string | |
userName | string | checked |
创建完整导入工作流
尽管在 ECMA2Host 中导入工作流是可选的,但借助导入工作流,你可以将现有 SAP 用户导入 ECMA2Host 内存中缓存,并避免在预配期间创建重复用户。
如果不创建导入工作流,则连接器在仅导出模式下运行,并导致 ECMA2Host 始终发出创建用户操作,即使对于现有用户也是如此。 除非由导出工作流处理重复项,否则使用标准 SAP BAPI 时,可能会导致失败或重复。
SAP ECC 不提供自上次读取以来进行的读取更改的内置机制。
因此,我们仅实现完全导入工作流。 如果需要出于性能原因实现增量导入,请咨询 SAP 管理员以获取一份 BAPI 列表,并将这些 BAPI 作为 SOAP Web 服务发布。 然后使用下面所述的方法和包含上一次成功运行的时间戳的 customData 属性实现增量导入工作流。
SAP ECC 提供了多个 BAPI 函数来获取包含其属性的用户列表:
- BAPI_USER_GETLIST - 获取连接到此系统的所有用户列表。
- BAPI_USER_GETDETAIL - 获取特定用户的详细信息。
只有这两个 BAPI 用于从此模板中的 SAP ECC 检索现有用户。
- 导航到“对象类型”->“用户”>-“导入”->“完全导入工作流”,并从右侧的工具箱将 Sequence 活动拖放到工作流设计器窗格中。
- 在左下角找到“变量”按钮,并选择它以展开此序列中定义的变量列表。
- 添加以下变量。 要选择从 SAP WSDL 生成的变量类型,请选择“浏览类型”并展开生成的变量类型,然后展开 SAPECC 命名空间。
名称 | 变量类型 | 范围 | 默认 |
---|---|---|---|
selRangeTable | SAPECC.TABLE_OF_BAPIUSSRGE | 序列 | 包含 {.item = new BAPIUSSRGE(){new BAPIUSSRGE}} 的新 TABLE_OF_BAPIUSSRGE |
getListRetTable | SAPECC.TABLE_OF_BAPIRET2 | 序列 | 新 TABLE_OF_BAPIRET2 |
pageSize | Int32 | 序列 | 200 |
returnedSize | Int32 | 序列 | |
usersTable | SAPECC.TABLE_OF_BAPIUSNAME | 序列 | 新 TABLE_OF_BAPIUSNAME() |
- 从工具箱将四个 Assign 活动拖放到 Sequence 活动内,并设置以下值:
selRangeTable.item(0).PARAMETER = "USERNAME"
selRangeTable.item(0).SIGN = "I" selRangeTable.item(0).OPTION = "GT" selRangeTable.item(0).LOW = ""
这些参数用于调用 BAPI_USER_GETLIST 函数并实现分页。
- 要实现分页,请从工具箱将 DoWhile 活动拖放到 Sequence 活动中上一次 Assign 操作之后。
- 在右窗格上切换到“属性”选项卡,并为 DoWhile 输入此条件
- 周期:
returnedSize = pageSize
- 选择“变量”,并在 DoWhile 周期中添加 int32 类型的 currentPageNumber 属性,默认值为 0。
- 可选步骤:如果计划实现增量导入工作流,请从工具箱将 Assign 活动拖放到 Sequence 活动中 DoWhile 周期之后。 设置此值:
customData(schemaType.Name + "_lastImportTime") = DateTimeOffset.UtcNow.Ticks.ToString()
这将保存上次完整导入运行的日期和时间,稍后可以在增量导入工作流中使用此时间戳。
- 从工具箱将 Sequence 活动拖放到 DoWhile 活动内。 将 WebServiceCall 活动拖放到该 Sequence 活动中,然后选择 SAPECC 服务名称、ZSAPCONNECTORWS 终结点和 BAPI_USER_GETLIST 操作。
- 选择“...”参数按钮以定义 Web 服务调用的参数,如下所示:
名称 | 方向 | 类型 | 值 |
---|---|---|---|
MAX_ROWS | In | Int32 | pageSize |
MAX_ROWSSpecified | In | 布尔 | True |
RETURN | 输入/输出 | TABLE_OF_BAPIRET2 | getListRetTable |
SELECTION_EXP | 输入/输出 | TABLE_OF_BAPIUSSEXP | |
SELECTION_RANGE | 输入/输出 | TABLE_OF_BAPIUSSRGE | selRangeTable |
USERLIST | 输入/输出 | TABLE_OF_BAPIUSNAME | usersTable |
WITH_USERNAME | In | 字符串 | |
ROWS | 出 | Int32 | returnedSize |
- 选择“确定”。 警告符号消失。 存储在 usersTable 变量中的用户列表。 由于 SAP 不会在单个响应中返回用户的完整列表,因此我们需要在切换页面时实现分页并多次调用此函数。 然后,对于导入的每个用户,需要通过进行单独的调用来获取该用户的详细信息。 这意味着,对于拥有 1,000 个用户且页面大小为 200 的环境,Web 服务连接器发出 5 次调用来检索用户列表,以及 1,000 次单独调用来检索用户的详细信息。 若要提高性能,请让 SAP 团队开发一个自定义 BAPI 程序,其中列出了其属性的所有用途。 这样就无需进行 1,000 个单独调用,并通过 SOAP WS 终结点公开该 BAPI 函数。
- 在 WebServiceCall 活动之后,从工具箱中将 IF 活动拖放到 DoWhile 活动中。 指定此条件以检查是否为非空响应以及是否无错误:
IsNothing(getListRetTable.item) OrElse getListRetTable.item.Count(Function(errItem) errItem.TYPE.Equals("E") = True) = 0
- 在工具箱中,将 Throw 活动拖放到 IF 活动的 Else 分支,以在导入失败时抛出错误。 切换到“属性”选项卡,然后针对 Throw 活动的异常属性输入此表达式:
New Exception(getListRetTable.item.First(Function(retItem) retItem.TYPE.Equals("E")).MESSAGE)
- 要处理导入用户的列表,请从工具箱将 ForEachWithBodyFactory 活动拖放到 IF 活动的 Then 分支中。 切换到“属性”选项卡并选择 SAPECC.BAPIUSNAME 作为 TypeArgument。 选择“...”按钮并针对值属性键入此表达式:
if(usersTable.item,Enumerable.Empty(of BAPIUSNAME)())
- 从工具箱中将 Sequence 活动拖放到 ForEach 活动内。 激活此序列活动窗口后,选择“变量”按钮并定义以下变量:
名称 | 变量类型 | 范围 | 默认 |
---|---|---|---|
company | SAPECC.BAPIUSCOMP | 序列 | new BAPIUSCOMP() |
address | SAPECC.BAPIADDR3 | 序列 | new BAPIADDR3() |
defaults | SAPECC.BAPIDEFAUL | 序列 | 新 BAPIDEFAUL() |
logondata | SAPECC.BAPILOGOND | 序列 | 新 BAPILOGOND() |
getDetailRetTable | SAPECC.TABLE_OF_BAPIRET2 | 序列 | 新 TABLE_OF_BAPIRET2() |
IF 活动如下所示:
- 在“序列”活动中拖放 CreateCSEntryChangeScope 活动。 在 DN 属性中,输入 schemaType.Name 和 item.USERNAME。 在 CreateAnchorAttribute AnchorValue 字段中输入 item.username。
- 若要检索每个用户的详细信息,请在 CreateAnchorAttribute 活动前从工具箱中拖放 WebServiceCall 活动到“序列”活动中。 选择 SAPECC 服务名称、ZSAPCONNECTORWS 终结点和 BAPI_USER_GET_DETAIL 操作。 选择“...”参数按钮以定义 Web 服务调用的参数,如下所示:
名称 | 方向 | 类型 | 值 |
---|---|---|---|
RETURN | 输入/输出 | TABLE_OF_BAPIRET2 | getDetailRetTable |
USERNAME | In | 字符串 | item.username |
地址 | 出 | BAPIADDR3 | address |
COMPANY | 出 | BAPIUSCOMP | company |
DEFAULTS | 出 | BAPIUSDEFAUL | defaults |
LOGONDATA | 出 | BAPILOGOND | logonData |
WITH_USERNAME | In | 字符串 | |
ROWS | 出 | Int32 | returnedSize |
- 选择“确定”。 警告符号消失。 用户的详细信息存储在上面列出的变量中。 IF 活动如下所示:
- 要查看 BAPI_USER_GET_DETAIL 操作的结果,请从工具箱拖放 IF 活动,并将其置于 WebServiceCall 和 CreateAnchorAttribute 活动之间的 Sequence 活动中。 输入此条件:
IsNothing(getDetailRetTable.item) OrElse getDetailRetTable.item.Count(Function(errItem) errItem.TYPE.Equals("E") = True) = 0
由于不应将缺少用户详细信息视为灾难性事件,因此我们希望指出此错误并继续处理其他用户。 将 Sequence 活动拖放到 IF 活动的 Else 分支。 在该新 Sequence 活动中添加 Log 活动。 切换到“属性”选项卡,将“级别”属性更改为“高”,将“标记”更改为“跟踪”。 在 LogText 属性中输入以下内容:string.Join("\n", getDetailRetTable.item.Select (Function(item) item.MESSAGE ))
- 将 Sequence 活动拖放到 IF 活动的 Then 分支。 将现有 CreateAnchorAttribute 活动拖放到 IF 活动 Then 分支内的 Sequence 活动。 ForEach 活动现在如下所示:
- 对于用户的每个属性(如城市、公司、部门、电子邮件),在 CreateAnchorAttribute 活动之后添加 IF 活动,并通过输入
Not string.IsNullOrEmpty(address.city)
等条件并将 CreateAttributeChange 活动添加到该 IF 活动的 Then 分支来检查非空值。
例如:使用以下映射表为所有用户属性添加 CreateAttributeChange 活动:
ECMA 用户属性 | SAP 属性 |
---|---|
city | address.city |
department | address.department |
company | company.company |
电子邮件 | address.e_mail |
firstName | address.firstName |
lastName | address.lastName |
middleName | address.middleName |
jobTitle | address.function |
expirationTime | logonData.GLTGB |
telephoneNumber | address.TEL1_NUMBR |
- 最后,在上一个 CreateAttributeChange 活动之后添加 SetImportStatusCode 活动。 在 Then 分支中将 ErrorCode 设置为 Success。 在 Else 分支中再添加一个 SetImportStatus 代码活动,并将 ErrorCode 设置为 ImportErrorCustomContinueRun。
- 折叠 ForEach 活动内的 Sequence 活动,使 DoWhile 周期如下所示:
- 要检索下一页用户,请更新
selRangeTable.item(0).LOW
属性。 将 IF 活动拖放到 DoWhile 中的 Sequence 活动中。 将其置于现有 IF 活动之后。 输入 returnedSize>0 作为条件。 将“分配”活动添加到 IF 活动的 Then 分支,并将selRangeTable.item(0).LOW
设置为usersTable.item(returnedSize-1).username
。
已完成“完整”导入工作流的定义。
创建“导出添加”工作流
若要在 SAP ECC 中创建用户,可以调用 BAPI_USER_CREATE1 程序并提供所有参数,包括帐户名称和初始密码。 如果需要在 SAP 端生成帐户名称,请咨询 SAP 管理员,并使用返回新创建的用户帐户的 userName 属性的自定义 BAPI 函数。
本指南不演示如何分配许可证、本地或全局活动组、系统或配置文件。 请与 SAP 管理员协商并相应地修改此工作流。
无需在导出工作流中实现分页。 工作流上下文中只有一个对象 objectToExport 可用。
- 导航到“对象类型”->“用户”->“导出”->“添加工作流”,从右侧的工具箱中将 Sequence 活动拖放到工作流设计器窗格中。
- 在左下角找到“变量”按钮,并选择它以展开此序列中定义的变量列表。
- 添加以下变量。 若要选择从 SAP WSDL 生成的变量类型,请选择“浏览类型”,先展开 生成的,再展开 SAPECC 命名空间。 这会初始化 BAPI_USER_CREATE1 程序使用的数据结构。
名称 | 变量类型 | 范围 | 默认 |
---|---|---|---|
address | SAPECC.BAPIADDR3 | 序列 | new BAPIADDR3() |
userName | 字符串 | 序列 | |
password | SAPECC.BAPIPWD | 序列 | 新 BAPIPWD() |
company | SAPECC.BAPIUSCOMP | 序列 | new BAPIUSCOMP() |
defaults | SAPECC.BAPIDEFAUL | 序列 | 新 BAPIDEFAUL() |
logOnData | SAPECC.BAPILOGOND | 序列 | 新 BAPILOGOND() |
bapiret2Table | SAPECC.TABLE_OF_BAPIRET2 | 序列 | 新 TABLE_OF_BAPIRET2() |
- 将 userName 属性定义为不可变 ID(定位点)时,我们需要从导出对象的定位点集合中提取 userName 值。 将 ForEachWithBodyFactory 活动从工具箱拖放到“序列”活动中。 将项变量名称替换为定位点,切换到属性并选择
Microsoft.MetadirectoryServices.AnchorAttribute
的 TypeArgument。 在“值”字段中,键入objectToExport.AnchorAttributes
。
- 若要提取 userName 定位点的字符串值,请将 Switch 活动拖放到 ForEach 活动内。 在弹出窗口中,选择开关
Microsoft.IdentityManagement.MA.WebServices.Activities.Extensions.AnchorAttributeNameWrapper
类型。 输入表达式值:New AnchorAttributeNameWrapper(anchor.Name)。 - 选择“切换”活动的“添加新事例区域”。 键入 userName 作为 用例值。 将 Assign 活动拖放到 userName 事例正文中,并将 anchor.Value.ToString() 分配到 userName 变量。
- 从导出的对象定位点属性中提取 userName 值后,需要填充其他结构,例如公司、默认值、地址、登录数据,其中包含其他 SAP 用户详细信息。 我们通过循环收集特性更改来执行此操作。
- 折叠 ForEach 活动,并在现有 ForEach 活动之后将另一个 ForEachWithBothFactory 活动拖放到 Sequence 活动中。 将项变量名称替换为 attributeChange,切换到属性并选择 TypeArgument
Microsoft.MetadirectoryServices.AttributeChange
。 在“值”字段中,键入objectToExport.AttributeChanges
。
- 将 Switch 活动拖放到 ForEach 活动的正文部分。
- 在弹出菜单中,选择
Microsoft.IdentityManagement.MA.WebServices.Activities.Extensions.AttributeNameWrapper
,然后选择“确定”。 - 输入以下表达式:New AttributeNameWrapper(attributeChange.Name)。 你将在 Switch 活动的右上角看到一个警告图标,说明未处理特性在架构中定义,且未分配给任何属性。
- 选择 Switch 活动的“添加新案例”区域,然后案例值 city。
- 将 Assign 活动拖放到此事例的正文部分。 将
attributeChange.ValueChanges(0).Value.ToString()
分配到 address.city。
- 添加其他缺失案例和分配。 将此映射表作为指南:
案例 | 分配 |
---|---|
city | address.city = attributeChange.ValueChanges(0)Value.ToString() |
company | company.company = attributeChange.ValueChanges(0)Value.ToString() |
department | address.department = attributeChange.ValueChanges(0)Value.ToString() |
电子邮件 | address.e_mail = attributeChange.ValueChanges(0)Value.ToString() |
expirationTime | logOnData.GLTGB = attributeChange.ValueChanges(0)Value.ToString() |
firstname | address.firstname = attributeChange.ValueChanges(0)Value.ToString() |
lastName | address.lastname = attributeChange.ValueChanges(0)Value.ToString() |
middleName | address.middlename = attributeChange.ValueChanges(0)Value.ToString() |
telephoneNumber | address.TEL1_Numbr = attributeChange.ValueChanges(0)Value.ToString() |
jobTitle | address.function = attributeChange.ValueChanges(0)Value.ToString() |
export_password | password.BAPIPWD1 = attributeChange.ValueChanges(0)Value.ToString() |
此处,export_password是一个特殊的虚拟属性,始终在架构中定义,可用于传递要创建的用户的初始密码。
- 折叠 ForEach 活动并在第二个 ForEach 活动之后将 IF 活动拖放到 Sequence 活动,以在提交创建用户请求之前验证用户属性。 我们至少需要 3 个非空值:用户名、姓和初始密码。 输入此条件:
(String.IsNullOrEmpty(address.lastname) = False ) AND (String.IsNullOrEmpty(userName) = False) AND (String.IsNullOrEmpty(password.BAPIPWD1) = False)
- 在 IF 活动的 Else 分支中再添加一个 IF 活动,因为我们希望根据缺少的内容抛出不同的错误。 输入条件值:String.IsNullOrEmpty(userName)。 将
CreateCSEntryChangeResult
活动拖放到第二个 IF 活动的两个分支,并设置 ErrorCodeExportErrorMissingAnchorComponent
和ExportErrorMissingProvisioningAttribute
。
- 将 Sequence 活动拖放到第一个 IF 活动的空 Then 分支中。 将 WebSeviceCall 活动拖放到 Sequence 活动中。 选择 SAPECC 服务名称、ZSAPCONNECTORWS 终结点和 BAPI_USER_CREATE1 操作。 选择“参数”按钮,以定义 Web 服务调用的参数,如下所示:
名称 | 方向 | 类型 | 值 |
---|---|---|---|
地址 | In | BAPIADDR3 | address |
COMPANY | In | BAPIUSCOMP | company |
DEFAULTS | In | BAPIDEFAUL | defaults |
LOGONDATA | In | BAPILOGOND | logOnData |
PASSWORD | In | BAPIPWD | password |
RETURN | 输入-输出 | TABLE_OF_BAPIRET2 | bapiret2Table |
SELF_REGISTER | In | 字符串 | "x" |
USERNAME | In | 字符串 | userName |
- 选择“确定”。 警告符号消失。
- 要处理创建用户请求结果,请将 IF 活动拖放到 Sequence 活动中 WebServiceCall 活动之后。 输入以下条件:
IsNothing (bapiret2Table.item) OrElse bapiret2Table.item.Count(Function(errItem) errItem.TYPE.Equals("E") = True) <> 0
- 如果未收到任何错误,则假定导出操作已成功完成,并且我们希望通过创建包含成功状态的 CSEntryChangeResult 来指示已成功导出此对象。 将 CreateCSEntryChangeResult 活动拖放到 IF 活动的 Else 分支,然后选择“成功”错误代码。
- 可选:如果 Web 服务调用返回用户的生成帐户名称,则需要更新导出对象的定位点值。 为此,请将
CreateAttrubuteChange
活动拖放到CreateCSEntryChangeResult
活动中,然后选择以添加用户名。 然后,将CreateValueChange
活动拖放到CreateAttributeChange
活动中,并输入由 Web 服务调用活动填充的变量名称。 本指南使用导出时未更新的用户名变量。
- 导出添加工作流的最后一步是处理和记录导出错误。 将 Sequence 活动拖放到 IF 活动的空 Then 分支中。
- 将 Log 活动拖放到 Sequence 活动中。 切换到“属性”选项卡并输入 LogText 值:
bapiret2Table.item.First(Function(retItem) retItem.TYPE.Equals("E"))
.MESSAGE。 保留高日志记录级别和跟踪标记。 启用详细跟踪时,此日志会将错误消息记录到 ConnectorsLog 或 ECMA2Host 事件日志中。 - 在日志活动后拖放“切换”活动到“序列”活动内。 在弹出窗口中,选择开关值的字符串类型。 输入以下表达式:
bapiret2Table.item.First(Function(retItem) retItem.TYPE.Equals("E")).NUMBER
- 选择 Default 事例,然后将 CreateCSEntryChangeResult 活动拖放到此事例的正文中。 选择 ExportErrorInvalidProvisioningAttributeValue 错误代码。
- 选择“添加新案例”区域,然后键入案例值 224。 将
CreateCSEntryChangeResult
活动拖放到此事例的正文中。 选择ExportErrorCustomContinueRun
错误代码。
已完成“导出添加”工作流的定义。
创建“导出删除”工作流
若要删除 SAP ECC 中的用户,可以调用BAPI_USER_DELETE程序并提供在连接系统中删除的帐户名称。 请咨询 SAP 管理员,以确定此方案是否是必需的。 通常,不会删除 SAP ECC 帐户,但设置为过期以保留历史记录。
本指南不包括与 SAP 通用用户管理系统、从连接系统取消用户配置、撤销许可证等相关的场景。
无需在导出工作流中实现分页。 工作流上下文中只有一个对象 objectToExport 可用。
- 导航到“对象类型” ->“用户”->“导出”->“删除工作流”,并从右侧的工具箱将“序列”活动拖放到工作流设计器窗格中。
- 在左下角找到“变量”按钮,并选择它以展开此序列中定义的变量列表。
- 添加以下变量。 要选择从 SAP WSDL 生成的变量类型,请选择“浏览类型”并展开生成的变量类型,然后展开 SAPECC 命名空间。 这会初始化 BAPI_USER_DELETE 程序使用的数据结构。
名称 | 变量类型 | 范围 | 默认 |
---|---|---|---|
userName | 字符串 | 序列 | |
bapiret2Table | SAPECC.TABLE_OF_BAPIRET2 | 序列 | 新 TABLE_OF_BAPIRET2() |
- 将 userName 属性定义为不可变 ID(定位点)时,我们需要从导出对象的定位点集合中提取 userName 值。 将 ForEachWithBodyFactory 活动从工具箱拖放到“序列”活动中。 将项变量名称替换为定位点,切换到属性并选择
Microsoft.MetadirectoryServices.AnchorAttribute
的 TypeArgument。 在“值”字段中,键入objectToExport.AnchorAttributes
。
- 若要提取 userName 定位点的字符串值,请将 Switch 活动拖放到 ForEach 活动内。 在弹出窗口中,选择开关
Microsoft.IdentityManagement.MA.WebServices.Activities.Extensions.AnchorAttributeNameWrapper
类型。 输入表达式值:新建AnchorAttributeNameWrapper(anchor.Name)
。 选择“切换”活动的“添加新事例区域”。 键入 userName 作为 用例值。 将 Assign 活动拖放到 userName 案例正文中,并将anchor.Value.ToString()
分配给 userName 变量。 - 在 ForEach 活动之后,将 WebSeviceCall 活动拖放到“序列”活动内。 选择 SAPECC 服务名称、ZSAPCONNECTORWS 终结点和 BAPI_USER_DELETE 操作。 选择“...参数”按钮以定义 Web 服务调用的参数,如下所示:
名称 | 方向 | 类型 | 值 |
---|---|---|---|
RETURN | 输入/输出 | TABLE_OF_BAPIRET2 | bapiret2Table |
USERNAME | In | 字符串 | userName |
- 选择“确定”。 警告符号消失。
- 要处理删除用户请求结果,请在 WebServiceCall 活动之后将 IF 活动拖放到 Sequence 活动内。 输入以下条件:
If(bapiRet2Table.item, Enumerable.Empty(Of BAPIRET2)()).Count(Function(errItem) errItem.TYPE.Equals("E") = True) <> 0
- 如果未收到任何错误,则假定删除操作已成功完成,并且我们希望通过创建带有成功状态的
CSEntryChangeResult
来指示已成功导出此对象。 将CreateCSEntryChangeResult
活动拖放到 IF 活动的 Else 分支,然后选择“成功”错误代码。
- 导出删除工作流中的最后一步是处理和记录导出错误。 将 Sequence 活动拖放到 IF 活动的空 Then 分支中。
- 将 Log 活动拖放到 Sequence 活动中。 切换到“属性”选项卡并输入 LogText 值:
bapiRetTable.item.First(Function(retItem) retItem.TYPE.Equals("E")= True).MESSAGE
。 保留高日志记录级别和跟踪标记。 当启用详细跟踪时,这会将错误消息记录到 ConnectorsLog 或 ECMA2Host 事件日志中。 - 在日志活动后拖放“切换”活动到“序列”活动内。 在弹出窗口中,选择开关值的字符串类型。 输入以下表达式:
bapiret2Table.item.First(Function(retItem) retItem.TYPE.Equals("E")).NUMBER
- 选择 Default 事例,然后将 CreateCSEntryChangeResult 活动拖放到此事例的正文中。 选择 ExportErrorSyntaxViolation 错误代码。
- 选择“添加新案例”区域,然后键入案例值 124。 将
CreateCSEntryChangeResult
活动拖放到此事例的正文中。 选择ExportErrorCustomContinueRun
错误代码。
已完成导出删除工作流的定义。
创建导出替换工作流
若要更新 SAP ECC 中的用户,可以调用BAPI_USER_CHANGE程序并提供所有参数,包括帐户名和所有用户详细信息,包括未更改的参数。 当需要提供所有用户属性时,ECMA2 导出模式称为“替换”。 相比之下,AttributeUpdate 的导出模式仅提供正在更改的属性,这可能会导致某些用户属性被空值覆盖。 因此,Webservice 连接器始终使用“对象替换”导出模式,并期望对连接器进行配置以用于导出类型:替换。
“导出替换”工作流与“导出添加”工作流几乎完全相同。 唯一的区别是需要为 BAPI_USER_CHANGE 程序指定额外的参数,例如 addressX 或 companyX。 addressX 末尾的 X 指示地址的结构确实包含更改。
- 导航到“对象类型”->“用户”->“导出”->“替换工作流”,并从右侧的工具箱将 Sequence 活动拖放到工作流设计器窗格中。
- 在左下角找到“变量”按钮,并选择它以展开此序列中定义的变量列表。
- 添加以下变量。 要选择从 SAP WSDL 生成的变量类型,请选择“浏览类型”并展开生成的变量类型,然后展开 SAPECC 命名空间。 这会初始化 BAPI_USER_CHANGE 程序使用的数据结构。
名称 | 变量类型 | 范围 | 默认 |
---|---|---|---|
userName | 字符串 | 序列 | |
bapiret2Table | SAPECC.TABLE_OF_BAPIRET2 | 序列 | 新 TABLE_OF_BAPIRET2() |
addressX | SAPECC.BAPIADDR3X | 序列 | new BAPIADDR3X() |
address | SAPECC.BAPIADDR3 | 序列 | new BAPIADDR3() |
companyX | SAPECC. BAPIUSCOMX | 序列 | 新 BAPIUSCOMX() |
company | SAPECC.BAPIUSCOMP | 序列 | new BAPIUSCOMP() |
defaultsX | SAPECC.BAPIDEFAX | 序列 | 新 BAPIDEFAX() |
defaults | SAPECC.BAPIDEFAUL | 序列 | 新 BAPIDEFAUL() |
logOnDataX | SAPECC.BAPILOGONX | 序列 | 新 BAPILOGONX() |
logOnData | SAPECC.BAPILOGOND | 序列 | 新 BAPILOGOND() |
导出替换工作流如下所示:
- 将 userName 属性定义为不可变 ID(定位点)时,我们需要从导出对象的定位点集合中提取 userName 值。 将 ForEachWithBodyFactory 活动从工具箱拖放到“序列”活动中。 将项变量名称替换为定位点,切换到属性并选择
Microsoft.MetadirectoryServices.AnchorAttribute
的 TypeArgument。 在“值”字段中,键入objectToExport.AnchorAttributes
。
- 若要提取 userName 定位点的字符串值,请将 Switch 活动拖放到 ForEach 活动内。 在弹出窗口中,选择开关
Microsoft.IdentityManagement.MA.WebServices.Activities.Extensions.AnchorAttributeNameWrapper
类型。 输入表达式值:新建AnchorAttributeNameWrapper(anchor.Name)
。 选择“切换”活动的“添加新事例区域”。 键入 userName 作为 用例值。 将 Assign 活动拖放到 userName 案例正文中,并将anchor.Value.ToString()
分配给 userName 变量。 导出替换工作流如下所示:
- 从导出的对象定位点属性中提取 userName 值后,需要填充其他结构,例如公司、默认值、地址、登录数据,其中包含其他 SAP 用户详细信息。 我们通过循环访问架构中定义的所有属性的集合来执行此操作。
- 折叠 ForEach 活动,并在现有 ForEach 活动之后将另一个 ForEachWithBothFactory 活动拖放到 Sequence 活动中。 将 item 变量名替换为 schemaAttr,切换到属性,选择 TypeArgument
Microsoft.MetadirectoryServices.SchemaAttribute
。 在“值”字段中,键入schemaType.Attributes
。
- 将 Sequence 活动拖放到 ForEach 活动的正文中。 在左下角找到“变量”按钮,并选择它以展开此序列中定义的变量列表。 添加以下变量:String 类型的 xValue。 将“分配”活动拖放到“序列”活动中。 为 xValue 分配表达式:
If(objectToExport.AttributeChanges.Contains(schemaAttr.Name), objectToExport.AttributeChanges(schemaAttr.Name).ValueChanges(0).Value.ToString(), String.Empty)
它提取该属性已准备好导出的更改,或使用空字符串对其进行初始化。 导出替换工作流如下所示:
- 在“分配”活动之后拖放“切换”活动。 在弹出菜单中,选择
Microsoft.IdentityManagement.MA.WebServices.Activities.Extensions.AttributeNameWrapper
,然后选择“确定”。 输入以下表达式:NewAttributeNameWrapper(schemaAttr.Name)
你将在“切换”活动的右上角看到一个警告图标,提示架构中定义且未分配给任何属性的未处理属性。 选择 Switch 活动的“添加新案例”区域,然后案例值 city。 将“序列”活动拖放到此案例的正文中。 将 Assign 活动拖放到此事例的正文部分中。 将“X”值分配给 addressX.city。 将另一个 Assign 活动拖放到此事例的正文部分中。 将 xValue 分配给 address.city。 导出替换工作流如下所示:
10.添加其他缺失案例和分配。 将此映射表作为指南:
案例 | 分配 |
---|---|
city | addressX.city = "X" address.city = xValue |
company | companyX.company = "X" company.company = xValue |
department | address.departmentX = "X" address.department = xValue |
电子邮件 | addressX.e_mail = "X" address.e_mail = xValue |
expirationTime | logOnDataX.GLTGB = "X" logOnData.GLTGB = xValue |
firstname | addressX.firstname = "X" address.firstname = xValue |
lastName | addressX.lastname = "X" address.lastname = xValue |
middleName | addressX.middlename = "X" address.middlename = xValue |
telephoneNumber | addressX.TEL1_Numbr = "X" address.TEL1_Numbr = xValue |
jobTitle | addressX.function = "X" address.function = xValue |
导出替换工作流如下所示:
在调用 BAPI_USER_CHANGE 程序之前,我们需要检查是否存在非空用户名。 折叠两个 ForEach 活动,并将 IF 活动拖放到第二个 ForEach 活动之后。 输入以下条件:
String.IsNullOrEmpty(userName ) = False
当用户名为空时,我们希望指示操作失败。 将
CreateCSEntryChangeResult
活动拖放到 IF 活动的 Else 分支,然后选择ExportErrorCustomContinueRun
错误代码。 你的导出替换工作流如下所示:将 Sequence 活动拖放到第一个 IF 活动的空 Then 分支中。 将 WebSeviceCall 活动拖放到 Sequence 活动中。 选择 SAPECC 服务名称、ZSAPCONNECTORWS 终结点和 BAPI_USER_CHANGE 操作。 选择“...”参数按钮以定义 Web 服务调用的参数,如下所示:
名称 | 方向 | 类型 | 值 |
---|---|---|---|
地址 | In | BAPIADDR3 | address |
ADDRESSX | In | BAPIADDR3X | addressX |
COMPANY | In | BAPIUSCOMP | company |
COMPANYX | In | BAPIUSCOMX | company |
DEFAULTS | In | BAPIDEFAUL | defaults |
DEFAULTSX | In | BAPIDEFAX | defaultsX |
LOGONDATA | In | BAPILOGOND | logOnData |
LOGONDATAX | In | BAPILOGONX | logOnDataX |
RETURN | 输入/输出 | TABLE_OF_BAPIRET2 | bapiret2Table |
USERNAME | In | 字符串 | userName |
- 选择“确定”。 警告符号消失。 导出替换工作流如下所示:
- 要处理更改用户请求结果,请在 WebServiceCall 活动之后将 IF 活动拖放到 Sequence 活动内。 输入以下条件:
Not IsNothing(bapiret2Table.item) AndAlso bapiret2Table.item.Count(Function(errItem) errItem.TYPE.Equals("E") = True) <> 0
- 如果未收到任何错误,则假定导出操作已成功完成,并且我们希望通过创建成功状态的
CSEntryChangeResult
来指示成功导出此对象。 将CreateCSEntryChangeResult
活动拖放到 IF 活动的 Else 分支,然后选择“成功”错误代码。 - 将 Sequence 活动拖放到 IF 活动的 Then 分支中。 使用 LogText 值
string.Join("\n",bapiret2Table.item.Where(Function(retItem) retItem.TYPE.Equals("E")).Select(Function(r) r.MESSAGE))
和错误标记添加日志活动。 在日志活动后添加CreateCSEntryChangeResult
活动,错误代码为ExportErrorCustomContinueRun
。 导出替换工作流如下所示:
已完成导出替换工作流的定义。
下一步是使用此模板配置 ECMA2Host Webservice 连接器。