Asp.Net Web API开发微信后台

如果说用Asp.Net开发微信后台是非主流,那么Asp.Net Web API的微信后台绝对是不走寻常路。

需要说明的是,本人认为Asp.Net Web API在开发很多不同的请求方法的Restful服务的时候是利器,可在开发微信后台的时候,因为微信调用我们这个后台的时候来来去去就一个方法,所以Web API有点杀鸡用牛刀的感觉。

而且由于Web API其实是微软封装了大量的类库,所以会导致后台相当臃肿。所以,不建议Asp.Net Web API开发微信后台。

如果好奇心太强实在想试一下,可以参看以下内容。

首先登陆微信公众平台,在左侧栏底下点击开发者中心填写服务器配置。

目前仅支持80端口,所以发布的时候需要在iis配置清楚。

创建一个Web API项目,然后添加controller,命名为:WechatController。

在WechatController类下添加以下一个方法:

        [HttpGet]                                        //标明HttpGet注解属性明确声明这个方法仅仅接受Get请求
        [ActionName("getMsg")]                                //ActionName注解属性覆盖了方法名,这个方法名将会映射到“/api/wechat/getmsg”(如果没有修改默认的路由规则的话)
        public HttpResponseMessage WetChatVerify(HttpRequestMessage content)     //HttpRequestMessage 和HttpResponseMessage,分别用于封装Requset和Response
        {
            string echostr = (from kvp in content.GetQueryNameValuePairs()
                              where kvp.Key == "echostr"
                              select kvp.Value).FirstOrDefault();

            string signature = (from kvp in content.GetQueryNameValuePairs()
                                where kvp.Key == "signature"
                                select kvp.Value).FirstOrDefault();

            string timestamp = (from kvp in content.GetQueryNameValuePairs()
                                where kvp.Key == "timestamp"
                                select kvp.Value).FirstOrDefault();

            string nonce = (from kvp in content.GetQueryNameValuePairs()
                            where kvp.Key == "nonce"
                            select kvp.Value).FirstOrDefault();

            string returnStr="";
            if (string.IsNullOrEmpty(echostr) | string.IsNullOrEmpty(signature) | string.IsNullOrEmpty(timestamp) | string.IsNullOrEmpty(nonce))
            {
                returnStr="error";
            }

            if (CheckSignature(signature, timestamp, nonce))
            {
                log.Info("验证成功,返回:" + echostr);
                returnStr=echostr;
            }

            HttpResponseMessage result = new HttpResponseMessage();
            result.Content = new StringContent(returnStr);
            return result;
        }    

CheckSignature的代码如下:

        /// <summary>
        /// 验证微信签名
        /// </summary>
        private bool CheckSignature(string signature, string timestamp, string nonce)
        {
            String[] ArrTmp = { Common.Common.Token, timestamp, nonce };

            Array.Sort(ArrTmp);
            String tmpStr = String.Join("", ArrTmp);

            tmpStr = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1").ToLower();

            if (tmpStr == signature)
            {
                return true;
            }
            else
            {
                return false;
            }
        }    

微信将会发送一个请求到后台,这个请求根据你在其开发平台填写的信息,类型可以是如下:

http://【server】/api/wechat/getMsg?signature=【signature】&echostr=【echostr】&timestamp=【timestamp】&nonce=【nonce】

只要按照CheckSignature的步骤将Token以及获取到的timestamp,nonce串联并用sha1加密,如果所得结果跟signature一致,就原样返回echostr,如此微信开发平台就会认为服务器配置成功了。

我们知道Web API的返回类型很灵活,可以返回string类型也可以int类型,当然也可以复杂一点采用上面的HttpResponseMessage类型,不过如果返回的是string类型,就有两个问题:

1、echostr不能原样返回,会自动给你加上双引号,所以微信开发平台会一直说验证失败,取巧一点的话,因为现在的echostr都是数字,可以返回整形;

2、返回的文字信息如果需要换行,直接返回string类型的话,“\n”就不会当作是换行符处理而回直接在消息中显示出来。这关乎下面的一些内容了……

验证成功之后,再写另外一个方法来接收并处理信息。

        [HttpPost]
        [ActionName("getMsg")]
        public HttpResponseMessage HandleMsgFromWeChat(HttpRequestMessage request)
        {
            List<KeyValuePair<string, string>> query = Request.GetQueryNameValuePairs().ToList();
            string xmlContent = request.Content.ReadAsStringAsync().Result;       string response = string.Empty;

            WeChatMessage msg = WeChatHelper.GetWxMessage(xmlContent);

            if (msg.MsgType.Trim() == "text")//用户发送一些文字信息
            {
                response = “oh my lady gaga”;
            }
            if (msg.MsgType.Trim() == "event")//点击菜单或者新增/取消关注
            {
                switch (msg.EventName.Trim().ToLower())
                {
                    case "click":      //点击菜单
                        response = "haha";
                        break;
                    case "subscribe":    //用户新增关注(可以返回一些欢迎信息之类)                                  
                        response = “wawa”;
                        break;
                    case "unsubscribe":   //用户取消关注(一般不需要去返回什么信息)
                    default:
                        break;
                }
            }

            HttpResponseMessage result = new HttpResponseMessage();
            result.Content = new StringContent(response);
            return result;
        }
    //自定义一个微信消息实体类
    public class WeChatMessage
    {
        public string FromUserName { get; set; }
        public string ToUserName { get; set; }
        public string MsgType { get; set; }
        public string EventName { get; set; }
        public string EventKey { get; set; }
        public string Content { get; set; }
    }

    //发送图文消息的列表项
    public class ArticleItem
    {
        public string title { get; set; }
        public string description { get; set; }
        public string picurl { get; set; }
        public string url { get; set; }
    }

    public class WeChatHelper
    {
        /// <summary>
        /// 获取微信信息。
        /// </summary>
        /// <returns></returns>
        public static WeChatMessage GetWxMessage(string xmlStr)
        {
            WeChatMessage wx = new WeChatMessage();
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(xmlStr);
            wx.ToUserName = xml.SelectSingleNode("xml").SelectSingleNode("ToUserName").InnerText;
            wx.FromUserName = xml.SelectSingleNode("xml").SelectSingleNode("FromUserName").InnerText;
            wx.MsgType = xml.SelectSingleNode("xml").SelectSingleNode("MsgType").InnerText;
            if (wx.MsgType.Trim() == "text")
            {
                wx.Content = xml.SelectSingleNode("xml").SelectSingleNode("Content").InnerText;
            }
            if (wx.MsgType.Trim() == "event")
            {
                wx.EventName = xml.SelectSingleNode("xml").SelectSingleNode("Event").InnerText;
                wx.EventKey = xml.SelectSingleNode("xml").SelectSingleNode("EventKey").InnerText;
            }
            return wx;
        }

        /// <summary>
        /// 发送文字消息
        /// </summary>
        public static string SendTextMessage(string fromUserName,string toUserName,string content)
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendFormat("<xml><ToUserName><![CDATA[{0}]]></ToUserName>", fromUserName);
            sb.AppendFormat("<FromUserName><![CDATA[{0}]]></FromUserName>", toUserName);
            sb.AppendFormat("<CreateTime>{0}</CreateTime>", DateTime.Now);
            sb.Append("<MsgType><![CDATA[text]]></MsgType>");
            sb.AppendFormat("<Content><![CDATA[{0}]]></Content>", content);
            sb.Append("<FuncFlag>0</FuncFlag></xml>");

            return sb.ToString();
        }

        /// <summary>
        /// 发送图文列表信息,如果列表为空,会转为发送“没有搜索到内容”的文字信息
        /// </summary>
        public static string SendImageListMessage(string fromUserName, string toUserName, List<ArticleItem> itemList)
        {
            if (itemList == null || itemList.Count == 0)
            {
                return SendTextMessage(fromUserName, toUserName, "没有搜索到相关内容");
            }

            StringBuilder sb = new StringBuilder();

            sb.Append("<xml>");
            sb.AppendFormat("<ToUserName><![CDATA[{0}]]></ToUserName>", fromUserName);
            sb.AppendFormat("<FromUserName><![CDATA[{0}]]></FromUserName>", toUserName);
            sb.AppendFormat("<CreateTime>{0}</CreateTime>", DateTime.Now);
            sb.Append("<MsgType><![CDATA[news]]></MsgType>");
            sb.AppendFormat("<ArticleCount>{0}</ArticleCount>", itemList.Count);
            sb.Append("<Articles>");
            foreach (ArticleItem item in itemList)
            {
                sb.Append("<item>");
                sb.AppendFormat("<Title><![CDATA[{0}]]></Title> ", item.title);
                sb.AppendFormat("<Description><![CDATA[{0}]]></Description>", item.description);
                sb.AppendFormat("<PicUrl><![CDATA[{0}]]></PicUrl>", item.picurl);
                sb.AppendFormat("<Url><![CDATA[{0}]]></Url>", item.url);
                sb.Append("</item>");
            }
            sb.Append("</Articles>");
            sb.Append("</xml>");

            return sb.ToString();
        }

        //http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96access_token
        public static string GetAccessToken()
        {
            string accessToken = string.Empty;
            //http请求方式: GET
            //https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
            string query=string.Format("grant_type=client_credential&appid={0}&secret={1}",Common.AppID,Common.AppSecret);
            string result = WebApiRequest.GetRequest("https://api.weixin.qq.com", "/cgi-bin/token", query);
            //result返回说明
            //正常情况下,微信会返回下述JSON数据包给公众号:
            //{"access_token":"ACCESS_TOKEN","expires_in":7200}
            //参数    说明
            //access_token    获取到的凭证
            //expires_in    凭证有效时间,单位:秒
            //错误时微信会返回错误码等信息,JSON数据包示例如下(该示例为AppID无效错误):
            //{"errcode":40013,"errmsg":"invalid appid"}
            JObject jOb = JObject.Parse(result);
            if (jOb["access_token"] != null)
            {
                accessToken = jOb["access_token"].ToString(); ;
            }
            return accessToken;
        }
    }

以上就搭建了一个简易的微信后台框架了。跟微信相关的内容大概也差不多了。想扩展内容、增加数据库支持等等,按照往常C#程序开发那样子做就好了。

时间: 12-18

Asp.Net Web API开发微信后台的相关文章

C#开发微信门户及应用(47) - 整合Web API、微信后台管理及前端微信小程序的应用方案

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

ASP.NET Web API实现微信公众平台开发(一)

最近朋友的微信公众号准备做活动,靠固定的微信公众平台模版搞定不了,于是请我代为开发微信后台.鉴于我也是第一次尝试开发微信后台,所以也踩了不少坑,此系列博客将会描述微信公众号各项功能的实现. 先决条件 1.一台可部署web服务的服务器或者云平台(我采用的是Microsoft Azure) 2.一个可以正常使用的微信公众账号 3.Visual Studio 开发准备 1.采用ASP.NET Web API网站项目作为微信公众号后台服务 成为微信公众号开发者 这一步很简单,只要在微信公众号后台的开发者

水果项目第3集-asp.net web api开发入门

app后台开发,可以用asp.net webservice技术. 也有一种重量级一点的叫WCF,也可以用来做app后台开发. 现在可以用asp.net web api来开发app后台. Asp.net web api 官方定义: ASP.NET Web API is a framework that makes it easy to build HTTP services that reach a broad range of clients, including browsers and mo

[目录]ASP.NET web api开发实战

第一章:Restful web service v.s. RPC style web service 第二章:ASP.NET web api v.s. WCF v.s. ASP.NET web service 第三章:基于ASP.NET MVC创建一个简单的web service 第四章:基于OAuth的登录验证 第五章:使用Entity Framework 第六章:使用Redis来做缓存 第七章:封装Socket来进行数据传输 第八章:集成Logging 第九章:基于Quartz定时执行任务

基于.Net Framework 4.0 Web API开发(3):ASP.NET Web APIs 异常的统一处理Attribute 和统一写Log 的Attribute的实现

概述:  ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作.但是项目,总有异常发生,本节就来谈谈API的异常的统一处理和写统一写log逻辑的解决方案. 问题: 在ASP.NET Web API编写时,如果每个API都写异常处理逻辑,不但加大了开发工作量,且每个开发人员处理异常返回的数据结构也不尽相同,在异常发生情况下,客户端处理异常的逻辑就不再通用,也同时加大了对接接口人员的工作量,好的API错误码和错误

基于.Net Framework 4.0 Web API开发(4):ASP.NET Web APIs 基于令牌TOKEN验证的实现

概述:  ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作.但是在使用API的时候总会遇到跨域请求的问题, 特别各种APP万花齐放的今天,对API使用者身份角色验证是不能避免的(完全开发的API不需要对使用者身份角色进行管控,可以绕过),这篇文章就来谈谈基于令牌TOKEN身份验证的实现. 问题: 对于Web API的选择性的开放,使用者无论使用AJAX,还是HttpClient对接,总要对使用者的身份角色

在ASP.NET Web API项目中使用Hangfire实现后台任务处理

当前项目中有这样一个需求:由前端用户的一个操作,需要触发到不同设备的消息推送.由于推送这个具体功能,我们采用了第三方的服务.而这个服务调用有时候可能会有延时,为此,我们希望将消息推送与用户前端操作实现异步执行,就是希望在后台自动执行,不阻塞前端用户的操作,而且最好能实现失败重试等功能. 经过一些研究比较,我们发现使用Hangfire这个组件可以较好地实现这个需求.为了给大家做一个演示,我这里简化了代码,做一个范例程序. 我在这里不准备详细介绍Hangfire的基本用法,有兴趣的同学们可以参考官方

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

开发工具 Visual Studio 2013 SQL Server 2008 R2 准备工作 启动Visual Studio 2013,新建一个ASP.NET Web应用程序,命名为SimpleAPI.选择Empty模板,并勾选"Web API",无身份验证,不添加单元测试. 准备用SQL Server数据库来存储数据,因此要安装下Entity Framework框架,免去写繁琐SQL语句的麻烦.打开工具->程序包管理器控制台输入以下命令安装. Install-Package

基于.Net Framework 4.0 Web API开发(5):ASP.NET Web APIs AJAX 跨域请求解决办法(CORS实现)

概述:  ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作.但是在使用API的时候总会遇到跨域请求的问题,特别各种APP万花齐放的今天,API的跨域请求是不能避免的. 在默认情况下,为了防止CSRF跨站的伪造攻击(或者是 javascript的同源策略(Same-Origin Policy)),一个网页从另外一个域获取数据时就会收到限制.有一些方法可以突破这个限制,那就是大家熟知的JSONP, 当然这只是