异步编程和跨域请求(04) 目录: 一.异步编程 二.跨域请求
- 异步编程
- 跨域请求
一.异步编程
- 线程池
创建的线程存起来,形成一个线程池(里面有多个线程),当要处理任务时,若线程池中有空闲线程(前一个任务执行完成后,线程不会被回收,会被设置为空闲状态),则直接调用线程池中的线程执行。
- Task 和 Task<TResult>
Task是.NET4.0加入的,跟线程池ThreadPool的功能类似,用Task开启新任务时,会从线程池中调用线程,而Thread每次实例化都会创建一个新的线程。
Console.WriteLine("主线程启动");
Task task = Task.Run(() => { //开启新任务的方法:Task.Run()或者Task.Factory.StartNew(),开启的是后台线程。
Thread.Sleep(1500);
Console.WriteLine("task启动");
});
task.Wait(); //主线程中等待后台线程执行完毕。不用Wait则会以异步的方式来执行。
Console.WriteLine("主线程结束");
//---------------------------------------------------------------------------------
//Task<TResult>
Console.WriteLine("主线程开始");
//返回值类型为string
Task<string> task = Task<string>.Run(() => { //Task<TResult>就是有返回值的Task,TResult就是返回值类型。
Thread.Sleep(2000);
return "任务返回的结果";
});
//会等到task执行完毕才会输出;
Console.WriteLine(task.Result);
Console.WriteLine("主线程结束");
通过task.Result可以取到返回值,若取值的时候,后台线程还没执行完,则会等待其执行完毕。
- async/await
C# 5.0中引入了async 和 await。这两个关键字可以让你更方便的写出异步代码。
static Task<string> GetString()
{
//Console.WriteLine("GetString方法开始执行")
return Task<string>.Run(() =>
{
Thread.Sleep(2000);
return "GetString的返回值";
});
}static async Task<int> GetStrLengthAsync()
{
Console.WriteLine("GetStrLengthAsync方法开始执行");
//此处返回的<string>中的字符串类型,而不是Task<string>
string str = await GetString(); //await不会阻塞主线程,只会让GetStrLengthAsync方法暂停执行。
Console.WriteLine("GetStrLengthAsync方法执行结束");
return str.Length;
}
static void Main(string[] args)
{
Console.WriteLine("-------主线程启动-------");
Task<int> task = GetStrLengthAsync();
Console.WriteLine("主线程继续执行");
Console.WriteLine("Task返回的值" + task.Result);
Console.WriteLine("-------主线程结束-------");
Console.Read();
}
运行效果:
async用来修饰方法,表明这个方法是异步的,声明的方法的返回类型必须为:void,Task或Task<TResult>。
await必须用来修饰Task或Task<TResult>,而且只能出现在已经用async关键字修饰的异步方法中。通常情况下,async/await成对出现才有意义。
- 在ASP.NET Web API中使用async/await
当在数据库中执行查询时,异步查询可避免阻止线程。异步操作还可以增加 Web 应用程序的吞吐量,可以在数据库操作完成时释放线程去处理其他请求。
//异步查询
public async Task<IHttpActionResult> GetStudentAsync()
{
Student student = null;
using (var context = new SchoolDBEntities())
{
//注意await和FirstOrDefaultAsync
student = await (context.Students.Where(s => s.StudentID == 1).FirstOrDefaultAsync<Student>());
}
return Json(student);
}
//异步保存
public async Task<IHttpActionResult> Put(Student stu)
{
using (var context = new SchoolDBEntities())
{
context.Entry(stu).State = EntityState.Modified;
int x = await (context.SaveChangesAsync());
return Ok("保存完成");
}
}
在System.Data.Entit.QueryableExtensions 扩展类中,提供了一系列异步方法,如:FirstOrDefaultAsync()、ToListAsync()、ToArrayAsync()、SingleAsync()等。另外还有DbContext对象的SaveChangesAsync()方法。
二.跨域请求
- 跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制。
- 所谓的同源是指:域名、协议、端口均为相同。
- 同源策略限制了以下行为:Cookie、LocalStorage 和 IndexDB 无法读取 || DOM 和 JS 对象无法获取 || Ajax请求发送不出去
- 常见的跨域场景
URL |
说明 |
是否允许 |
http://www.aoxiang.cn/index.html http://www. aoxiang.cn/server.php |
非跨域 |
允许 |
http://www. aoxiang.cn/index.html http://www.neal.cn/server.php |
跨域,主域不同 |
不允许 |
http://abc. aoxiang.cn/index.html http://def. aoxiang.cn/server.php |
跨域,子域名不同 |
不允许 |
http://www.aoxiang.cn:8080/index.html http://www. aoxiang.cn/server.php |
跨域,端口不同 |
不允许 |
https://www. aoxiang.cn/index.html http://www. aoxiang.cn/server.php |
跨域,协议不同 |
不允许 |
当发生跨域时,经常会引发如下形式的异常。
- 跨域问题的解决方案
1.Mvc和WebApi通用的模式
只需要在WebConfig中进行配置,缺点是只能进行全局配置。
<system.webServer>
<!--允许跨域请求的配置 WebApi和MVC通用-->
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Access-Control-Allow-Origin, AppKey, Authorization"/>
<add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS" />
<add name="Access-Control-Request-Methods" value="GET, POST, OPTIONS" />
</customHeaders>
</httpProtocol>
<!--允许跨域请求的配置 WebApi和MVC通用 至此结束-->
<!—略……-->
</system.webServer>
其中,
l Access-Control-Allow-Origin :代表允许请求的地址,如:" http://localhost:2131, http://localhost:2133" 多个地址之间用逗号隔开,* 代表运行所有
l Access-Control-Allow-headers: 代表允许的表头
l Access-Control-Allow-method: 代表允许请求的方法。如:"GET,PUT,POST,DELETE"
2. WebApi特有的处理方式
- 首先通过Nuget添加【Microsoft.AspNet.WebApi.Cors】程序集。
- 核心方法:EnableCorsAttribute(string origins, string headers, string methods)
分别表示:origins代表允许请求的地址:" http://localhost:2131, http://localhost:2133" 多个地址之间用逗号隔开。
headers代表允许的表头。
method代表允许请求方法:"GET,PUT,POST,DELETE"
* 代表允许所有。
- 可以作用于全局,也可以特性的形式作用于Controller,或者直接作用于Action。
1.作用于全局
在WebApiConfig类中的Register方法中添加:config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
2. 作用于Controller
(1). 在WebApiConfig类中的Register方法中添加:config.EnableCors();
(2). 在FifthController控制器上添加特性:[EnableCors("*", "*", "*")]
3. 作用于Action
(1). 在WebApiConfig类中的Register方法中添加:config.EnableCors();
(2). 在GetUserName2方法上添加特性:[EnableCors("*", "*", "*")]
部分代码如下所示: