为了更好地适应微信越来越快的API更新速度和越来越多的API数量,本次Senparc.Weixin.dll v4.3.3对一些通用功能进行了深度的重构。

  本次更新同时影响以下所有Senparc.Weixin相关版本的dll:

  • Senparc.Weixin.dll 升级到 v4.3.3
  • Senparc.Weixin.MP.dll 升级到 v13.3.0(重要)
  • Senparc.Weixin.MP.MvcExtension.dll 升级到 v1.4.1
  • Senparc.Weixin.Open 升级到 v1.4.1(重要)
  • Senparc.Weixin.QY.dll 升级到 v3.1.1(尚处内测中,近期发布,重要)

  下面详细介绍一下本次更新的内容,及小于上述版本的dll的项目升级方式(已经尽量确保方法的兼容性,基本上只需要批量替换)。

Senparc.Weixin.dll

  升级内容:

  1、为JSON字符串输出过程中,过滤值为null的属性,提供了解决方案。

  涉及到的文件如下图所示:

  其中:SerializerHelper.cs为升级,Conventers文件夹为新增的两个用于支持SerializerHelper的转换器。

  ExpandoJsonConverter.cs用于提供ExpandoObject类型到JSON字符串的转换:

/*----------------------------------------------------------------
Copyright (C) 2015 Senparc 文件名:ExpandoJsonConverter.cs
文件功能描述:Expando-JSON字符串转换 创建标识:Senparc - 20151002 ----------------------------------------------------------------*/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Web.Script.Serialization; namespace Senparc.Weixin.Helpers
{
/// <summary>
/// Allows JSON serialization of Expando objects into expected results (e.g., "x: 1, y: 2") instead of the default dictionary serialization.
/// </summary>
public class ExpandoJsonConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
// See source code link for this extension method at the bottom of this post (/Helpers/IDictionaryExtensions.cs)
return dictionary.ToExpando();
} public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
var result = new Dictionary<string, object>();
var dictionary = obj as IDictionary<string, object>;
foreach (var item in dictionary)
result.Add(item.Key, item.Value);
return result;
} public override IEnumerable<Type> SupportedTypes
{
get
{
return new ReadOnlyCollection<Type>(new Type[] { typeof(ExpandoObject) });
}
}
}
}

  WeixinJsonConventer.cs用于提供微信中部分字段为null时,整个属性都不输出的配置方法:

/*----------------------------------------------------------------
Copyright (C) 2015 Senparc 文件名:WeixinJsonConventer.cs
文件功能描述:微信JSON字符串转换 创建标识:Senparc - 20150930 ----------------------------------------------------------------*/ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Web.Script.Serialization;
using Senparc.Weixin.Entities; namespace Senparc.Weixin.Helpers
{
/// <summary>
/// JSON输出设置
/// </summary>
public class JsonSetting
{
/// <summary>
/// 是否忽略当前类型以及具有IJsonIgnoreNull接口,且为Null值的属性。如果为true,符合此条件的属性将不会出现在Json字符串中
/// </summary>
public bool IgnoreNulls { get; set; }
/// <summary>
/// 需要特殊忽略null值的属性名称
/// </summary>
public List<string> PropertiesToIgnore { get; set; }
/// <summary>
/// 指定类型(Class,非Interface)下的为null属性不生成到Json中
/// </summary>
public List<Type> TypesToIgnore { get; set; } /// <summary>
/// JSON输出设置 构造函数
/// </summary>
/// <param name="ignoreNulls">是否忽略当前类型以及具有IJsonIgnoreNull接口,且为Null值的属性。如果为true,符合此条件的属性将不会出现在Json字符串中</param>
/// <param name="propertiesToIgnore">需要特殊忽略null值的属性名称</param>
/// <param name="typesToIgnore">指定类型(Class,非Interface)下的为null属性不生成到Json中</param>
public JsonSetting(bool ignoreNulls = false, List<string> propertiesToIgnore = null, List<Type> typesToIgnore = null)
{
IgnoreNulls = ignoreNulls;
PropertiesToIgnore = propertiesToIgnore ?? new List<string>();
TypesToIgnore = typesToIgnore ?? new List<Type>();
}
} /// <summary>
/// 微信JSON转换器
/// </summary>
public class WeixinJsonConventer : JavaScriptConverter
{
private readonly JsonSetting _jsonSetting;
private readonly Type _type; public WeixinJsonConventer(Type type, JsonSetting jsonSetting = null)
{
this._jsonSetting = jsonSetting ?? new JsonSetting();
this._type = type;
} public override IEnumerable<Type> SupportedTypes
{
get
{
var typeList = new List<Type>(new[] { typeof(IJsonIgnoreNull)/*,typeof(JsonIgnoreNull)*/ }); if (_jsonSetting.TypesToIgnore.Count > )
{
typeList.AddRange(_jsonSetting.TypesToIgnore);
} if (_jsonSetting.IgnoreNulls)
{
typeList.Add(_type);
} return new ReadOnlyCollection<Type>(typeList);
}
} public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
var result = new Dictionary<string, object>();
if (obj == null)
{
return result;
} var properties = obj.GetType().GetProperties();
foreach (var propertyInfo in properties)
{
if (!this._jsonSetting.PropertiesToIgnore.Contains(propertyInfo.Name))
{
bool ignoreProp = propertyInfo.IsDefined(typeof(ScriptIgnoreAttribute), true); if ((this._jsonSetting.IgnoreNulls || ignoreProp) && propertyInfo.GetValue(obj, null) == null)
{
continue;
} result.Add(propertyInfo.Name, propertyInfo.GetValue(obj, null));
}
}
return result;
} public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
throw new NotImplementedException(); //Converter is currently only used for ignoring properties on serialization
}
}
}

  WeixinJsonConventer提供了多种过滤的方式:

  • 过滤当前数据对象类型(或任一指定类型)下,所有为null的属性(根据JsonSetting.IgnoreNulls配置)
  • 过滤当前数据对象类型(或任一指定类型)下,所有为null,且指定名称的属性(根据JsonSetting.PropertiesToIgnore配置)
  • 过滤指定类型下(可多个),所有为null的属性(根据JsonSetting.TypesToIgnore配置)
  • 过滤实现了IJsonIgnoreNull接口的类型下,,所有为null的属性(自动)

  以上通过配置或自动的过滤规则只要满足其中一条即被过滤)

  目前已经发现的需要过滤null的地方不多(猜测是微信的bug),通常情况下此方法不需要在SDK外部使用,目前SDK内部部分接口已经在使用,如创建卡券的接口:

         /// <summary>
/// 创建卡券
/// </summary>
/// <param name="accessTokenOrAppId"></param>
/// <param name="cardInfo">创建卡券需要的数据,格式可以看CardCreateData.cs</param>
/// <param name="timeOut">代理请求超时时间(毫秒)</param>
/// <returns></returns>
public static CardCreateResultJson CreateCard(string accessTokenOrAppId, BaseCardInfo cardInfo, int timeOut = Config.TIME_OUT)
{
return ApiHandlerWapper.TryCommonApi(accessToken =>
{
var urlFormat = string.Format("https://api.weixin.qq.com/card/create?access_token={0}", accessToken); CardCreateInfo cardData = null;
CardType cardType = cardInfo.GetCardType(); switch (cardType)
{
...
} var jsonSetting = new JsonSetting(true, null,
new List<Type>()
{
//typeof (Modify_Msg_Operation),
//typeof (CardCreateInfo),
typeof (Card_BaseInfoBase)//过滤Modify_Msg_Operation主要起作用的是这个
}); var result = CommonJsonSend.Send<CardCreateResultJson>(null, urlFormat, cardData, timeOut: timeOut,
//针对特殊字段的null值进行过滤
jsonSetting: jsonSetting);
return result; }, accessTokenOrAppId);
}

  第一步:定义JsonSetting,确定需要过滤的规则。

  第二步:将JsonSetting对象传入CommonJsonSend.Send()方法。

  2、增加Containers基础功能:用于作为其他子库中所有Container(如AccessTokenContainer)的基类,并提供配套的ContainerBag(信息包)基类。

  如下图所示:

  BaseContainerBag.cs 用于提供信息报的基类:

/*----------------------------------------------------------------
Copyright (C) 2015 Senparc 文件名:BaseContainerBag.cs
文件功能描述:微信容器接口中的封装Value(如Ticket、AccessToken等数据集合) 创建标识:Senparc - 20151003 ----------------------------------------------------------------*/ namespace Senparc.Weixin.Containers
{
/// <summary>
/// IBaseContainerBag
/// </summary>
public interface IBaseContainerBag
{
string Key { get; set; }
} /// <summary>
/// BaseContainer容器中的Value类型
/// </summary>
public class BaseContainerBag : IBaseContainerBag
{
/// <summary>
/// 通常为AppId
/// </summary>
public string Key { get; set; }
} }

  BaseContainer.cs用于提供所有Container容器的基类:

/*----------------------------------------------------------------
Copyright (C) 2015 Senparc 文件名:WeixinContainer.cs
文件功能描述:微信容器(如Ticket、AccessToken) 创建标识:Senparc - 20151003 ----------------------------------------------------------------*/ using System;
using System.Collections.Generic;
using System.Linq; namespace Senparc.Weixin.Containers
{
/// <summary>
/// 微信容器接口(如Ticket、AccessToken)
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class BaseContainer<T> where T : IBaseContainerBag, new()
{
/// <summary>
/// 所有数据集合的列表
/// </summary>
private static readonly Dictionary<Type, Dictionary<string, T>> _collectionList = new Dictionary<Type, Dictionary<string, T>>(); /// <summary>
/// 获取当前容器的数据项集合
/// </summary>
/// <returns></returns>
protected static Dictionary<string, T> ItemCollection
{
get
{
if (!_collectionList.ContainsKey(typeof(T)))
{
_collectionList[typeof(T)] = new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase);
}
return _collectionList[typeof(T)];
}
} /// <summary>
/// 获取完整的数据集合的列表(建议不要进行任何修改操作)
/// </summary>
/// <returns></returns>
public static Dictionary<Type, Dictionary<string, T>> GetCollectionList()
{
return _collectionList;
} /// <summary>
/// 获取所有容器内已经注册的项目
/// (此方法将会遍历Dictionary,当数据项很多的时候效率会明显降低)
/// </summary>
/// <returns></returns>
public static List<T> GetAllItems()
{
return ItemCollection.Select(z => z.Value).ToList();
} /// <summary>
/// 尝试获取某一项Bag
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static T TryGetItem(string key)
{
if (ItemCollection.ContainsKey(key))
{
return ItemCollection[key];
} return default(T);
} /// <summary>
/// 尝试获取某一项Bag中的具体某个属性
/// </summary>
/// <param name="key"></param>
/// <param name="property">具体某个属性</param>
/// <returns></returns>
public static K TryGetItem<K>(string key, Func<T, K> property)
{
if (ItemCollection.ContainsKey(key))
{
var item = ItemCollection[key];
return property(item);
}
return default(K);
} /// <summary>
/// 更新数据项
/// </summary>
/// <param name="key"></param>
/// <param name="value">为null时删除该项</param>
public static void Update(string key, T value)
{
if (value == null)
{
ItemCollection.Remove(key);
}
else
{
ItemCollection[key] = value;
}
} /// <summary>
/// 更新数据项
/// </summary>
/// <param name="key"></param>
/// <param name="partialUpdate">为null时删除该项</param>
public static void Update(string key, Action<T> partialUpdate)
{
if (partialUpdate == null)
{
ItemCollection.Remove(key);//移除对象
}
else
{
if (!ItemCollection.ContainsKey(key))
{
ItemCollection[key] = new T()
{
Key = key//确保这一项Key已经被记录
};
}
partialUpdate(ItemCollection[key]);//更新对象
}
} /// <summary>
/// 检查Key是否已经注册
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static bool CheckRegistered(string key)
{
return ItemCollection.ContainsKey(key);
}
}
}

  以上两个基类将被用于其他所有子库(MP、Open、QY等)的各种Container中,为其提供统一数据管理能力和集中的缓存存储支持。

  

Senparc.Weixin.MP.dll

  升级内容:

  1、删除JsApiTicketContainer,合并入AccessTokenContainer,同时以BaseContainer为基类重构AccessTokenContainer。

  之前我们需要这样分别注册两次AccessTokenContainer和JsApiTicketContainer,分别注册两个容器:

            //全局只需注册一次
AccessTokenContainer.Register(_appId, _appSecret); //全局只需注册一次
JsApiTicketContainer.Register(_appId, _appSecret);

  现在只需要第一行就行了:

            //全局只需注册一次
AccessTokenContainer.Register(_appId, _appSecret);

  随着JsApiTicketContainer的合并,AccessTokenContainer内部的方法名也进行了调整,具体如下:

原方法名称 现方法名称
AccessTokenContainer.Register() 不变
AccessTokenContainer.GetFirstOrDefaultAppId() 不变
AccessTokenContainer.TryGetToken() AccessTokenContainer.TryGetAccessToken()
AccessTokenContainer.GetToken() AccessTokenContainer.GetAccessToken()
AccessTokenContainer.GetTokenResult() AccessTokenContainer.GetAccessTokenResult()
JsApiTicketContainer.TryGetTicket() AccessTokenContainer.TryGetJsApiTicket()
JsApiTicketContainer.GetTicket() AccessTokenContainer.GetJsApiTicket()
8 JsApiTicketContainer.GetTicketResult() AccessTokenContainer.GetJsApiTicketResult()

  所有相关的升级只需要替换上述对应的方法名称即可,参数不需要变化。其中最常用的应该是#4和#7。

  升级方法:

  第一步:升级SDK(方法略,建议用nuget)

  第二步:编译。会出一些错,随便找到一个,如之前使用了AccessTokenContainer.GetToken()的方法,按Ctrl+F进行替换:

  第三步:替换完成、保存:

  对于JsApiTicketContainer相关的替换也参考以上步骤:

  2、对接口进行常规升级,包括JSON字符串过滤null值的处理。

Senparc.Weixin.MP.MvcExtension.dll

  升级内容:

  fixbug(重要)。

Senparc.Weixin.Open.dll

  升级内容:

  1、创建ComponentContainer。

  ComponentContainer是用于存放第三方平台信息的容器,Key为ComponentId,信息包为ComponentBag。

  ComponentContainer提供了所有第三方平台需要用到的缓存信息以及获取方法,包括:ComponentVerifyTicketPreAuthCodeAuthorizerAccessToken

  其中PreAuthCode相关的对象由原来的PreAuthCodeContainer合并而来,PreAuthCodeContainer现已删除(升级方法参考Senparc.Weixin.MP的JsApiTicketContainer)。

  ComponentContainer.cs代码如下:

 /*----------------------------------------------------------------
Copyright (C) 2015 Senparc 文件名:ComponentContainer.cs
文件功能描述:通用接口ComponentAccessToken容器,用于自动管理ComponentAccessToken,如果过期会重新获取 创建标识:Senparc - 20150430 修改标识:Senparc - 20151004
修改描述:v1.4.1 改名为ComponentContainer.cs,合并多个ComponentApp相关容器 ----------------------------------------------------------------*/ using System;
using Senparc.Weixin.Containers;
using Senparc.Weixin.Exceptions;
using Senparc.Weixin.Open.Entities;
using Senparc.Weixin.Open.Exceptions; namespace Senparc.Weixin.Open.CommonAPIs
{
/// <summary>
/// 第三方APP信息包
/// </summary>
public class ComponentBag : BaseContainerBag
{
/// <summary>
/// 第三方平台AppId
/// </summary>
public string ComponentAppId { get; set; }
/// <summary>
/// 第三方平台AppSecret
/// </summary>
public string ComponentAppSecret { get; set; } /// <summary>
/// 第三方平台ComponentVerifyTicket(每隔10分钟微信会主动推送到服务器,IP必须在白名单内)
/// </summary>
public string ComponentVerifyTicket { get; set; } /// <summary>
/// ComponentAccessTokenResult
/// </summary>
public ComponentAccessTokenResult ComponentAccessTokenResult { get; set; }
/// <summary>
/// ComponentAccessToken过期时间
/// </summary>
public DateTime ComponentAccessTokenExpireTime { get; set; } /// <summary>
/// PreAuthCodeResult 预授权码结果
/// </summary>
public PreAuthCodeResult PreAuthCodeResult { get; set; }
/// <summary>
/// 预授权码过期时间
/// </summary>
public DateTime PreAuthCodeExpireTime { get; set; } public string AuthorizerAccessToken { get; set; } /// <summary>
/// 只针对这个AppId的锁
/// </summary>
public object Lock = new object(); /// <summary>
/// ComponentBag
/// </summary>
public ComponentBag()
{
ComponentAccessTokenResult = new ComponentAccessTokenResult();
ComponentAccessTokenExpireTime = DateTime.MinValue; PreAuthCodeResult = new PreAuthCodeResult();
PreAuthCodeExpireTime = DateTime.MaxValue;
}
} /// <summary>
/// 通用接口ComponentAccessToken容器,用于自动管理ComponentAccessToken,如果过期会重新获取
/// </summary>
public class ComponentContainer : BaseContainer<ComponentBag>
{
private const string UN_REGISTER_ALERT = "此appId尚未注册,ComponentContainer.Register完成注册(全局执行一次即可)!"; /// <summary>
/// 检查AppId是否已经注册,如果没有,则创建
/// </summary>
/// <param name="componentAppId"></param>
/// <param name="componentAppSecret"></param>
/// <param name="getNewToken"></param>
private static void TryRegister(string componentAppId, string componentAppSecret, bool getNewToken = false)
{
if (!CheckRegistered(componentAppId) || getNewToken)
{
Register(componentAppId, componentAppSecret, null);
}
} /// <summary>
/// 获取ComponentVerifyTicket的方法
/// </summary>
public static Func<string> GetComponentVerifyTicketFunc = null; /// <summary>
/// 注册应用凭证信息,此操作只是注册,不会马上获取Token,并将清空之前的Token,
/// </summary>
/// <param name="componentAppId"></param>
/// <param name="componentAppSecret"></param>
/// <param name="getComponentVerifyTicketFunc">获取ComponentVerifyTicket的方法</param>
public static void Register(string componentAppId, string componentAppSecret, Func<string> getComponentVerifyTicketFunc)
{
if (GetComponentVerifyTicketFunc == null)
{
GetComponentVerifyTicketFunc = getComponentVerifyTicketFunc;
} Update(componentAppId, new ComponentBag()
{
ComponentAppId = componentAppId,
ComponentAppSecret = componentAppSecret,
});
} /// <summary>
/// 检查是否已经注册
/// </summary>
/// <param name="componentAppId"></param>
/// <returns></returns>
public static bool CheckRegistered(string componentAppId)
{
return ItemCollection.ContainsKey(componentAppId);
} #region component_verify_ticket /// <summary>
/// 获取ComponentVerifyTicket
/// </summary>
/// <param name="componentAppId"></param>
/// <returns>如果不存在,则返回null</returns>
public static string TryGetComponentVerifyTicket(string componentAppId)
{
if (!CheckRegistered(componentAppId))
{
throw new WeixinOpenException(UN_REGISTER_ALERT);
} var componentVerifyTicket = TryGetItem(componentAppId, bag => bag.ComponentVerifyTicket);
if (componentVerifyTicket == default(string))
{
if (GetComponentVerifyTicketFunc == null)
{
throw new WeixinOpenException("GetComponentVerifyTicketFunc必须在注册时提供!", TryGetItem(componentAppId));
}
componentVerifyTicket = GetComponentVerifyTicketFunc(); //获取最新的componentVerifyTicket
}
return componentVerifyTicket;
} /// <summary>
/// 更新ComponentVerifyTicket信息
/// </summary>
/// <param name="componentAppId"></param>
/// <param name="componentVerifyTicket"></param>
public static void UpdateComponentVerifyTicket(string componentAppId, string componentVerifyTicket)
{
Update(componentAppId, bag =>
{
bag.ComponentVerifyTicket = componentVerifyTicket;
});
} #endregion #region component_access_token /// <summary>
/// 使用完整的应用凭证获取Token,如果不存在将自动注册
/// </summary>
/// <param name="componentAppId"></param>
/// <param name="componentAppSecret"></param>
/// <param name="getNewToken"></param>
/// <returns></returns>
public static string TryGetComponentAccessToken(string componentAppId, string componentAppSecret, bool getNewToken = false)
{
TryRegister(componentAppId, componentAppSecret, getNewToken);
return GetComponentAccessToken(componentAppId);
} /// <summary>
/// 获取可用AccessToken
/// </summary>
/// <param name="componentAppId"></param>
/// <param name="getNewToken">是否强制重新获取新的Token</param>
/// <returns></returns>
public static string GetComponentAccessToken(string componentAppId, bool getNewToken = false)
{
return GetComponentAccessTokenResult(componentAppId, getNewToken).component_access_token;
} /// <summary>
/// 获取可用AccessToken
/// </summary>
/// <param name="componentAppId"></param>
/// <param name="getNewToken">是否强制重新获取新的Token</param>
/// <returns></returns>
public static ComponentAccessTokenResult GetComponentAccessTokenResult(string componentAppId, bool getNewToken = false)
{
if (!CheckRegistered(componentAppId))
{
throw new WeixinOpenException(UN_REGISTER_ALERT);
} var accessTokenBag = ItemCollection[componentAppId];
lock (accessTokenBag.Lock)
{
if (getNewToken || accessTokenBag.ComponentAccessTokenExpireTime <= DateTime.Now)
{
//已过期,重新获取
var componentVerifyTicket = TryGetComponentVerifyTicket(componentAppId); accessTokenBag.ComponentAccessTokenResult = CommonApi.GetComponentAccessToken(accessTokenBag.ComponentAppId, accessTokenBag.ComponentAppSecret, componentVerifyTicket); accessTokenBag.ComponentAccessTokenExpireTime = DateTime.Now.AddSeconds(accessTokenBag.ComponentAccessTokenResult.expires_in);
}
}
return accessTokenBag.ComponentAccessTokenResult;
}
#endregion #region pre_auth_code /// <summary>
/// 使用完整的应用凭证获取Token,如果不存在将自动注册
/// </summary>
/// <param name="componentAppId"></param>
/// <param name="componentAppSecret"></param>
/// <param name="componentVerifyTicket"></param>
/// <param name="getNewToken"></param>
/// <returns></returns>
public static string TryGetPreAuthCode(string componentAppId, string componentAppSecret, string componentVerifyTicket, bool getNewToken = false)
{
TryRegister(componentAppId, componentAppSecret, getNewToken);
return GetGetPreAuthCode(componentAppId);
} /// <summary>
/// 获取可用Token
/// </summary>
/// <param name="componentAppId"></param>
/// <param name="getNewToken">是否强制重新获取新的Token</param>
/// <returns></returns>
public static string GetGetPreAuthCode(string componentAppId, bool getNewToken = false)
{
return GetPreAuthCodeResult(componentAppId, getNewToken).pre_auth_code;
} /// <summary>
/// 获取可用Token
/// </summary>
/// <param name="componentAppId"></param>
/// <param name="getNewToken">是否强制重新获取新的Token</param>
/// <returns></returns>
public static PreAuthCodeResult GetPreAuthCodeResult(string componentAppId, bool getNewToken = false)
{
if (!CheckRegistered(componentAppId))
{
throw new WeixinOpenException(UN_REGISTER_ALERT);
} var accessTokenBag = ItemCollection[componentAppId];
lock (accessTokenBag.Lock)
{
if (getNewToken || accessTokenBag.PreAuthCodeExpireTime <= DateTime.Now)
{
//已过期,重新获取
var componentVerifyTicket = TryGetComponentVerifyTicket(componentAppId); accessTokenBag.PreAuthCodeResult = CommonApi.GetPreAuthCode(accessTokenBag.ComponentAppId, accessTokenBag.ComponentAppSecret, componentVerifyTicket); accessTokenBag.PreAuthCodeExpireTime = DateTime.Now.AddSeconds(accessTokenBag.PreAuthCodeResult.expires_in);
}
}
return accessTokenBag.PreAuthCodeResult;
}
#endregion }
}

  在第一次使用ComponentContainer之前,和诸如AccessTokenContainer一样,需要进行一次全局的注册:

//全局只需注册一次
ComponentContainer.Register(componentAppId, componentAppSecret,
_componentAppId =>{
//获取ComponentVerifyTicket的方法,通常是从数据库或者日志文件中获取
});

  注意在上面的方法中,最后一个参数是getComponentVerifyTicketFunc,里面需要写入用于获取ComponentVerifyTicket的方法,通常是从数据库或者日志文件中获取(微信每10分钟会推送一次最新的ComponentVerifyTicket到第三方服务器)。

  下面是一种可能的实现:

             //注册第三方平台
//定义ComponentVerifyTicketFunc
Func<string, string> getComponentVerifyTicketFunc = componentAppId =>
{
var file = Core.Utility.Server.GetMapPath(
"~/App_Data/OpenTicket/ComponentVerifyTicket/{0}.txt".With(componentAppId));
using (var fs = new FileStream(file, FileMode.Open))
{
using (var sr = new StreamReader(fs))
{
var ticket = sr.ReadToEnd();
return ticket;
}
}
};
//执行注册
ComponentContainer.Register(
ConfigurationManager.AppSettings["Component_Appid"],
ConfigurationManager.AppSettings["Component_Secret"], getComponentVerifyTicketFunc);

  2、创建AuthorizerContainer

  AuthorizerContainer负责储存单个授权方(微信公众号)所有相关的信息,包括:AuthorizerInfoResultJsApiTicketResult

  其中JsApiTicketResult相关的对象由原来的JsApiTicketContainer合并而来,JsApiTicketContainer现已删除(升级方法参考Senparc.Weixin.MP的JsApiTicketContainer)。

  经常可能需要用到的AuthorizerInfoAuthorizerInfo_AuthorizationInfo都在AuthorizerInfoResult对象内。

  注意:AuthorizerContainer不需要外部执行Register()方法。因为它是依赖于ComponentContainer的,所以在执行AuthorizerContainer相关方法之前,请确保已经对ComponentContainer进行注册。

  3、增加WeixinOpenException异常类型,用于捕捉更加精确的Senaprc.Weixin.Open相关的异常。

 /*----------------------------------------------------------------
Copyright (C) 2015 Senparc 文件名:WeixinOpenException.cs
文件功能描述:微信开放平台异常处理类 创建标识:Senparc - 20151004 ----------------------------------------------------------------*/ using System;
using Senparc.Weixin.Exceptions;
using Senparc.Weixin.Open.CommonAPIs; namespace Senparc.Weixin.Open.Exceptions
{
public class WeixinOpenException : WeixinException
{
public ComponentBag ComponentBag { get; set; } public WeixinOpenException(string message, ComponentBag componentBag = null, Exception inner=null)
: base(message, inner)
{
ComponentBag = ComponentBag;
}
}
}

Senparc.Weixin.QY.dll

  升级内容(尚未正式发布):

  1、重构Container。

  2、完善接口。

  整个升级过程尽量确保了最小幅度的改动,之前版本的其他接口功能都不受影响,更多教程见:

 

【重要更新】Senparc.Weixin SDK v4.3.3升级说明的更多相关文章

  1. 【重要更新】Senparc.Weixin SDK v4.4 升级说明

    本次更新同时影响以下所有Senparc.Weixin相关版本的dll: Senparc.Weixin.dll 升级到 v4.4.2(重要) Senparc.Weixin.MP.dll 升级到 v13. ...

  2. Senparc.Weixin SDK 微信公众号 .NET 开发教程 索引

    Senparc.WeixinSDK从一开始就坚持开源的状态,这个过程中得到了许多朋友的认可和支持. 目前SDK已经达到比较稳定的版本,这个过程中我觉得有必要整理一些思路和经验,和大家一起分享.也欢迎大 ...

  3. 【重要更新】Senparc.Weixin SDK v6.5 升级说明(支持 .NET Core 3.0 及分布式消息上下文)

    Senparc.Weixin SDK v6.5 开始支持 .NET Core 3.0,并将微信消息上下文进行了大幅度的重构,支持了使用分布式缓存存储上下文信息,这意味着在分布式系统中,现在 Senpa ...

  4. Senparc.Weixin SDK v5.0 升级公告

    经过五年半的持续维护,Senparc.Weixin SDK 逐步丰满和完善,在升级的过程中,我们为基础库(Senparc.Weixin.dll)加入了许多通用的功能,例如加密/解密算法.通用缓存方法等 ...

  5. 利用Senparc.Weixin SDK 实现微信用户的授权,并获取信息

    前一段时间在学校做过一个项目,就是利用的Senparc.Weixin SDK 做的,于是翻看以前代码,虽然有注释,但是还是看的迷迷糊糊的,干脆就单步执行一遍看看是怎么实现的,然后就重新写了个简易的授权 ...

  6. [公告]Senparc.Weixin.MP v14.2.1 升级说明

    在Senparc.Weixin.MP v14.2.1中,所有Senparc.Weixin.MP下的Container,命名空间已经从 Senparc.Weixin.MP.CommonAPIs 改为了  ...

  7. 如何使用Senparc.Weixin SDK 底层的Redis缓存并设置过期时间

    最近在微信第三方平台项目开发中,有一个需求,所有绑定的公众号的回复规则按照主公众号的关键词配置来处理,我的处理思路是获取主公众号配置的关键词回复规则,缓存10分钟,由于需要使用Redis缓存来存储一些 ...

  8. 微信公众账号 Senparc.Weixin.MP SDK 开发教程 索引

    Senparc.Weixin.MP SDK从一开始就坚持开源的状态,这个过程中得到了许多朋友的认可和支持. 目前SDK已经达到比较稳定的版本,这个过程中我觉得有必要整理一些思路和经验,和大家一起分享. ...

  9. 微信公众平台C# SDK:Senparc.Weixin.MP.dll

    https://github.com/Senparc/WeiXinMPSDK [转] http://www.cnblogs.com/szw/archive/2013/01/13/senparc-wei ...

随机推荐

  1. select制作分层级目录,让select显示和可下拉选择的"不一样"

    今天遇到一个特殊的select问题,需求是这样的:每次点击这个select时,根据选择的option的值做出相应的处理并返回新的select,option内容.所以大致思路是给这个select绑定ch ...

  2. MvcPager 免费开源分页控件3.0版发布!

    MvcPager 3.0版在原2.0版的基础上进行了较大的升级,对MvcPager脚本插件重写并进行了大量优化.修复了部分bug并新增了客户端Javascript API等功能,使用更方便,功能更强大 ...

  3. C# "=="、Equals()、ReferenceEquals()区别

    对于值类型: ; ; 1.== 比较的是值内容 2.age2.Equals(age1) = false; Equals比较前需要转换成同类型,age1(int型)需显示转换成byte型 3.age1. ...

  4. 站内信对话列表sql语句

  5. select值的获取及修改

    例子: <select id="a" name="a"> <options value="1">a</opti ...

  6. MATLAB 画出三个通信小区cell边界示意图

    d=1000; %两个小区中心间距离的一半 rcell=2*d/sqrt(3); %小区半径 ncell=3; %小区个数 cellposition=zeros(ncell,2); %初始化小区中心位 ...

  7. Android广播大全

    1.String ADD_SHORTCUT_ACTION 动作:在系统中添加一个快捷方式. 2.String ALL_APPS_ACTION 动作:列举所有可用的应用.输入:无. 3.String A ...

  8. 解决Canvas.toDataURL 图片跨域问题

    如题,在将页面的图片地址进行本地输出时(Html2Canvas.js),因不同源存在跨域问题,会出现toDataURL访问权限问题: [Redirect at origin 'http://sub1. ...

  9. Vertica数据查询优化

    vertica是惠普公司推出的列式分布式数据库,在OLAP领域有其独到的地方,目前社区版免费,但是只能存放1T的数据.我在工作中维护的bi系统后端就是使用的vertica数据库,平时也经常需要对于数据 ...

  10. JS中可拖拽的甘特图和流程图

    甘特图: https://www.douban.com/note/441706674/ https://www.uedsc.com/jquery-ganttview.html https://gith ...