ASP.NET MVC C# 微信小程序优惠券领取源码解析与实战
简介这是一套面向微信小程序与.NET开发者的淘宝客优惠券领取系统源码适合想学习小程序对接第三方API、或需要搭建优惠券导购平台的初中级开发者。后台基于ASP.NET MVC框架与C#语言开发调用阿里妈妈淘宝客接口实现商品搜索与优惠券领取并已内置内容管理、会员、订单、微信及WAP等模块便于二次开发成完整站点。压缩包共76个文件约22.8MB包含22个js、17个json、17个wxss、16个wxml等分别对应小程序逻辑、页面配置、样式与结构另有后台源码压缩包与数据库脚本。开发环境为Visual Studio 2010搭配SQL Server 2008与.NET 4.0管理员账号密码及数据库连接字符串均有说明上手门槛较低。目前已有1784人学习下载读者可借此掌握小程序前后台联调、淘宝客API调用与MVC分层设计思路快速搭建可运行的优惠券领取项目。1. 从一份 2019 完整版源码说起ASP.NET MVC C# 优惠券领取小程序能跑通什么手里这份 ASP.NET MVC C# 优惠券领取微信小程序源码是 2019 年前后比较典型的一套「服务端 小程序端」组合。服务端用 ASP.NET MVC.NET Framework 4.x 时代搭后台C# 写业务逻辑小程序端负责展示优惠券列表、领取按钮、我的券包这几个核心页面。它解决的不是「从零设计一个营销系统」的问题而是给了一个能直接跑起来的领券闭环用户授权登录、拉取可领券列表、点击领取、写入领取记录、回显已领状态。适合两类人一是手上有个 .NET 老项目、想快速加一个小程序入口的后端同学二是想学 C# 微信小程序源码怎么把 MVC 控制器和小程序请求对接起来的新手。这套代码的边界也很清楚——它是 2019 年的完整版不是云开发也不是 .NET Core别拿现在的架构标准去套它。2. 拆开这套 .NET 微信小程序源码目录结构与请求链路2.1 服务端 MVC 分层与关键文件拿到源码先别急着 F5先看目录。ASP.NET MVC 的骨架基本固定Controllers、Models、Views、App_Start、Content、Scripts。这套领券项目里真正要盯的是三块控制器里的接口方法、Models 里的实体、以及Web.config里的数据库连接串。常见做法是控制器按业务拆比如CouponController管券的列表和领取UserController管登录和用户信息。小程序端不请求 View只请求返回 JSON 的 Action所以你会看到很多方法直接return Json(...)而不是return View()。这一点是新手最容易懵的地方——MVC 在这里其实只用了 M 和 CV 那层基本是给后台管理页面用的。// Controllers/CouponController.cs 典型结构 public class CouponController : Controller { // 小程序拉取可领取的优惠券列表 public ActionResult List() { // 只取未过期、库存大于 0 的券 var list db.Coupons .Where(c c.ExpireTime DateTime.Now c.Stock 0) .Select(c new { c.Id, c.Title, c.Amount, c.Stock }).ToList(); return Json(new { code 0, data list }, JsonRequestBehavior.AllowGet); } }这段代码的逻辑很直白查库、过滤、投影成匿名对象、序列化成 JSON。参数上要注意JsonRequestBehavior.AllowGet2019 年的 MVC 默认禁止 GET 返回 JSON不加这行小程序 GET 请求会直接 500。code 0是这套源码约定的成功码小程序端靠它判断别自己改成 200 又不改前端。2.2 小程序端请求与登录态小程序端目录一般是pages、utils、app.js、app.json。领券逻辑集中在pages/coupon这类页面里核心是wx.request调服务端接口加上wx.login拿 code 换 openid。// pages/coupon/coupon.js 领取动作 wx.request({ url: baseUrl /Coupon/Receive, // 对应 MVC 的 Receive Action method: POST, data: { couponId: this.data.currentId, openid: app.globalData.openid // 登录后缓存的用户标识 }, success: (res) { if (res.data.code 0) { wx.showToast({ title: 领取成功 }); } else { wx.showToast({ title: res.data.msg, icon: none }); } } });这里baseUrl必须是小程序后台配置过的合法域名本地调试要在开发者工具里勾「不校验合法域名」。openid是登录后存在globalData里的如果没登录就点领取服务端拿不到 openid会返回错误码。参数说明couponId是券主键openid是用户唯一标识服务端靠这两个字段做「一人一券」的去重判断。2.3 数据库表与领取去重逻辑这套源码一般带.sql脚本核心两张表券表Coupons和领取记录表CouponRecords。去重就靠CouponRecords里Openid CouponId的唯一约束或者服务端先查再插。-- 领取记录表关键字段 CREATE TABLE CouponRecords ( Id INT IDENTITY(1,1) PRIMARY KEY, Openid NVARCHAR(64) NOT NULL, CouponId INT NOT NULL, ReceiveTime DATETIME DEFAULT GETDATE() ); -- 防重复领取同一用户同一券只能有一条 CREATE UNIQUE INDEX UX_Openid_Coupon ON CouponRecords(Openid, CouponId);有了唯一索引即使小程序端连点两次第二次插入也会被数据库拦下服务端捕获异常返回「已领取」。这比在 C# 里先Any()再Add()更稳因为并发下先查后插有窗口期。参数上Openid长度给 64 够用ReceiveTime默认值省得代码里再赋值。3. 把源码跑起来环境、配置与接口联调3.1 服务端环境与 Web.config 配置2019 年的 ASP.NET MVC 项目环境要求是 Windows IIS 或 IIS Express SQL Server Visual Studio 2017/2019。用 VS 打开.sln先还原 NuGet 包再改Web.config里的连接串。!-- Web.config 连接串改成自己的库 -- connectionStrings add nameDefaultConnection connectionStringData Source.;Initial CatalogCouponDb;User IDsa;Password你的密码 providerNameSystem.Data.SqlClient / /connectionStrings逻辑说明Data Source.表示本机默认实例Initial Catalog是库名要和.sql脚本建的库一致。参数上如果用的是 LocalDB连接串写法不同别照抄。改完连接串先在 VS 里跑一次浏览器访问/Coupon/List能返回 JSON 就说明服务端通了。这一步不通后面小程序怎么调都是白搭。3.2 小程序端配置与合法域名小程序端用微信开发者工具打开改app.js里的baseUrl指向你的服务端地址。本地调试阶段在开发者工具「详情 - 本地设置」里勾上「不校验合法域名、web-view、TLS 版本以及 HTTPS 证书」。// app.js 全局配置 App({ globalData: { openid: , baseUrl: http://localhost:端口号 // 本地调试用上线必须 HTTPS } });参数说明baseUrl本地可以写http://localhost:xxxx但真机预览和上线必须是 HTTPS 且域名已备案、已在小程序后台配置。这是硬门槛不是玄学。很多人本地跑通、真机白屏九成是域名没配或用了 http。3.3 登录换 openid 的完整链路小程序登录不是拿微信账号密码而是wx.login拿临时 code传给服务端服务端用 code AppId AppSecret 调微信接口换 openid。这套源码里通常有个UserController/Login干这事。// 服务端用 code 换 openid示意 public ActionResult Login(string code) { var url $https://api.weixin.qq.com/sns/jscode2session $?appid{appId}secret{appSecret} $js_code{code}grant_typeauthorization_code; var result HttpGet(url); // 返回 openid 和 session_key var openid ParseOpenid(result); return Json(new { code 0, openid openid }); }逻辑说明appId和appSecret在小程序后台拿appSecret绝不能放小程序端只能放服务端。参数上grant_type固定authorization_code。拿到 openid 后存进globalData后续所有请求带上它。这一步的坑是 code 只能用一次且五分钟过期重复用会报错。4. 避坑与排查这套 2019 源码最容易翻车的五个地方4.1 现象小程序请求一直失败报「不在以下 request 合法域名列表中」原因开发者工具没勾「不校验合法域名」或者真机环境下域名没在小程序后台配置。解决本地调试勾选跳过校验真机测试必须用已备案 HTTPS 域名并在小程序后台「开发 - 开发设置 - 服务器域名」里加上 request 合法域名。4.2 现象服务端返回 JSON 但小程序解析出来是字符串原因MVC 的Json()默认返回text/html内容类型部分情况下小程序按字符串处理。解决改用return Json(data, application/json, JsonRequestBehavior.AllowGet);显式指定内容类型或者统一封装一个返回 JSON 的基类方法。4.3 现象同一用户能重复领同一张券原因只在小程序端做了按钮置灰服务端没做去重或者去重逻辑是「先查后插」在并发下失效。解决在CouponRecords表上建Openid CouponId唯一索引服务端插入时捕获唯一约束冲突返回「已领取」。别只信前端。4.4 现象库存扣成负数原因扣库存用的是「先读再减再写」并发领取时多个请求读到同一个库存值。解决用UPDATE Coupons SET Stock Stock - 1 WHERE Id Id AND Stock 0靠数据库行锁保证原子性再判断受影响行数是否为 1。4.5 现象换台机器部署后登录换不到 openid原因appId和appSecret写死在代码里换环境没改或者服务端服务器时间不准导致签名类接口失败。解决把微信配置抽到Web.config的appSettings里部署时改配置不改代码同时校准服务器时间。5. 在 2019 版基础上做二次开发三个能直接落地的改造点这套源码跑通之后真正有价值的是怎么在它上面加东西。第一个改造点是「券的领取上限」——现在是一人一券实际业务常需要「每人最多领 N 张」。做法是在CouponRecords上按Openid分组计数领取前判断Count N同时把唯一索引从Openid CouponId改成普通索引否则一人多领会被拦。这个改动要同步改服务端判断和小程序端的提示文案别只改一半。第二个改造点是「领取时间窗口」。2019 版一般只判断券是否过期没做「每天几点开抢」。可以在Coupons表加StartTime和EndTime两个字段List接口的过滤条件从ExpireTime Now改成StartTime Now EndTime Now。参数上注意时区服务端和数据库都用同一时区别一个 UTC 一个本地时间这种问题排查起来就是黑匣子。第三个改造点是「接口返回结构统一」。原版每个 Action 各写各的Json(new { code, data, msg })字段名不统一。建议抽一个ApiResult类public class ApiResult { public int Code { get; set; } // 0 成功非 0 失败 public string Msg { get; set; } public object Data { get; set; } public static ApiResult Ok(object data null) new ApiResult { Code 0, Msg ok, Data data }; public static ApiResult Fail(string msg) new ApiResult { Code -1, Msg msg }; }这样所有 Action 统一return Json(ApiResult.Ok(list))小程序端只认code一个字段维护成本直线下降。参数上Code用 0 表示成功是这套源码的约定改成 200 要全局替换不划算。验证改造是否生效我一般会走一遍「登录 → 拉列表 → 领取 → 再拉列表看状态 → 查库核对记录」这条链路每一步都看返回的code和数据库实际数据是否一致。光看小程序界面不够界面会骗人库不会。从那以后我每次拿到这类 .NET 小程序源码都先把登录换 openid 和领取去重这两条链路单独跑通再动别的顺序反了就是给自己找麻烦。希望帮到你。本文还有配套的精品资源点击获取