皇冠新现金官网 > 皇冠官网 > 都可以直接调用基于JSON数据格式的WebAPI接口,在微信开发框架中
都可以直接调用基于JSON数据格式的WebAPI接口,在微信开发框架中
2020-01-04 103

 在我们的很多框架或者项目应用中,缓存在一定程度上可以提高程序的响应速度,以及减轻服务器的承载压力,因此在一些地方我们都考虑引入缓存模块,这篇随笔介绍使用开源缓存框架CacheManager来实现数据的缓存,在微信开发框架中,我们有一些常用的处理也需要应用到缓存,因此本随笔以微信框架为例介绍缓存的实际使用,实际上,在我们很多框架中,如混合式开发框架、Web开发框架、Bootstrap开发框架中,这个模块都是通用的。

在微信开发中,我一直强调需要建立一个比较统一的WebAPI接口体系,以便实现数据的集中化,这样我们在常规的Web业务系统,Winform业务系统、微信应用、微信小程序、APP等方面,都可以直接调用基于JSON数据格式的WebAPI接口,在我之前的几篇随笔中,对这方面都有一定的介绍,本篇继续这个主题,细致深入的阐述如何在接口和源码的基础上整合Web API、微信后台管理及前端微信小程序的应用方案。

1、框架的缓存设计

在我们的微信开发框架中,缓存作为数据库和对外接口之间的一个分层,提供数据的缓存响应处理,如下结构所示是Web API层对缓存的架构设计。

图片 1

图片 2

在缓存的处理中,我侧重于使用CacheManager,这个缓存框架是一个集大成者,关于CacheManager 的介绍,我们可以回顾下我之前的随笔《.NET缓存框架CacheManager在混合式开发框架中的应用(1)-CacheManager的介绍和使用》。

CacheManager是一个以C#语言开发的开源.Net缓存框架抽象层。它不是具体的缓存实现,但它支持多种缓存提供者(如Redis、Memcached等)并提供很多高级特性。
CacheManager 主要的目的使开发者更容易处理各种复杂的缓存场景,使用CacheManager可以实现多层的缓存,让进程内缓存在分布式缓存之前,且仅需几行代码来处理。
CacheManager 不仅仅是一个接口去统一不同缓存提供者的编程模型,它使我们在一个项目里面改变缓存策略变得非常容易,同时也提供更多的特性:如缓存同步、并发更新、序列号、事件处理、性能计算等等,开发人员可以在需要的时候选择这些特性。

CacheManager的GitHub源码地址为:,如果需要具体的Demo及说明,可以访问其官网:http://cachemanager.michaco.net

 

1、基于WebAPI的微信开发框架

首先我们各个业务模块,都应该围绕着WebAPI进行展开,如果是都部署在同一个服务器或者局域网内的系统,考虑到开发的复杂性,退而求其次,也可以基于同一个数据库进行开发。

总体而言,我们是以Web API为核心进行的应用框架构建的,如下图所示。

图片 3

图片 4

图片 5

在项目场景中,我们这里的微信后台管理系统,是一个独立维护微信后台数据的管理系统,对于操作微信相关API所需要的接口调用凭证,我们可以通过WebAPI接口获得,这样保证各个平台(如Winform界面、其他Web界面),操作的接口token都保持一致

图片 6

而后台管理系统,我们通过下面的来了解整体功能,整个后台管理系统使用了Bootstrap的框架进行前端处理。

图片 7

2、在微信框架中整合CacheManager 缓存框架

在使用CacheManager 缓存的时候,我们可以直接使用相关对象进行处理,首先需要定义一个类来进行初始化缓存的设置,然后进行调用,调用的时候可以使用IOC的方式构建对象,如下代码所示创建一个自定义的缓存管理类

    /// <summary>
    /// 基于CacheManager的接口处理
    /// </summary>
    public class CacheManager : ICacheManager
    {
        /// <summary>
        /// ICacheManager对象
        /// </summary>
        public ICacheManager<object> Manager { get; set; }

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public CacheManager()
        {
            // 初始化缓存管理器
            Manager = CacheFactory.Build("getStartedCache", settings =>
            {
                settings
                .WithSystemRuntimeCacheHandle("handleName")
                .And
                .WithRedisConfiguration("redis", config =>
                {
                    config.WithAllowAdmin()
                        .WithDatabase(0)
                        .WithEndpoint("localhost", 6379);
                })
                .WithMaxRetries(100)
                .WithRetryTimeout(50)
                .WithRedisBackplane("redis")
                .WithRedisCacheHandle("redis", true)
                ;
            });
        }
    }
}

然后在Autofac的配置文件中配置缓存的相关信息,如下文件所示。

图片 8

如果直接使用Autofac的构造类来处理,那么调用缓存处理的代码如下所示。

            //通过AutoFac工厂获取对应的接口实现
            var cache = AutoFactory.Instatnce.Container.Resolve<ICacheManager>();
            if (cache != null)
            {
                accountInfo = cache.Manager.Get(key) as AccountInfo;
                if (accountInfo == null)
                {
                    var value = BLLFactory<Account>.Instance.FindByID(accountId);
                    var item = new CacheItem<object>(key, value, ExpirationMode.Absolute, TimeSpan.FromMinutes(TimeOut_Minutes));
                    cache.Manager.Put(item);

                    accountInfo = cache.Manager.Get(key) as AccountInfo;
                }
            } 

 

如果为了使用方便,我们还可以对这个辅助类进行进一步的封装,以便对它进行统一的调用处理即可。

    /// <summary>
    /// 基于.NET CacheManager的缓存管理,文档参考:http://cachemanager.michaco.net/documentation
    /// </summary>
    public class CacheManagerHelper
    {
        /// <summary>
        /// 锁定处理变量
        /// </summary>
        private static readonly object locker = new object();

        /// <summary>
        /// 创建一个缓存的键值,并指定响应的时间范围,如果失效,则自动获取对应的值
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="key">对象的键</param>
        /// <param name="cachePopulate">获取缓存值的操作</param>
        /// <param name="expiration">失效的时间范围</param>
        /// <param name="mode">失效类型</param>
        /// <returns></returns>
        public static T GetCacheItem<T>(string key, Func<T> cachePopulate, TimeSpan expiration, 
            string region = "_", ExpirationMode mode = ExpirationMode.Sliding) where T :class 
        {
            CacheItem<object> outItem = null;
            //通过AutoFac工厂获取对应的接口实现
            var cache = AutoFactory.Instatnce.Container.Resolve<ICacheManager>();
            if (cache != null)
            {
                if (cache.Manager.Get(key, region) == null)
                {
                    lock (locker)
                    {
                        if (cache.Manager.Get(key, region) == null)
                        {
                            //Add、Put差异,Add只有在空值的情况下执行加入并返回true,Put总会替换并返回True
                            //如果按下面的方式加入,那么会留下历史丢弃的键值: cache.Manager.Put(key, value);

                            var value = cachePopulate();
                            var item = new CacheItem<object>(key, region, value, mode, expiration);
                            cache.Manager.Put(item);
                        }
                    }
                }

                return cache.Manager.Get(key, region) as T;
            }
            else
            {                
                throw new ArgumentNullException("AutoFac配置参数错误,请检查autofac.config是否存在ICacheManager的定义");
            }
        }
    }

不过由于官方已经提供了一个类似上面的代码逻辑的TryGetOrAdd方法,这个方法的定义如下所示。

2、整合Web API、微信后台管理及前端微信小程序应用

首先我们在WebAPI平台上,创建一个AccountController的MVC控制器来提供对应的API接口,实现对账号相关的信息查询,接口访问凭证的获取等业务。

    /// <summary>    /// 微信公众号、小程序、企业号的账号配置    /// </summary>    public class AccountController : BusinessController<Account, AccountInfo>

然后增加获取token的方法

        /// <summary>        /// 获取公众号/企业号/小程序操作的访问令牌AccessToken        /// </summary>        /// <param name="accountId">账号ID</param>        /// <returns></returns>        [HttpGet]        public string GetAccessTokenByAccount(string accountId)        {            var result = MyMemoryCache.GetAccessTokenByAccount(accountId);            return result;        }

这个token的生成,是存储在内存缓存里面的,定期刷新的,这样我们可以避免频繁的请求接口凭证token,可以统一生成给各个业务系统使用 。

        /// <summary>        /// 获取公众号操作的访问令牌AccessToken        /// </summary>        /// <param name="accountId">账号ID</param>        /// <returns></returns>        public static string GetAccessTokenByAccount(string accountId)        {            var key = string.Format("{0}_{1}", System.Reflection.MethodBase.GetCurrentMethod().Name, accountId);            var token = MemoryCacheHelper.GetCacheItem<string>(key, delegate()            {                string result = "";                AccountInfo info = MyMemoryCache.GetAccountByID(accountId);                if (info != null)                {                    if (info.AccountType == AccountType.企业号.ToString                    {                        // 获取微信企业号操作的访问令牌AccessToken                        ICorpBasicApi baseBLL = new CorpBasicApi();                        result = baseBLL.GetAccessToken(info.CorpID, info.CorpSecret);                    }                    else                    {                        //小程序、订阅号、服务器号共享一个逻辑                        // 获取微信操作的访问令牌AccessToken                        WHC.Weixin.Interface.IBasicApi baseBLL = new WHC.Weixin.API.BasicApi();                        result = baseBLL.GetAccessToken(info.AppID, info.AppSecret);                    }                }                return result;            },               new TimeSpan(0, 5, 0)//5分钟过期           );                        return token;        }

解决了token的统一生成和存储外,我们就可以在各个不同的系统中使用这个token接口获取并使用来操作微信对应接口了。

                //客户端调试和服务端应用统一采用一个AccessToken的方式                //避免客户端测试的时候,替换更新了服务端的AccessToken,从而导致服务端的AccessToken无效。                HttpHelper helper = new HttpHelper();                var tokenWebSiteUrl = string.Format("https://www.youdomain.com/api/Framework/Account/GetAccessTokenByAccount?accountId={0}", accountId);                var result = helper.GetHtml(tokenWebSiteUrl);                if(!string.IsNullOrEmpty                {                    result = result.Trim('"');                }                Console.WriteLine("通过Web API 获取到的Token为:" + result);                this.token = result;

关于微信后台管理系统,这个是对微信相关数据,如账号配置、菜单、事件、权限控制、业务数据定义等方面的综合管理,通过基于Bootstrap的MVC的技术进行Web端的数据维护,如下界面所示。

系统登录后,通过水平菜单进行后台功能管理。

图片 9

系统支持多微信账号的接入管理和使用,同时支持订阅号、公众号、企业号、小程序的账号配置。

图片 10

在系统中管理菜单,并通过把菜单提交到服务器上,实现菜单的动态配置和生成,能够为我们系统适应各种的需要,实现灵活的处理。

图片 11

在微信服务账号的门户上,菜单的表现效果如下所示。

图片 12

为了更有效管理订阅用户以及分组信息,我们可以从微信服务器上获取相关的信息,供我们了解关注的用户信息,也可以为后续的群发消息做准备。

图片 13

基于Bootstrap的Web前端,我们处理H5页面起来也是得心应手,非常方便。

在我前面的一些案例中,都利用了We UI样式来进行很多微信H5页面的功能设计,包括微信支付页面、签到页面等等。如微信支付页面如下所示:

图片 14图片 15图片 16

以及签到页面效果如下所示。

图片 17图片 18

基于微信的H5页面,我们后台管理系统整合了一个实际的设备维修案例的微信应用场景,该需求主要围绕固定资产的微信应用展开,包括录入及查询资产信息、资产盘点、设备的维修保养、日常巡检、维修、计量检测等事务。

整个案例微信端应用采用的是H5页面以及微信的JSDK进行相关的接口开发,符合微信的界面风格。后端管理就是本后台管理系统。

图片 19图片 20

TryGetOrAdd(String, String, Func<String, String, TCacheValue>, out TCacheValue)

Tries to either retrieve an existing item or add the item to the cache if it does not exist. The valueFactory will be evaluated only if the item does not exist.

 

图片 21图片 22

设备盘点和设备计量如下所示:

图片 23

预防性维护和设备计量界面如下所示。

图片 24