开始折腾 ASP.NET 5 & MVC

TOC

安装 ASP.NET 5 RC1

现在的最新版本是于11月18日发布的ASP.NET 5 RC1。其具体安装方法可以参阅说明文档中的Getting Started一节。

顺带一提,如果 Visual Studio 2015 出现了“’JavaScriptWebExtensionsPackage’ 未正确加载”的问题,可以尝试以下操作(参阅 Microsoft Connect 的 Workarounds 一节)

在命令行中运行

devenv /updateconfiguration
devenv /clearcache

和/或更新VS2015的 Tools for Universal Windows Apps 1.1 功能。(是的,安装过程极为缓慢。)

接下来就可以按照 Your First ASP.NET 5 Web App Using Visual Studio 的教程走下去了。

使用SQLite

顺带着试用 SQLite 作为后台数据库。不过据说 SQLite 的并发支持是锁掉整个数据库……

首先,修改 project.json,在`dependencies`小节中插入对SQLite的引用

    "dependencies": {
        //...
        "Microsoft.Extensions.Logging.Debug": "1.0.0-rc1-final",
        "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0-rc1-final",
        "EntityFramework.SQLite": "7.0.0-*",
        "EntityFramework.Sqlite.Design": "7.0.0-*"
    },

安装`Sqlite.Design`之后,才能使用 dnx ef 进行体数据模型[EF]的操作。

保存文件,VS随即会开始下载相关的 NuGet包。

接下来修改实体数据模型[EF]的数据上下文(`DbContext`)的数据连接。注意到 ASP.NET 5 默认是使用依赖项注入[DI]的。所以我不建议直接重写`ApplicationDbContext.OnConfiguring`,而应该找到注册服务的位置。在这里我们定位到 `Startup.ConfigureServices`函数,并将`AddSqlServer`修改为`AddSqlite`。

        public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            //services.AddEntityFramework()
            //    .AddSqlServer()
            //    .AddDbContext<ApplicationDbContext>(options =>
            //        options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
            services.AddEntityFramework().AddSqlite().AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlite(Configuration["Data:DefaultConnection:ConnectionString"]));
            
            // 调整用户认证设置。
            services.AddIdentity<ApplicationUser, IdentityRole>(options =>
                options.Password.RequireUppercase =
                    options.Password.RequireLowercase =
                        options.Password.RequireDigit =
                            options.Password.RequireNonLetterOrDigit = false)
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();

            services.AddMvc();

            // Add application services.
            services.AddTransient<IEmailSender, AuthMessageSender>();
            services.AddTransient<ISmsSender, AuthMessageSender>();
        }

注意到默认情况下,`ApplicationDbContext`派生自支持用户认证的`IdentityDbContext`,所以我们也可以在这里修改用户认证的选项。当然了,我只是为了方便起见,所以才把密码强度要求将到最低的……不要学我 😉

我们还需要修改连接字符串。注意到代码中`Configuration`的索引器,我们定位到 appsettings.json,修改链接字符串

{
  "Data": {
    "DefaultConnection": {
        //"ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=aspnet5-RemoteFileUploader-02527226-e969-4800-89ef-e49afee1d080;Trusted_Connection=True;MultipleActiveResultSets=true"
        "ConnectionString": "Data Source=site.sqlite;"
    }
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Verbose",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}

关于SQLite的连接字符串格式,可以参考 ConnectionString.com (居然有这样的网站)上的 SQLite connection strings

在网站第一次访问数据库的时候,会出现错误页面。可以根据提示创建数据库。

EF数据模型

可以使用 Code First 模式来搭建数据模型。关于数据标注[Data Annotation]的介绍,可以参阅 Entity Framework Code First Data Annotations

SQLite的数据迁移问题

根据 EF 模型的 Code First Migration 数据迁移方法,在对数据模型进行修改后,需要在命令行中定位到项目根目录,然后运行

dnx ef migrations add ThisStage
dnx ef database update

其中,`ThisStage`可以换为任意名称,用来标记当前数据库阶段,方便以后对数据库的前进/回退操作。

如果提示找不到dnx,则需要执行

dnvm use 1.0.0-rc1-final -p

如果使用的是SQLite,随后使用`ef database update`执行数据库更新时就会发现问题

Applying migration '20151125022036_AddFileEntries'.
System.NotSupportedException: SQLite cannot support this migration operation.
   在 Microsoft.Data.Entity.Migrations.SqliteMigrationsSqlGenerator.Generate(DropForeignKeyOperation operation, IModel model, RelationalCommandListBuilder builder)
   在 Microsoft.Data.Entity.Migrations.MigrationsSqlGenerator.<>c.<.cctor>b__50_10(MigrationsSqlGenerator g, MigrationOperation o, IModel m, RelationalCommandListBuilder b)
   在 Microsoft.Data.Entity.Migrations.MigrationsSqlGenerator.Generate(MigrationOperation operation, IModel model, RelationalCommandListBuilder builder)
   在 Microsoft.Data.Entity.Migrations.MigrationsSqlGenerator.Generate(IReadOnlyList`1 operations, IModel model)
   在 Microsoft.Data.Entity.Migrations.SqliteMigrationsSqlGenerator.Generate(IReadOnlyList`1 operations, IModel model)
   在 Microsoft.Data.Entity.Migrations.Internal.Migrator.GenerateUpSql(Migration migration)
   在 Microsoft.Data.Entity.Migrations.Internal.Migrator.<>c__DisplayClass12_4.<GetMigrationCommands>b__10()
   在 Microsoft.Data.Entity.Migrations.Internal.Migrator.Migrate(String targetMigration)
   在 Microsoft.Data.Entity.Design.MigrationsOperations.UpdateDatabase(String targetMigration, String contextType)
   在 Microsoft.Data.Entity.Commands.Program.Executor.<>c__DisplayClass7_0.<UpdateDatabase>b__0()
   在 Microsoft.Data.Entity.Commands.Program.Executor.Execute(Action action)
SQLite cannot support this migration operation.

注意到是`DropForeignKeyOperation`,说明SQLite对外建约束的支持可能不完善。实际上,SQLite只是一个轻型数据库(例如,SQLite在实现的时候只有NULL、INTEGER[整数]、REAL[实数]、TEXT[文本]和BLOB[数据块]这几种类型)。去网上找了一下,果然……(ref = Entity Framework Code-First Migrations support for Oracle, MySQL, PostgreSQL and SQLite

SQLite 不支持外键的修改和删除操作。
SQLite 不支持外键的修改和删除操作。

**** The ADD FOREIGN KEY constraint operation for a foreign key, consisting of a single column, is supported for the case when a new column for the foreign key is created.

同理,SQLite也不支持AlterColumn。所以,一个比较简单的办法是,直接打开 Miigrations 文件夹中的迁移文件,注释`Migration`派生类的`Up`函数中掉包含修改外键(`DropForeignKey`、`AddForeignKey`)和修改列(`AlterColumn`)相关的操作。然后再运行

dnx ef database update

当然,这样做可能意味着无法使SQLite数据库进行平滑演进,尤其是准备对包含数据的表格进行列调整或者外键调整时。不过,在一脚踏入 SQLite 的深基坑时,这一点觉悟还是必须要有的 😉

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

ERROR: si-captcha.php plugin: GD image support not detected in PHP!

Contact your web host and ask them to enable GD image support for PHP.

ERROR: si-captcha.php plugin: imagepng function not detected in PHP!

Contact your web host and ask them to enable imagepng for PHP.

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

Content is available under CC BY-SA 3.0 unless otherwise noted.