《SQL Server 2012 数据库服务搭建流程》
安装 .net 3.5 并重启!
知识一、安装,选 64 位版本,安装功能:
实例:数据库引擎服务及子项全选,其它暂时用不到
共享:管理工具-完整
知识NN、若实例安装到其它磁盘,确保目录有“NETWORK SERVICE”权限!!!
知识二、卸载,参:http://technet.microsoft.com/zh-cn/library/hh231731.aspx
必须严格按照说明卸载,否则会出现卸载不干净,重装装不上的问题。
若不幸遇上 0x851A001A,参:http://social.msdn.microsoft.com/Forums/zh-CN/8f4d5cf8-4ab8-4a37-81df-7c294f994515/sql-server-2012-install-error-851a001a
用户名好像是:NT Service\MSSQLSERVER
知识三、18456错误:
服务器身份验证:SQL Server 和 Windows 身份验证模式
具体设置在:SSMS - Windows 身份验证模式 登录后 - 对象资源管理器 - 选中当前服务器 - 右键属性 - 安全性
SQL Server 配置管理器 - SQL Server 服务 - 重启
知识四、修改端口:
SQL Server 配置管理器 - SQL Server 网络配置 - 相应实例的协议 - TCP/IP - IP 地址 - 将所有1433改掉
SQL Server 配置管理器 - SQL Server 服务 - 重启
知识五、sa - 登录 - 禁用
知识六、维护计划:
开启 SQL Server 代理,并在服务里设置自动(延时)
SSMS - 当前服务器 - 管理 - 维护计划 - 右键 维护计划向导 每天4:03:02
工具箱-拖入:收缩数据库-重新组织索引-重新生成索引-更新统计信息-清除历史记录-备份数据库(完整)-“清除维护”任务
编辑每项任务,在“所有用户数据库”中勾选“忽略未处理联机状态的数据库”,这是关键,如果不勾选,一旦某个数据库被设置为脱机,备份就会出错。
在新建的维护计划上右键,执行,完成以后,右键“查看历史记录”,如有错误作相应修改
完整备份+差异备份方式:http://www.cnblogs.com/zhangq723/archive/2012/03/13/2394102.html 从“下面我来讲一下”开始做
需要开放远程连接的,在防火墙设置允许通过的程序,如:
D:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Binn\sqlservr.exe
创建或还原数据库
一、(还原时)改:
常规 - 目标 - 数据库(B)
文件 - 表格“还原为”列 - 改文件名如:dbTest.mdf / dbTest_log.ldf
二、(还原时)dbTest - 安全性 - 用户 - 删除原用户,默认那些用户不要删
三、(还原后)属性 - 文件 - 数据库文件 - 逻辑名称,初始大小全是0
如不需要日志,则:属性 - 选项 - 恢复模式 - 简单
四、安全性 - 登录名 - 新建登录名:
常规 - 填写登录名 - SQL Server 身份验证 - 取消“强制实施密码策略” - 默认数据库
用户映射 - 映射对应数据库 - 勾:db_owner / public (若只读则勾:db_datareader / public)
用户映射确定后再检查一次,第一次有可能未设置成功
前言
最近在学习Web Api框架的时候接触到了async/await,这个特性是.NET 4.5引入的,由于之前对于异步编程不是很了解,所以花费了一些时间学习一下相关的知识,并整理成这篇博客,如果在阅读的过程中发现不对的地方,欢迎大家指正。
同步编程与异步编程
通常情况下,我们写的C#代码就是同步的,运行在同一个线程中,从程序的第一行代码到最后一句代码顺序执行。而异步编程的核心是使用多线程,通过让不同的线程执行不同的任务,实现不同代码的并行运行。
前台线程与后台线程
关于多线程,早在.NET2.0时代,基础类库中就提供了Thread实现。默认情况下,实例化一个Thread创建的是前台线程,只要有前台线程在运行,应用程序的进程就一直处于运行状态,以控制台应用程序为例,在Main方法中实例化一个Thread,这个Main方法就会等待Thread线程执行完毕才退出。而对于后台线程,应用程序将不考虑其是否执行完毕,只要应用程序的主线程和前台线程执行完毕就可以退出,退出后所有的后台线程将被自动终止。来看代码应该更清楚一些:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("主线程开始");
//实例化Thread,默认创建前台线程
Thread t1 = new Thread(DoRun1);
t1.Start();
//可以通过修改Thread的IsBackground,将其变为后台线程
Thread t2 = new Thread(DoRun2) { IsBackground = true };
t2.Start();
Console.WriteLine("主线程结束");
}
static void DoRun1()
{
Thread.Sleep(500);
Console.WriteLine("这是前台线程调用");
}
static void DoRun2()
{
Thread.Sleep(1500);
Console.WriteLine("这是后台线程调用");
}
}
}运行上面的代码,可以看到DoRun2方法的打印信息“这是后台线程调用”将不会被显示出来,因为应用程序执行完主线程和前台线程后,就自动退出了,所有的后台线程将被自动终止。这里后台线程设置了等待1.5s,假如这个后台线程比前台线程或主线程提前执行完毕,对应的信息“这是后台线程调用”将可以被成功打印出来。
Task
.NET 4.0推出了新一代的多线程模型Task。async/await特性是与Task紧密相关的,所以在了解async/await前必须充分了解Task的使用。这里将以一个简单的Demo来看一下Task的使用,同时与Thread的创建方式做一下对比。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Threading;
using System.Threading.Tasks;
namespace TestApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("主线程启动");
//.NET 4.5引入了Task.Run静态方法来启动一个线程
Task.Run(() => { Thread.Sleep(1000); Console.WriteLine("Task1启动"); });
//Task启动的是后台线程,假如要在主线程中等待后台线程执行完毕,可以调用Wait方法
Task task = Task.Run(() => { Thread.Sleep(500); Console.WriteLine("Task2启动"); });
task.Wait();
Console.WriteLine("主线程结束");
}
}
}首先,必须明确一点是Task启动的线程是后台线程,不过可以通过在Main方法中调用task.Wait()方法,使应用程序等待task执行完毕。Task与Thread的一个重要区分点是:Task底层是使用线程池的,而Thread每次实例化都会创建一个新的线程。这里可以通过这段代码做一次验证:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Threading;
using System.Threading.Tasks;
namespace TestApp
{
class Program
{
static void DoRun1()
{
Console.WriteLine("Thread Id =" + Thread.CurrentThread.ManagedThreadId);
}
static void DoRun2()
{
Thread.Sleep(50);
Console.WriteLine("Task调用Thread Id =" + Thread.CurrentThread.ManagedThreadId);
}
static void Main(string[] args)
{
for (int i = 0; i < 50; i++)
{
new Thread(DoRun1).Start();
}
for (int i = 0; i < 50; i++)
{
Task.Run(() => { DoRun2(); });
}
//让应用程序不立即退出
Console.Read();
}
}
}运行代码,可以看到DoRun1()方法每次的Thread Id都是不同的,而DoRun2()方法的Thread Id是重复出现的。我们知道线程的创建和销毁是一个开销比较大的操作,Task.Run()每次执行将不会立即创建一个新线程,而是到CLR线程池查看是否有空闲的线程,有的话就取一个线程处理这个请求,处理完请求后再把线程放回线程池,这个线程也不会立即撤销,而是设置为空闲状态,可供线程池再次调度,从而减少开销。
Task<TResult>
Task<TResult>是Task的泛型版本,这两个之间的最大不同是Task<TResult>可以有一个返回值,看一下代码应该一目了然:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Threading;
using System.Threading.Tasks;
namespace TestApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("主线程开始");
Task task = Task.Run(() => { Thread.Sleep(1000); return Thread.CurrentThread.ManagedThreadId.ToString(); });
Console.WriteLine(task.Result);
Console.WriteLine("主线程结束");
}
}
}Task<TResult>的实例对象有一个Result属性,当在Main方法中调用task.Result的时候,将等待task执行完毕并得到返回值,这里的效果跟调用task.Wait()是一样的,只是多了一个返回值。
async/await 特性
经过前面的铺垫,终于迎来了这篇文章的主角async/await,还是先通过代码来感受一下这两个特性的使用。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Threading;
using System.Threading.Tasks;
namespace TestApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("-------主线程启动-------");
Task task = GetLengthAsync();
Console.WriteLine("Main方法做其他事情");
Console.WriteLine("Task返回的值" + task.Result);
Console.WriteLine("-------主线程结束-------");
}
static async Task GetLengthAsync()
{
Console.WriteLine("GetLengthAsync Start");
string str = await GetStringAsync();
Console.WriteLine("GetLengthAsync End");
return str.Length;
}
static Task GetStringAsync()
{
return Task.Run(() => { Thread.Sleep(2000); return "finished"; });
}
}
}首先来看一下async关键字。async用来修饰方法,表明这个方法是异步的,声明的方法的返回类型必须为:void或Task或Task<TResult>。返回类型为Task的异步方法中无需使用return返回值,而返回类型为Task<TResult>的异步方法中必须使用return返回一个TResult的值,如上述Demo中的异步方法返回一个int。而返回类型可为void,则是为了和事件处理程序兼容,比如下面的示例:
public Form1()
{
InitializeComponent();
btnDo.Click += Down;
}
public async void Down(object sender, EventArgs e)
{
btnDo.Enabled = false;
string str = await Run();
labText.Text = str;
btnDo.Enabled = true;
}
public Task Run()
{
return Task.Run(() => { Thread.Sleep(5000); return DateTime.Now.ToString(); });
}再来看一下await关键字。await必须用来修饰Task或Task<TResult>,而且只能出现在已经用async关键字修饰的异步方法中。
通常情况下,async/await必须成对出现才有意义,假如一个方法声明为async,但却没有使用await关键字,则这个方法在执行的时候就被当作同步方法,这时编译器也会抛出警告提示async修饰的方法中没有使用await,将被作为同步方法使用。了解了关键字async\await的特点后,我们来看一下上述Demo在控制台会输入什么吧。

输出的结果已经很明确地告诉我们整个执行流程了。GetLengthAsync异步方法刚开始是同步执行的,所以"GetLengthAsync Start"字符串会被打印出来,直到遇到第一个await关键字,真正的异步任务GetStringAsync开始执行,await相当于起到一个标记/唤醒点的作用,同时将控制权放回给Main方法,"Main方法做其他事情"字符串会被打印出来。之后由于Main方法需要访问到task.Result,所以就会等待异步方法GetLengthAsync的执行,而GetLengthAsync又等待GetStringAsync的执行,一旦GetStringAsync执行完毕,就会回到await GetStringAsync这个点上执行往下执行,这时"GetLengthAsync End"字符串就会被打印出来。
当然,我们也可以使用下面的方法完成上面控制台的输出。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Threading;
using System.Threading.Tasks;
namespace TestApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("-------主线程启动-------");
Task task = GetLengthAsync();
Console.WriteLine("Main方法做其他事情");
Console.WriteLine("Task返回的值" + task.Result);
Console.WriteLine("-------主线程结束-------");
}
static Task GetLengthAsync()
{
Console.WriteLine("GetLengthAsync Start");
Task task = Task.Run(() => { string str = GetStringAsync().Result;
Console.WriteLine("GetLengthAsync End");
return str.Length; });
return task;
}
static Task GetStringAsync()
{
return Task.Run(() => { Thread.Sleep(2000); return "finished"; });
}
}
}对比两种方法,是不是async\await关键字的原理其实就是通过使用一个线程完成异步调用吗?答案是否定的。async关键字表明可以在方法内部使用await关键字,方法在执行到await前都是同步执行的,运行到await处就会挂起,并返回到Main方法中,直到await标记的Task执行完毕,才唤醒回到await点上,继续向下执行。更深入点的介绍可以查看文章末尾的参考文献。
async/await 实际应用
微软已经对一些基础类库的方法提供了异步实现,接下来将实现一个例子来介绍一下async/await的实际应用。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Threading;
using System.Threading.Tasks;
using System.Net;
namespace TestApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("开始获取博客园首页字符数量");
Task task1 = CountCharsAsync("http://www.cnblogs.com");
Console.WriteLine("开始获取百度首页字符数量");
Task task2 = CountCharsAsync("http://www.baidu.com");
Console.WriteLine("Main方法中做其他事情");
Console.WriteLine("博客园:" + task1.Result);
Console.WriteLine("百度:" + task2.Result);
}
static async Task CountCharsAsync(string url)
{
WebClient wc = new WebClient();
string result = await wc.DownloadStringTaskAsync(new Uri(url));
return result.Length;
}
}
}参考文献:<IIIustrated C# 2012> 关于async/await的FAQ 《深入理解C#》
http://npoi.codeplex.com/documentation
免费,开源,无需安装 Office,功能强大,兼容性好,使用方便,可以在 Visual Studio 的 NuGet 管理器中直接搜索安装。
导出 Excel 简单示例:
HSSFWorkbook book = new HSSFWorkbook();
ISheet sheet = book.CreateSheet("工作表1");
IRow r0 = sheet.CreateRow(0);
r0.CreateCell(0).SetCellValue("行1列1");
r0.CreateCell(1).SetCellValue("行1列2");
IRow r1 = sheet.CreateRow(1);
r1.CreateCell(0).SetCellValue("行2列1");
r1.CreateCell(2).SetCellValue("行2列3");
MemoryStream ms = new MemoryStream();
book.Write(ms);
Response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}.xls", "文件名"));
Response.BinaryWrite(ms.ToArray());
Response.End();
book = null;
ms.Close();
ms.Dispose();字体相关:
ICellStyle style = book.CreateCellStyle();
IFont font = book.CreateFont();
font.FontHeightInPoints = 20; // 字体大小
font.Color = HSSFColor.White.Index; // 字体颜色
style.SetFont(font);
style.FillForegroundColor = HSSFColor.Red.Index; // 背景色
style.FillPattern = FillPattern.SolidForeground;
cell.CellStyle = style;合并单元格:
CellRangeAddress cra = new CellRangeAddress(r - 1, r - 1, c - 1, c);
sheet.AddMergedRegion(cra);宽度自适应:
for (int i = 1; i < c; i++) {
sheet.AutoSizeColumn(i);
}函数:
cell.SetCellFormula("SUM(B2:B4)");顺便提一句,ICellStyle 和 IFont 最好一种样式一个变量先定义好再用,不要在循环里疯狂地 Create,否则超出数量(512个)会导致样式失效。
其它参考:http://www.ez2o.com/Blog/Post/csharp-Excel-NPOI-Font-Style
wxy0510:经过用户表优化后,论坛不活跃用户将被转至存档表。这将意味着论坛在常规调用、查询都不会遍历这些存档表的数据。这也大大提高服务器工作效率,减少服务器负载。当然处于存档表的用户在执行一次登录操作后,数据会重新转入主表。
xoyozo:这个登录是指论坛本身的用户登录,如果用第三方客户端 App 登录一般是不起作用的(除非 App 考虑到了这个情况)
common_member 是主表,common_member_archive 是存档表,这两个表的用户数相加即为 UC 用户表 ucenter_members 中的用户总和。
PW 的 pw_bbs_threads 存主题, pw_bbs_posts 存回复
DZ 的 pre_forum_thread 存主题,pre_forum_post 存主题+回复
论坛当初是从 PW 转到 DZ 的,转换程序把主题往帖子表(pre_forum_post)上插了一份,所以现在发现旧帖的主题的 pid 比它的回复的 pid 还要大的情况。
准备:
先把超时时间改成 300 秒,参 http://www.cnblogs.com/jackluo/p/3366612.html
了解一下分表基本原理:http://www.discuz.net/thread-2132691-1-1.html
主题分表:
可以任意创建主题存档表(forum_thread_X)
使用“主题移动”功能,筛选符合条件的主题,移动到主题存档表
新发表的主题仍然存于原始表(forum_thread)
移动到存档表中的主题,会在主题所在的版块下建立一个存档区,通过存档区可浏览存档表中的主题。
存档表中的主题,只供浏览,不可回复、评分,不能进行管理操作,但可以删除和移动到非存档区。
帖子分表:
帖子没有存档的概念
可以任意创建帖子分表(分表时创建新表或选择已存在分表)
一次分表操作可移动100MB的整数倍数据
根据主题表中最后回复时间正序排列的主题(first=1)tid 来获取帖子数据的
并将该主题的所有帖子移到目标表中
更新主题表中 posttableid 这个字段,来标识帖子的存储表
关闭论坛
关闭论坛监控
关闭数据库自动备份
主题先不分
第一个 100MB 用了 75 分钟,后来发现问题,数据库恢复了一下
然后1G用了1个半小时,估计恢复的时候顺便“优化”了
转移后打开帖子提示“没有找到帖子”,或者优化后打开帖子提示“没有找到帖子”,只要在数据库里“修复”一下就行了。(在Navicat“对象”中选中所有表,右键分析)
海鲜大部分是冷冻包装产品,小部分是散装称重产品,与超市类似,应选择“商超版”,除了钱箱、扫描枪,还应接电子秤。
触摸屏
不用记键盘快捷键,商品少的话直接点选,连扫码、输码、搜索都省了
好用的收银软件
见下方表格
称重一体
散装商品方便取重
Windows 7 及以上版本 或 安卓 操作系统
安心连网,用于支付宝/微信收款,方便连锁店共享数据。选择 Windows 的话建议选到 win10,因为 win7 将在 2020 年停止支持;新的收银机基本用的安卓,可能因为各种成本低吧,不过听说安卓收银机会卡顿,类似于安卓手机的操作感,核心数和内存跟PC也不是一个概念。
固态硬盘
Windows 建议选固态,开机快;安卓是闪存
销售过程中任何时间使用会员卡,而不是必须先扫会员卡,再扫商品
标签打印机,支持打印价格签(不干胶热敏纸条码),称重商品需要贴上即时生成的条码
支持扫描枪或扫码器扫描客户手机上的支付宝、微信(动态)付款码,以规避客户使用支付成功的截图来欺骗。需要一些配置,提现扣手续费。
支持拼音简码销售
选购步骤 先选择适合自己的收银软件,再选择配置和外观,当然要考虑外接设备的兼容性(电子秤同步称重、软件开钱箱、是否需要标签打印机或后厨打印机、扫描枪是否需要支持支付宝微信 等等)。
注:标签打印机不同于小票打印机,前者用于打印临时标签,可以包含名称、价格、重量、条码等信息,贴于散装称重商品,需选购;后者打印小票给顾客提供购买商品的明细,一般收银机自带。
附:几大收银软件功能对比(从商超的角度分析)注:部分功能可能因配置不同而不同,具体应咨询客服。
| 二维火 | 来钱快 | 美团收银 | |
| 版本 | 餐饮版 商超版 奶茶版:适用连锁店 | 基础版:适用餐饮 零售版:适用超市 专业版:适用连锁餐厅 | |
| 操作系统 | 安卓 | 安卓 | 安卓 |
| 适配触摸屏 | √ | √ | √ |
| 扫描商品条码、支付二维码 | √ | √ | √ |
| 对接外卖平台 | 美团外卖、饿了么、百度外卖 | 美团外卖、饿了么 | 美团外卖 |
| 手机下单 | √ | 免费微店、客户自助点餐 | 收银机点餐、顾客扫码点餐、服务员点餐 |
| 收银方式 | 聚合支付、支付宝、微信、现金 | 现金、支付宝、微信、银联、优惠券组合付款 | 现金、支付宝、微信、优惠券、会员、记账 |
| 会员功能 | 会员等级、积分、折扣、微信公众号营销 | 会员等级、充值、积分、折扣、俏销短信、报表 | 短信、储值、积分 |
| 支持手机 | 火掌柜App | 来钱快App 收银助手 | 美团管理APP |
| 报表 | √ | √ | √ |
| 自制条码(接标签打印机) | 商超版、奶茶版支持 | ||
| 盘点库存 | √ | 手机操作 | 电脑端 |
| 对接电子秤 | √ | 商超版支持 | |
| 连锁店管理 | √ | √ | 专业版支持 |
| 其它特点 | 排队叫号; 自主微信公众号粉丝运营; 小程序点餐 | 免费微信店铺,推广公众号 | 提高美团和大众点评店铺人气; 排队软件; 一店多收银台; |
售价 | 买收银机赠(零售 488 元),免费升级,连锁版每用户 599 元 | 零售版和基础版免费(买收银机赠),专业版收费 | |
| 相关链接 | 来钱快: 杭州萨宝科技: 软件和驱动: | 官方网站: 视频教程: http://shouyin.meituan.com/productGuide | |
| 我的评价 | 界面拟物还不错,具体没有深究 | 公司没有美团有名,但是入行比美团早,产品成熟,创新力强 | 可能更适合于奶茶店类型,对打包、外卖完美适用,有机会试用的话可以给出更客观的评价 |
本文资料整理于 2018 年 7 月
舟山海鲜捕鱼人品牌诚招代理,电话:13646674565(微信同号)
在开发微信中的网页时,会遇到一些域名相关的配置:
① 公众号设置 - 功能设置 - 业务域名
② 公众号设置 - 功能设置 - JS接口安全域名
③ 接口权限 - 网页授权获取用户基本信息
④ 商户平台 - 产品中心 - 开发配置 - JSAPI支付授权目录
⑤ 小程序 - 开发 - 开发设置 - 业务域名
⑥ 公众号开发 - 基本设置 - IP白名单
第①种 业务域名:相对不重要,只是用来禁止显示“防欺诈盗号,请勿支付或输入qq密码”提示框,可配置 3 个二级或二级以上域名(个人理解是“非顶级域名”,即填写了 b.a.com 的话,对 c.b.a.com 不起作用,待测)。
我们网站的域名和公众号是没有绑定关系的,那么你在打开一个(可能是朋友分享的)网页时,跟哪个公众号的配置去关联呢,答案是 JS-SDK。
测试结果:由于一个月只有3次修改机会,这次先测二级域名,有效;再测顶级域名,有效;删除所有,仍有效。所以应该是缓存作用。过几天再试,然后下个月先测顶级域名,来确定直接填写顶级域名是否对所有二级域名有效。
第②种 JS接口安全域名:是配置所配置的域名下的网页可调用 JS-SDK。可配置 5 个一级或一级以上域名(个人理解是“任何级域名”,即填写了 b.a.com 对 c.b.a.com 也有效,但对 c.z.a.com 无效,待测。如果我们拥有顶级域名对应网站的控制权(上传验证文件到网站根目录),直接填写顶级域名即可)。
使用 JS-SDK 的每个网页都必须注入配置信息(wx.config),而之前必须获取 jsapi_ticket,jsapi_ticket api 的调用次数非常有限,必须全局缓存。而获取 jsapi_ticket 之前必须先获取 access_token,同样需要全局缓存。所以,我们专门做个接口,功能是传入需要使用 JS-SDK 的网页的 url,输出 wx.config 需要用到的配置信息,来实现在不同网页(网站)使用 JS-SDK。
第③种 网页授权域名:这是已认证的服务号才能享有的特权,主要作用是获取用户在该服务号中的 openid 和 unionid。可配置 1 个 2 个回调域名(可填写任意级别的域名,但仅对该域名的网页(网站)有效,若填写了 a.com 对 b.a.com 是无效的)。
因此,如果我们需要在不同二级域名甚至不同顶级域名下的网页(以下称之为活动页面)实现用户授权,需要做一个统一的代理授权页面(回调域名当然是填写这个页面所在的域名),引导用户依次打开:微信授权页面 - 代理授权页面 - 活动页面,根据开发说明文档,具体实现如下:
当用户第一次打开活动页面时,引导打开微信授权页面(https://open.weixin.qq.com/connect/oauth2/authorize),其中参数 redirect_uri 指定回调地址,即代理授权页面地址,参数 state 指定活动页面地址。微信授权页面返回 code 和 state,code 作为换取网页授权 access_token 的票据。到这一步,本来可以由代理授权页面直接拿这个 code 去换取 access_token、openid 和 unionid 了,但是由于当前用户还在 302 重定向过程中,将这些信息带入到活动页面时势必导致信息泄露,所以这里将 code 追加到 state 指定的网址上后重定向到活动页面,活动页面拿到 code 再通过服务器端向代理授权页面所在服务器请求 openid 和 unionid,并将它们保存于 Session 中视为用户登录。这样,服务号的 appid 和 secret 也能得到保护。代理授权页面请求的微信服务器接口地址是 https://api.weixin.qq.com/sns/oauth2/access_token。
注:网页授权 access_token 不同于 JS-SDK 中使用的全局唯一接口调用凭据 access_token,没有请求次数限制。
流程既然通了,实现逻辑可以这样设定:
活动页面首先判断 Session 中是否有 openid 或 unionid,若有表示已授权登录;没有再判断地址栏是否有 code 参数,若有则调用代理授权页面所在服务器的接口,用 code 换 openid 和 unionid;没有则直接重定向到代理授权页面,带上 state。用 code 换 openid 和 unionid 时若成功则保存至 Session,若失败则仍然重定向到代理授权页面,带上 state,特别注意 state 中的活动页面地址确保没有 code 参数。
第④种 JSAPI支付授权目录:涉及到微信支付时用到,顾名思义是固定某一个网站内的某个目录,以“/”结尾。最多可添加 5 个。如果支付页面在目录 https://www.a.com/b/ 下,那么可以填写 https://www.a.com/b/ 或 https://www.a.com/(建议后者),暂未测试填写 https://a.com/ 会不会起作用。涉及支付安全,建议设置支付页面的最深一层不可写的目录,以防目录内被上传后门文件带来的安全隐患。
第⑤种 小程序业务域名:任何需要在小程序的 web-view 组件中打开的网页,都必须配置小程序业务域名,限制 20 个。该域名要求必须 https,可填入“任何级域名”(建议填顶级域名,即填写了 a.com 对 b.a.com 也有效。如果我们拥有顶级域名对应网站的控制权(上传验证文件到网站根目录),直接填写顶级域名即可)。
第⑥种 IP白名单:仅填写管理全局 access_token 的中控服务器的 IP。
总结:在上述自定义接口部署完成后,如果微信中的网页想获取用户的 unionid,则不需要配置域名,直接使用统一的代理授权即可;如果需要使用 JS-SDK 功能,如分享、上传等等,则需要配置 JS 接口安全域名;如果有表单,最好配置一下业务域名。
本文系个人经验总结,部分结果未经证实,欢迎指正!QQ:940534113
推荐:参考此文:如何升级 ASP.NET 项目 MySql.Data 和 Connector/NET 至 8.0.x
-------------------------------------------------------------------------------------------------------
这是 MySQL 官方提供的,用来帮助 .NET 开发者使用 LINQ 来方便操作 MySQL 数据库的解决方案。
我们所需要的软件全部被封装在 MySQL Installer 套件当中,非常方便。
下载后选择“Custom”自定义选择需要安装的产品和功能:
MySQL Server - 在本机安装 MySQL 数据库,如果我们直接连接远程数据库则不需要安装
MySQL for Visual Studio - 是一款 Visual Studio 插件,用于连接和管理 MySQL 数据库
Connector/NET - ADO.NET 托管提供程序
使用也非常方便:
在“服务资源管理器”中添加连接,更改数据源为“MySQL”。(如果没有该项,重启计算机试试;仍然没有,重新运行 MySQL Installer,选择“Modify ...”,勾选对应 VS 版本的“Visual Studio Integration”和“Entity Framework Designer Integration”)
项目中“添加新项”,在“数据”中选择“ADO.NET 实体数据模型”,即 Entity Framework,而非“LINQ to SQL 类”,根据需要选择表、视图和存储过程
Windows Server 服务器上安装 MySQL Server 过程中(或安装完成后再次运行 MySQL Installer)可配置端口(同时配置防火墙)。
建议勾选安装 MySQL Workbench 来管理 MySQL 数据库。
新建用户时,主机填“%”即该用户允许远程连接。
如果报以下错误:
不支持直接到存储查询(DbSet、DbQuery、DbSqlQuery)的数据绑定。应使用数据填充 DbSet (例如通过对 DbSet 调用 Load),然后绑定到本地数据。对于 WPF,绑定到 DbSet.Local。对于 WinForms,绑定到 DbSet.Local.ToBindingList()。
记得在绑定时加一个 .ToList() 即可。
如果发布后报以下错误:
找不到请求的 .Net Framework Data Provider。可能没有安装。
那么在服务器上安装 Connector/NET 即可。
如果在 VS 中连接此 EF 时如果遇到:
您的项目引用了最新版的实体框架;但是,找不到进行数据连接所需的与此版本兼容的实体框架数据库提供程序。请退出向导,安装兼容提供程序,重新生成您的项目,然后再执行此操作。
或
指定的架构无效。错误 0152: 未找到具有固定名称“MySql.Data.MySqlClient”的 ADO.NET 提供程序的实体框架提供程序。请确保在应用程序配置文件的“entityFramework”节中注册了该提供程序。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkId=260882。
那么,只需在 NuGet 中搜索并重新安装 MySql.Data.Entity ,重新生成项目。如果仍然提示,请检查 Connector/NET 是否有更新。
6.10.4 版本相关的问题参:MySQL Connector/Net 6.10.4 不支持 VS
升级“微信登录 1.1.6”插件后,发现微社区发帖提示“抱歉,您的请求来路不正确或表单验证串不符,无法提交”,查看更新日记发现微社区域名更换为 wsq.discuz.com,导致表单验证不通过的原因就是它了。
解决方法是打开:\source\class\helper\helper_form.php
找到:'
http://wsq.discuz.qq.com', 24
或:'
http://wsq.discuz.qq.com/', 25
替换为:'http://wsq.discuz.com/', 22
然后清空目录:\data\cache\qrcode\
至于帖子分享给朋友或朋友圈的标题和图片不正常的问题,目前还没有办法解决,听说是该插件要收费的节奏,具体可以参与官方讨论:
http://www.discuz.net/forum-2-1.html
另外,如果发现微社区里的用户头像或表情不能正常显示,一般是由于做了防盗链引起的,只要在白名单里加上 *.discuz.com 就行了