VSTO 系列(04)- 做一个真正方便的 SAP 表查看器

之前想了不少方法,为了在 Excel 中直接查看 SAP 表的结构和数据,比如 厌倦了SE11/SE16N? 告诉你如何在Excel中查看SAP的表数据 这篇博文的介绍。本次基于 VSTO COM AddIn 的方式则是我认为最方便的。

设计的思路大致如下:


结合 C# 和 Python 语言,通过 PyRFC 调用 SAP 的 RFC_READ_TABLE 函数,获取数据表的 data dictionary 和 data,由 Flask 将数据对以 Restful API 方式暴露。在 VSTO 中,通过第三方库 RestSharp 消费 Flask 的 Restful Service,并数据导入到 Excel 工作表。之所以选择 Python,主要考虑两点,一是对 SAP 没有侵入性,不需要 SAP 系统的编程配合;二是 PyRFC 调用 RFC 函数的代码最为简洁。

本篇的示例,不对 PyRFC 的函数调用做过多说明,将写另外的文章来介绍。为了解决 RFC_READ_TABLE 函数字段长度的限制,在调用的时候采取分批每次调用 5 个字段的方法解决。RFC_READ_TABLE 函数的局限性请参考我之前的博文。

Flask 提供的 Restful API 有两个接口:

/tabledata/<tablename>/<lines>?options=xxx

上面的接口用户获取表的数据,lines 表示获取数据的行数,默认为 200 行,options 表示符合 ABAP 符合 RFC_READ_TABLE 筛选条件的字符串。下面是 Postman 调用 T001 表的示例:

/tablefields/<tablename>

根据 tablename 获取数据表的 DDIC,如 Postman 测试的结果:

消费 Restful API

从上篇示例工程代码,拷贝一份作为新的工程,创建 SAPTableService 类,从服务器端的 URL 获取 json 格式的数据:

using RestSharp;
using System.Data;

namespace VSTODemo {
    
    
    public class SapTableService {
    
    
        private string baseUrl = "http://localhost:5000";
        private RestClient restClient;

        public SapTableService() {
    
    
            restClient = new RestClient(baseUrl);
        }

        public DataTable GetTableFields(string tableName) {
    
    
            DataTable result = null;

            var url = baseUrl + "/tablefields/" + tableName;
            var request = new RestRequest(url, Method.GET);
            var resp = restClient.Execute(request);
            if (resp.IsSuccessful) {
    
    
                result = JsonUtils.ToTable(resp.Content);
            }

            return result;
        }

        public DataTable GetTableContent(string tableName, string criteria, string rows) {
    
    
            DataTable result = null;

            string url = null;
            if (string.IsNullOrEmpty(criteria)) {
    
    
                url = baseUrl + $"/tabledata/{tableName}/{rows}";
            }
            else {
    
    
                url = baseUrl + $"/tabledata/{tableName}/{rows}?options={criteria}";
            }
            

            var request = new RestRequest(url, Method.GET);
            var resp = restClient.Execute(request);
            if (resp.IsSuccessful) {
    
    
                result = JsonUtils.ToTable(resp.Content);
            }

            return result;
        }
    }
}

代码中用到了 RestSharp 第三方模块,用于 Http 请求,以及 Newtonsoft.Json 模块,用于将 json 数据转换为 DataTable 类型。Json 转 DataTable 使用下面的代码:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Data;

namespace VSTODemo {
    
    
    public class JsonUtils {
    
    
        public static DataTable ToTable(string json) {
    
    
            var srcArray = JArray.Parse(json); // json格式约定最上层为 array

            var trgArray = new JArray();
            foreach (JObject row in srcArray.Children<JObject>()) {
    
    
                var cleanRow = new JObject();
                foreach (JProperty column in row.Properties()) {
    
    
                    // Only include JValue types
                    if (column.Value is JValue) {
    
    
                        cleanRow.Add(column.Name, column.Value);
                    }
                }

                trgArray.Add(cleanRow);
            }

            return JsonConvert.DeserializeObject<DataTable>(trgArray.ToString());
        }
    }
}

这段代码来自 StackOverflow 的这篇帖子:c# - Convert JSON to DataTable - Stack Overflow,稍作变更。

设计界面

在工程中,新建一个 WinForm,界面如下:


Ribbon 菜单增加一个按钮,弹出该 Form,点击该 Form 的确认按钮,将输入导入到工作表中:


数据导入到工作表:

using Microsoft.Office.Interop.Excel;
using System;
using System.Windows.Forms;

namespace VSTODemo {
    
    
    public partial class SAPTableForm : Form {
    
    
        public SAPTableForm() {
    
    
            InitializeComponent();
        }

        private void btnConfirm_Click(object sender, EventArgs e) {
    
    
            var sapService = new SapTableService();

            if (tableFieldsCheckBox.Checked) {
    
    
                var tableFields = sapService.GetTableFields(txtTableName.Text.Trim().ToUpper());
                Worksheet sheet = ThisAddIn.ExcelApp.Worksheets.Add();
                sheet.Name = $"{txtTableName.Text.ToUpper()}_strucutre_{sheet.Name}";
                ExcelUtils.CopyFromDataTable(tableFields, sheet);
            }

            if (tableContentCheckBox.Checked) {
    
    
                var tableContent = sapService.GetTableContent(
                    txtTableName.Text.ToUpper().Trim(), 
                    txtCriteria.Text.Trim(), 
                    txtRows.Text);

                Worksheet sheet = ThisAddIn.ExcelApp.Worksheets.Add();
                sheet.Name = $"{txtTableName.Text.ToUpper()}_{sheet.Name}";
                ExcelUtils.CopyFromDataTable(tableContent, sheet);
            }

            this.Close();
        }
    }
}

源代码

Gitee - 04-Query SAP Table

猜你喜欢

转载自blog.csdn.net/stone0823/article/details/114809786