初识Identity(二)
本文参考了【ASP.NET Identity系列教程(一)】ASP.NET Identity入门
一、Identity使用前准备项目
本文创建了一个名称为Users的项目。在创建过程中选择了“Empty(空)” 模板,并在“Add the folders and references(添加文件夹和引用)”中选中了“MVC”复选框。本文使用Bootstrap来设置视图的样式,因此在vs中的包管理器控制台中输入以下命令,并按回车,下载并安装这个NuGet包。
Install-Package -version 3.0. bootstrap
1、创建ASP.NET Identity数据库
ASP.NET Identity未像Membership那样,被绑定到SQL Server架构,但关系型存储仍是默认的,而且是最简单的选择,这也是我接下来会使用的形式。
ASP.NET Identity使用Entity Framework的Code First特性自动地创建它的数据架构(Schema),但我仍然需要创建一个用来放置此数据架构以及用户数据的数据库。我这里要使用localdb特性来创建数据库。要记住的是,localdb是包含在Visual Studio之中的,而且是一个简化版的SQL Server,能够让开发者方便地创建和使用数据库。
2、添加Identity包
Identity是作为一组NuGet包发布的,可将其安装到任何项目,可在“Package Manager Console(包管理器控制台)”中寻找这些安装:
Install-Package Microsoft.AspNet.Identity.EntityFramework –Version 2.0.0(2.2.1)
Install-Package Microsoft.AspNet.Identity.OWIN -Version 2.0.0(2.2.1)
Install-Package Microsoft.Owin.Host.SystemWeb -Version 2.1.0(3.0.1)
3、更新Web.config文件
为了做好项目使用ASP.NET Identity的准备,需要在Web.config文件中做两处修改。第一处是连接字符串,它描述了之前创建的数据库。第二处修改是定义一个应用程序设置,它命名对OWIN中间件进行初始化的类,并将它用于配置Identity。
<connectionStrings>
<add name="IdentityDb" providerName="System.Data.SqlClient"connectionString="Data Source=(localdb)\v11.0; Initial Catalog=IdentityDb;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=False;MultipleActiveResultSets=True"/>
</connectionStrings>
注:要确保将connectionString的值放在一行中,ASP.NET要求是单一无断行的字符串。
4、创建Entity Framework类
如果你曾使用过Membership,可能会奇怪ASP.NET Identity为什么需要这么多初始化准备。ASP.NET Identity具有Membership缺乏的可扩展性,但其代价是需要创建一组实现类,由Entity Framework用于管理数据库。在以下,我会演示如何创建所需要的这些类,以便让Entity Framework将它们用于ASP.NET Identity的存储系统。
1.创建用户类
第一个要定义的类是表现一个用户的类,我这里将它称为“User Class(用户类)”。这个用户类派生于IdentityUser,它是在Microsoft.AspNet.Identity.EntityFramework命名空间中定义的。IdentityUser提供了基本的用户表示,可以通过在它派生的类中添加属性的办法,对这个类进行扩展。下表列出了IdentityUser所定义的内建属性,本文会使用这些属性。
目前最重要的是这个IdentityUser类只提供了对用户基本信息的访问:用户名、E-mail、电话、哈希口令、角色成员等等。如果希望存储用户的各种附加信息,就需要在IdentityUser派生的类上添加属性,并将它用于表示应用程序中的用户。
注:(1)“内建”和“内置”在含义上是有区别的,“内建”完全是自己创建的,而“内置”有可能是别人做的东西拿来放入其中的。
(2)Microsoft.AspNet.Identity.EntityFramework命名空间中的类是, Microsoft.AspNet.Identity命名空间中所定义接口的Entity Framework专用的具体实现。例如,IdentityUser便是IUser接口的实现。我使用这些具体类是因为还需要Entity Framework在数据库中存储用户数据。
IdentityUser类定义的属性
名称 | 描述 |
---|---|
Claims | 返回用户的声明集合 |
返回用户的E-mail地址 | |
Id | 返回用户的唯一ID |
Logins | 返回用户的登录集合 |
PasswordHash | 返回哈希格式的用户口令,在“实现Edit特性”中会用到它 |
Roles | 返回用户所属的角色集合 |
PhoneNumber | 返回用户的电话号码 |
SecurityStamp | 返回变更用户标识时被修改的值,例如被口令修改的值 |
UserName | 返回用户名 |
为了创建应用程序中的用户类,我在Models文件夹中创建了一个类文件,名称为AppUser.cs,并用它创建了AppUser类。下列代码为AppUser.cs文件的内容。
using System;
using Microsoft.AspNet.Identity.EntityFramework; namespace Users.Models {
public class AppUser : IdentityUser {
// additional properties will go here
// 这里将放置附加属性
}
}
2.创建数据库上下文类
本步骤是创建Entity Framework数据库的上下文,用于对AppUser类进行操作。这可以用Code First特性来创建和管理数据架构,并对数据库所存储的数据进行访问。这个上下文类派生于IdentityDbContext<T> ,其中的T是用户类(即此例中的AppUser)。我在项目中创建了一个文件夹,名称为Infrastructure,并在其中添加了一个类文件,名称为AppIdentityDbContext.cs,其代码如下:
using System.Data.Entity;
using Microsoft.AspNet.Identity.EntityFramework;
using Users.Models; namespace Users.Infrastructure {
public class AppIdentityDbContext : IdentityDbContext<AppUser> { public AppIdentityDbContext() : base("IdentityDb") { } static AppIdentityDbContext() {
Database.SetInitializer<AppIdentityDbContext>(new IdentityDbInit());
} public static AppIdentityDbContext Create() {
return new AppIdentityDbContext();
}
} public class IdentityDbInit
: DropCreateDatabaseIfModelChanges<AppIdentityDbContext> { protected override void Seed(AppIdentityDbContext context) {
PerformInitialSetup(context);
base.Seed(context);
} public void PerformInitialSetup(AppIdentityDbContext context) {
// initial configuration will go here
// 初始化配置将放在这儿
}
}
}
这个AppIdentityDbContext类的构造器调用了它的基类,其参数是连接字符串的名称,IdentityDb,用于与数据库连接。这是让下列代码定义的连接字符串与ASP.NET Identity联结起来的方法。
这个AppIdentityDbContext类还定义了一个静态的构造器,它使用Database.SetInitializer方法指定了一个种植数据库的类(种植数据库的含义是往数据库中植入数据的意思,说穿了,就是用一些数据对数据库进行初始化——译者注),当通过Entity Framework的Code First特性第一次创建数据库架构时,会用到这个类。这个种植类叫做IdentityDbInit,而且我已经提供了一个类,创建了一个占位符,后面可以回过头来在PerformInitialSetup方法中添加语句,就可以种植数据库了。
最后,AppIdentityDbContext类定义了一个Create方法。这是由OWIN在必要时创建类实例的办法,这个由OWIN使用的类将在“创建启动类”中进行描述。
3. 创建用户管理器类
最重要的Identity类之一是“User Manager(用户管理器)”,用来管理用户类实例。用户管理器类必须派生于UserManager<T> ,其中T是用户类。这个UserManager<T> 类并非是专用于Entity Framework的,而且它提供了很多通用特性,用以创建用户并对用户数据进行操作。下表列出了UserManager<T> 类为管理用户而定义的基本方法和操作。还有一些其他方法,这里并未全部列出来,我会在适当的情形下对它们进行描述,那时会介绍管理用户数据的不同方式。
名称 | 描述 |
---|---|
ChangePasswordAsync(id, old, new) | 为指定用户修改口令 |
CreateAsync(user) | 创建一个不带口令的新用户 |
CreateAsync(user, pass) | 创建一个带有指定口令的新用户 |
DeleteAsync(user) | 删除指定用户 |
FindAsync(user, pass) | 查找代表该用户的对象,并认证其口令 |
FindByIdAsync(id) | 查找与指定ID相关联的用户对象 |
FindByNameAsync(name) | 查找与指定名称相关联的用户对象 |
UpdateAsync(user) | 将用户对象的修改送入数据库 |
Users | 返回用户枚举 |
请注意方法名以Async结尾的那些方法。因为ASP.NET Identity几乎完全是用C#的异步编程特性实现的,这意味着会并发地执行各种操作,而不会阻塞其他活动。在我开始演示如何创建和管理用户数据时,你便会看到这种情况。对于每一个Async方法也有相应的同步扩展方法。对于大多数示例,我会坚持这种异步方法。但是,如果你需要按顺序执行一些相关的操作,同步方法是有用的。如果你要是想从属性内部的getter或setter代码块中调用Identity方法时,同步方法也是有用的。
我在Infrastructure文件夹中添加了一个类文件,名称为AppUserManager.cs,用它定义了用户管理器类,名称为AppUserManager,如下:
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
using Users.Models; namespace Users.Infrastructure {
public class AppUserManager : UserManager<AppUser> { public AppUserManager(IUserStore<AppUser> store)
: base(store) {
} public static AppUserManager Create(
IdentityFactoryOptions<AppUserManager> options,
IOwinContext context) {
AppIdentityDbContext db = context.Get<AppIdentityDbContext>();
AppUserManager manager = new AppUserManager(new UserStore<AppUser>(db));
return manager;
}
}
}
在Identity需要一个AppUserManager的实例时,将会调用静态的Create方法,这种情况将在对用户数据执行操作时发生——也是在完成设置之后要演示的事情。
为了创建AppUserManager类的实例,我需要一个UserStore<AppUser> 实例。这个UserStore<T> 类是IUserStore<T> 接口的Entity Framework实现,它提供了UserManager类所定义的存储方法的实现。为了创建UserStore<AppUser> ,又需要AppIdentityDbContext类的一个实例,这是通过OWIN按如下办法得到的:
AppIdentityDbContext db = context.Get<AppIdentityDbContext>();
4. 创建启动类
为了使ASP.NET Identity就绪并能运行,要做的最后一个片段是Start Class(启动类)。在清下列代码中,我定义了一个应用程序设置,它为OWIN指定配置类,如下所示:
<add key="owin:AppStartup" value="Users.IdentityConfig" />
OWIN是独立出现在ASP.NET中的,并且有它自己的约定。其中之一就是,为了加载和配置中间件,并执行所需的其他配置工作,需要有一个被实例化的类。默认情况下,这个类叫做Start,而且是在全局命名空间中定义的。这个类含有一个名称为Configuration的方法,该方法由OWIN基础架构进行调用,并为该方法传递一个Owin.IAppBuilder接口的实现,由它支持应用程序所需中间件的设置。Start类通常被定义成分部类,还有一些其他的类文件,它们分别专用于要用的每一种中间件。
我随意地忽略了这一约定,因为我在MVC框架应用程序中使用的唯一OWIN中间件就是Identity。为了在应用程序的顶级命名空间定义一个类,我喜欢在Web.config文件中使用应用程序设置。于是我在App_Start文件夹中添加了一个类文件,名称为IdentityConfig.cs,并用它定义了如下的类,是我在Web.config文件中指定的一个类。
using Microsoft.AspNet.Identity;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Owin;
using Users.Infrastructure; namespace Users {
public class IdentityConfig {
public void Configuration(IAppBuilder app) { app.CreatePerOwinContext<AppIdentityDbContext>(AppIdentityDbContext.Create);
app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create); app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
});
}
}
}
IAppBuilder接口是由一些扩展方法提供的,这些扩展方法的定义在Owin命名空间的一些类中。CreatePerOwinContext用于创建AppUserManager的新实例,AppIdentityDbContext类用于每一个请求。这样保证每一个请求对ASP.NET Identity数据有清晰的访问,我不必为同步时的情况或匮乏的数据缓存而操心。
UseCookieAuthentication方法告诉ASP.NET Identity如何用Cookie去标识已认证的用户,以及通过CookieAuthenticationOptions类指定的选项在哪儿。这里重要的部分是LoginPath属性,它指定了一个URL,这是未认证客户端请求内容时要重定向的地址。我在其中指定了/Account/Login,创建这个控制器来处理这些重定向。
5、Identity的使用
1.枚举账号管理
集中化的用户管理工具在几乎所有应用程序中都是有用的,即使是那些允许用户创建并管理自己账号的情况也是如此。例如,总会有这样一些客户,他们需要大量创建账号,并支持需要检查和调整用户数据的问题。根据本章的观点,管理工具是有用的,因为它们将许多基本的用户管理功能整合到了少量的几个类之中,这对于演示ASP.NET Identity的基本特性是很有用的。
首先,在项目中添加一个控制器,名称为Admin,如清单13-9所示,我将用它定义我的用户管理功能。
using System.Web;
using System.Web.Mvc;
using Microsoft.AspNet.Identity.Owin;
using Users.Infrastructure; namespace Users.Controllers {
public class AdminController : Controller { public ActionResult Index() {
return View(UserManager.Users);
} private AppUserManager UserManager {
get {
return HttpContext.GetOwinContext().GetUserManager<AppUserManager>();
}
}
}
}
动作方法枚举由Identity系统管理的用户,当然,此刻还没有任何用户,但马上就会有了。该清单重要的部分是我获得类实例的方式,通过它,我可以管理用户信息。在我实现不同的管理功能时,我会反复使用AppUserManager类,而且,我在Admin控制器中定义了UserManager属性,以便简化代码。
Microsoft.Owin.Host.SystemWeb程序集为HttpContext类添加了一些扩展方法,其中之一便是GetOwinContext。它通过一个IOwinContext对象,将基于每请求的上下文对象提供给WOIN API。MVC框架应用程序对IOwinContext不感兴趣,但是有另外一个扩展方法,叫做GetUserManager<T> ,可以用来得到用户管理器类的实例。
就像我们看到的,ASP.NET Identity中有许多扩展方法,总体而言,这个API是一种混合体,它试图将WOIN、抽象Identity功能以及具体的Entity Framework存储实现混合在一起。
我用一个泛型参数调用了GetUserManager,用以指定本章前面创建的AppUserManager类,如下所示:
return HttpContext.GetOwinContext().GetUserManager<AppUserManager>();
一旦有了AppUserManager类的实例,便可以开始查询数据存储了。AppUserManager.Users属性返回了一个用户对象的枚举——应用程序中AppUser类的实例——于是可以用LINQ对这个枚举进行查询和维护。
在Index动作方法中,给View方法传递了Users属性的值,以便能够在视图列出用户的细节。下面代码显示了Views/Admin/Index.cshtml文件的内容,这是通过右击Index动作方法,并从弹出菜单选择“Add View(添加视图)”而创建的。
@using Users.Models
@model IEnumerable<AppUser>
@{
ViewBag.Title = "Index";
} <div class="panel panel-primary">
<div class="panel-heading">
User Accounts
</div>
<table class="table table-striped"> <tr><th>ID</th><th>Name</th><th>Email</th></tr>
@if (Model.Count() == ) {
<tr><td colspan="" class="text-center">No User Accounts</td></tr>
} else {
foreach (AppUser user in Model) {
<tr>
<td>@user.Id</td>
<td>@user.UserName</td>
<td>@user.Email</td>
</tr>
}
}
</table>
</div>
@Html.ActionLink("Create", "Create", null, new { @class = "btn btn-primary" })
这个视图含有一个表格,每个用户为一行,带有唯一ID、用户名以及E-mail地址的表格列。如果数据库中没有用户,那么会显示一条消息“No User Accounts”消息。
在视图中有一个Create的链接(其样式用Bootstrap形成了一个按钮),它的目标是Admin控制器中的Create动作。为了支持添加用户,我会很快实现这个动作。
当启动应用程序并导航到/Admin/Index URL时,在视图渲染的内容被显示出来之前,会花一些时间。这是因为Entity Framework已经链接到数据库,并发现此时尚未定义数据库架构。Code First特性使用本章前面定义的类(以及包含在Identity程序集中的类)创建该架构,以便做好查询和存储数据的准备。
通过打开Visual Studio的“SQL Server Object Explorer(SQL Server对象资源管理器)”窗口,并展开IdentityDB数据库架构,便可以看到其中包含了一些数据表,如AspNetUsers和AspNetRoles等等 。
要删除该数据库,右击IdentityDb条目,并从弹出菜单选择“Delete(删除)”。选中“Delete Database(删除数据库)”对话框中的复选框,并点击OK,以删除该数据库。
右击“Databases(数据库)”条目,选择“Add New Database(添加新数据库)”(如图13-3所示),并在“Database Name(数据库名)”字段中输入IdentityDb,点击OK,便可以创建空数据库。下一次启动应用程序,并导航到Admin/Index URL时,Entity Framework又将侦测到没有数据库架构,又会重新创建此数据库。
2.创建用户
对于应用程序接收的输入,我打算使用MVC架构的模型验证,最容易的做法是为控制器所支持的每一种操作创建一个简单的视图模型。我在Models文件夹中添加了一个类文件,名称为serViewModels.cs,并用它定义了如下所示的类。随着我为其他特性定义模型,会进一步地在这个文件中添加一些类。
using System.ComponentModel.DataAnnotations; namespace Users.Models { public class CreateModel {
[Required]
public string Name { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string Password { get; set; }
}
}
我所定义的第一个模型叫做CreateModel,它定义了创建用户账号所需要的基本属性:用户名、E-mail地址以及口令。这个模型中所定义的所有属性都使用了System.ComponentModel.DataAnnotations命名空间中的Required注释属性,用以说明这些值是必须的。
我在Admin控制器中添加了一对Create动作方法,它们是上一小节Index视图中的那个链接所指向的目标,而且,对于GET请求以及处理表单数据的POST请求,使用的是标准的控制器模式将视图表现给用户。可以从下列代码中看到这两个新的动作方法。
using System.Web;
using System.Web.Mvc;
using Microsoft.AspNet.Identity.Owin;
using Users.Infrastructure;
using Users.Models;
using Microsoft.AspNet.Identity;
using System.Threading.Tasks; namespace Users.Controllers {
public class AdminController : Controller { public ActionResult Index() {
return View(UserManager.Users);
} public ActionResult Create() {
return View();
} [HttpPost]
public async Task<ActionResult> Create(CreateModel model) {
if (ModelState.IsValid) {
AppUser user = new AppUser {UserName = model.Name, Email = model.Email};
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded) {
return RedirectToAction("Index");
} else {
AddErrorsFromResult(result);
}
}
return View(model);
} private void AddErrorsFromResult(IdentityResult result) {
foreach (string error in result.Errors) {
ModelState.AddModelError("", error);
}
} private AppUserManager UserManager {
get {
return HttpContext.GetOwinContext().GetUserManager<AppUserManager>();
}
}
}
}
该代码重要的部分是以CreateModel为参数并在管理员递交其表单数据时调用的那个Create动作方法(POST版的Create动作方法——译者注)。我用ModelState.IsValid属性检查所接收到的数据是否包含了我所需要的数据,如果是,便创建一个AppUser类的新实例,并将它传递给UserManager.CreateAsync方法,如下所示:
...
AppUser user = new AppUser {UserName = model.Name, Email = model.Email};
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
...
CreateAsync方法的结果是一个IdentityResult接口的实现,它通过下表的属性描述操作的输出。
名称 | 描述 |
---|---|
Errors | 返回一个字符串枚举,其中列出了尝试操作期间所遇到的错误 |
Succeeded | 在操作成功时返回true |
可以看到,维护用户数据的所有操作,如上述所用到的UserManager.CreateAsync方法,都可以作为异步方法来使用。这种方法很容易与async和await关键字一起使用。使用异步的Identity方法让你的动作方法能够异步执行,这可以从整体上改善应用程序。
同时也也可以使用那些由Identity API提供的同步扩展方法。所有常用的异步方法都有一个同步的封装程序,因此UserManager.CreateAsync方法的功能可以通过同步的UserManager.Create方法进行调用。当需要执行多个有依赖的操作时,为了形成简单的代码,同步方法可能是有用的。
在Create动作方法中,我检测了Succeeded属性,以确定是否能够在数据库创建一条新的用户记录。如果Succeeded属性为true,那么便将浏览器重定向到Index动作,以便显示用户列表:
...
if (result.Succeeded) {
return RedirectToAction("Index");
} else {
AddErrorsFromResult(result);
}
...
如果Succeeded属性为false,那么便调用AddErrorsFromResult方法,该方法枚举了Errors属性中的消息,并将它们添加到模型状态的错误消息集合中,此过程利用了MVC框架的模型验证特性。我定义AddErrorsFromResult方法,是因为随着进一步地构建这个管理控制器的功能,还必须处理来自其他操作的错误消息。最后一步是创建视图,让管理员创建新账号。
@model Users.Models.CreateModel
@{ ViewBag.Title = "Create User";} <h2>Create User</h2>
@Html.ValidationSummary(false)
@using (Html.BeginForm()) {
<div class="form-group">
<label>Name</label>
@Html.TextBoxFor(x => x.Name, new { @class = "form-control"})
</div>
<div class="form-group">
<label>Email</label>
@Html.TextBoxFor(x => x.Email, new { @class = "form-control" })
</div>
<div class="form-group">
<label>Password</label>
@Html.PasswordFor(x => x.Password, new { @class = "form-control" })
</div>
<button type="submit" class="btn btn-primary">Create</button>
@Html.ActionLink("Cancel", "Index", null, new { @class = "btn btn-default"})
}
该视图只是一个简单的表单,用来收集一些值,MVC框架会将它们绑定到模型类的属性上,然后传递给Create动作方法。
初识Identity(二)的更多相关文章
- 初识Identity
初识Identity 摘要 通过本文你将了解ASP.NET身份验证机制,表单认证的基本流程,ASP.NET Membership的一些弊端以及ASP.NET Identity的主要优势. 目录 身份验 ...
- 初识Identity并添加身份验证管理页面
目录 初识Identity并添加身份验证管理页面 前言 什么是ASP.NET Core Identity 创建带有身份验证的WebApp 尝试运行 检查解决方案中的项目文件 发现问题 原因 解决问题 ...
- 初识JavaScript(二)
初识JavaScript(二) 我从上一篇<初识JavaScript(一)>知道和认识JavaScript的词法结构,也开始慢慢接触到了JavaScript的使用方法,是必须按照JavaS ...
- 初识Identity(一)
一.Authentication(身份验证)和Authorization(授权) 如何构建安全的web应用?authentication和authorization是asp.net中最重要最基本的防护 ...
- python初识(二)
目录: 进制 基本数据类型 整形 布尔值 字符串 列表 元祖 字典 集合 range & enumerate 一.进制 二进制转换十进制计算: 十进制:==47 一个字节公式:==128 64 ...
- ASP.NET Identity入门系列教程(一) 初识Identity
摘要 通过本文你将了解ASP.NET身份验证机制,表单认证的基本流程,ASP.NET Membership的一些弊端以及ASP.NET Identity的主要优势. 目录 身份验证(Authentic ...
- webpack入门教程之初识loader(二)
上一节我们学习了webpack的安装和编译,这一节我们来一起学习webpack的加载器和配置文件. 要想让网页看起来绚丽多彩,那么css就是必不可少的一份子.如果想要在应用中增加一个css文件,那么w ...
- python day2:python 初识(二)
大纲: 一.运算符 1.算数运算符 notice: 除法运算在python2.7和python3.x 的不同 2.比较运算符 3.赋值运算符 4.逻辑运算符 5.成员运算符 二.基本数据类型和方法介绍 ...
- Python 基础系列一:初识python(二)基本数据类型
上节拾遗 1.编码转换过程,utf-8转换gbk 过程 经过解码(py27): x.decode('utf-8')-->unicode-->编码x.encode('gbk') ps:py3 ...
随机推荐
- CSS效果:CSS select样式优化 含jquery代码
CSS 下拉选择菜单基本的CSS样式不怎么好看,通过一些简单的样式优化,可以得到如下图这样的: html结构如下: <div class="sel_wrap"> < ...
- iOS-WKWebView的使用
参考文章:http://www.cocoachina.com/ios/20180831/24753.html WK时苹果在iOS8.0之后推出的控件,相比于UIWebView: 内存消耗少: 解决了网 ...
- JavaWeb:jsp
本文内容: JSP的介绍 jsp的使用 EL表达式 JSTL的使用 首发日期:2018-06-18 JSP的介绍: JSP全称Java Server Pages. 与静态网页格式的html不同的是,j ...
- 结对项目-四则运算"软件"之升级版
本次作业要求来自:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/2213 github地址为:https://github.com/L ...
- genymotion 模拟器内安装软件 the app contains ARM native code and your devices cannot run ARM instructions
问题如图: 解决方法: 下载一个Genymotion-ARM-Translation软件,安装到模拟器中就好了
- [20171031]markhot.txt
[20171031]markhot.txt --//昨天看了https://jonathanlewis.wordpress.com/2017/10/02/markhot/,测试看看这样时候可以减少争用 ...
- 洗礼灵魂,修炼python(25)--自定义函数(6)—从匿名函数进阶话题讲解中解析“函数式编程”
匿名函数进阶 前一章已经说了匿名函数,匿名函数还可以和其他内置函数结合使用 1.map map():映射器,映射 list(map(lambda x:x*2,range(10))) #把range产生 ...
- mysqlreport工具
进行MySQL的配置优化,首先必须找出MySQL的性能瓶颈所在:而SHOW STATUS输出的报告正是用来计算性能瓶颈的参考数据.mysqlreport不像SHOW STATUS那样简单的罗列数据,而 ...
- oh-my-zsh安装与使用
使用oh-my-zsh之前确保安装过zsh 通过脚本安装: sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussel ...
- ccf--20150303--节日
本题思路:首先,计算a月1日是星期几,然后再通过b和c得出日期monday,最后判断monday是否合法. 题目与代码如下: 问题描述 试题编号: 201503-3 试题名称: 节日 时间限制: 1. ...