当前位置:网站首页>金蝶云星空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