【重要更新】Senparc.Weixin SDK v4.3.3升级说明
为了更好地适应微信越来越快的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内部的方法名也进行了调整,具体如下:
# | 原方法名称 | 现方法名称 |
1 | AccessTokenContainer.Register() | 不变 |
2 | AccessTokenContainer.GetFirstOrDefaultAppId() | 不变 |
3 | AccessTokenContainer.TryGetToken() | AccessTokenContainer.TryGetAccessToken() |
4 | AccessTokenContainer.GetToken() | AccessTokenContainer.GetAccessToken() |
5 | AccessTokenContainer.GetTokenResult() | AccessTokenContainer.GetAccessTokenResult() |
6 | JsApiTicketContainer.TryGetTicket() | AccessTokenContainer.TryGetJsApiTicket() |
7 | 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提供了所有第三方平台需要用到的缓存信息以及获取方法,包括:ComponentVerifyTicket、PreAuthCode、AuthorizerAccessToken。
其中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负责储存单个授权方(微信公众号)所有相关的信息,包括:AuthorizerInfoResult、JsApiTicketResult。
其中JsApiTicketResult相关的对象由原来的JsApiTicketContainer合并而来,JsApiTicketContainer现已删除(升级方法参考Senparc.Weixin.MP的JsApiTicketContainer)。
经常可能需要用到的AuthorizerInfo和AuthorizerInfo_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升级说明的更多相关文章
- 【重要更新】Senparc.Weixin SDK v4.4 升级说明
本次更新同时影响以下所有Senparc.Weixin相关版本的dll: Senparc.Weixin.dll 升级到 v4.4.2(重要) Senparc.Weixin.MP.dll 升级到 v13. ...
- Senparc.Weixin SDK 微信公众号 .NET 开发教程 索引
Senparc.WeixinSDK从一开始就坚持开源的状态,这个过程中得到了许多朋友的认可和支持. 目前SDK已经达到比较稳定的版本,这个过程中我觉得有必要整理一些思路和经验,和大家一起分享.也欢迎大 ...
- 【重要更新】Senparc.Weixin SDK v6.5 升级说明(支持 .NET Core 3.0 及分布式消息上下文)
Senparc.Weixin SDK v6.5 开始支持 .NET Core 3.0,并将微信消息上下文进行了大幅度的重构,支持了使用分布式缓存存储上下文信息,这意味着在分布式系统中,现在 Senpa ...
- Senparc.Weixin SDK v5.0 升级公告
经过五年半的持续维护,Senparc.Weixin SDK 逐步丰满和完善,在升级的过程中,我们为基础库(Senparc.Weixin.dll)加入了许多通用的功能,例如加密/解密算法.通用缓存方法等 ...
- 利用Senparc.Weixin SDK 实现微信用户的授权,并获取信息
前一段时间在学校做过一个项目,就是利用的Senparc.Weixin SDK 做的,于是翻看以前代码,虽然有注释,但是还是看的迷迷糊糊的,干脆就单步执行一遍看看是怎么实现的,然后就重新写了个简易的授权 ...
- [公告]Senparc.Weixin.MP v14.2.1 升级说明
在Senparc.Weixin.MP v14.2.1中,所有Senparc.Weixin.MP下的Container,命名空间已经从 Senparc.Weixin.MP.CommonAPIs 改为了 ...
- 如何使用Senparc.Weixin SDK 底层的Redis缓存并设置过期时间
最近在微信第三方平台项目开发中,有一个需求,所有绑定的公众号的回复规则按照主公众号的关键词配置来处理,我的处理思路是获取主公众号配置的关键词回复规则,缓存10分钟,由于需要使用Redis缓存来存储一些 ...
- 微信公众账号 Senparc.Weixin.MP SDK 开发教程 索引
Senparc.Weixin.MP SDK从一开始就坚持开源的状态,这个过程中得到了许多朋友的认可和支持. 目前SDK已经达到比较稳定的版本,这个过程中我觉得有必要整理一些思路和经验,和大家一起分享. ...
- 微信公众平台C# SDK:Senparc.Weixin.MP.dll
https://github.com/Senparc/WeiXinMPSDK [转] http://www.cnblogs.com/szw/archive/2013/01/13/senparc-wei ...
随机推荐
- select制作分层级目录,让select显示和可下拉选择的"不一样"
今天遇到一个特殊的select问题,需求是这样的:每次点击这个select时,根据选择的option的值做出相应的处理并返回新的select,option内容.所以大致思路是给这个select绑定ch ...
- MvcPager 免费开源分页控件3.0版发布!
MvcPager 3.0版在原2.0版的基础上进行了较大的升级,对MvcPager脚本插件重写并进行了大量优化.修复了部分bug并新增了客户端Javascript API等功能,使用更方便,功能更强大 ...
- C# "=="、Equals()、ReferenceEquals()区别
对于值类型: ; ; 1.== 比较的是值内容 2.age2.Equals(age1) = false; Equals比较前需要转换成同类型,age1(int型)需显示转换成byte型 3.age1. ...
- 站内信对话列表sql语句
- select值的获取及修改
例子: <select id="a" name="a"> <options value="1">a</opti ...
- MATLAB 画出三个通信小区cell边界示意图
d=1000; %两个小区中心间距离的一半 rcell=2*d/sqrt(3); %小区半径 ncell=3; %小区个数 cellposition=zeros(ncell,2); %初始化小区中心位 ...
- Android广播大全
1.String ADD_SHORTCUT_ACTION 动作:在系统中添加一个快捷方式. 2.String ALL_APPS_ACTION 动作:列举所有可用的应用.输入:无. 3.String A ...
- 解决Canvas.toDataURL 图片跨域问题
如题,在将页面的图片地址进行本地输出时(Html2Canvas.js),因不同源存在跨域问题,会出现toDataURL访问权限问题: [Redirect at origin 'http://sub1. ...
- Vertica数据查询优化
vertica是惠普公司推出的列式分布式数据库,在OLAP领域有其独到的地方,目前社区版免费,但是只能存放1T的数据.我在工作中维护的bi系统后端就是使用的vertica数据库,平时也经常需要对于数据 ...
- JS中可拖拽的甘特图和流程图
甘特图: https://www.douban.com/note/441706674/ https://www.uedsc.com/jquery-ganttview.html https://gith ...