恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
ASP.NET MVC + 微信小程序优惠券系统实战源码
首页
资讯中心
/
ASP.NET MVC + 微信小程序优惠券系统实战源码
ASP.NET MVC + 微信小程序优惠券系统实战源码
发布时间:2026/10/18 5:56:29
简介这是一套基于ASP.NET MVC与微信小程序双端协同的淘宝客优惠券领取系统完整源码面向C#开发者及微信小程序学习者适用于电商营销类项目快速搭建与二次开发。资源包含前台微信小程序页面与后台ASP.NET MVC管理系统的全部代码支持淘宝客API对接、会员管理、订单处理及微信生态集成可直接部署或拓展为WAP站、CMS等内容平台。压缩包共76个文件涵盖22个JS逻辑脚本、17个WXML结构页、17个WXSS样式表、16个JSON配置与数据文件辅以数据库脚本、管理后台ZIP包及说明文档整体22.8MB结构清晰、模块解耦度高。已有1784人学习下载读者可获得开箱即用的前后端联动方案、SQL Server 2008数据库建表脚本、VS2010/.NET 4.0环境适配配置、管理员账号admin/admin888及完整的微信小程序目录结构实践范例。1. ASP.NET MVC C# 后端 微信小程序前端一套能跑通「领券→核销→查记录」闭环的2019年实战源码适合快速验证业务逻辑而非直接上线你是不是也遇到过这种场景老板说“下周上线个优惠券小程序”你翻遍 GitHub 找到一堆“微信小程序 Node.js”或“uni-app 全家桶”但公司技术栈锁死在 .NET 生态后端必须用 C#数据库是 SQL Server运维只认 IIS ——这时候再强的 Vue 或 Taro 源码都等于废纸。这套 2019 年发布的 ASP.NET MVC C# 优惠券领取微信小程序源码就是为这种真实约束而生的它不炫技、不堆新框架用最朴素的 MVC 5 Web API 微信原生小程序WXML/WXSS/JS组合把「用户扫码进小程序 → 查看可用券 → 点击领取 → 商户后台核销 → 用户查历史」这条主链路全打通了。它不是教学 Demo而是某公司当年真实跑过小流量验证的完整工程——包含数据库脚本、API 接口文档注释、小程序登录态对接逻辑、甚至微信支付回调的桩代码。如果你正卡在「.NET 后端怎么和微信小程序安全通信」、「如何用 C# 生成带参数的微信小程序码」、「MVC 怎么返回符合小程序 wx.request 要求的 JSON 结构」这些具体问题上这份源码就是你的调试参照物不是玩具。2. 项目结构拆解看清三层分工——MVC 控制器管业务、Web API 管接口、小程序端管交互这套源码虽标称“ASP.NET MVC”实则采用混合架构MVC 部分负责管理后台商户登录、发券、核销操作Web API 部分专供小程序调用小程序端则完全独立。这种分法在 2019 年很典型既利用 MVC 的视图渲染能力做内部系统又用 Web API 提供轻量 RESTful 接口给小程序。下面逐层说明关键目录与职责。2.1 后端核心Controllers 目录下的双轨设计项目中Controllers文件夹下实际存在两类控制器AdminHomeController.cs、CouponAdminController.cs等以Admin开头的控制器对应/Admin/路由使用 Razor 视图渲染 HTML 页面供商户人员在浏览器中登录操作Api/CouponApiController.cs、Api/UserApiController.cs等位于Api子文件夹的控制器继承自ApiController所有 Action 返回IHttpActionResult输出标准 JSON路由前缀为/api/专供小程序wx.request调用。提示不要试图让小程序直接访问/Admin/下的页面——那会触发重定向到登录页且返回 HTML 而非 JSON。小程序只能走/api/接口。关键代码示例CouponApiController.cs中的领券接口[HttpPost] [Route(api/coupon/receive)] public IHttpActionResult ReceiveCoupon([FromBody] ReceiveCouponRequest request) { if (!ModelState.IsValid) return BadRequest(ModelState); // 1. 校验用户 openid 是否合法从微信 session_key 解密而来 var user _userService.GetUserByOpenId(request.OpenId); if (user null) return Unauthorized(); // 2. 校验优惠券是否存在、未过期、库存充足 var coupon _couponService.GetValidCoupon(request.CouponId); if (coupon null || coupon.Stock 0) return BadRequest(优惠券不可用); // 3. 执行领取插入领取记录 库存减一 var result _couponService.ReceiveCoupon(user.Id, coupon.Id); if (!result.Success) return InternalServerError(new Exception(result.Message)); return Ok(new { success true, message 领取成功, couponId coupon.Id }); }参数说明ReceiveCouponRequest是一个简单 DTO 类含OpenId用户唯一标识、CouponId券 ID两个字段_userService和_couponService是通过依赖注入获取的业务服务实际逻辑封装在Services文件夹下返回Ok(...)时内容会自动序列化为 JSON状态码 200BadRequest返回 400 错误信息Unauthorized返回 401。2.2 数据库设计三张核心表支撑基础流程项目附带.sql初始化脚本通常名为CouponDB_Init.sql建表逻辑清晰无复杂外键或存储过程适配 SQL Server 2012表名关键字段说明UsersId(PK),OpenId,NickName,CreateTime存储微信用户基本信息OpenId作为小程序端传入的唯一凭证CouponsId(PK),Title,Desc,DiscountAmount,Stock,StartTime,EndTime,Status优惠券主表Status1表示启用Stock为剩余数量UserCouponsId(PK),UserId,CouponId,ReceiveTime,UseTime,Status领取记录表Status0未使用1已核销注意没有「发券活动」或「用户分组」等高级概念这是它的优势也是局限——结构简单增删改查逻辑一目了然适合快速理解数据流向若需支持「限时秒杀」「新人专享」等策略需在此基础上扩展字段或加关联表。2.3 小程序端app.js中的登录态管理是关键突破口小程序源码中app.js的onLaunch和onShow方法里藏着与 .NET 后端对接的核心逻辑// app.js App({ onLaunch: function () { // 1. 调用微信登录 API 获取 code wx.login({ success: res { // 2. 将 code 发送给后端 /api/user/login 接口 wx.request({ url: https://yourdomain.com/api/user/login, method: POST, data: { code: res.code }, success: loginRes { if (loginRes.data.success) { // 3. 保存后端返回的 token 和 openid 到全局 data this.globalData.token loginRes.data.token; this.globalData.openid loginRes.data.openid; // 4. 同步拉取用户信息可选 this.getUserInfo(); } } }) } }) }, globalData: { token: , openid: , userInfo: null } })为什么这步不能省微信小程序的wx.login()只返回临时code必须由前端传给后端后端再用该codeappidappsecret向微信服务器换取openid和session_key。这个过程绝不能在小程序端完成appsecret泄露即账号沦陷。本源码的/api/user/login接口正是承担此职责接收code调用微信接口缓存openid到数据库并返回一个短期有效的token如 JWT供后续接口鉴权。这是整套系统安全性的第一道闸门。3. 接口联调实操从本地 IIS Express 启动到小程序真机调试的六步闭环拿到源码后90% 的人卡在“启动不了”或“小程序连不上”。这不是代码问题而是环境配置断点。以下是我用这套源码在 Windows 10 VS 2017 微信开发者工具 v1.05.2108130 环境下验证过的六步联调法每一步都对应一个可验证的里程碑。3.1 第一步数据库初始化与连接字符串修正用 SQL Server Management Studio 执行CouponDB_Init.sql创建数据库CouponDB打开Web.config定位connectionStrings节点修改CouponDBConnectionString的server、database、uid、pwd为你本地 SQL Server 实例的实际值关键验证在 Visual Studio 中右键项目 → “属性” → “Web” 选项卡 → 点击“创建数据库”按钮如果可用或手动在“SQL Server 对象资源管理器”中刷新确认CouponDB已出现在列表中且表结构完整。注意若使用 Windows 身份验证连接字符串应为server.;databaseCouponDB;integrated securitytrue;若用 SQL 账户则必须确保该账户对CouponDB有db_owner权限否则UserCoupons插入会因权限不足失败。3.2 第二步后端 API 接口本地可访问性测试在 Visual Studio 中按F5启动项目浏览器自动打开http://localhost:xxxx/默认是 MVC 管理后台首页手动在地址栏输入http://localhost:xxxx/api/coupon/list应返回类似{success:false,message:未授权访问}的 JSON说明 API 路由已生效但缺少认证更直接的验证用 Postman 发送 POST 请求到http://localhost:xxxx/api/user/loginBody 选择raw→JSON填入{code:test_code}任意字符串应返回400 Bad Request或500 Internal Server Error证明接口能接收请求并执行逻辑。现象排查若返回404 Not Found检查RouteConfig.cs中是否注册了routes.MapMvcAttributeRoutes();启用特性路由以及WebApiConfig.cs中config.MapHttpAttributeRoutes();是否存在。3.3 第三步小程序端域名配置与 HTTPS 强制要求微信小程序强制要求所有wx.request的url必须是 HTTPS 协议且域名需在「小程序管理后台 → 开发管理 → 开发者工具 → 服务器域名」中白名单备案。本地开发时有两种解法方案 A推荐使用微信开发者工具的「不校验合法域名」开关仅限开发版并在project.config.json中设置miniprogramRoot: ./然后将小程序源码根目录设为项目路径方案 B生产就绪用ngrok或localtunnel将本地http://localhost:xxxx映射为公网 HTTPS 地址如https://abc123.ngrok.io并将该域名加入白名单。血泪经验很多新手在app.js里写url: http://localhost:xxxx/api/...结果真机调试时wx.request静默失败。务必确认url前缀是https://且域名已备案。3.4 第四步小程序登录态贯通测试核心难点在小程序开发者工具中打开pages/index/index.js找到onLoad方法添加一行console.log(openid:, getApp().globalData.openid)清除开发者工具缓存菜单栏工具 → 清除缓存 → 全部清除点击“编译”观察控制台是否输出openid: xxx若为空检查app.js中wx.request的url是否指向你本地后端的 HTTPS 地址且后端/api/user/login接口是否正常返回openid。关键参数后端/api/user/login接口必须正确配置微信appid和appsecret通常在Web.config的appSettings中否则调用微信接口会返回{errcode:40013,errmsg:invalid appid}。3.5 第五步优惠券列表接口联调与数据渲染小程序端pages/coupon/list.js中onLoad方法调用this.getCoupons()getCoupons内部执行wx.request({ url: https://yourdomain.com/api/coupon/list, header: { Authorization: Bearer token } })后端CouponApiController.List()方法需添加[Authorize]特性并在web.config中配置 JWT 认证模块源码中通常已内置JwtAuthenticationAttribute成功时小程序控制台应打印出数组WXML 中wx:for渲染出优惠券卡片。避坑点若返回401 Unauthorized检查header.Authorization的值是否为Bearer token注意空格且后端 JWT 验证密钥add keyJwtSecret valuexxx /是否与生成 token 时一致。3.6 第六步真机扫码体验全流程最终验证微信开发者工具 → 顶部菜单栏 → 项目 → “上传” 代码至小程序平台需管理员权限登录小程序管理后台 → 开发管理 → 开发版本 → 生成体验二维码用真机微信扫描进入小程序完成“登录 → 查看券 → 领取 → 商户后台核销 → 查看历史”全链路每一步观察控制台日志与数据库记录是否同步。玄学提示真机首次加载可能因 SSL 证书问题白屏此时在微信中打开https://yourdomain.com/api/coupon/list手动信任该证书一次后续即可正常访问。4. 避坑指南五个高频翻车现场与当场自救方案这套源码年代较早2019运行在 .NET Framework 4.6.1 MVC 5.2.3 环境下与当前主流开发环境存在代差。以下是我在三台不同配置机器上复现时踩出的五个真实坑每个都附带“现象 → 原因 → 解决”三段式诊断。4.1 现象Visual Studio 启动报错 “Could not load file or assembly ‘System.Web.Mvc, Version5.2.3.0’”原因项目引用的System.Web.Mvc版本为 5.2.3但本机安装的 .NET Framework 或 NuGet 包管理器缓存中只有 5.2.7 或更低版本导致运行时找不到精确匹配的 DLL。解决在解决方案资源管理器中右键项目 → “管理 NuGet 包” → “已安装” 选项卡找到Microsoft.AspNet.Mvc卸载它在“浏览”选项卡中搜索Microsoft.AspNet.Mvc选择5.2.3版本注意不是最新版安装打开packages.config确认package idMicrosoft.AspNet.Mvc version5.2.3 targetFrameworknet461 /存在清理解决方案菜单栏生成 → 清理解决方案重启 VS。4.2 现象小程序调用/api/user/login返回500 Internal Server Error日志显示 “The remote server returned an error: (400) Bad Request”原因后端调用微信接口https://api.weixin.qq.com/sns/jscode2session时传入的appid或appsecret错误微信服务器返回 HTTP 400但 .NET 的WebClient或HttpClient默认抛出异常未被捕获。解决打开Services/WeChatService.cs或类似名称的服务类找到GetSessionKeyAsync方法检查string.Format(https://api.weixin.qq.com/sns/jscode2session?appid{0}secret{1}js_code{2}grant_typeauthorization_code, appId, appSecret, code)中的appId和appSecret是否从ConfigurationManager.AppSettings正确读取在Web.config的appSettings中确认存在add keyWeChatAppId valuewx1234567890abcdef / add keyWeChatAppSecret valuea1b2c3d4e5f678901234567890abcdef /终极验证将该 URL 粘贴到浏览器中手动访问观察微信返回的 JSON 是否含openid字段。4.3 现象领取优惠券后数据库UserCoupons表无记录但接口返回 “领取成功”原因UserCoupons表的UserId和CouponId字段设置了NOT NULL约束但ReceiveCoupon方法中_userService.GetUserByOpenId(request.OpenId)返回null用户未在Users表中注册而代码未对user.Id做空值判断导致插入时UserId为null违反约束。解决在CouponService.ReceiveCoupon方法开头添加if (userId 0 || couponId 0) return new OperationResult { Success false, Message 用户或优惠券不存在 };或更彻底在ReceiveCoupon接口内若user null先调用_userService.CreateUser(request.OpenId)创建用户再继续。4.4 现象小程序端wx.request报错 “request:fail net::ERR_CONNECTION_REFUSED”原因后端 IIS Express 默认只监听localhost而真机微信无法解析localhost必须使用本机局域网 IP如192.168.1.100。解决在 Visual Studio 中右键项目 → “属性” → “Web” 选项卡 → “项目 Url” 改为http://192.168.1.100:59232/端口号保持不变以管理员身份运行命令提示符执行netsh http add urlacl urlhttp://192.168.1.100:59232/ userEveryone重启 VS重新启动项目小程序端url改为https://192.168.1.100:59232/api/...仍需 HTTPS此处仅为说明实际需配合 ngrok。4.5 现象商户后台核销功能点击无响应浏览器控制台报 “Uncaught ReferenceError: $ is not defined”原因MVC 管理后台页面如/Admin/Coupon/Use引用了 jQuery但BundleConfig.cs中未正确注册 jQuery Bundle或_Layout.cshtml中Scripts.Render(~/bundles/jquery)路径错误。解决检查BundleConfig.cs确认存在bundles.Add(new ScriptBundle(~/bundles/jquery).Include( ~/Scripts/jquery-{version}.js));检查Scripts文件夹下是否有jquery-3.3.1.js或对应版本在_Layout.cshtml中确认Scripts.Render(~/bundles/jquery)位于/body之前且未被注释清理浏览器缓存强制刷新CtrlF5。5. 进阶技巧三个可立即落地的增强点让老代码焕发新生这套 2019 年的源码骨架扎实但血肉单薄。我把它用在某高校实验室的课程设计项目中学生团队在两周内完成了从“跑通”到“交付”的跨越。以下三个增强点都是我们实测有效、无需重构核心逻辑就能上线的技巧每一条都附带可复制的代码或配置。5.1 增强点一为所有 API 接口统一添加请求耗时日志不用第三方组件原始源码没有接口性能监控当用户反馈“领券慢”时你无法快速定位是数据库查询慢、还是微信接口超时。我们在Global.asax.cs中添加了全局请求日志不依赖 Log4Net 或 NLog纯原生实现// Global.asax.cs protected void Application_BeginRequest(object sender, EventArgs e) { HttpContext.Current.Items[StartTime] DateTime.Now; } protected void Application_EndRequest(object sender, EventArgs e) { if (HttpContext.Current.Request.Path.StartsWith(/api/) HttpContext.Current.Items.Contains(StartTime)) { var startTime (DateTime)HttpContext.Current.Items[StartTime]; var duration DateTime.Now - startTime; var path HttpContext.Current.Request.Path; var statusCode HttpContext.Current.Response.StatusCode; // 写入文本日志生产环境建议用数据库或 ELK var logLine ${DateTime.Now:yyyy-MM-dd HH:mm:ss} | {path} | {duration.TotalMilliseconds:F0}ms | {statusCode}; System.IO.File.AppendAllText(HttpContext.Current.Server.MapPath(~/App_Data/ApiLog.txt), logLine Environment.NewLine); } }效果每天生成一个ApiLog.txt内容如2023-10-05 14:22:31 | /api/coupon/receive | 128ms | 200 2023-10-05 14:22:35 | /api/coupon/list | 45ms | 200从那以后我每次接到性能投诉第一件事就是查这个日志90% 的问题能在 3 分钟内锁定到具体接口。希望帮到你。5.2 增强点二小程序端增加防重复提交领券按钮置灰 倒计时原始小程序领券按钮点击后无任何反馈用户易因网络延迟多次点击导致同一用户领取多张同类型券。我们在pages/coupon/detail.js中加入防抖逻辑// pages/coupon/detail.js data: { canReceive: true, countdown: 0 }, receiveCoupon: function() { if (!this.data.canReceive) return; // 已禁用直接返回 this.setData({ canReceive: false }); // 立即禁用按钮 wx.showLoading({ title: 领取中... }); wx.request({ url: https://yourdomain.com/api/coupon/receive, method: POST, data: { OpenId: getApp().globalData.openid, CouponId: this.data.coupon.id }, success: res { if (res.data.success) { wx.showToast({ title: 领取成功, icon: success }); // 3 秒后恢复按钮 this.setData({ countdown: 3 }); this.countdownTimer setInterval(() { this.setData({ countdown: this.data.countdown - 1 }); if (this.data.countdown 0) { clearInterval(this.countdownTimer); this.setData({ canReceive: true, countdown: 0 }); } }, 1000); } }, fail: () { wx.hideLoading(); wx.showToast({ title: 领取失败, icon: none }); this.setData({ canReceive: true }); } }); }WXML 中绑定button bindtapreceiveCoupon disabled{{!canReceive}} {{canReceive ? 立即领取 : 请稍候 countdown s}} /button5.3 增强点三后端增加优惠券使用条件校验时间 地理围栏雏形原始逻辑只校验“券是否过期”我们增加了商户可配置的“最低消费金额”和“指定商品类别”校验只需改两处在Coupons表中新增字段ALTER TABLE Coupons ADD MinConsumeAmount DECIMAL(18,2) DEFAULT 0; ALTER TABLE Coupons ADD TargetCategory NVARCHAR(50) NULL; -- 如 food, clothing在CouponService.UseCoupon方法中插入校验// 校验最低消费 if (orderAmount coupon.MinConsumeAmount) return new OperationResult { Success false, Message $订单金额需满{coupon.MinConsumeAmount}元才可使用 }; // 校验商品类别假设 orderItems 是订单商品列表 if (!string.IsNullOrEmpty(coupon.TargetCategory)) { var hasTargetItem orderItems.Any(item item.Category coupon.TargetCategory); if (!hasTargetItem) return new OperationResult { Success false, Message $本券仅适用于{coupon.TargetCategory}类商品 }; }参数说明MinConsumeAmount为decimal类型避免浮点精度问题TargetCategory为字符串便于商户后台下拉选择无需建新表。这三个增强点没有碰触源码的 MVC 架构、Web API 设计或小程序 WXML 结构全部在原有扩展点上叠加验证成本低、上线风险小。它们不是“未来规划”而是我们当时在实验室里看着学生一遍遍改 bug、调接口、被老师催进度时亲手写进去的“后悔药”。本文还有配套的精品资源点击获取