Access to XMLHttpRequest at '********' from origin '********' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
如果仅仅是在开发环境调试,可以安装 Chrome 插件;
也可以在 PHP、ASP.NET 等后端语言中设置 header;
当然还可以在 Web 服务器上设置,如在 IIS 中:
点击“IIS 响应标头”,添加 Access-Control-Allow-Origin
总之,是在资源端设置是否允许跨域访问。
譬如使用网页播放器播放阿里云直播流时,需要在阿里云视频点播控制台-域名管理-HTTP头配置 中设置。
更多信息:
本文不定时更新中……
收集了一些在开发过程中遇到的一些问题的解决方法,适合新手。
异常:
出现脚本错误或者未正确调用 Page()
原因:不小心删了第一行内容:<template>
异常:
模块编译失败:TypeError: Cannot read property 'for' of undefined
at fixDefaultIterator (D:\HBuilderX\plugins\uniapp\lib\mpvue-template-compiler\build.js:4277:24)
at mark (D:\HBuilderX\plugins\uniapp\lib\mpvue-template-compiler\build.js:4306:5)
at markComponent (D:\HBuilderX\plugins\uniapp\lib\mpvue-template-compiler\build.js:4371:5)
at baseCompile (D:\HBuilderX\plugins\uniapp\lib\mpvue-template-compiler\build.js:4384:15)
at compile (D:\HBuilderX\plugins\uniapp\lib\mpvue-template-compiler\build.js:4089:28)
at Object.module.exports (D:\HBuilderX\plugins\uniapp\lib\mpvue-loader\lib\template-compiler\index.js:43:18)
原因:新建的页面(简单模板)只有以下 3 个标签,须在 <template /> 中添加一些代码,如 <view />
<template>
</template>
<script>
</script>
<style>
</style>
异常:
模块编译失败:TypeError: Cannot read property 'toString' of undefined
at Object.preprocess (D:\HBuilderX\plugins\uniapp\lib\preprocess\lib\preprocess.js:56:15)
at Object.module.exports (D:\HBuilderX\plugins\uniapp\lib\preprocessor-loader.js:9:25)
原因:没有原因,纯抽风,HX 关掉再开就好了。
异常:
Cannot set property 'xxx' of undefined;at pages/... onLoad function;at api request success callback function
原因:属性未定义,例如
data() {
return {
item: { }
}
}
而直接赋值 this.item.abc.xxx = '123';
解决:
data() {
return {
item: {
abc: ''
}
}
}
问:page 页面怎样修改 tabBar?
答:官方文档未给出答案,百度了一圈也无果(2018-10-23),但有人说小程序的 setTabBarBadge() 方法设置角标是可以用的。
坑:
VM1694:1 获取 wx.getUserInfo 接口后续将不再出现授权弹窗,请注意升级
参考文档: https://developers.weixin.qq.com/community/develop/doc/0000a26e1aca6012e896a517556c01
填坑:放弃使用 uni.getUserInfo 接口来获取用户信息,uni.login 可返回用于换取 openid / unionid 的 code,参:uni.login、 code2Session
坑:字符搜索(当前目录)(Ctrl+Alt+F)搜不出所有结果
填坑:顾名思义他只搜索当前目录,即当前打开文件所在目录,而非我误认为的整个项目根目录。在“项目管理器”中选中要搜索字符的目录即可。
坑:uni.navigateTo() 或 uni.redirectTo() 没反应
填坑:这两个方法不允许跳转到 tabbar 页面,用 uni.switchTab() 代替。
坑:使用“Ctrl+/”快捷键弹出“QQ五笔小字典”窗口
解决:打开QQ五笔“属性设置”,切换到“快捷键设置”选项卡,把“五笔小字典”前的勾取消(即使该组合键是设置为Ctrl+?)。
坑:<rich-text /> 中的 <img /> 太大,超出屏幕宽度
填坑:用正则表达式给 <img /> 加上最大宽度
data.data.Content = data.data.Content.replace(/\<img/gi, '<img style="max-width:100%;height:auto" ');
坑:无法重命名或删除目录或文件
填坑一:“以管理员身份运行”HBuilder X 后再试。
填坑二:关闭微信开发者工具、各种手机和模拟器后再试。
填坑三:打开“任务管理器”,结束所有“node.exe”进程后再试。
坑:
thirdScriptError
sdk uncaught third Error
(intermediate value).$mount is not a function
TypeError: (intermediate value).$mount is not a function
Page[pages/xxxx/xxxx] not found. May be caused by: 1. Forgot to add page route in app.json. 2. Invoking Page() in async task.
Page is not constructed because it is not found.
填坑:关闭微信开发者工具、各种手机和模拟器后,删除“unpackage”目录。
坑:
Unexpected end of JSON input;at "pages/news/view" page lifeCycleMethod onLoad function
SyntaxError: Unexpected end of JSON input
填坑:给 uni.navigateTo() 的 url 传参时,如果简单地将对象序列化 JSON.stringify(item),那么如果内容中包含“=”等 url 特殊字符,就会发生在接收页面 onLoad() 中无法获取到完整的 json 对象,发生异常。
uni.navigateTo({
url: "../news/view?item=" + JSON.stringify(item)
})
所以应该把参数值编码:
uni.navigateTo({
url: "../news/view?item=" + escape(JSON.stringify(item))
})
如果是一般的 web 服务器来接收,那么会自动对参数进行解码,但 uni-app 不会,如果直接使用:
onLoad(e) {
this.item = JSON.parse(e.item);
}
会发生异常:
Unexpected token % in JSON at position 0;at "pages/news/view" page lifeCycleMethod onLoad function
SyntaxError: Unexpected token % in JSON at position 0
需要解码一次:
onLoad(e) {
this.item = JSON.parse(unescape(e.item));
}
需要注意的是,unescape(undefined) 会变成 'undefined',如果要判断是否 undefined,应是 unescape 之前。
坑:图片变形
填坑:mode="widthFix"
坑:页面如何向 tabBar 传参
填坑:全局或缓存
坑:编译为 H5 后,出现:Access-Control-Allow-Origin
填坑:参阅
坑:编译为 H5 后,GET 请求的 URL 中出现“?&”
填坑 :客户端只求 DCloud 官方能够尽快修复这个 bug,IIS 端可以暂时用 URL 重写来防止报 400 错误,参此文。
坑:[system] errorHandler TypeError: Cannot read property 'forEach' of undefined
填坑:待填
发布选项 \ 项目类型 | Web 窗体网站 | Web 应用程序 (Web 窗体) | Web 应用程序 (MVC) | ASP.NET Core Web 应用程序 |
在发布期间预编译 Precompile during publishing | 若勾选,将 .cs 文件编译为 .dll | 无论是否勾选,都将 .cs 文件编译为 .dll | ||
允许更新预编译站点 Allow precompiled site to be updatable | 若不允许,则会将 .aspx 等页面也一同编译,并以内容“这是预编译工具生成的标记文件,不应删除!”代替 |
未进行完整的测试和分析,总结有误请指正。
重点提前看:
https://xoyozo.net/Blog/Details/MySQL-on-Windows
Connector/Net 6.10.4(暂)不支持在 Visual Studio 2015/2017 添加 ADO.NET 实体数据模型时选择 MySQL Data Provider 数据源。并且,在编译项目时会出现“违反了继承安全性规则”的异常。
只能降回 Connector/Net 6.9.10,NuGet 中将 MySql.Data 和 MySql.Data.Entity 用 6.9.10 和 6.10.4 版本皆可(除非遇到下文中提到的异常)。
重新生成或重启 VS 使之生效。
另外,MySql.Data 和 MySql.Data.Entity 6.9.10 可以配合 EnityFramework 和 EntityFramework.zh-Hans 6.1.x 和 6.2.0 使用。
MySql.Data 和 MySql.Data.Entity 6.9.9 在创建/更新实体模型向导中会出现闪退,更换为 6.9.10 试试。
或重新安装 Connector/NET 和 MySQL for Visual Studio 并重启电脑试试。
仍然闪退,参此文:https://xoyozo.net/Blog/Details/mysql-for-vs-flashback。
重要提醒,如果在添加 EF 模型时报错:
您的项目引用了最新版的实体框架;但是,找不到进行数据连接所需的与此版本兼容的实体框架数据库提供程序。请退出向导,安装兼容提供程序,重新生成您的项目,然后再执行此操作。
那么在菜单中选择:生成 - 清理解决方案,然后直接添加数据模型。如果在添加前生成了项目(bin 目录下有相关 .dll 文件),那么将出现上述错误。
类型“MySql.Data.MySqlClient.MySqlProviderServices”违反了继承安全性规则。派生类型必须与基类型的安全可访问性匹配或者比基类型的安全可访问性低。
将 MySql.Data 和 MySql.Data.Entity 从 6.10.4 退回 6.9.10 版本即可。
以上问题出现在:
VS 15.4.*
VS 15.4.4
VS 15.4.5
----------------
VS 15.5 已经可以在 EF 向导中连接 MySQL 数据库(Connector/Net 6.10.4),但 MySql.Data.Entity 6.10.4 编译仍然出现“违反了继承安全性规则”。另:MySQL 官网下架了 Connector/Net 6.10.4,退回提供 6.9.10 版本。
2017-12-9 发布的 Connector/Net 6.10.5 仍然存在无法在 EF 向导中连接 MySQL 数据源的问题。
服务器上安装 Connector/Net 6.10.4 没有任何问题。
经常会看到这样似错非错的提示:
当前上下文中不存在名称"__o"
The name '__o' does not exist in the current context
实际上,我没有定义任何名为 __o 的变量。
发生这种情况的原因可能是使用了类似如下的代码:
<% if(true) { %>
<%= 1 %>
<% } %>
<%= 2 %>
为了在设计界面的 <%= %> 代码块中提供智能感知,ASP.NET(VB 或 C#)会自动生成一个名为“__o”的临时变量,这在页面编译器看到第一个 <%= %> 块时就完成了。但是在这里,<%= %> 块在 if 中出现,所以当关闭 if 后再使用 <%= %> 时,变量超出了定义的范围。
if (true)
{
object @__o;
@__o = 1;
}
@__o = 2;
解决方法:在页面的早期添加一个虚表达式。例如:<%= "" %>。这将不会呈现任何内容,并且它将确保在任何潜在的 if(或其他范围界定)语句之前,在 Render 方法中将 __o 声明为顶级。
当然还有一种治标不治本的方法就是隐藏这些错误提示(这并不影响程序正常运行):
点击错误列表面板左上角的过滤器按钮,CS0103,其中包含错误代码:当前上下文中不存在名称"__o",这些错误将不再显示,您仍然可以有其他 IntelliSense 错误和警告。
windows 7和vista提高的系统的安全性,同时需要明确指定“以管理员身份运行”才可赋予被运行软件比较高级的权限,比如访问注册表等。否则,当以普通身份运行的程序需要访问较高级的系统资源时,将会抛出异常。
如何让程序在启动时,自动要求“管理员”权限了,我们只需要修改app.manifest文件中的配置项即可。
app.manifest文件默认是不存在的,我们可以通过以下操作来自动添加该文件。
(1)进入项目属性页。
(2)选择“安全性”栏目。
(3)将“启用ClickOnce安全设置”勾选上。
现在,在Properties目录下就自动生成了app.manifest文件,打开该文件,将trustInfo/security/requestedPrivileges节点的requestedExecutionLevel的level的值修改为requireAdministrator即可。如下所示:
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
记住,如果不需要ClickOnce,可以回到项目属性页将“启用ClickOnce安全设置”不勾选。
接下来,重新编译你的程序就OK了。
前言
最近在学习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#》
将 Windows\Temp 目录的权限 Network Service 帐户赋予了完全控制的权限
出错快照:
“/”应用程序中的服务器错误。
编译错误
说明: 在编译向该请求提供服务所需资源的过程中出现错误。请检查下列特定错误详细信息并适当地修改源代码。
编译器错误消息: CS0016: Could not write to output file 'c:\Windows\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\138641eb\e8d016c8\App_Web_default.aspx.bb4e7940.re_hlwux.dll' -- '拒绝访问。 '