C#接入steam内购

这一篇文章主要记录了C#服务端唤起steam交易授权页面时遇到的问题。
问题主要在于steam文档太难读了。
这一段是重点:
steam文档中关于请求的要求描述
第一步:获取客户端请求生成订单时,要先请求GetUserInfo接口
请求地址:https://partner.steam-api.com/ISteamMicroTxn/GetUserInfo/v2/?key={steam_key}&appid={steam_appid}&steamid={steamID}
接口是GET请求方式,直接贴代码,其中steamID是客户端调用SteamUser.GetSteamID()获取的,返回值是一个UInt64类型,直接tostring()传给服务端就行:

private string GetSteamUserInfo(string steamID)
        {
            string ret = "";
            if (!string.IsNullOrEmpty(steamID))
            {
                try
                {
                    string country = "";
                    string url_userinfo = "";
                    if (isSandBox == "0")
                    {
                        //沙盒环境
                        url_userinfo = $"https://partner.steam-api.com/ISteamMicroTxnSandBox/GetUserInfo/v2/?key={steam_key}&appid={steam_appid}&steamid={steamID}";
                    }
                    else
                    {
                        url_userinfo = $"https://partner.steam-api.com/ISteamMicroTxn/GetUserInfo/v2/?key={steam_key}&appid={steam_appid}&steamid={steamID}";
                    }
                    string res = GetHttpRequest(url_userinfo);//就是封装的Get请求方式,函数代码就不贴了
                    if (string.IsNullOrEmpty(res))
                    {
                        return ret;
                    }
                    var jsonResult = JsonConvert.DeserializeObject<JObject>(res);
                    var result = JsonConvert.DeserializeObject<JObject>(jsonResult["response"].ToString());
                    if (result["result"].ToString() == "OK")
                    {
                        var resParam = JsonConvert.DeserializeObject<Dictionary<string, string>>(result["params"].ToString());
                        country = resParam["country"].ToString();
                        ret = resParam["currency"].ToString();
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex.ToString());
                }
            }
            return ret;
        }

第二步:在获取steam接口返回的currency之后,就可以请求拉起steam支付授权页面了,这里要注意,客户端通过Steam接口SteamApps.GetCurrentGameLanguage()获取到的,这里要转化一下:

public static string TransferLanguage(string str)
        {
            string res = "";
            switch (str)
            {
                case "arabic":
                    res = "ar";
                    break;
                case "bulgarian":
                    res = "bg";
                    break;
                case "schinese":
                    res = "zh-CN";
                    break;
                case "tchinese":
                    res = "zh-TW";
                    break;
                case "czech":
                    res = "cs";
                    break;
                case "danish":
                    res = "da";
                    break;
                case "dutch":
                    res = "nl";
                    break;
                case "english":
                    res = "en";
                    break;
                case "finnish":
                    res = "fi";
                    break;
                case "french":
                    res = "fr";
                    break;
                case "german":
                    res = "de";
                    break;
                case "greek":
                    res = "el";
                    break;
                case "hungarian":
                    res = "hu";
                    break;
                case "italian":
                    res = "it";
                    break;
                case "japanese":
                    res = "ja";
                    break;
                case "koreana":
                    res = "ko";
                    break;
                case "norwegian":
                    res = "no";
                    break;
                case "polish":
                    res = "pl";
                    break;
                case "portuguese":
                    res = "pt";
                    break;
                case "brazilian":
                    res = "pt-BR";
                    break;
                case "romanian":
                    res = "ro";
                    break;
                case "russian":
                    res = "ru";
                    break;
                case "spanish":
                    res = "es";
                    break;
                case "latam":
                    res = "es-419";
                    break;
                case "swedish":
                    res = "sv";
                    break;
                case "thai":
                    res = "th";
                    break;
                case "turkish":
                    res = "tr";
                    break;
                case "ukrainian":
                    res = "uk";
                    break;
                case "vietnamese":
                    res = "vn";
                    break;
            }
            return res;
        }

然后,请求steam,这里steam会自己在你的客户端拉起steam的支付授权界面,贴代码:
请求地址:https://partner.steam-api.com/ISteamMicroTxn/InitTxn/v3/

private async Task<bool> CallSteamPay(string steamID, string cpOrderID, string language, int ammount, string itemID, string productName, string currency)
        {
            bool ret = false;
            if (string.IsNullOrEmpty(steamID) || string.IsNullOrEmpty(cpOrderID) || string.IsNullOrEmpty(language) || string.IsNullOrEmpty(itemID)
                || string.IsNullOrEmpty(productName) || string.IsNullOrEmpty(currency) || ammount <= 0)
            {
                return ret;
            }
            try
            {
                var urlParams = new Dictionary<string, string>()
                    {
                        { "key",steam_key},//Steamworks Web API 发行商验证密钥。
                        { "orderid",cpOrderID},//	订单的 64 位唯一 ID。
                        { "steamid",steamID},//进行购买的用户的 Steam ID。
                        { "appid",steam_appid},//	此交易所针对的游戏的 app ID。
                        { "itemcount","1"},//购物车中的物品数量。
                        { "language",language},//物品描述的 ISO 639-1 语言代码。
                        { "currency",currency},//ISO 4217 货币代码。 参见支持币种,了解每个币种的正确格式。
                        { "itemid[0]",itemID},//	物品的第三方 ID。
                        { "qty[0]","1"},//物品的数量。
                        { "amount[0]",ammount.ToString()},//目前要收取的物品的总费用(以分计)。
                        { "description[0]",productName}//物品的描述。 最大长度为 128 字符。
                    };
                string url_initTxn = "";
                if (isSandBox == "0")
                {
                    //沙盒环境
                    url_initTxn = "https://partner.steam-api.com/ISteamMicroTxnSandBox/InitTxn/v3/";
                }
                else
                {
                    url_initTxn = "https://partner.steam-api.com/ISteamMicroTxn/InitTxn/v3/";
                }
                var res = await GetHttpRequestToPostFormData(url_initTxn, urlParams);
                if (!string.IsNullOrEmpty(res))
                {
                    var callResult = JsonConvert.DeserializeObject<JObject>(res);
                    var result = JsonConvert.DeserializeObject<JObject>(callResult["response"].ToString());
                    if (result["result"].ToString() == "OK")
                    {
                        ret = true;
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex.ToString());
            }
            return ret;
        }

这个接口在我尝试了好几种方法后,始终提示400 BadRequest,当我从HttpWebRequest更换为HttpClient请求方式后,返回了Required param‘orderid’ is missing,我就知道是我ContentType定义错了:

public static async Task<string> GetHttpRequestToPostFormData(string url, Dictionary<string, string> postData)
        {
            if (string.IsNullOrEmpty(url))
                return string.Empty;

            HttpClient httpClient = new HttpClient();
            httpClient.DefaultRequestHeaders.Connection.Add("keep-alive");
            httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));


            HttpContent cont = new FormUrlEncodedContent(postData);
            cont.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
            string result= string.Empty;
            try
            {
                var response = await httpClient.PostAsync(url, cont);
                if(response.StatusCode == HttpStatusCode.OK)
                {
                	result = await response.Content.ReadAsStringAsync();
                }
                
            }
            catch (Exception ex)
            {
                result = ex.ToString();
            }
            return result;
        }

第三步:用户在支付授权成功授权后,steam会通过客户端回调方法通知,之后客户端请求服务端发放道具,服务端在收到成功授权后,调用ISteamMicroTxnSandBox/FinalizeTxn接口,查看订单状态,之后就可以发道具了:
请求地址:https://partner.steam-api.com/ISteamMicroTxn/FinalizeTxn/v2/

		[HttpPost]
        public async Task<string> Finalize()
        {
            var ret = new { code = 1, msg = "", data = "" };
            try
            {
                var orderID = GetFormValue(Request.Form, "cpOrderID");
                var sign = GetFormValue(Request.Form, "sign");
                StringBuilder sb = new StringBuilder();
                sb.Append("orderID=" + orderID);
                sb.Append(shaKey);
                //针对客户端的请求需要做md5加密
                var ticket = MD5DecryptLong(sb.ToString()).ToLower();
                if (ticket.Equals(sign))
                {
                    var urlParams = new Dictionary<string, string>()
                    {
                        { "key",steam_key},
                        { "orderid",orderID},
                        { "appid",steam_appid}
                    };
                    string finalUrl;
                    if (isSandBox == "0")
                    {
                        finalUrl = "https://partner.steam-api.com/ISteamMicroTxnSandBox/FinalizeTxn/v2/";
                    }
                    else
                    {
                        finalUrl = "https://partner.steam-api.com/ISteamMicroTxn/FinalizeTxn/v2/";
                    }
                    string res = await GetHttpRequestToPostFormData(finalUrl, urlParams);
                    if (!string.IsNullOrEmpty(res))
                    {
                        var jsonResult = JsonConvert.DeserializeObject<JObject>(res);
                        var result = JsonConvert.DeserializeObject<JObject>(jsonResult["response"].ToString());
                        if (result["result"].ToString() == "OK")
                        {
                            //
                            //在这里可以添加你发放道具的代码了
                            //
                            ret = new { code = 0, msg = msg, data = "" };
                        }
                        else
                        {
                            ret = new { code = 2, msg = "Not Pay", data = "" };
                        }
                    }
                    else
                    {
                        ret = new { code = 1, msg = "Query Error", data = "" };
                    }
                }
                else
                {
                    ret = new { code = 5, msg = "Sign Error", data = "" };
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex.ToString());
                ret = new { code = 500, msg = "Server Error", data = "" };
            }
            return JsonConvert.SerializeObject(ret);
        }

到这里,整个内购充值流程就结束了。
总结了一下在接入过程中遇到的几种问题:
1、拉起支付页面必须要客户端打包上传到steam Workers后台,然后通过steam下载后运行才能唤起支付页面。
2、ISteamMicroTxnSandBox/FinalizeTxn接口返回User ‘xxxxxxxx’ is not logger in,一般是你请求参数中appid和web api key错误导致的,一定检查一下appid和客户端打包的appid是否一致!
3、唤起的支付授权界面会出现页面加载错误,或者样式啥的没加载出来,这个一般是网络问题,可以开vpn,或者下载一个网易UU加速器,里面有免费的Steam社区加速。

记录一下自己的学习记录。
接入steam,还是要把文档多读几遍!!!!

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值