当前位置:网站首页>金蝶云星空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
边栏推荐
- Technologie zéro copie
- AttributeError: ‘dict‘ object has no attribute ‘iteritems‘
- Android: answers to the recruitment and interview of intermediate Android Development Agency in early 2019 (medium)
- Ora-16047 of a DG environment: dgid mismatch between destination setting and target database troubleshooting and listening vncr features
- JS 力扣刷题 102. 二叉树的层序遍历
- Quartus prime hardware experimental development (de2-115 board) experiment II function adjustable comprehensive timer design
- Chapter 15 new technologies of software engineering
- Analysis of the problem that the cluster component GIPC in RAC environment cannot correctly identify the heartbeat network state
- Un modèle universel pour la construction d'un modèle d'apprentissage scikit
- 趣谈网络协议
猜你喜欢
cnpm的诡异bug
【vmware】vmware tools 地址
10g database cannot be started when using large memory host
JS brain burning interview question reward
3300万IOPS、39微秒延迟、碳足迹认证,谁在认真搞事情?
Question bank and answer analysis of the 2022 simulated examination of the latest eight members of Jiangxi construction (quality control)
蓝绿发布、滚动发布、灰度发布,有什么区别?
ACFs file system creation, expansion, reduction and other configuration steps
freeCodeCamp----arithmetic_ Arranger exercise
Port occupied 1
随机推荐
ACFs file system creation, expansion, reduction and other configuration steps
JS 力扣刷题 102. 二叉树的层序遍历
Scientists say Australian plan to cull up to 10,000 wild horses doesn’t go far enough
Introduction to spark basic operation
【报名】TF54:工程师成长地图与卓越研发组织打造
神经元与神经网络
Function executes only the once function for the first time
第一章 电商秒杀商品回顾
JMeter pressure test tool
[code analysis (3)] communication efficient learning of deep networks from decentralized data
Oracle RAC database instance startup exception analysis IPC send timeout
Go语言 RPC通讯
Multithreading
趣谈网络协议
Express ② (routage)
蓝绿发布、滚动发布、灰度发布,有什么区别?
L2-024 部落 (25 分)
19c environment ora-01035 login error handling
Analysis of redo log generated by select command
OSS cloud storage management practice (polite experience)