[.NET Core] 使用 WebApiClient 获取小程序码

wxacode.getUnlimited

 

  1. 安装 WebApiClient.JIT 和 Microsoft.AspNetCore.Http
    Install-Package WebApiClient.JIT -Version 1.0.8
    Install-Package Microsoft.AspNetCore.Http -Version 2.1.1
    
  2. IAuthApi.cs
    /// <summary>
    /// 权限API
    /// </summary>
    public interface IAuthApi : IHttpApi
    {
        /// <summary>
        /// 获取小程序全局唯一后台接口调用凭据(access_token)
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpGet("https://api.weixin.qq.com/cgi-bin/token")]
        ITask<GetAccessTokenResponse> GetAccessToken(GetAccessTokenRequest request);
    }
    
    /// <summary>
    /// 获取小程序全局唯一后台接口调用凭据 参数
    /// </summary>
    public class GetAccessTokenRequest
    {
        /// <summary>
        /// 填写 client_credential
        /// </summary>
        [AliasAs("grant_type")]
        public string GrantType { get; set; } = "client_credential";
    
        /// <summary>
        /// 小程序唯一凭证,即 AppID
        /// </summary>
        [AliasAs("appid")]
        public string AppId { get; set; }
    
        /// <summary>
        /// 小程序唯一凭证密钥,即 AppSecret
        /// </summary>
        [AliasAs("secret")]
        public string Secret { get; set; }
    }
    
    /// <summary>
    /// 获取小程序全局唯一后台接口调用凭据 返回值
    /// </summary>
    public class GetAccessTokenResponse : WXBaseResponse
    {
        /// <summary>
        /// 接口调用凭证
        /// </summary>
        [AliasAs("access_token")]
        public string AccessToken { get; set; }
    
        /// <summary>
        /// 凭证有效时间,单位:秒。目前是7200秒之内的值。
        /// </summary>
        [AliasAs("expires_in")]
        public int ExpiresIn { get; set; }
    }
    
    /// <summary>
    /// 微信基础返回信息
    /// </summary>
    public class WXBaseResponse
    {
        /// <summary>
        /// 错误码:
        ///   -1 : 系统繁忙,此时请开发者稍候再试;
        ///   0 : 请求成功;
        ///   ... ...
        /// </summary>
        [AliasAs("errcode")]
        public int ErrCode { get; set; }
    
        /// <summary>
        /// 错误信息
        /// </summary>
        [AliasAs("errmsg")]
        public string ErrMsg { get; set; }
    }
    
  3. IWxacodeApi.cs

    因为 wxacode.getUnlimited 返回的类型可能是 Json 也可能是图片,所以这里返回值类型为 HttpResponseMessage 。

    /// <summary>
    /// 小程序码API
    /// </summary>
    public interface IWxacodeApi : IHttpApi
    {
        /// <summary>
        /// 获取小程序码,适用于需要的码数量极多的业务场景。通过该接口生成的小程序码,永久有效,数量暂无限制。
        /// </summary>
        /// <param name="request"></param>
        /// <param name="access_token"></param>
        /// <returns></returns>
        [HttpPost("https://api.weixin.qq.com/wxa/getwxacodeunlimit")]
        ITask<HttpResponseMessage> GetUnlimited([JsonContent] GetUnlimitedRequest request, [PathQuery] string access_token);
    }
    
    /// <summary>
    /// 获取小程序码 参数
    /// </summary>
    public class GetUnlimitedRequest
    {
        /// <summary>
        /// 参数 : 最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&amp;'()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式)
        /// </summary>
        [AliasAs("scene")]
        public string Scene { get; set; }
    
        /// <summary>
        /// 主页 : 必须是已经发布的小程序存在的页面(否则报错),例如 pages/index/index, 根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面
        /// </summary>
        [AliasAs("page")]
        public string Page { get; set; }
    
        /// <summary>
        /// 二维码的宽度,单位 px,最小 280px,最大 1280px
        /// </summary>
        [AliasAs("width")]
        public int width { get; set; } = 430;
    
        /// <summary>
        /// 接口调用凭证
        /// </summary>
        [AliasAs("auto_color")]
        public bool AutoColor { get; set; } = false;
    
        /// <summary>
        /// auto_color 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} 十进制表示
        /// </summary>
        [AliasAs("line_color")]
        public RGBColor LineColor { get; set; }
    
        /// <summary>
        /// 是否需要透明底色,为 true 时,生成透明底色的小程序
        /// </summary>
        [AliasAs("is_hyaline")]
        public bool IsHyaline { get; set; } = false;
    }
    
    /// <summary>
    /// RGB
    /// </summary>
    public class RGBColor
    {
        /// <summary>
        /// R
        /// </summary>
        [AliasAs("r")]
        public int R { get; set; }
    
        /// <summary>
        /// G
        /// </summary>
        [AliasAs("g")]
        public int G { get; set; }
    
        /// <summary>
        /// B
        /// </summary>
        [AliasAs("b")]
        public int B { get; set; }
    }    
    
  4. WXApiFactory.cs
    /// <summary>
    /// 微信API工厂类
    /// </summary>
    public class WXApiFactory
    {
        /// <summary>
        /// 注册API
        /// </summary>
        public static void Register()
        {
            // 权限API
            HttpApi.Register<IAuthApi>().ConfigureHttpApiConfig(c => { });
    
            // 小程序码API
            HttpApi.Register<IWxacodeApi>().ConfigureHttpApiConfig(c => { });
        }
    }
    
  5. ESSearchApiExtension.cs
    /// <summary>
    /// 微信 Api 扩展类
    /// </summary>
    public static class ESSearchApiExtension
    {
        /// <summary>
        /// 使用微信Api
        /// </summary>
        /// <param name="app"></param>
        public static void UseWXApi(this IApplicationBuilder app)
        {
            WXApiFactory.Register();
        }
    }
    
  6. Startup.cs
    /// <summary>
    /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    /// </summary>
    /// <param name="app"></param>
    /// <param name="env"></param>
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        // ...
    
        app.UseMvc();
    
        // ...
    
        // 使用微信API
        app.UseWXApi();
    }
    
  7. WXAccessTokenUtils.cs
    /// <summary>
    /// 微信接口调用凭证通用方法
    /// </summary>
    public class WXAccessTokenUtils
    {
        /// <summary>
        /// 刷新接口调用凭证
        /// </summary>
        /// <param name="appId"></param>
        public static async Task<GetAccessTokenResponse> RefreshAccessTokenAsync(string appId)
        {
            var response = await HttpApi.Resolve<IAuthApi>().GetAccessToken(new GetAccessTokenRequest()
            {
                AppId = appId,
                Secret = ZConfig.GetConfigString(ApolloConfigKey.AppSecret),
            });
    
            if (response.ErrCode == 0)
            {
                // 将接口调用凭据保存到缓存
                RedisUtil.Set($"{CacheKey.WXAccessTokenPrefix}_{appId}", new AccessTokenCacheModel()
                {
                    AccessToken = response.AccessToken,
                    ExpiresTime = DateTime.Now.AddSeconds(response.ExpiresIn),
                }, response.ExpiresIn / 60);
            }
    
            return response;
        }
    
        /// <summary>
        /// 获取接口调用凭证
        /// </summary>
        /// <param name="appId"></param>
        /// <returns></returns>
        public static async Task<string> GetAccessTokenAsync(string appId)
        {
            var cacheKey = $"{CacheKey.WXAccessTokenPrefix}_{appId}";
            // 将接口调用凭据保存到缓存
            var cachedAccessToken = RedisUtil.Get<AccessTokenCacheModel>(cacheKey);
    
            if (cachedAccessToken == null || cachedAccessToken.ExpiresTime < DateTime.Now)
            {
                // 没有缓存或凭证已过期时,刷新凭证
                var response = await RefreshAccessTokenAsync(appId);
                if (response != null && response.ErrCode == 0)
                {
                    return response.AccessToken;
                }
                else
                {
                    return string.Empty;
                }
            }
            else if(cachedAccessToken.ExpiresTime.AddMinutes(-5) < DateTime.Now)
            {
                // 即将过期时重新获取凭证
                var response = await RefreshAccessTokenAsync(appId);
                if (response != null && response.ErrCode != 0)
                {
                    return response.AccessToken;
                }
                else
                {
                    return cachedAccessToken.AccessToken;
                }
            }
    
            return cachedAccessToken.AccessToken;
        }
    }
    
  8. QRCodeController.cs

    失败时返回的是 Json 字符串,成功时返回的是图片的 buffer。
    这里通过返回消息的 ContentType 来判断是哪种类型。

    /// <summary>
    /// 获取小程序码
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    [HttpPost("wxacode-unlimited")]
    public async Task<Result> GetWXACodeUnlimited(GetUnlimitedRequest request)
    {
        var appId = ZConfig.GetConfigString(ApolloConfigKey.AppID);
        var accessToken = await WXAccessTokenUtils.GetAccessTokenAsync(appId);
    
        var responseMessage = await HttpApi.Resolve<IWxacodeApi>().GetUnlimited(request, accessToken);
        if (responseMessage == null || responseMessage.StatusCode != System.Net.HttpStatusCode.OK)
        {
            return new Result()
            {
                IsSuccess = false,
                Msg = "访问微信API异常",
            };
        }
        if (responseMessage.Content.Headers.ContentType.MediaType == "image/jpeg")
        {
            return new Result()
            {
                IsSuccess = true,
                Msg = Convert.ToBase64String(await responseMessage.Content.ReadAsByteArrayAsync()),
            };
        }
        else if (responseMessage.Content.Headers.ContentType.MediaType == "application/json")
        {
            var response = JsonHelper.DeserializeObject<WXBaseResponse>(await responseMessage.Content.ReadAsStringAsync());
            return new Result()
            {
                IsSuccess = false,
                Msg = response.ErrMsg,
            };
        }
    
        return new Result()
        {
            IsSuccess = false,
            Msg = "未处理的二维码类型,请联系客服。",
        };
    }
    
    /// <summary>
    /// 获取小程序码图片
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    [HttpPost("wxacode-unlimited-img")]
    public async Task GetWXACodeUnlimitedImage(GetUnlimitedRequest request)
    {
        var appId = ZConfig.GetConfigString(ApolloConfigKey.ZYXY_AppID);
        var accessToken = await WXAccessTokenUtils.GetAccessTokenAsync(appId);
        var responseMessage = await HttpApi.Resolve<IWxacodeApi>().GetUnlimited(request, accessToken);
    
        if (responseMessage != null
            && responseMessage.StatusCode == HttpStatusCode.OK
            && responseMessage.Content.Headers.ContentType.MediaType == "image/jpeg")
        {
            Response.Clear();
            Response.ContentType = responseMessage.Content.Headers.ContentType.MediaType;
            await Response.Body.WriteAsync(await responseMessage.Content.ReadAsByteArrayAsync());
            return;
        }
    
        Response.StatusCode = (int)HttpStatusCode.InternalServerError;
    }
    
  9. QRCode.wxml
    <image wx:if="{{result.isSuccess}}" src='data:image/jpeg;base64,{{result.msg}}' />
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值