原文:ASP.NET WEB API微信支付通知接口,返回xml数据,微信服务器不识别问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/MrTraum/article/details/80897239

最近开发微信小程序中用到了微信支付功能,接口开发用的ASP.NET WEB API;

在支付成功后,接口接受到微信服务器的支付通知结果,处理完数据,接口返回给微信服务数据时出现了问题。

微信服务器识别不到返回的数据,导致重复通知。

最终解决代码如下:

        protected virtual HttpResponseMessage RetMessage(object msg)
{
return new HttpResponseMessage
{
Content = new StringContent(msg.ToString(),new UTF8Encoding(false)
, "text/plain")
}; }
        [HttpPost]
public HttpResponseMessage Wx_Notify()
{
//业务处理代码,以下为返回
WxPayData res = new WxPayData();
res.SetValue("return_code", "SUCCESS");
res.SetValue("return_msg", "OK");
return RetMessage(res.ToXml());
}

WxPayData 为腾讯官方提供源码中的类

namespace WxPayAPI
{
/// <summary>
/// 微信支付协议接口数据类,所有的API接口通信都依赖这个数据结构,
/// 在调用接口之前先填充各个字段的值,然后进行接口通信,
/// 这样设计的好处是可扩展性强,用户可随意对协议进行更改而不用重新设计数据结构,
/// 还可以随意组合出不同的协议数据包,不用为每个协议设计一个数据包结构
/// </summary>
public class WxPayData
{
public WxPayData()
{ } //采用排序的Dictionary的好处是方便对数据包进行签名,不用再签名之前再做一次排序
private SortedDictionary<string, object> m_values = new SortedDictionary<string, object>(); /**
* 设置某个字段的值
* @param key 字段名
* @param value 字段值
*/
public void SetValue(string key, object value)
{
m_values[key] = value;
} /**
* 根据字段名获取某个字段的值
* @param key 字段名
* @return key对应的字段值
*/
public object GetValue(string key)
{
object o = null;
m_values.TryGetValue(key, out o);
return o;
} /**
* 判断某个字段是否已设置
* @param key 字段名
* @return 若字段key已被设置,则返回true,否则返回false
*/
public bool IsSet(string key)
{
object o = null;
m_values.TryGetValue(key, out o);
if (null != o)
return true;
else
return false;
} /**
* @将Dictionary转成xml
* @return 经转换得到的xml串
* @throws WxPayException
**/
public string ToXml()
{
//数据为空时不能转化为xml格式
if (0 == m_values.Count)
{
Log.Error(this.GetType().ToString(), "WxPayData数据为空!");
throw new WxPayException("WxPayData数据为空!");
} string xml = "<xml>";
foreach (KeyValuePair<string, object> pair in m_values)
{
//字段值不能为null,会影响后续流程
if (pair.Value == null)
{
Log.Error(this.GetType().ToString(), "WxPayData内部含有值为null的字段!");
throw new WxPayException("WxPayData内部含有值为null的字段!");
} if (pair.Value.GetType() == typeof(int))
{
xml += "<" + pair.Key + ">" + pair.Value + "</" + pair.Key + ">";
}
else if (pair.Value.GetType() == typeof(string))
{
xml += "<" + pair.Key + ">" + "<![CDATA[" + pair.Value + "]]></" + pair.Key + ">";
}
else//除了string和int类型不能含有其他数据类型
{
Log.Error(this.GetType().ToString(), "WxPayData字段数据类型错误!");
throw new WxPayException("WxPayData字段数据类型错误!");
}
}
xml += "</xml>";
return xml;
} /**
* @将xml转为WxPayData对象并返回对象内部的数据
* @param string 待转换的xml串
* @return 经转换得到的Dictionary
* @throws WxPayException
*/
public SortedDictionary<string, object> FromXml(string xml)
{
if (string.IsNullOrEmpty(xml))
{
Log.Error(this.GetType().ToString(), "将空的xml串转换为WxPayData不合法!");
throw new WxPayException("将空的xml串转换为WxPayData不合法!");
} XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
XmlNode xmlNode = xmlDoc.FirstChild;//获取到根节点<xml>
XmlNodeList nodes = xmlNode.ChildNodes;
foreach (XmlNode xn in nodes)
{
XmlElement xe = (XmlElement)xn;
m_values[xe.Name] = xe.InnerText;//获取xml的键值对到WxPayData内部的数据中
} try
{
//2015-06-29 错误是没有签名
if(m_values["return_code"] != "SUCCESS")
{
return m_values;
}
CheckSign();//验证签名,不通过会抛异常
}
catch(WxPayException ex)
{
throw new WxPayException(ex.Message);
} return m_values;
} /**
* @Dictionary格式转化成url参数格式
* @ return url格式串, 该串不包含sign字段值
*/
public string ToUrl()
{
string buff = "";
foreach (KeyValuePair<string, object> pair in m_values)
{
if (pair.Value == null)
{
Log.Error(this.GetType().ToString(), "WxPayData内部含有值为null的字段!");
throw new WxPayException("WxPayData内部含有值为null的字段!");
} if (pair.Key != "sign" && pair.Value.ToString() != "")
{
buff += pair.Key + "=" + pair.Value + "&";
}
}
buff = buff.Trim('&');
return buff;
} /**
* @Dictionary格式化成Json
* @return json串数据
*/
public string ToJson()
{
string jsonStr = Json.ToJson(m_values);
return jsonStr;
} /**
* @values格式化成能在Web页面上显示的结果(因为web页面上不能直接输出xml格式的字符串)
*/
public string ToPrintStr()
{
string str = "";
foreach (KeyValuePair<string, object> pair in m_values)
{
if (pair.Value == null)
{
Log.Error(this.GetType().ToString(), "WxPayData内部含有值为null的字段!");
throw new WxPayException("WxPayData内部含有值为null的字段!");
} str += string.Format("{0}={1}<br>", pair.Key, pair.Value.ToString());
}
Log.Debug(this.GetType().ToString(), "Print in Web Page : " + str);
return str;
} /**
* @生成签名,详见签名生成算法
* @return 签名, sign字段不参加签名
*/
public string MakeSign()
{
//转url格式
string str = ToUrl();
//在string后加入API KEY
str += "&key=" + WxPayConfig.KEY;
//MD5加密
var md5 = MD5.Create();
var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(str));
var sb = new StringBuilder();
foreach (byte b in bs)
{
sb.Append(b.ToString("x2"));
}
//所有字符转为大写
return sb.ToString().ToUpper();
} /**
*
* 检测签名是否正确
* 正确返回true,错误抛异常
*/
public bool CheckSign()
{
//如果没有设置签名,则跳过检测
if (!IsSet("sign"))
{
Log.Error(this.GetType().ToString(), "WxPayData签名存在但不合法!");
throw new WxPayException("WxPayData签名存在但不合法!");
}
//如果设置了签名但是签名为空,则抛异常
else if(GetValue("sign") == null || GetValue("sign").ToString() == "")
{
Log.Error(this.GetType().ToString(), "WxPayData签名存在但不合法!");
throw new WxPayException("WxPayData签名存在但不合法!");
} //获取接收到的签名
string return_sign = GetValue("sign").ToString(); //在本地计算新的签名
string cal_sign = MakeSign(); if (cal_sign == return_sign)
{
return true;
} Log.Error(this.GetType().ToString(), "WxPayData签名验证错误!");
throw new WxPayException("WxPayData签名验证错误!");
} /**
* @获取Dictionary
*/
public SortedDictionary<string, object> GetValues()
{
return m_values;
}
}
}

ASP.NET WEB API微信支付通知接口,返回xml数据,微信服务器不识别问题的更多相关文章

  1. 用ASP.NET Web API技术开发HTTP接口

    开发工具 Visual Studio 2013 SQL Server 2008 R2 准备工作 启动Visual Studio 2013,新建一个ASP.NET Web应用程序,命名为SimpleAP ...

  2. 用ASP.NET Web API技术开发HTTP接口(一)

    开发工具 Visual Studio 2013 SQL Server 2008 R2 准备工作 启动Visual Studio 2013,新建一个ASP.NET Web应用程序,命名为SimpleAP ...

  3. 用ASP.NET Web API技术开发HTTP接口(二)

    在第一部分,我们创建了一个基本的ASP.NET Web API项目,新建成功了数据表,然后添加了一些测试数据,最后创建了API控制器,用json格式把数据表里面的内容成功输出到浏览器上.接下来我们将继 ...

  4. ASP.NET Web API 2:Action的返回类型

    Web API控制器中的Action方法有如下几种返回类型: void HttpResponseMessage IHttpActionResult 其它类型 基于上面几种不同的返回类型,Web API ...

  5. 能省则省:在ASP.NET Web API中通过HTTP Headers返回数据

    对于一些返回数据非常简单的 Web API,比如我们今天遇到的“返回指定用户的未读站内短消息数”,返回数据就是一个数字,如果通过 http response body 返回数据,显得有些奢侈.何不直接 ...

  6. .NetCore Web Api 利用ActionFilterAttribute统一接口返回值格式

    .Net Core 同 Asp.Net MVC一样有几种过滤器,这里不再赘述每个过滤器的执行顺序与作用. 在实际项目开发过程中,统一API返回值格式对前端或第三方调用将是非常必要的,在.NetCore ...

  7. How do I get ASP.NET Web API to return JSON instead of XML using Chrome

    public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.Ro ...

  8. ASP.NET Web API路由系统:路由系统的几个核心类型

    虽然ASP.NET Web API框架采用与ASP.NET MVC框架类似的管道式设计,但是ASP.NET Web API管道的核心部分(定义在程序集System.Web.Http.dll中)已经移除 ...

  9. ASP.NET Web API 2 入门

    本文参考:http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web ...

随机推荐

  1. MyBatis数据持久化(六)resultMap使用

    resultMap是MyBatis最强大也是最重要的特性,使用它我们可以將查询结果或者sql输入条件和一个HashMap的key进行映射,大大简化了sql查询条件的输入,而且使得数据的查询变得非常灵活 ...

  2. windows2008搭建ftp服务器

    控制面板 操作—〉添加角色 (web,文件服务) windows 搜索中: 添加ftp站点: 计算机---管理 –服务器管理  --- 添加一个用户 ,密码. 防护墙高级设置中添加 出入站规则 允许2 ...

  3. CDR X6三折促销活动,可入

    继CDR X6双十二限量活动之后,CorelDRAW官方为庆祝2018新年新气象,折扣狂潮,又来一波.上次活动由于时间短,任务急,数量少,使得不少小伙伴抱憾而止,选择默默等待良机.现在,良机来了,即便 ...

  4. h5实现 微信的授权登录

    本文重点 判断是不是微信环境 localstorage设置一个值 微信授权登录 获取一个时间戳 new Date().getTime() const wx = (function () { retur ...

  5. json对象获取长度以及字符串和json对象的转换

    var arr = Object.keys(typeARR); var str = ''; var len = arr.length; for(var i = 0;i<len;i++){ str ...

  6. 【BZOJ4002】[JLOI2015]有意义的字符串 - 矩阵乘法

    题意: 给出b,d,n,求$\lfloor(\frac{b+\sqrt{d}}{2})^n\rfloor \mod 999999999999999989$(原题是7528443412579576937 ...

  7. tinymce原装插件源码分析(二)-link

    link 功能描述如下: 单纯放置光标: 1.如果光标放到了<a>上,读取a标签的内容,并弹框显示,确定的时候,更新当前a标签. 2.否则,就创建弹框,确定的时候,按照参数添加a标签. s ...

  8. Linux系统下安装配置 OpenLDAP + phpLDAPadmin

    实验环境: 操作系统:Centos 7.4 服务器ip:192.168.3.41 运行用户:root 网络环境:Internet LDAP(轻量级目录访问协议)是一个能实现提供被称为目录服务的信息服务 ...

  9. man 7 glob

    GLOB(7) Linux Programmer's Manual GLOB(7) NAME glob - 形成路径名称 描述 (DESCRIPTION) 很久以前 在 UNIX V6 版 中 有一个 ...

  10. 紫书 习题 11-4 UVa 1660 (网络流拆点法)

    这道题改了两天-- 因为这道题和节点有关, 所以就用拆点法解决节点的容量问题. 节点拆成两个点, 连一条弧容量为1, 表示只能经过一次. 然后图中的弧容量无限. 然后求最小割, 即最大流, 即为答案. ...