Asp.net Core基於MVC框架實現PostgreSQL操做

簡單介紹

Asp.net Core最大的價值在於跨平臺、跨平臺、跨平臺。重要的事情說三遍。可是目前畢竟是在開發初期,雖然推出了1.0.0 正式版,可是其實好多功能尚未完善。比方說編譯時的一些文件編碼問題,輔助工具Tools的一些Bug,還有一些好用的模板和平臺實現還沒有完成等一些問題。但這畢竟是一個好的開始,而且在Github上,你們都還在積極的完善,你也能夠參與進來。地址:https://github.com/aspnet html

Asp.net Core在學習的時候,首先你應該跟着微軟官方的入門教材來學習,在這裏: https://docs.asp.net/en/latest/tutorials/first-mvc-app/start-mvc.html。這個入門教材很淺顯易懂的讓你瞭解了Asp.net Core mvc框架以及entity framework core的用法。不過缺點是,使用的是Sql compact數據庫,也就是SQL Server數據庫。要知道,咱們使用Asp.net 的主要目的是實現跨平臺部署,因此數據庫的選擇上,首選確定不是SqlServer,不然意義何在?固然,目前Entity Framework core暫時還不支持全部數據庫。截止2016年7月,支持狀況以下: mysql

Database Providers jquery

The following providers are available linux

因此提供給咱們選擇的數據庫仍是有限的(主要是不支持MySql,Devart這東西筆者不瞭解,不評論)。總得來講,對MS SQL Server的支持確定是最好的,因此場景容許下,首選Sql server。其次,就DB2和PostgreSQL可選了。筆者不喜歡DB2(不少緣由,主要是開發操做管理麻煩,並不是說DB2自己存在問題),PostgreSQL其實也不太好用,不過誰叫他免費呢,確定是好多國內公司首選。 git

PostgreSQL自己歷史悠久,記得好像上世紀80年代就存在了,免費開源,並且是有專門社區維護。設計理念是以健壯性爲首選,因此收到光打企業級平臺歡迎。關於PostgreSQL和MySQL之間的優缺點,這個其實不太好說,MySQL在損失健壯性的同時,提升了性能,而且支持不少非標準新特性,而PostgreSQL在健壯性上,號稱不弱於Oracle,性能優秀,徹底支持SQL標準,因此其實並不差。 github

準備環境

Ubuntu Server(16.04)虛擬機1臺,IP:192.168.1.6 預裝了PostgreSQL數據庫,並配置好防火牆,ssh鏈接等基礎環境。確保可以外部訪問。 ajax

VS2015 Update3 sql

Putty 和SSH Secure File Transfer Client chrome

服務器環境部署

    參考以前的博客:http://blog.csdn.net/lanwilliam/article/details/51880124 數據庫

開始

  1. 新建項目,選擇Asp.net Core Web Application項目模板。

  2. 選擇Web應用程序模板,而後修改身份驗證哪裏,選擇不進行身份驗證。

    這裏要說一下,Asp.net core項目中,包含一個Identity子項目,在GitHub上有介紹以下:

    這裏你們一看就知道了,這就是原來提供的ASP.net自帶的權限框架。這個框架如今其實很是強大了,還支持Google和TWriter等OAuth用法,不過缺點是隻支持SQL Server數據庫。若是選擇了我的用戶帳戶,那麼會默認使用這個框架建立項目。咱們但願用PostgreSQL,因此不能選他,很遺憾。並且目前建立控制器等一些內置模板用法,都是基於SqlServer,用到這個Identity,你們若是看過微軟的GettingStarted,就會看到介紹,因此建議你們首先學習微軟GettingStarted。

    固然,不要勾選雲中託管。

  3. 空白項目結構

    上圖是新建完成的空白項目結構,你會發現Models,Data等文件夾都不存在,這裏須要手動新建,而且丟進去一個class。

    必需要丟進去個class文件,讓類定義的時候聲明出Models和Data的命名空間,不然待會生成models文件的時候會報錯。

  4. 增長項目引用

    Asp.net core項目有兩種方法增長引用,一種是直接修改project.json,另外一種是nuget。

    上述方法打開控制檯

    輸入以下命令

    會發現最後的Tools安裝不了,可能nuget沒同步過來,能夠在project.json中手動添加。

    最後的文件以下:

    主要是圈選中的部分。能夠看到這裏咱們用來操做PostgreSQL的Provider是Npgsql,這是aspnet下的一個子項目。能夠在github找到。

    其餘EntityFrameworkCore的引用,是從示例項目中搬來的。

  5. 生成Models文件

    這裏要說明一下,微軟MVC教程中時使用的模板建立的Controller,他會自動建立ApplicationDBContext和對應的Views視圖文件,以及一些其餘的內容。由於他更新了ApplicationDBContext文件和ApplicationDbContextModelSnapshot文件,因此控制檯執行dotnet ef命令纔會正常完成,這裏沒法用到這些方法。由於沒選"我的用戶帳戶",這裏請自行嘗試。

    dotnet ef migrations add Initial

    dotnet ef database update

    因爲自行寫DBContext類實現太麻煩,咱們這裏採起開發中經常使用的辦法,首先設計數據庫,而後根據數據庫生成類。

    在數據庫新建表以下:(測試用,看看就好)

    而後回到VS2015,在Nuget程序包控制檯輸入:

    Scaffold-DbContext "Server=192.168.1.6;Database=testdb;User ID=test;Password=test;" Npgsql.EntityFrameworkCore.PostgreSQL -OutputDir Models

這個命令不用解釋了吧?數據庫鏈接,使用的數據庫provider和輸出目錄。

順利完成的話,Models下會出現幾個類文件。

若是報錯的話,請根據錯誤提示進行處理。處理原則,首先保證程序可以編譯經過,而後確保Models下面沒有存在本次要生成的同名文件,而後確認目前系統沒有其餘DBContext存在。如今dotnet core的好多工具都在完善中,健壯性都有待提升。

打開看看生成的文件:

using System;

using Microsoft.EntityFrameworkCore;

using Microsoft.EntityFrameworkCore.Metadata;

 

namespace PostgresSqlDemo.Models

{

public partial class testdbContext : DbContext

{

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

{

#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.

optionsBuilder.UseNpgsql(@"Server=192.168.1.6;Database=testdb;User ID=test;Password=test;");

}

 

protected override void OnModelCreating(ModelBuilder modelBuilder)

{

modelBuilder.Entity<Blog>(entity =>

{

entity.ToTable("blog");

 

entity.Property(e => e.Id)

.HasColumnName("id")

.ValueGeneratedNever();

 

entity.Property(e => e.Title)

.IsRequired()

.HasColumnName("title")

.HasColumnType("varchar")

.HasMaxLength(300);

 

entity.Property(e => e.Url)

.IsRequired()

.HasColumnName("url")

.HasColumnType("varchar")

.HasMaxLength(300);

});

 

modelBuilder.Entity<TbUser>(entity =>

{

entity.HasKey(e => e.Userid)

.HasName("PK_tb_user");

 

entity.ToTable("tb_user");

 

entity.Property(e => e.Userid)

.HasColumnName("userid")

.ValueGeneratedNever();

 

entity.Property(e => e.Age).HasColumnName("age");

 

entity.Property(e => e.Name)

.IsRequired()

.HasColumnName("name")

.HasColumnType("varchar")

.HasMaxLength(30);

});

}

 

public virtual DbSet<Blog> Blog { get; set; }

public virtual DbSet<TbUser> TbUser { get; set; }

}

}

Entityframework中,默認是一個數據庫使用惟一一個DBContext類進行管理。

  1. 修改DBContext文件

    模板已經提示給你,須要修改這部分代碼,實現動態配置鏈接的目的。

    進行以下修改:

    註釋掉OnConfiguring方法,增長構造函數,咱們把註冊放到Startup中去完成。

  2. 添加數據庫鏈接配置項

    打開appsetting.json文件,增長以下配置:

    其實這就至關於原來asp.net中的Web.config中的ConnectionStrings。

  3. 註冊DBContext

    打開StartUP.cs 文件,找到ConfigureServices方法,添加選中代碼:

        到這裏就看明白了吧,註冊DBContext,使用Npgsql,並給出數據庫鏈接字符串。

  1. 增長控制器Controller

    在Controller文件夾下新建Controller文件,並添加以下代碼:

    using Microsoft.AspNetCore.Mvc;

    using PostgresSqlDemo.Data;

    using PostgresSqlDemo.Models;

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Threading.Tasks;

    using Microsoft.EntityFrameworkCore;

     

    namespace PostgresSqlDemo.Controllers

    {

    public class TbUserController : Controller

    {

    private readonly testdbContext _context;

     

    public TbUserController(testdbContext context)

    {

    _context = context;

    }

     

    // GET: tbusers

    public async Task<IActionResult> Index()

    {

    return View(await _context.TbUser.ToListAsync());

    }

     

    public async Task<IActionResult> Details(Guid? id)

    {

    if (id == null)

    {

    return NotFound();

    }

     

    var tbuser = await _context.TbUser.SingleOrDefaultAsync(m => m.Userid == id);

    if (tbuser == null)

    {

    return NotFound();

    }

     

    return View(tbuser);

    }

     

    // GET: tbusers/Create

    public IActionResult Create()

    {

    return View();

    }

     

    // POST: tbusers/Create

    // To protect from overposting attacks, please enable the specific properties you want to bind to, for

    // more details see http://go.microsoft.com/fwlink/?LinkId=317598.

    [HttpPost]

    [ValidateAntiForgeryToken]

    public async Task<IActionResult> Create([Bind("Userid,Name,Age")] TbUser tbuser)

    {

    if (ModelState.IsValid)

    {

    tbuser.Userid = Guid.NewGuid();

    _context.Add(tbuser);

    await _context.SaveChangesAsync();

    return RedirectToAction("Index");

    }

    return View(tbuser);

    }

     

    // GET: tbusers/Edit/5

    public async Task<IActionResult> Edit(Guid? id)

    {

    if (id == null)

    {

    return NotFound();

    }

     

    var tbuser = await _context.TbUser.SingleOrDefaultAsync(m => m.Userid == id);

    if (tbuser == null)

    {

    return NotFound();

    }

    return View(tbuser);

    }

     

    // POST: tbusers/Edit/5

    // To protect from overposting attacks, please enable the specific properties you want to bind to, for

    // more details see http://go.microsoft.com/fwlink/?LinkId=317598.

    [HttpPost]

    [ValidateAntiForgeryToken]

    public async Task<IActionResult> Edit(Guid id, [Bind("Userid,Name,Age")] TbUser tbuser)

    {

    if (id != tbuser.Userid)

    {

    return NotFound();

    }

     

    if (ModelState.IsValid)

    {

    try

    {

    _context.Update(tbuser);

    await _context.SaveChangesAsync();

    }

    catch (DbUpdateConcurrencyException)

    {

    if (!tbuserExists(tbuser.Userid))

    {

    return NotFound();

    }

    else

    {

    throw;

    }

    }

    return RedirectToAction("Index");

    }

    return View(tbuser);

    }

     

    // GET: tbusers/Delete/5

    public async Task<IActionResult> Delete(Guid? id)

    {

    if (id == null)

    {

    return NotFound();

    }

     

    var tbuser = await _context.TbUser.SingleOrDefaultAsync(m => m.Userid == id);

    if (tbuser == null)

    {

    return NotFound();

    }

     

    return View(tbuser);

    }

     

    // POST: tbusers/Delete/5

    [HttpPost, ActionName("Delete")]

    [ValidateAntiForgeryToken]

    public async Task<IActionResult> DeleteConfirmed(Guid id)

    {

    var tbuser = await _context.TbUser.SingleOrDefaultAsync(m => m.Userid == id);

    _context.TbUser.Remove(tbuser);

    await _context.SaveChangesAsync();

    return RedirectToAction("Index");

    }

     

    private bool tbuserExists(Guid id)

    {

    return _context.TbUser.Any(e => e.Userid == id);

    }

    }

    }

    若是你看過Getting Started Asp.net core MVC的話,相信應該可以看懂,基本是把使用新增Controller模板生成的方法修改了一下拿過來用了。

    Asp.net core mvc中,默認路由名成爲(name)Controller,因此咱們這裏叫TbUserController,訪問的時候是http://youip/TbUser這樣。而且默認是觸發Index方法。

    Controller中,每一個方法,都至關於一個客戶端Form的Action。沒有特殊聲明的方法,默認爲HttpGet,能夠直接請求。須要Post數據的,請手動增長[HttpPost]聲明。

    Async是C# 5.0後提供的關鍵字,是自動實現一個異步的方法,須要配合await關鍵字使用。Await會被自動轉換爲一個async的異步請求,後面的代碼,會被自動放到completed方法中執行。這樣處理可以極大的提升服務器的併發性能,具體請自行學習。

  2. 增長Views頁面

    增長對應的頁面以下:

Index.cshtml

@model IEnumerable<PostgresSqlDemo.Models.TbUser>

 

@{

ViewData["Title"] = "Index";

}

 

<h2>Index</h2>

 

<p>

<a asp-action="Create">Create New</a>

</p>

<table class="table">

<thead>

<tr>

<th>

@Html.DisplayNameFor(model => model.Userid)

</th>

<th>

@Html.DisplayNameFor(model => model.Name)

</th>

<th>

@Html.DisplayNameFor(model => model.Age)

</th>

 

<th></th>

</tr>

</thead>

<tbody>

@foreach (var item in Model)

{

<tr>

<td>

@Html.DisplayFor(modelItem => item.Userid)

</td>

<td>

@Html.DisplayFor(modelItem => item.Name)

</td>

<td>

@Html.DisplayFor(modelItem => item.Age)

</td>

 

<td>

<a asp-action="Edit" asp-route-id="@item.Userid">Edit</a> |

<a asp-action="Details" asp-route-id="@item.Userid">Details</a> |

<a asp-action="Delete" asp-route-id="@item.Userid">Delete</a>

</td>

</tr>

}

</tbody>

</table>

 

Create.cshtml

@model PostgresSqlDemo.Models.TbUser

 

@{

ViewData["Title"] = "Create";

}

 

<h2>Create</h2>

 

<form asp-action="Create">

<div class="form-horizontal">

<h4>TbUser</h4>

<hr />

<div asp-validation-summary="ModelOnly" class="text-danger"></div>

<div class="form-group">

<label asp-for="Name" class="col-md-2 control-label"></label>

<div class="col-md-10">

<input asp-for="Name" class="form-control" />

<span asp-validation-for="Name" class="text-danger" />

</div>

</div>

<div class="form-group">

<label asp-for="Age" class="col-md-2 control-label"></label>

<div class="col-md-10">

<input asp-for="Age" class="form-control" />

<span asp-validation-for="Age" class="text-danger" />

</div>

</div>

<div class="form-group">

<div class="col-md-offset-2 col-md-10">

<input type="submit" value="Create" class="btn btn-default" />

</div>

</div>

</div>

</form>

 

<div>

<a asp-action="Index">Back to List</a>

</div>

 

@section Scripts {

@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}

}

 

Delete.cshtml

@model PostgresSqlDemo.Models.TbUser

 

@{

ViewData["Title"] = "Delete";

}

 

<h2>Delete</h2>

 

<h3>Are you sure you want to delete this?</h3>

<div>

<h4>Blog</h4>

<hr />

<dl class="dl-horizontal">

<dt>

@Html.DisplayNameFor(model => model.Userid)

</dt>

<dd>

@Html.DisplayFor(model => model.Userid)

</dd>

<dt>

@Html.DisplayNameFor(model => model.Name)

</dt>

<dd>

@Html.DisplayFor(model => model.Name)

</dd>

<dt>

@Html.DisplayNameFor(model => model.Age)

</dt>

<dd>

@Html.DisplayFor(model => model.Age)

</dd>

</dl>

 

<form asp-action="Delete">

<div class="form-actions no-color">

<input type="submit" value="Delete" class="btn btn-default" /> |

<a asp-action="Index">Back to List</a>

</div>

</form>

</div>

 

Details.cshtml

@model PostgresSqlDemo.Models.TbUser

 

@{

ViewData["Title"] = "Details";

}

 

<h2>Details</h2>

 

<div>

<h4>Blog</h4>

<hr />

<dl class="dl-horizontal">

<dt>

@Html.DisplayNameFor(model => model.Userid)

</dt>

<dd>

@Html.DisplayFor(model => model.Userid)

</dd>

<dt>

@Html.DisplayNameFor(model => model.Name)

</dt>

<dd>

@Html.DisplayFor(model => model.Name)

</dd>

<dt>

@Html.DisplayNameFor(model => model.Age)

</dt>

<dd>

@Html.DisplayFor(model => model.Age)

</dd>

</dl>

</div>

<div>

<a asp-action="Edit" asp-route-id="@Model.Userid">Edit</a> |

<a asp-action="Index">Back to List</a>

</div>

 

Edit.cshtml

@model PostgresSqlDemo.Models.TbUser

 

@{

ViewData["Title"] = "Edit";

}

 

<h2>Edit</h2>

 

<form asp-action="Edit">

<div class="form-horizontal">

<h4>Blog</h4>

<hr />

<div asp-validation-summary="ModelOnly" class="text-danger"></div>

<input type="hidden" asp-for="Userid" />

<div class="form-group">

<label asp-for="Name" class="col-md-2 control-label"></label>

<div class="col-md-10">

<input asp-for="Name" class="form-control" />

<span asp-validation-for="Name" class="text-danger" />

</div>

</div>

<div class="form-group">

<label asp-for="Age" class="col-md-2 control-label"></label>

<div class="col-md-10">

<input asp-for="Age" class="form-control" />

<span asp-validation-for="Age" class="text-danger" />

</div>

</div>

<div class="form-group">

<div class="col-md-offset-2 col-md-10">

<input type="submit" value="Save" class="btn btn-default" />

</div>

</div>

</div>

</form>

 

<div>

<a asp-action="Index">Back to List</a>

</div>

 

@section Scripts {

@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}

}

 

  1. 增長驗證腳本引用View文件

    <environment names="Development">

    <script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>

    <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>

    </environment>

    <environment names="Staging,Production">

    <script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.14.0/jquery.validate.min.js"

    asp-fallback-src="~/lib/jquery-validation/dist/jquery.validate.min.js"

    asp-fallback-test="window.jQuery && window.jQuery.validator">

    </script>

    <script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js"

    asp-fallback-src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"

    asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive">

    </script>

    </environment>

 

  1. 修改Layout.cshtml文件

    增長如上兩個鏈接。Blog的添加參考TbUser。這裏主要是想讓你們看出來DBContext的用法,因此特地弄了兩個實體類。

  2. 而後vs裏面能夠運行了,效果以下:

    這裏沒有改默認的頁面。

    再看咱們加的頁面。

    而且asp.net mvc默認使用了bootstrap,因此咱們能夠用chrome的手機模式看看。

  3. 改爲中文顯示

    改一下TbUser.cs

    using System;

    using System.Collections.Generic;

    using System.ComponentModel.DataAnnotations;

     

    namespace PostgresSqlDemo.Models

    {

    public partial class TbUser

    {

    [Display(Name = "用戶編號")]

    public Guid Userid { get; set; }

    [Display(Name = "用戶姓名")]

    public string Name { get; set; }

    [Display(Name = "用戶年齡")]

    public int? Age { get; set; }

    }

    }

    再看看頁面

  4. 加一下驗證

    改爲中文驗證

            [Display(Name = "用戶姓名")]

        [StringLength(10, MinimumLength = 3,ErrorMessage = "字段{0}長度不能小於3,總長度不能大於10")]

        [Required]

    public string Name { get; set; }

    

  1. 最後就是部署到Ubuntu服務器了。

    將WebApp項目發佈出來,使用SSH Secure File Transfer上傳到服務器,而後參照前文發佈。

    前文:http://blog.csdn.net/lanwilliam/article/details/51880124

總結:

    Asp.net Core 目前來講功能性還不完善,暫時不建議大型應用往上遷移,可是若是是小型項目,比較簡單,能夠在仔細論證後嘗試使用。注意仔細論證,由於目前.net core並非全部類庫都可以實現跨平臺。簡單來講,System.Drawing就沒法使用,因此後臺畫水印就須要其餘三方庫,這個請自行仔細論證。不太小項目發佈到linux虛擬機上面,確實能夠省一筆錢。

相關文章
相關標籤/搜索