当前位置:网站首页>金蝶云星空API调用实践
金蝶云星空API调用实践
2022-04-23 13:59:00 【流苏1990】
SDK的方式没法在NetCore平台中使用。所以就采用了最原始的HTTP访问调用来实现,具体如下:
1、设定接口IK3CloudApi,IAfterK3CloudApi(有需要的可以自行扩展与实现)
public interface IK3CloudApi
{
/// <summary>
/// 执行保存
/// </summary>
/// <returns></returns>
IK3CloudApi Save(string formid, string data);
/// <summary>
/// 执行审核
/// </summary>
/// <returns></returns>
IK3CloudApi Audit(string formid, string data);
/// <summary>
/// 执行反审核
/// </summary>
/// <returns></returns>
IK3CloudApi UnAudit(string formid, string data);
/// <summary>
/// 执行反审核
/// </summary>
/// <returns></returns>
IK3CloudApi Submit(string formid, string data);
/// <summary>
/// 执行删除
/// </summary>
/// <returns></returns>
IK3CloudApi Delete(string formid, string data);
/// <summary>
/// 执行操作
/// </summary>
/// <returns></returns>
IK3CloudApi ExcuteOperation(string formid, string opNumber, string data);
/// <summary>
/// 随后执行
/// </summary>
/// <returns></returns>
IAfterK3CloudApi After();
/// <summary>
/// 执行
/// </summary>
/// <param name="resultCallback">回调方法</param>
/// <returns></returns>
Task<MessageResult> SendAsync(Func<CallBack, bool> resultCallback = null);
/// <summary>
/// 执行
/// </summary>
/// <param name="resultCallback">回调方法</param>
/// <returns></returns>
MessageResult Send(Func<CallBack, bool> resultCallback = null);
}
其中随后执行是为了满足 单据审核时 需要先调用提交动作 而产生的,具体如下:
随后执行 目前只支持通过formid的操作,也就是只能操作同一个类型的单据/档案
public interface IAfterK3CloudApi
{
/// <summary>
/// 执行保存
/// </summary>
/// <returns></returns>
IK3CloudApi Save(string data = "");
/// <summary>
/// 执行审核
/// </summary>
/// <returns></returns>
IK3CloudApi Audit(string data = "");
/// <summary>
/// 执行反审核
/// </summary>
/// <returns></returns>
IK3CloudApi UnAudit(string data = "");
/// <summary>
/// 执行提交
/// </summary>
/// <returns></returns>
IK3CloudApi Submit(string data = "");
/// <summary>
/// 执行删除
/// </summary>
/// <returns></returns>
IK3CloudApi Delete(string data = "");
/// <summary>
/// 执行操作
/// </summary>
/// <returns></returns>
IK3CloudApi ExcuteOperation(string opNumber, string data = "");
}
实现类如下:
1、AppSettings 是对接配置文件,有需要可以自行替换为IConfiguration获取
2、需要配置的有地址、用户名、密码、数据帐套,对应(urlValue,starryskyusername,starryskyuserpwd,starryskyid)这里我区分了测试环境与生产环境的取值
3、SendAsync与Send方法设置了processResultCallback的回调,传入Action与返回值,并要求回传True或者False。作用是多个动作执行过程中,返回True (默认值)则前面的动作执行失败后不执行后续动作
4、插入动作的那个方法如果参数有多个则自行在新增方法实现,
/// <summary>
/// 云星空的API调用
/// </summary>
[Serializable]
internal class K3CloudApi : IK3CloudApi
{
private readonly string LoginServiceName = "Kingdee.BOS.WebApi.ServicesStub.AuthService.ValidateUserEnDeCode";
private readonly string ExceServiceName = "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.";
private readonly AppSettings optionSetting = null;
private readonly IHttpClientFactory httpClientFactory = null;
private readonly List<Tuple<string, object[]>> executeList = null;
private readonly AfterK3CloudApi afterK3CloudApi = null;
private readonly string urlValue = string.Empty;
private readonly string starryskyid = string.Empty;
private readonly string starryskyusername = string.Empty;
private readonly string starryskyuserpwd = string.Empty;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="appSettings"></param>
/// <param name="httpClientFactory"></param>
public K3CloudApi(IOptionsMonitor<AppSettings> appSettings, IHttpClientFactory httpClientFactory)
{
this.optionSetting = appSettings.CurrentValue;
this.httpClientFactory = httpClientFactory;
this.executeList = new List<Tuple<string, object[]>>();
this.urlValue = this.optionSetting.erpurl;
this.starryskyid = this.optionSetting.starryskyid;
this.starryskyusername = this.optionSetting.starryskyusername;
this.starryskyuserpwd = this.optionSetting.starryskyuserpwd;
if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development")
{
this.urlValue = this.optionSetting.erpurlDevelopment;
this.starryskyid = this.optionSetting.starryskyidDevelopment;
this.starryskyusername = this.optionSetting.starryskyusernameDevelopment;
this.starryskyuserpwd = this.optionSetting.starryskyuserpwdDevelopment;
}
if (this.urlValue.EndsWith("/") == false)
this.urlValue += "/";
this.afterK3CloudApi = new AfterK3CloudApi(this);
}
/// <summary>
/// 执行保存
/// </summary>
/// <returns></returns>
public IK3CloudApi Save(string formid, string data)
{
this.executeList.Add(Tuple.Create("Save", new object[] { formid, data }));
return this;
}
/// <summary>
/// 执行审核
/// </summary>
/// <returns></returns>
public IK3CloudApi Audit(string formid, string data)
{
this.executeList.Add(Tuple.Create("Audit", new object[] { formid, data }));
return this;
}
/// <summary>
/// 执行反审核
/// </summary>
/// <returns></returns>
public IK3CloudApi UnAudit(string formid, string data)
{
this.executeList.Add(Tuple.Create("UnAudit", new object[] { formid, data }));
return this;
}
/// <summary>
/// 执行反审核
/// </summary>
/// <returns></returns>
public IK3CloudApi Submit(string formid, string data)
{
this.executeList.Add(Tuple.Create("Submit", new object[] { formid, data }));
return this;
}
/// <summary>
/// 执行删除
/// </summary>
/// <returns></returns>
public IK3CloudApi Delete(string formid, string data)
{
this.executeList.Add(Tuple.Create("Delete", new object[] { formid, data }));
return this;
}
/// <summary>
/// 执行操作
/// </summary>
/// <returns></returns>
public IK3CloudApi ExcuteOperation(string formid, string opNumber, string data)
{
this.executeList.Add(Tuple.Create("ExcuteOperation", new object[] { formid, opNumber, data }));
return this;
}
/// <summary>
/// 执行
/// </summary>
/// <param name="resultCallback">回调方法</param>
/// <returns></returns>
public async Task<MessageResult> SendAsync(Func<CallBack, bool> resultCallback = null)
{
MessageResult loginTuple = await Login();
if (loginTuple.IsSuccess == false)
return loginTuple;
//执行动作
string result = string.Empty;
string unionResult = string.Empty;
string successItems = string.Empty;
bool iserror = false;
foreach (Tuple<string, object[]> tuple in executeList)
{
result = await Request(string.Concat(ExceServiceName, tuple.Item1), JsonConvert.SerializeObject(tuple.Item2));
K3ResponseEntity k3ResponseEntity = K3ResponseEntity.Create(result);
iserror = k3ResponseEntity.IsSuccess;
unionResult += iserror == false ? k3ResponseEntity.ErrorMsg : k3ResponseEntity.SuccessMsg;
if (iserror == false)
successItems += JsonConvert.SerializeObject(k3ResponseEntity.SuccessItems) + Environment.NewLine;
if (resultCallback != null && resultCallback(new CallBack(tuple.Item1, k3ResponseEntity, this)) == false)
break;
}
return new MessageResult(iserror, unionResult, successItems);
}
/// <summary>
/// 执行
/// </summary>
/// <param name="resultCallback">回调方法</param>
/// <returns></returns>
public MessageResult Send(Func<CallBack, bool> resultCallback = null)
{
Task<MessageResult> loginTuple = Login();
if (loginTuple.Result.IsSuccess == false)
return loginTuple.Result;
//执行动作
Task<string> result;
string unionResult = string.Empty;
string successItems = string.Empty;
bool iserror = false;
foreach (Tuple<string, object[]> tuple in executeList)
{
result = Request(string.Concat(ExceServiceName, tuple.Item1), JsonConvert.SerializeObject(tuple.Item2));
//解析message
K3ResponseEntity k3ResponseEntity = K3ResponseEntity.Create(result.Result);
iserror = k3ResponseEntity.IsSuccess;
unionResult += iserror == false ? k3ResponseEntity.ErrorMsg : k3ResponseEntity.SuccessMsg;
if (iserror == false)
successItems += JsonConvert.SerializeObject(k3ResponseEntity.SuccessItems) + Environment.NewLine;
if (resultCallback != null && resultCallback(new CallBack(tuple.Item1, k3ResponseEntity, this)) == false)
break;
}
return new MessageResult(iserror, unionResult, successItems);
}
/// <summary>
/// 登录
/// </summary>
/// <returns></returns>
private async Task<MessageResult> Login()
{
object[] paramslist = new object[] { this.starryskyid, EnDecode.Encode(this.starryskyusername), EnDecode.Encode(this.starryskyuserpwd), 2052 };
string loginResult = await Request(LoginServiceName, JsonConvert.SerializeObject(paramslist));
var resultJson = JObject.Parse(loginResult);
var resultType = resultJson["LoginResultType"].Value<int>();
//登录结果类型等于1,代表登录成功
if (resultType != 1)
return new MessageResult(false, resultJson["Message"].Value<string>());
return new MessageResult(true, string.Empty);
}
/// <summary>
/// 执行请求
/// </summary>
/// <returns></returns>
private async Task<string> Request(string serviceName, string postContent)
{
using (HttpClient httpClient = this.httpClientFactory.CreateClient())
{
httpClient.Timeout = TimeSpan.FromSeconds(30);//30s
httpClient.DefaultRequestHeaders.Add("Accept-Charset", Encoding.UTF8.HeaderName);
JObject jObj = new JObject();
jObj.Add("format", 1);
jObj.Add("useragent", "ApiClient");
jObj.Add("rid", Guid.NewGuid().ToString().GetHashCode().ToString());
jObj.Add("parameters", postContent);
jObj.Add("timestamp", DateTime.Now);
jObj.Add("v", "1.0");
var buffer = Encoding.UTF8.GetBytes(jObj.ToString());
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var requestMsg = await httpClient.PostAsync(new Uri(new Uri(this.urlValue), string.Concat(serviceName, ".common.kdsvc")), byteContent);
return ValidateResult(await requestMsg.Content.ReadAsStringAsync());
}
}
/// <summary>
/// 校验返回值
/// </summary>
/// <param name="responseText"></param>
/// <returns></returns>
private string ValidateResult(string responseText)
{
if (responseText.StartsWith("response_error:"))
return responseText.TrimStart("response_error:".ToCharArray());
return responseText;
}
/// <summary>
/// 插入动作
/// </summary>
private void InsertAction(string action, string data = "")
{
if (this.executeList.Any() == false)
return;
var lastItem = this.executeList.LastOrDefault();
if (lastItem == null)
return;
if (string.IsNullOrEmpty(data) && lastItem.Item2.Length > 1)
data = lastItem.Item2[1].ToString();
var newItem = Tuple.Create(action, new object[] { lastItem.Item2[0], data });
this.executeList.Add(newItem);
}
/// <summary>
/// 插入动作
/// </summary>
private void InsertAction(string action, string data0 = "", string data1 = "")
{
if (this.executeList.Any() == false)
return;
var lastItem = this.executeList.LastOrDefault();
if (lastItem == null)
return;
if (string.IsNullOrEmpty(data0) && lastItem.Item2.Length > 1)
data0 = lastItem.Item2[1].ToString();
if (string.IsNullOrEmpty(data1) && lastItem.Item2.Length > 2)
data1 = lastItem.Item2[2].ToString();
var newItem = Tuple.Create(action, new object[] { lastItem.Item2[0], data0, data1 });
this.executeList.Add(newItem);
}
/// <summary>
/// 随后执行
/// </summary>
/// <returns></returns>
public IAfterK3CloudApi After()
{
return this.afterK3CloudApi;
}
/// <summary>
/// 之后执行
/// </summary>
private class AfterK3CloudApi : IAfterK3CloudApi
{
private readonly K3CloudApi cloudApi;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="k3CloudApi"></param>
internal AfterK3CloudApi(K3CloudApi k3CloudApi)
{
this.cloudApi = k3CloudApi;
}
/// <summary>
/// 执行审核
/// </summary>
/// <returns></returns>
public IK3CloudApi Audit(string data = "")
{
this.cloudApi.InsertAction("Audit", data);
return this.cloudApi;
}
/// <summary>
/// 执行删除
/// </summary>
/// <returns></returns>
public IK3CloudApi Delete(string data = "")
{
this.cloudApi.InsertAction("Delete", data);
return this.cloudApi;
}
/// <summary>
/// 执行保存
/// </summary>
/// <returns></returns>
public IK3CloudApi Save(string data = "")
{
this.cloudApi.InsertAction("Save", data);
return this.cloudApi;
}
/// <summary>
/// 执行提交
/// </summary>
/// <returns></returns>
public IK3CloudApi Submit(string data = "")
{
this.cloudApi.InsertAction("Submit", data);
return this.cloudApi;
}
/// <summary>
/// 执行反审核
/// </summary>
/// <returns></returns>
public IK3CloudApi UnAudit(string data = "")
{
this.cloudApi.InsertAction("UnAudit", data);
return this.cloudApi;
}
/// <summary>
/// 执行操作
/// </summary>
/// <returns></returns>
public IK3CloudApi ExcuteOperation(string opNumber, string data = "")
{
this.cloudApi.InsertAction("ExcuteOperation", opNumber, data);
return this.cloudApi;
}
}
}
反馈消息实体如下:
1、K3ResponseEntity 构造函数实现了返回JSON的解析,目前只取了部分
/// <summary>
/// 云星空反馈消息实体
/// </summary>
[Serializable]
public sealed class K3ResponseEntity
{
private readonly string errorCode = string.Empty;
private readonly bool isSuccess = false;
private readonly string msgCode = string.Empty;
private readonly string originalString = string.Empty;
private readonly List<ErrorsItem> errors = new List<ErrorsItem>();
private readonly List<ErrorsItem> successs = new List<ErrorsItem>();
private readonly List<SuccessItem> successsItemList = new List<SuccessItem>();
/// <summary>
/// 创建
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
public static K3ResponseEntity Create(string json)
{
return new K3ResponseEntity(json);
}
/// <summary>
/// 构造函数
/// </summary>
private K3ResponseEntity(string json)
{
this.originalString = json;
var jsonObj = JObject.Parse(json);
if (jsonObj["Result"]["ResponseStatus"]["ErrorCode"] != null)
this.errorCode = jsonObj["Result"]["ResponseStatus"]["ErrorCode"].ToString();
this.isSuccess = jsonObj["Result"]["ResponseStatus"]["IsSuccess"].ToString() == Boolean.TrueString;
this.msgCode = jsonObj["Result"]["ResponseStatus"]["MsgCode"].ToString();
var errorsJarray = JArray.Parse(jsonObj["Result"]["ResponseStatus"]["Errors"].ToString());
foreach (var errorItem in errorsJarray)
this.errors.Add(new ErrorsItem(errorItem["FieldName"].ToString(), errorItem["Message"].ToString(), Convert.ToInt32(errorItem["DIndex"].ToString())));
var successJarray = JArray.Parse(jsonObj["Result"]["ResponseStatus"]["SuccessMessages"].ToString());
foreach (var errorItem in errorsJarray)
this.successs.Add(new ErrorsItem(errorItem["FieldName"].ToString(), errorItem["Message"].ToString(), Convert.ToInt32(errorItem["DIndex"].ToString())));
var succesEntityarray = JArray.Parse(jsonObj["Result"]["ResponseStatus"]["SuccessEntitys"].ToString());
foreach (var errorItem in succesEntityarray)
this.successsItemList.Add(new SuccessItem(Convert.ToInt32(errorItem["Id"].ToString()), errorItem["Number"].ToString(), Convert.ToInt32(errorItem["DIndex"].ToString())));
}
public string OriginalString
{
get { return this.originalString; }
}
/// <summary>
/// 错误码
/// </summary>
public string ErrorCode
{
get { return this.errorCode; }
}
/// <summary>
/// 是否成功
/// </summary>
public bool IsSuccess
{
get { return this.isSuccess; }
}
/// <summary>
/// 错误消息
/// </summary>
public IEnumerable<ErrorsItem> Errors
{
get { return this.errors; }
}
/// <summary>
/// 成功消息
/// </summary>
public IEnumerable<ErrorsItem> SuccessMessages
{
get { return this.successs; }
}
/// <summary>
/// 成功的实体
/// </summary>
public IEnumerable<SuccessItem> SuccessItems
{
get { return this.successsItemList; }
}
/// <summary>
/// 错误码
/// </summary>
public string MsgCode
{
get { return this.msgCode; }
}
public string ErrorMsg
{
get
{
if (this.errors.Any())
return string.Join<string>(Environment.NewLine, this.errors.Select(y => y.Message));
return string.Empty;
}
}
public string SuccessMsg
{
get
{
if (this.successs.Any())
return string.Join<string>(Environment.NewLine, this.successs.Select(y => y.Message));
return string.Empty;
}
}
/// <summary>
///
/// </summary>
[Serializable]
public class ErrorsItem
{
private readonly string fieldName = string.Empty;
private readonly string message = string.Empty;
private readonly int dindex = 0;
/// <summary>
/// 构造函数
/// </summary>
internal ErrorsItem(string field, string msg, int dindex)
{
this.fieldName = field;
this.message = msg;
this.dindex = dindex;
}
public string FieldName { get { return this.fieldName; } }
public string Message { get { return this.message; } }
public int DIndex { get { return this.dindex; } }
}
[Serializable]
public class SuccessItem
{
private readonly int id = Int32.MinValue;
private readonly string number = string.Empty;
private readonly int dindex = 0;
/// <summary>
/// 构造函数
/// </summary>
internal SuccessItem(int id, string number, int dindex)
{
this.id = id;
this.number = number;
this.dindex = dindex;
}
public int Id { get { return this.id; } }
public string Number { get { return this.number; } }
public int DIndex { get { return this.dindex; } }
}
}
/// <summary>
/// 消息结果
/// </summary>
[Serializable]
public sealed class MessageResult
{
private readonly string msg = string.Empty;
private readonly bool isSuccess = false;
private readonly string objData = string.Empty;
/// <summary>
/// 消息结果
/// </summary>
public MessageResult()
{
}
/// <summary>
/// 消息结果
/// </summary>
public MessageResult(string message)
: this(false, message)
{
}
/// <summary>
/// 消息结果
/// </summary>
public MessageResult(bool issuccess, string message)
{
this.isSuccess = issuccess;
this.msg = message;
}
/// <summary>
/// 消息结果
/// </summary>
public MessageResult(bool issuccess, string message, string objdata)
: this(issuccess, message)
{
this.objData = objdata;
}
/// <summary>
/// 合并消息实体
/// </summary>
/// <param name="messageResult"></param>
/// <returns></returns>
public MessageResult Combine(MessageResult messageResult)
{
return new MessageResult(this.IsSuccess && messageResult.IsSuccess, string.Concat(this.Message, Environment.NewLine, messageResult.Message, messageResult.objData));
}
public bool IsSuccess { get { return this.isSuccess; } }
public string Message { get { return this.msg; } }
public string ObjData { get { return this.objData; } }
}
/// <summary>
/// 返回值
/// </summary>
[Serializable]
public sealed class CallBack
{
/// <summary>
/// 消息结果
/// </summary>
internal CallBack(string formId, K3ResponseEntity result, IK3CloudApi k3CloudApi)
{
this.FormId = formId;
this.Result = result;
this.K3CloudApi = k3CloudApi;
}
public string FormId { get; private set; }
public K3ResponseEntity Result { get; private set; }
public IK3CloudApi K3CloudApi { get; private set; }
}
登录时使用了DES加密了账号与密码,代码如下:
/// <summary>
///
/// </summary>
[Serializable]
public class EnDecode
{
public static string Encode(object data)
{
string result = string.Empty;
try
{
byte[] inArray = null;
int length = 0;
using (DESCryptoServiceProvider dESCryptoServiceProvider = new DESCryptoServiceProvider())
{
int arg_38_0 = dESCryptoServiceProvider.KeySize;
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, dESCryptoServiceProvider.CreateEncryptor(Encoding.ASCII.GetBytes("KingdeeK"), Encoding.ASCII.GetBytes("KingdeeK")), CryptoStreamMode.Write))
{
using (StreamWriter streamWriter = new StreamWriter(cryptoStream))
{
streamWriter.Write(data);
streamWriter.Flush();
cryptoStream.FlushFinalBlock();
streamWriter.Flush();
inArray = memoryStream.GetBuffer();
length = (int)memoryStream.Length;
}
}
}
}
result = Convert.ToBase64String(inArray, 0, length);
}
catch (Exception ex)
{
result = ex.Message;
}
return result;
}
}
在Startup注册:
//注入接口
services.AddTransient<IK3CloudApi, K3CloudApi>();
调用如下:
/// <summary>
/// 构造函数
/// </summary>
public PoorderService(IOptionsMonitor<AppSettings> appSettings, IFreeSql freeSql, IHttpClientFactory httpClientFactory, ILogger<PoorderService> logger, IK3CloudApi iK3CloudApi)
{
this.optionSetting = appSettings.CurrentValue;
this.logger = logger;
this.freeSql = freeSql;
this.httpClientFactory = httpClientFactory;
this.iK3CloudApi = iK3CloudApi;
}
//采购订单审核时:
MessageResult messageResult = await this.iK3CloudApi.Audit("PUR_PurchaseOrder", postJson).SendAsync();
//采购订单提交&审核:
MessageResult messageResult = await this.iK3CloudApi.Submit("PUR_PurchaseOrder", postJson).After().Audit().SendAsync();
版权声明
本文为[流苏1990]所创,转载请带上原文链接,感谢
https://blog.csdn.net/fuweiping/article/details/121300164
边栏推荐
- Business case | how to promote the activity of sports and health app users? It is enough to do these points well
- 2022年江西最新建筑八大员(质量员)模拟考试题库及答案解析
- Dynamic subset division problem
- Leetcode? The first common node of two linked lists
- freeCodeCamp----arithmetic_ Arranger exercise
- Analysis of redo log generated by select command
- leetcode--380.O(1) 时间插入、删除和获取随机元素
- 2021年秋招,薪资排行NO
- Jenkins construction and use
- Solution of discarding evaluate function in surprise Library
猜你喜欢
Modify the Jupiter notebook style
Dolphin scheduler integrates Flink task pit records
JS brain burning interview question reward
Quartus Prime硬件实验开发(DE2-115板)实验一CPU指令运算器设计
Strange bug of cnpm
SQL learning window function
2021年秋招,薪资排行NO
程序编译调试学习记录
Express中间件③(自定义中间件)
Un modèle universel pour la construction d'un modèle d'apprentissage scikit
随机推荐
Quartus Prime硬件实验开发(DE2-115板)实验一CPU指令运算器设计
Express middleware ③ (custom Middleware)
村上春树 --《当我谈跑步时,我谈些什么》句子摘录
Failure to connect due to improper parameter setting of Rac environment database node. Troubleshooting
趣谈网络协议
cnpm的诡异bug
蓝绿发布、滚动发布、灰度发布,有什么区别?
1256:献给阿尔吉侬的花束
专题测试05·二重积分【李艳芳全程班】
函数只执行第一次的执行一次 once函数
Processing of ASM network not automatically started in 19C
19c RAC steps for modifying VIP and scanip - same network segment
AtCoder Beginner Contest 248C Dice Sum (生成函数)
About me
服务器中挖矿病毒了,屮
Dynamic subset division problem
The latest development of fed digital currency
leetcode--357. 统计各位数字都不同的数字个数
JS 力扣刷题 102. 二叉树的层序遍历
FDFS start