本篇文章内容比较基础,主要是向大家展示如何创建一个 ASP.NET 5 工程,主要包含内容如下:
- 创建ASP.NET 5 工程
- 添加 Todo 控制器
- 安装 K Version Manager
- 执行 EF 迁移
打开Visual Studio 2015 Preview。选择 ”File” 菜单,选择New > Project。
在New Project 对话框中,点击Templates > Visual C# > Web,选择ASP.NET Web Application 工程模板。命名工程为"TodoList",点击OK。
添加Todo 控制器
1. 下载完整工程completed project。
2. 在工程解决方案管理器中,右键点击Controllers 文件夹> Add > Exiting Item。输入下载工程中的TodoController.cs 文件路径。
3. 使用相同的方法添加 Models\TodoItem.cs 和Models\TodoItemEditModel.cs 文件到 Models 文件夹。
4. 在Views下创建ToDo 文件夹。使用同样方法,添加Views\ToDo 文件夹下所有View文件到Views\Todo 文件夹。
5. 更改Views\Shared\_Layout.cshtml 文件下的ActionLink 调用Todo 控制器:
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title - Todo</title>
<link rel="stylesheet" href="~/lib/bootstrap/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
@Html.ActionLink("Todo app", "Index", "Todo", new { area = "" }, new { @class = "navbar-brand" })
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
@* Markup removed for brevity *@
</body>
</html>
6. 添加 DbSet 包含TodoItem 模型到Models\IdentityModels.cs 文件。
{
private static bool _created = false;
public DbSet<TodoItem> TodoItems { get; set; }
// Code removed for brevity.
}
7. 运行app 点击Todo app 链接。你会遇到以下错误信息 (将在后续文章中解决这个问题)。
A database operation failed while processing the request.
SqlException: Invalid object name 'TodoItem'.
There are pending model changes for ApplicationDbContext
Scaffold a new migration for these changes and apply them to the database from the command line
> k ef migration add [migration name]
> k ef migration apply
安装K Version Manager (KVM)
1. 以管理员身份运行Visual Studio 命令提示工具。
2. 执行以下指令:
@powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/aspnet/Home/master/kvminstall.ps1'))"
以上指令将为当前用户安装KVM。
3. 退出Visual Studio 命令提示工具,重新使用管理员身份运行Visual Studio命令提示工具(你需要使用新的命令提示工具获取已经更新的路径环境)。
4. 使用以下指令升级KVM :
KVM upgrade
现在已经可以运行 EF 迁移了。.
执行EF 迁移
1. 在管理员命令提示窗体中,更改当前操作路径为工程文件夹,工程文件夹下包含project.json 文件。
2. 在命令提示窗体中运行以下指令:
k ef migration add initial
k ef migration apply
ef migration add initial
指令将以<date>_<migration name>.cs 命名形式添加一个迁移文件,迁移文件中包含了迁移代码that adds the TodoItem DbSet. TheMigrations\ApplicationDbContextModelSnapshot.cs 文件file will be updated to include instructions to create theTodoItem entity.
{
b.Property<int>("第三十课:JSDeferred详解1 - chaojidan 阅读原文»
本课难度非常大,看一遍,蛋会疼,第二遍蛋不舒服,第三遍应该貌似懂了。初学者莫来,没必要,这完全就是一个研究。
JSDeferred是日本高手cho45搞出来的,其易用性远胜于Mochikit Deferred,它的实现形态基本上奠定了后来称为Promise/A的范式,是js在异步编程上的一个里程碑作品。
JSDeferred不像Mochikit Deferred那样用数组保存回调,而是用Deferred对象自身作为载体来保存回调。司徒正美说:看懂这个库的代码,对你的能力提升很大,如是我去看了。
Deferred.define();
next(function(){});
上面代码的意思是:创建一个匿名的Deferred实例,并且绑定一个成功时执行的回调方法。它使用next而不是addCallback来添加回调方法。
当然上面的这种方式,会污染全局作用域,比如:next方法就是在全局作用域下。它还有两种无侵入(不污染全局作用域)的写法:
var o = {}; //定义一个对象
Deferred.define(o); //把Deferred的方法全部赋到o对象上,因为第一个next方法是Deferred上的静态方法,所以o对象上也有next方法了
o.next(function(){}) //然后就可以调用o对象的next方法添加回调函数。
或者直接使用Deferred:
Deferred.next(function(){}) //它会在内部创建一个Deferred实例,然后调用这个实例的next方法,以及你调用其他的方法时,直接就可以用链式方式进行调用,就跟jQuery的链式操作一样。
上面的这三种方式,无论哪个,第一次调用的next方法,其实是一个静态方法,它的作用是提供一个JSDeferred实例,并执行第一个异步操作。
异步操作在JSDeferred中有很多实现方式,如setTimeout,image.onerror,script.onreadystatechange等,那么当调用第一个next时,它的异步操作是执行那种方式实现的异步操作呢?其实它会根据不同的浏览器,选择在这个浏览器中最快的API来执行。我们先来看一个最简单的实现方式,用setTimeout实现第一个next的异步操作。由于第一个next方法是静态方法,所以它的定义是:第一个next方法就是在Deferred构造函数中的next_default方法(有很多方式来实现它的异步操作,这里我们只讲setTimeout是如何实现的)。
Deferred.next_default = function(fun){
var d = new Deferred();
var id = setTimeout(function(){
clearTimeout(id);
d.call()
},0);
d.canceller = function(){
try{
clearTimeout(id);
}catch(e){}
};
if(fun){
d.callback.on = fun;
}
return d;
};
我们来看第一次调用next方法时,它所做的操作。首先,new一个新的Deferred,赋给局部变量d。然后弄一个0秒定时器(它的意思是0秒后执行回调方法,但是由于浏览器有最小时钟间隔,因此这个定时器后面的代码会先执行)。这时,给新建的Deferred对象定义canceller属性,如果有传入fun参数(成功时执行的回调函数),就把这个函数加载到新建的Deferred对象的callback.ok(new 出来的Deferred会默认有callback属性,它的值是一个对象,对象里面有ok,ng属性,这里是重写了它的ok属性值)属性上,返回新建的Deferred对象。最后等过了浏览器的最小时钟间隔后,就会立即执行setTimeout里面的回调方法,代码开始时首先清除这个定时器(这时setTimeout就失效了,但是这里无法阻止回调方法里面的代码执行),然后调用新建的Deferred对象的call方法(此方法就会执行next方法中添加的函数)。
第二个调用的next方法,以及后面调用的next方法都是实例方法,也就是Deferred.prototype原型对象中的方法,因为第一次调用next方法时,执行的是Deferred的静态方法next_default,它会返回一个Deferred的实例对象,所以后面的链式调用next方法,其实调用的都是Deferred实例对象的next方法。因此第二个以及后面的next方法跟第一个next的方法完全不同。举个例子:
Deferred.define();
next(function fun1(){alert(1)}).next(function fun2(){alert(2)}); //第一个next方法是Deferred的静态方法next_default,返回一个new出来的Deferred实例对象,然后调用第二个next方法时,其实就是d.next(function fun2(){ alert(2)}),这时第二个next方法就是Deferred的实例方法(Deferred.prototype对象中的方法)。
alert(3);
上面的结果:3,1,2。因为第一个next中添加的函数,会延迟执行(里面有个定时器),所以3先打印出来。第二个next方法,是实例方法,它会新建一个Deferred对象,把它赋给当前Deferred对象的._next属性,它里面没有定时器。所以2不会弹出,只有等定时器结束,弹出1后,当前的Deferred对象会通过._next属性找到新建的Deferred对象,然后执行它的回调函数,弹出2。
我们来看下Deferred构造函数的源码:
function Deferred(){
return (this instanceof Deferred) ? this.init() : new Deferred(); //new Deferred时,执行上下文必须是Deferred对象,才能初始化,不然就new一个新的Deferred对象再初始化
}
Deferred.ok = function(x) { return x};
Deferred.ng = function(x) { return x};
Deferred.prototype = {
init:function(){ //new Deferred时,调用的就是init方法,来对Deferred对象进行初始化
this._next = null;
this.callback = { //new出来的Deferred对象,会有默认的callback属性,它的值是一个json对象,json对象中有ok属性和ng属性,ok属性其实就是成功时,回调的方法,ng是失败时,回调的方法。当你在next方法中添加回调函数时,会覆盖这ok,ng这两个属性值。
ok:Deferred.ok,
ng:Deferred.ng
};
return this;
},
call:function(val){
return this._fire("ok",val); //这就是上面的d.call方法,也就是定时器中的回调方法执行时,调用的方法。定时器一结束,就立即执行。call方法,会调用next中添加的函数。
},
_fire:function(okng,value){
var next = "ok";
try{
value = this.callback[okng].call(this,value); //执行next中添加的函数,如果此函数抛出错误,就会执行catch中的代码,上面的例子,其实就是弹出1,不会执行catch中的代码。(这里的意思是,如果这个next中添加的函数抛出错误,那么它之后的那个next中的异步操作会调用ng的函数,也就是失败时执行的函数)
}catch(e){
next = "ng";
value = e;
}
if(value instanceof Deferred){ //如果next添加的函数返回值是Deferred对象d1,就把当前Deferred对象的_next属性值赋给d1的next属性。
value._next = this._next;
}else{ //如果返回值不是Deferred,就是上面例子的结果
if(this._next){ //判断当前的Deferred对象是否有._next属性(第二个next方法创建的Deferred实例对象),如果有,就调用它的_fire方法,上面的例子是有的,所以会调用第二个next方法添加的回调函数。
this._next._fire(next,value); //如果当前Deferred对象的ok回调函数报错(next="ng"),那么下一个Deferred对象(下一个next新建的Deferred对象)调用的是名为ng的回调函数。而且当前回调函数返回的值可以作为下一个next的回调函数中的参数值。
}
}
return this;
},
next:function(fun){ //这就是第二次以及之后调用next的执行方法,是Deferred对象的实例方法,在Deferred的原型上
return this._post("ok",fun);
},阅读更多内容
没有评论:
发表评论