asp.net core2.0學習筆記

1、Corecss

  1,防止過分發布html

  2,Mainjquery

  3,Startupweb

  4,添加過濾器ajax

  5,依賴注入正則表達式

  6,中間件sql

  7,靜態文件數據庫

  8,路由json

  9,環境bootstrap

  10,配置和選項

  11,日誌

  12,使用Sesstion

  13,使用po文件配置本地化

  14,在 ASP.NET 管道中運行 OWIN 中間件

  15,WebSockets

  16,使用內存緩存

2、EF

  1,Include和ThenInclude

  2,經過依賴關係注入註冊上下文

  3,種子數據

  4,級聯刪除

  5,組合PK

  6,使用原始sql

3、Razor頁面

4、MVC

  1,模型綁定

  2,視圖

  3,標記幫助程序

  4,內置標記幫助程序

  5,分部視圖

  6,視圖組件

  7,上傳文件

  8,篩選器

  9,綁定與壓縮

5、Model

6、配置

 

1、Core

1,防止過分發布

①TryUpdateModelAsync

        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }
            var emptyStudent = new Student();
            if (await TryUpdateModelAsync<Student>(emptyStudent, "student", s => s.FirstMidName, s => s.LastName, s => s.EnrollmentDate))
            {
                _context.Students.Add(emptyStudent);
                await _context.SaveChangesAsync();
                return RedirectToPage("./Index");

            }
            return null;
        }
code
        [BindProperty]
        public Student Student { get; set; }
        public async Task<IActionResult> OnPostAsync(int? id)
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            var studentToUpdate =await _context.Students.FindAsync(id);
            if (await TryUpdateModelAsync<Student>(studentToUpdate, "student", s => s.LastName, s => s.EnrollmentDate))
            {
                await _context.SaveChangesAsync();
                return RedirectToPage("./Index");
            }
            return Page();
        }
code2

僅更新TryUpdateModelAsync列出的值

在上述示例中:

  • 第二個自變量 ("student", // Prefix) 是用於查找值的前綴。 該自變量不區分大小寫。
  • 已發佈的表單值經過模型綁定轉換爲 Student 模型中的類型。

 ②經過屬性名稱匹配

using System;

namespace ContosoUniversity.Models
{
    public class StudentVM
    {
        public int ID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }
    }
}
StudentVM
[BindProperty]
public StudentVM StudentVM { get; set; }

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    var entry = _context.Add(new Student());
    entry.CurrentValues.SetValues(StudentVM);
    await _context.SaveChangesAsync();
    return RedirectToPage("./Index");
}
code

 

2,Main

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;

namespace aspnetcoreapp
{
    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .Build();
    }
}
Main

UseHttpSys:用於在 HTTP.sys 中託管應用

UseContentRoot:用於指定根內容目錄

Build 和 Run 方法生成 IWebHost 對象,該對象託管應用並開始偵聽 HTTP 請求

 UseStartup:指定Startup 類

 

3,Startup

ConfigureServices 定義應用所使用的服務(如 ASP.NET Core MVC、Entity Framework Core 和Identity)(可選擇)

Configure 定義請求管道的中間件(必須)

ConfigureServices在 Configure以前執行

UseMvc 擴展方法將路由中間件添加到請求管道,並將 MVC 配置爲默認設置。 

 

4,添加過濾器

①定義Middleware

using System;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using WebApplication1.Models;

namespace WebApplication1
{
    public class RequestSetOptionsMiddleware
    {
        private readonly RequestDelegate _next;
        private IOptions<AppOptions> _injectedOptions;

        public RequestSetOptionsMiddleware(
            RequestDelegate next, IOptions<AppOptions> injectedOptions)
        {
            _next = next;
            _injectedOptions = injectedOptions;
        }

        public async Task Invoke(HttpContext httpContext)
        {
            Console.WriteLine("RequestSetOptionsMiddleware.Invoke");

            var option = httpContext.Request.Query["option"];

            if (!string.IsNullOrWhiteSpace(option))
            {
                _injectedOptions.Value.Option = WebUtility.HtmlEncode(option);
            }

            await _next(httpContext);
        }
    }
}
RequestSetOptionsMiddleware

②實現IStartupFilter

using Microsoft.AspNetCore.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;

namespace WebApplication1
{
    public class RequestSetOptionsStartupFilter : IStartupFilter
    {
        public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
        {
            return builder =>
            {
                builder.UseMiddleware<RequestSetOptionsMiddleware>();
                next(builder);
            };
        }
    }
}
RequestSetOptionsStartupFilter

③在 ConfigureServices 的服務容器中註冊 IStartupFilter

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<IStartupFilter, RequestSetOptionsStartupFilter>();
            services.AddMvc();
        }
Code

 

5,依賴注入

①註冊案例

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseInMemoryDatabase()
    );

    // Add framework services.
    services.AddMvc();

    // Register application services.
    services.AddScoped<ICharacterRepository, CharacterRepository>();
    services.AddTransient<IOperationTransient, Operation>();
    services.AddScoped<IOperationScoped, Operation>();
    services.AddSingleton<IOperationSingleton, Operation>();
    services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));
    services.AddTransient<OperationService, OperationService>();
}
View Code

 

6,中間件

①中間件排序

Configure方法中定義的中間的順序決定請求的順序,響應的順序則相反

②Use、Run 和 Map

Run:不會調用next方法。後面的管道將不會執行

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            
            app.Run(async (context)=>{
                 await context.Response.WriteAsync("Map Test 1");
            });

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            //使用wwwroot
            app.UseStaticFiles();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });

           
        }
Run

Use:若是中間件不調用next方法,會使管道短路。

Map:若是請求路徑以給定路徑開頭,則執行分支。

public class Startup
{
    private static void HandleMapTest1(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map Test 1");
        });
    }

    private static void HandleMapTest2(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map Test 2");
        });
    }

    public void Configure(IApplicationBuilder app)
    {
        app.Map("/map1", HandleMapTest1);

        app.Map("/map2", HandleMapTest2);

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from non-Map delegate. <p>");
        });
    }
}
Map

public class Startup
{
    private static void HandleBranch(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            var branchVer = context.Request.Query["branch"];
            await context.Response.WriteAsync($"Branch used = {branchVer}");
        });
    }

    public void Configure(IApplicationBuilder app)
    {
        app.MapWhen(context => context.Request.Query.ContainsKey("branch"),
                               HandleBranch);

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from non-Map delegate. <p>");
        });
    }
}
MapWhen 基於給定謂詞的結果建立請求管道分支

app.Map("/level1", level1App => {
       level1App.Map("/level2a", level2AApp => {
           // "/level1/level2a"
           //...
       });
       level1App.Map("/level2b", level2BApp => {
           // "/level1/level2b"
           //...
       });
   });
Map 支持嵌套
app.Map("/level1/level2", HandleMultiSeg);
Map 還可同時匹配多個段

③自定義Middleware

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.Globalization;
using System.Threading.Tasks;

namespace IocDemo
{
    public class CustomMiddleware
    {
        private readonly RequestDelegate _next;

        public CustomMiddleware(RequestDelegate next)
        {
            _next=next;
        }
        public Task InvokeAsync(HttpContext context)
        {
            this._next.Invoke(context); 
            context.Response.WriteAsync("CustomMiddleware");
            return Task.CompletedTask;
        }
    }
    public static class CustomMiddlewareExtensions
    {
        public static IApplicationBuilder UseCustomer(this IApplicationBuilder budiler)
        {
            return budiler.UseMiddleware<CustomMiddleware>();
        }

    }

   
}
CustomMiddleware
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace IocDemo
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            //使用自定義middleware
            app.UseCustomer();

            //使用wwwroot
            app.UseStaticFiles();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });

           
        }
    }
}
Startup

 

7,靜態文件

提供 Web 根目錄外的文件

請求 http://<server_address>/StaticFiles/images/banner1.svg 提供 banner1.svg 文件

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles(); // For the wwwroot folder

    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), "MyStaticFiles")),
        RequestPath = "/StaticFiles"
    });
}
View Code

設置 HTTP 響應標頭

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles(new StaticFileOptions
    {
        OnPrepareResponse = ctx =>
        {
            // Requires the following import:
            // using Microsoft.AspNetCore.Http;
            ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=600");
        }
    });
}
View Code

③靜態文件受權方法

新建個靜態文件根文件夾

[Authorize]
public IActionResult BannerImage()
{
    var file = Path.Combine(Directory.GetCurrentDirectory(), 
                            "MyStaticFiles", "images", "banner1.svg");

    return PhysicalFile(file, "image/svg+xml");
}
View Code

④默認提供文檔

public void Configure(IApplicationBuilder app)
{
    app.UseDefaultFiles();
    app.UseStaticFiles();
}
View Code

要提供默認文件,必須在 UseStaticFiles 前調用 UseDefaultFiles。 UseDefaultFiles 實際上用於重寫 URL,不提供文件。 經過 UseStaticFiles 啓用靜態文件中間件來提供文件。

 

public void Configure(IApplicationBuilder app)
{
    // Serve my app-specific default file, if present.
    DefaultFilesOptions options = new DefaultFilesOptions();
    options.DefaultFileNames.Clear();
    options.DefaultFileNames.Add("mydefault.html");
    app.UseDefaultFiles(options);
    app.UseStaticFiles();
}
將默認文件名更改成 mydefault.html

 

8,路由

routes.MapRoute(
    name: "default",
    template: "{controller=Home}/{action=Index}/{id?}");
典型路由
routes.MapRoute(
    name: "default",
    template: "{controller=Home}/{action=Index}/{id:int}");
路由約束

①尾隨句點  .  是可選: files/{filename}.{ext?} 

②*全方位參數: blog/{*slug} 

 將匹配以 /blog 開頭且其後帶有任何值(將分配給 slug 路由值)的 URI

 

9,環境

ASP.NET Core 在應用程序啓動時讀取環境變量 ASPNETCORE_ENVIRONMENT(若是未設置 ASPNETCORE_ENVIRONMENT,將默認爲 Production

ASPNETCORE_ENVIRONMENT值:

  • Development(開發)
  • Production(生產)
  • Staging(暫存)

 

10,配置和選項

nuget Microsoft.Extensions.Configuration 

①讀取json文件

nuget Microsoft.Extensions.Configuration.Json 

using System;
using System.IO;
// Requires NuGet package
// Microsoft.Extensions.Configuration.Json
using Microsoft.Extensions.Configuration;

public class Program
{
    public static IConfiguration Configuration { get; set; }

    public static void Main(string[] args = null)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json");

        Configuration = builder.Build();

        Console.WriteLine($"option1 = {Configuration["Option1"]}");
        Console.WriteLine($"option2 = {Configuration["option2"]}");
        Console.WriteLine(
            $"suboption1 = {Configuration["subsection:suboption1"]}");
        Console.WriteLine();

        Console.WriteLine("Wizards:");
        Console.Write($"{Configuration["wizards:0:Name"]}, ");
        Console.WriteLine($"age {Configuration["wizards:0:Age"]}");
        Console.Write($"{Configuration["wizards:1:Name"]}, ");
        Console.WriteLine($"age {Configuration["wizards:1:Age"]}");
        Console.WriteLine();

        Console.WriteLine("Press a key...");
        Console.ReadKey();
    }
}
View Code
{
  "option1": "value1_from_json",
  "option2": 2,

  "subsection": {
    "suboption1": "subvalue1_from_json"
  },
  "wizards": [
    {
      "Name": "Gandalf",
      "Age": "1000"
    },
    {
      "Name": "Harry",
      "Age": "17"
    }
  ]
}
json文件內容

 節點由冒號  :  分隔: Configuration["subsection:suboption1"] 

 獲取數組值: Configuration["wizards:0:Name"] 

②讀取xml文件

nuget Microsoft.Extensions.Configuration.Xml 

using System;
using Microsoft.Extensions.Configuration;
using System.IO;

namespace ConsoleDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            var builder= new ConfigurationBuilder()
                        .SetBasePath(Directory.GetCurrentDirectory())
                        .AddXmlFile("test.xml");
            var configuration=builder.Build();
            Console.WriteLine(configuration["wizard:Harry:age"]);
        }
    }
}
View Code
<wizards>
  <wizard name="Gandalf">
    <age>1000</age>
  </wizard>
  <wizard name="Harry">
    <age>17</age>
  </wizard>
</wizards>
xml文件內容

③json綁定到對象裏面

nuget Microsoft.Extensions.Configuration.Binder 

using System;
using Microsoft.Extensions.Configuration;
using System.IO;
using System.Collections.Generic;

namespace ConsoleDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            var dic=new Dictionary<string,string>();
            dic.Add("Person:Name","hunter");
            dic.Add("Person:Age","10");


            var builder=new ConfigurationBuilder()
                        .AddInMemoryCollection(dic);
            IConfiguration configuration=builder.Build();

            var person=new Person();
            configuration.GetSection("Person").Bind(person);
            Console.WriteLine(person.Name);
            Console.WriteLine(person.Age);

        }
    }

    public class Person{
        public string Name{get;set;}
        public int Age{get;set;}
    }
}
View Code

 ④在razor視圖獲取mvc視圖中使用configuration

@page
@model IndexModel

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Index Page</title>
</head>
<body>
    <h1>Access configuration in a Razor Pages page</h1>
    <p>Configuration[&quot;key&quot;]: @Configuration["key"]</p>
</body>
</html>
在 Razor 頁面頁中
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Index View</title>
</head>
<body>
    <h1>Access configuration in an MVC view</h1>
    <p>Configuration[&quot;key&quot;]: @Configuration["key"]</p>
</body>
</html>
在 MVC 視圖中

 ④注入option配置

{
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "Option":{
    "option1":"value1_from_json",
    "option2":-1
  }
 
}
appsettings.json
  public class MyOption{
        public string option1{get;set;}
        public int option2{get;set;}
    }
自定義MyOption類
 services.Configure<MyOption>(Configuration.GetSection("Option"));
在ConfigureServices註冊
        private  IOptions<MyOption> _option;
        public BlogController(IOptions<MyOption> option)
        {
            _option=option;
           _option.Value.option1+_option.Value.option2
        }
構造注入並使用

 

11,日誌

①建立日誌

nuget Microsoft.Extensions.Logging 

public class TodoController : Controller
{
    private readonly ITodoRepository _todoRepository;
    private readonly ILogger _logger;

    public TodoController(ITodoRepository todoRepository,
        ILogger<TodoController> logger)
    {
        _todoRepository = todoRepository;
        _logger = logger;
    }
要建立日誌,請先從依賴關係注入容器獲取 ILogger 對象
public IActionResult GetById(string id)
{
    _logger.LogInformation(LoggingEvents.GetItem, "Getting item {ID}", id);
    var item = _todoRepository.Find(id);
    if (item == null)
    {
        _logger.LogWarning(LoggingEvents.GetItemNotFound, "GetById({ID}) NOT FOUND", id);
        return NotFound();
    }
    return new ObjectResult(item);
}
而後在該記錄器對象上調用日誌記錄方法

②事件ID

LoggingEvents本身定義例如:

public class LoggingEvents
{
    public const int GenerateItems = 1000;
    public const int ListItems = 1001;
    public const int GetItem = 1002;
    public const int InsertItem = 1003;
    public const int UpdateItem = 1004;
    public const int DeleteItem = 1005;

    public const int GetItemNotFound = 4000;
    public const int UpdateItemNotFound = 4001;
}
LoggingEvents
public IActionResult GetById(string id)
{
    _logger.LogInformation(LoggingEvents.GetItem, "Getting item {ID}", id);
    var item = _todoRepository.Find(id);
    if (item == null)
    {
        _logger.LogWarning(LoggingEvents.GetItemNotFound, "GetById({ID}) NOT FOUND", id);
        return NotFound();
    }
    return new ObjectResult(item);
}
使用案例

 

12,使用Sesstion

 using Microsoft.AspNetCore.Http 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;

namespace MvcDemo
{
    public class Startup
    {
        public Startup(IConfiguration configuration, IHostingEnvironment env)
        {
            Configuration = configuration;
            HostingEnvironment=env;
        }

        public IConfiguration Configuration { get; }
        public IHostingEnvironment HostingEnvironment{get;}

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            var physicalProvider= HostingEnvironment.ContentRootFileProvider;
            services.AddSingleton<IFileProvider>(physicalProvider);

            services.AddSession(option=>{
                option.IdleTimeout=TimeSpan.FromSeconds(10);
                option.Cookie.HttpOnly=true;//指示客戶端腳本是否能夠訪問cookie。
            });

            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseSession();//要在UseMvc以前調用

            app.UseStaticFiles();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}
Startup
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using MvcDemo.Models;
using Microsoft.Extensions.FileProviders;
using Microsoft.AspNetCore.Http;

namespace MvcDemo.Controllers
{
    public class SesstionController : Controller
    {

        public string Index(string str)
        {
            HttpContext.Session.SetString("str",str);
            
            return "sesstion已經設置";
        }

        public string GetSession()
        {
           var val= HttpContext.Session.GetString("str");
           return val;
        }
        

    }
}
使用

 

13,使用po文件配置本地化

nuget OrchardCore.Localization.Core 

①配置Startup

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Localization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;

namespace MvcDemo
{
    public class Startup
    {
        public Startup(IConfiguration configuration, IHostingEnvironment env)
        {
            Configuration = configuration;
            HostingEnvironment=env;
        }

        public IConfiguration Configuration { get; }
        public IHostingEnvironment HostingEnvironment{get;}

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            var physicalProvider= HostingEnvironment.ContentRootFileProvider;
            services.AddSingleton<IFileProvider>(physicalProvider);

            services.AddSession(option=>{
                option.IdleTimeout=TimeSpan.FromSeconds(10);
                option.Cookie.HttpOnly=true;//指示客戶端腳本是否能夠訪問cookie。
            });

            services.AddLocalization(option=>{

            });
            services.AddMvc()
                    .AddViewLocalization();
            services.AddPortableObjectLocalization(options=>{
                options.ResourcesPath="Localization";
            });
            services.Configure<RequestLocalizationOptions>(options =>
            {
                var supportedCultures = new List<CultureInfo>
                {
                    new CultureInfo("en-US"),
                    new CultureInfo("en"),
                    new CultureInfo("fr-FR"),
                    new CultureInfo("fr"),
                    new CultureInfo("zh-CHS")
                };

                options.DefaultRequestCulture = new RequestCulture("zh-CHS");
                options.SupportedCultures = supportedCultures;
                options.SupportedUICultures = supportedCultures;
            });

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseSession();//要在UseMvc以前調用

            app.UseStaticFiles();

            app.UseRequestLocalization();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}
配置Startup

②使應用內容可本地化

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using MvcDemo.Models;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Builder;
using System.Globalization;
using Microsoft.AspNetCore.Localization;

namespace MvcDemo.Controllers
{
    public class LocalizationController : Controller
    {

        private readonly IStringLocalizer<LocalizationController> _localization;

        public LocalizationController(IStringLocalizer<LocalizationController> localization)
        {
            _localization=localization;
        }

        public string Index()
        {
            return _localization["Localization"];
        }

        public string Get()
        {
            return _localization["Test{0}",1];
        }

    }
}
LocalizationController

③視圖本地化

@using Microsoft.AspNetCore.Mvc.Localization
@inject IViewLocalizer Localizer
@{
    ViewData["Title"] = "Home Page";
}
<p>@Localizer["Localization"]</p>
<p>@Localizer["Test{0}",1]</p>
視圖

④DataAnnotations本地化

⑤po文件

msgid "Localization"
msgstr "Localization"

msgid "Home"
msgstr "Home"

msgid "Test{0}"
msgstr "Test{0}"
en.po
msgid "Localization"
msgstr "本地化"

msgid "Home"
msgstr "主頁"

msgid "Test{0}"
msgstr "測試{0}"
zh-CHS.po

msgid:鍵

msgstr:值

 

14,在 ASP.NET 管道中運行 OWIN 中間件

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Owin;
using System.Text;
using System.IO;
using System.Globalization;

namespace AspNetCoreOwin
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseOwin(pipeline=>{
                pipeline(next=>OwinHello);
            });

            app.UseStaticFiles();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }

        public Task OwinHello(IDictionary<string,object> environment)
        {
            string responseText="hello owin";
            byte[] responseBytes=Encoding.UTF8.GetBytes(responseText);
            var responseStream=(Stream)environment["owin.ResponseBody"];
            var responseHeaders=(IDictionary<string,string[]>)environment["owin.ResponseHeaders"];
            responseHeaders["Content-Length"]=new string[]{responseBytes.Length.ToString(CultureInfo.InvariantCulture)};
            responseHeaders["Content-Type"]=new string[] {"text/plain"};
            return responseStream.WriteAsync(responseBytes,0,responseBytes.Length);
        }
    }
}
Startup

案例下載:https://pan.baidu.com/s/1FLfBuqsMuKnv7wSF3BSW4w 

 

15,WebSockets

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.WebSockets;
using System.Net.WebSockets;
using Microsoft.AspNetCore.Http;
using System.Threading;
using System.Collections.Concurrent;

namespace WebSocketsDemo
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseDefaultFiles();
            app.UseStaticFiles();

            var webSocketOption=new WebSocketOptions()
            {
                KeepAliveInterval=TimeSpan.FromSeconds(120),//向客戶端發送「ping」幀的頻率,以確保代理保持鏈接處於打開狀態
                ReceiveBufferSize=4*1024//用於接收數據的緩衝區的大小
            };
            app.UseWebSockets(webSocketOption);

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });

            app.Use(async (context,next)=>{
                if(context.Request.Path=="/ws")
                {
                    if(context.WebSockets.IsWebSocketRequest)//判斷是不是websocket請求
                    {
                        //將TCP鏈接升級到WebSocket鏈接,並提供websocket對象
                        WebSocket webSocket=await context.WebSockets.AcceptWebSocketAsync();
                        WebSockets.TryAdd(webSocket,"1");
                        await Echo(context,webSocket);
                    }
                    else
                    {
                        context.Response.StatusCode=400;
                    }
                }
                else
                {
                    await next();
                }
            });
        }

        private async Task Echo(HttpContext context,WebSocket websocket)
        {
            var buffer=new byte[4*1024];
            WebSocketReceiveResult result=await websocket.ReceiveAsync(new ArraySegment<byte>(buffer),CancellationToken.None);
            while(!result.CloseStatus.HasValue)
            {
                //廣播
                foreach(var ws in WebSockets)
                {
                    if(!ws.Key.CloseStatus.HasValue)
                    {
                       await ws.Key.SendAsync(new ArraySegment<byte>(buffer,0,buffer.Length),result.MessageType,result.EndOfMessage,CancellationToken.None);
                    }
                    else
                    {
                        string value;
                        WebSockets.TryRemove(ws.Key,out value);
                    }
                    //await ws.SendAsync(new ArraySegment<byte>(buffer,0,buffer.Length),result.MessageType,result.EndOfMessage,CancellationToken.None);
                }
                
                result=await websocket.ReceiveAsync(new ArraySegment<byte>(buffer),CancellationToken.None);
            }
            await websocket.CloseAsync(result.CloseStatus.Value,result.CloseStatusDescription,CancellationToken.None);
        }
        //能夠開一個線程去檢測WebSocket是否掉線,掉線則從字典中刪除
        private static ConcurrentDictionary<WebSocket,string> WebSockets=new ConcurrentDictionary<WebSocket,string>();
    }
}
Startup
<!doctype html>
<html lang="en">
  <head>
    <title>Title</title>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <script src="lib/jquery/dist/jquery.min.js"></script>
    </head>
  <body>
    
    <input type="text" id="message"/><input type="button" id="send" value="發送"/>

    <div id="context"></div>

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
  </body>

  <script>

      var ws;
      if("WebSocket" in window)
      {
         ws=new WebSocket("ws://localhost:5000/ws");
         ws.onopen=function(){
          alert("開始")
         }
         ws.onmessage=function(res){
           $("#context").append(res.data+"<br/>")
         }
         ws.onclose=function(){
           alert("退出")
         }
      }
      else
      {
          alert("不支持websocket");
      }

   $(function(){

          $("#send").click(function(){
            ws.send($("#message").val())
          })
   })

  </script>
</html>
index.html

案例下載:https://pan.baidu.com/s/1C5CLrtD6Mr66oiM7sfEHaw

 

16,使用內存緩存

nuget Microsoft.Extensions.Caching.Memory 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Caching;

namespace CacheDemo
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            services.AddMemoryCache();
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}
Startup
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using CacheDemo.Models;
using Microsoft.Extensions.Caching.Memory;

namespace CacheDemo.Controllers
{
    public class HomeController : Controller
    {

        private IMemoryCache _cache;

        public HomeController(IMemoryCache cache)
        {
            _cache=cache;
        }

        public IActionResult Index()
        {
            DateTime date;
            if(_cache.TryGetValue("date",out date))
            {
                ViewData["date"]=date;
            }
            else
            {
                ViewData["date"]="未設置緩存";
            }
            return View();
        }


        public IActionResult Set()
        {
            _cache.Set<DateTime>("date",DateTime.Now);
            return RedirectToAction("Index");
        }

        
    }
}
HomeController

案例下載:https://pan.baidu.com/s/1DEpF-_HLlEQFWswPyb-WkA

 

 

2、EF

1,Include和ThenInclude

使上下文加載 Student.Enrollments 導航屬性,並在每一個註冊中加載 Enrollment.Course 導航屬性

    public class Student
    {
        public int ID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }

    public class Enrollment
    {
        public int EnrollmentID { get; set; }
        public int CourseID { get; set; }
        public int StudentID { get; set; }
        public Grade? Grade { get; set; }

        public Course Course { get; set; }
        public Student Student { get; set; }
    }
    public class Course
    {
        //主鍵
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int CourseID { get; set; }
        public string Title { get; set; }
        public int Credits { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }
實體

2,經過依賴關係注入註冊上下文

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<SchoolContext>(options =>
      options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddMvc();
}

配置鏈接字符串

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;ConnectRetryCount=0;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  }
}
appsettings.json

ConnectRetryCount=0 來防止 SQLClient 掛起 

3,種子數據

using ContosoUniversity.Models;
using System;
using System.Linq;

namespace ContosoUniversity.Data
{
    public static class DbInitializer
    {
        public static void Initialize(SchoolContext context)
        {
            context.Database.EnsureCreated();

            // Look for any students.
            if (context.Students.Any())
            {
                return;   // DB has been seeded
            }

            var students = new Student[]
            {
            new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2005-09-01")},
            new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2003-09-01")},
            new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2001-09-01")},
            new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2003-09-01")},
            new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2005-09-01")}
            };
            foreach (Student s in students)
            {
                context.Students.Add(s);
            }
            context.SaveChanges();

            var courses = new Course[]
            {
            new Course{CourseID=1050,Title="Chemistry",Credits=3},
            new Course{CourseID=4022,Title="Microeconomics",Credits=3},
            new Course{CourseID=4041,Title="Macroeconomics",Credits=3},
            new Course{CourseID=1045,Title="Calculus",Credits=4},
            new Course{CourseID=3141,Title="Trigonometry",Credits=4},
            new Course{CourseID=2021,Title="Composition",Credits=3},
            new Course{CourseID=2042,Title="Literature",Credits=4}
            };
            foreach (Course c in courses)
            {
                context.Courses.Add(c);
            }
            context.SaveChanges();

            var enrollments = new Enrollment[]
            {
            new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
            new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
            new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
            new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
            new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
            new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
            new Enrollment{StudentID=3,CourseID=1050},
            new Enrollment{StudentID=4,CourseID=1050},
            new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
            new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
            new Enrollment{StudentID=6,CourseID=1045},
            new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
            };
            foreach (Enrollment e in enrollments)
            {
                context.Enrollments.Add(e);
            }
            context.SaveChanges();
        }
    }
}
DbInitializer
// Unused usings removed
using System;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using ContosoUniversity.Data;

namespace ContosoUniversity
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = BuildWebHost(args);

            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;
                try
                {
                    var context = services.GetRequiredService<SchoolContext>();
                    DbInitializer.Initialize(context);
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred while seeding the database.");
                }
            }

            host.Run();
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .Build();
    }
}
Program.cs

第一次運行該應用時,會使用測試數據建立並填充數據庫。 更新數據模型時:

  • 刪除數據庫。
  • 更新 seed 方法。
  • 運行該應用,並建立新的種子數據庫。


4,級聯刪除 

modelBuilder.Entity<Department>()
   .HasOne(d => d.Administrator)
   .WithMany()
   .OnDelete(DeleteBehavior.Restrict)
Code

 

5,組合PK

    public class CourseAssignment
    {
        public int InstructorID { get; set; }
        public int CourseID { get; set; }
        public Instructor Instructor { get; set; }
        public Course Course { get; set; }
    }
Model
protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
modelBuilder.Entity<CourseAssignment>()
                .HasKey(c => new { c.CourseID, c.InstructorID });
 }
SchoolContext

 

 6,使用原始sql

調用返回實體的查詢

public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    string query = "SELECT * FROM Department WHERE DepartmentID = {0}";
    var department = await _context.Departments
        .FromSql(query, id)
        .Include(d => d.Administrator)
        .AsNoTracking()
        .SingleOrDefaultAsync();

    if (department == null)
    {
        return NotFound();
    }

    return View(department);
}
FromSql

調用返回其餘類型的查詢

public async Task<ActionResult> About()
{
    List<EnrollmentDateGroup> groups = new List<EnrollmentDateGroup>();
    var conn = _context.Database.GetDbConnection();
    try
    {
        await conn.OpenAsync();
        using (var command = conn.CreateCommand())
        {
            string query = "SELECT EnrollmentDate, COUNT(*) AS StudentCount "
                + "FROM Person "
                + "WHERE Discriminator = 'Student' "
                + "GROUP BY EnrollmentDate";
            command.CommandText = query;
            DbDataReader reader = await command.ExecuteReaderAsync();

            if (reader.HasRows)
            {
                while (await reader.ReadAsync())
                {
                    var row = new EnrollmentDateGroup { EnrollmentDate = reader.GetDateTime(0), StudentCount = reader.GetInt32(1) };
                    groups.Add(row);
                }
            }
            reader.Dispose();
        }
    }
    finally
    {
        conn.Close();
    }
    return View(groups);
}
Code

調用更新查詢

[HttpPost]
public async Task<IActionResult> UpdateCourseCredits(int? multiplier)
{
    if (multiplier != null)
    {
        ViewData["RowsAffected"] = 
            await _context.Database.ExecuteSqlCommandAsync(
                "UPDATE Course SET Credits = Credits * {0}",
                parameters: multiplier);
    }
    return View();
}
Code

 

 

 

 

3、Razor頁面

1,路由

<a asp-action="Edit" asp-route-studentID="@item.ID">Edit</a>
<a href="/Students/Edit?studentID=6">Edit</a>

2,命令搭建基架

參考文檔:https://docs.microsoft.com/zh-cn/aspnet/core/data/ef-rp/intro#add-scaffold-tooling 

3,SelectList

using ContosoUniversity.Data;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using System.Linq;

namespace ContosoUniversity.Pages.Courses
{
    public class DepartmentNamePageModel : PageModel
    {
        public SelectList DepartmentNameSL { get; set; }

        public void PopulateDepartmentsDropDownList(SchoolContext _context,
            object selectedDepartment = null)
        {
            var departmentsQuery = from d in _context.Departments
                                   orderby d.Name // Sort by name.
                                   select d;

            DepartmentNameSL = new SelectList(departmentsQuery.AsNoTracking(),
                        "DepartmentID", "Name", selectedDepartment);
        }
    }
}


  <div class="form-group">
                <label asp-for="Course.Department" class="control-label"></label>
                <select asp-for="Course.DepartmentID" class="form-control"
                        asp-items="@Model.DepartmentNameSL">
                    <option value="">-- Select Department --</option>
                </select>
                <span asp-validation-for="Course.DepartmentID" class="text-danger" />
            </div>
Code

 

 

 

4、MVC

1,模型綁定 

 ①經常使用的驗證屬性

  • [CreditCard]:驗證屬性是否具備信用卡格式。

  • [Compare]:驗證某個模型中的兩個屬性是否匹配。

  • [EmailAddress]:驗證屬性是否具備電子郵件格式。

  • [Phone]:驗證屬性是否具備電話格式。

  • [Range]:驗證屬性值是否落在給定範圍內。

  • [RegularExpression]:驗證數據是否與指定的正則表達式匹配。

  • [Required]:將屬性設置爲必需屬性。

  • [StringLength]:驗證字符串屬性是否最多具備給定的最大長度。

  • [Url]:驗證屬性是否具備 URL 格式。

 

2,視圖

①Razor語法

<p>Last week this time: @(DateTime.Now - TimeSpan.FromDays(7))</p>
計算 @() 括號中的全部內容,並將其呈現到輸出中
@{
    var joe = new Person("Joe", 33);
}

<p>Age@(joe.Age)</p>
使用顯式表達式將文本與表達式結果串聯起來
@Html.Raw("<span>Hello World</span>")
輸出不進行編碼,但呈現爲 HTML 標記
@for (var i = 0; i < people.Length; i++)
{
    var person = people[i];
    <text>Name: @person.Name</text>
}
帶分隔符的顯式轉換
@for (var i = 0; i < people.Length; i++)
{
    var person = people[i];
    @:Name: @person.Name
}
使用 @ 的顯式行轉換
@if (value % 2 == 0)
{
    <p>The value was even.</p>
}
else if (value >= 1337)
{
    <p>The value is large.</p>
}
else
{
    <p>The value is odd and small.</p>
}
@if、else if、else
@switch (value)
{
    case 1:
        <p>The value is 1!</p>
        break;
    case 1337:
        <p>Your number is 1337!</p>
        break;
    default:
        <p>Your number wasn't 1 or 1337.</p>
        break;
}
@switch
@for (var i = 0; i < people.Length; i++)
{
    var person = people[i];
    <p>Name: @person.Name</p>
    <p>Age: @person.Age</p>
}
@for
@foreach (var person in people)
{
    <p>Name: @person.Name</p>
    <p>Age: @person.Age</p>
}
@foreach
@{ var i = 0; }
@while (i < people.Length)
{
    var person = people[i];
    <p>Name: @person.Name</p>
    <p>Age: @person.Age</p>

    i++;
}
@while
@{ var i = 0; }
@do
{
    var person = people[i];
    <p>Name: @person.Name</p>
    <p>Age: @person.Age</p>

    i++;
} while (i < people.Length);
@do while
@using (Html.BeginForm())
{
    <div>
        email:
        <input type="email" id="Email" value="">
        <button>Register</button>
    </div>
}
複合語句 @using
@try
{
    throw new InvalidOperationException("You did something invalid.");
}
catch (Exception ex)
{
    <p>The exception message: @ex.Message</p>
}
finally
{
    <p>The finally statement.</p>
}
@try、catch、finally

②@inherits 指令對視圖繼承的類提供徹底控制

using Microsoft.AspNetCore.Mvc.Razor;

public abstract class CustomRazorPage<TModel> : RazorPage<TModel>
{
    public string CustomText { get; } = "Gardyloo! - A Scottish warning yelled from a window before dumping a slop bucket on the street below.";
}
自定義 Razor 頁面類型
@inherits CustomRazorPage<TModel>

<div>Custom text: @CustomText</div>
CustomText 顯示在視圖中
<div>Custom text: Gardyloo! - A Scottish warning yelled from a window before dumping a slop bucket on the street below.</div>
呈現

@functions 指令容許 Razor 頁面將 C# 代碼塊添加到視圖中

@functions {
    public string GetHello()
    {
        return "Hello";
    }
}

<div>From method: @GetHello()</div> 
視圖
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Razor;

public class _Views_Home_Test_cshtml : RazorPage<dynamic>
{
    // Functions placed between here 
    public string GetHello()
    {
        return "Hello";
    }
    // And here.
#pragma warning disable 1998
    public override async Task ExecuteAsync()
    {
        WriteLiteral("\r\n<div>From method: ");
        Write(GetHello());
        WriteLiteral("</div>\r\n");
    }
#pragma warning restore 1998
生成的 Razor C# 類

④_ViewImports.cshtml導入共享指令

 支持的指令:

  • @addTagHelper

  • @removeTagHelper

  • @tagHelperPrefix

  • @using

  • @model

  • @inherits

  • @inject

 針對 ASP.NET Core MVC 應用的 _ViewImports.cshtml 文件一般放置在 Views 文件夾中

 

3,標記幫助程序

①@addTagHelper

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper MvcDemo2.TagHelpers.EmailTagHelper,MvcDemo2
@addTagHelper以後第一個參數:須要加載的標記幫助類(*表示全部)
第二個參數:標記幫助類所在的程序集

②簡單的將 <email>hunter</email> 變成 <a>hunter</a>  

using Microsoft.AspNetCore.Razor.TagHelpers;
using System.Threading.Tasks;
namespace MvcDemo2.TagHelpers
{
    //EmailTagHelper 的根名稱是 email,所以 <email> 標記將做爲目標名稱
    public class EmailTagHelper:TagHelper
    {
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            output.TagName="a";//用<a>標籤替換<email>
        }

    }
}
①添加EmailTagHelper

@using MvcDemo2
@using MvcDemo2.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper MvcDemo2.TagHelpers.EmailTagHelper,MvcDemo2
②修改_ViewImports.cshtml

這時,在頁面上的 <email>hunter</email> 會變成<a>hunter</a> 

③設置自結束標籤 <email/>  

    [HtmlTargetElement("email",TagStructure=TagStructure.WithoutEndTag)]
    public class EmailTagHelper:TagHelper
HtmlTargetElement

若是存在不是自結束標籤,就會報錯

④將 <email mail-to="hunter"></email> 變成 <a href="hunter@qq.com">hunter@qq.com</a> 

using Microsoft.AspNetCore.Razor.TagHelpers;
using System.Threading.Tasks;
namespace MvcDemo2.TagHelpers
{
    //EmailTagHelper 的根名稱是 email,所以 <email> 標記將做爲目標名稱
    public class EmailTagHelper:TagHelper
    {
        public const string EmailDomain="qq.com";
        //能夠經過<email mail-to =「...」/>傳遞
        //標記幫助程序採用 Pascal 大小寫格式的類和屬性名將轉換爲各自相應的小寫短橫線格式
        public string MailTo{get;set;}
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            output.TagName="a";//用<a>標籤替換<email>
            var address=MailTo+"@"+EmailDomain;

            //給標籤添加屬性
            output.Attributes.SetAttribute("href",address);
            //設置<email></email>裏面的內容
            output.Content.SetContent(address);
        }

    }
}
EmailTagHelper

⑤將 <email>hunter</email> 變成<a href="hunter@qq.com">hunter@qq.com</a> 

using Microsoft.AspNetCore.Razor.TagHelpers;
using System.Threading.Tasks;
namespace MvcDemo2.TagHelpers
{
    //EmailTagHelper 的根名稱是 email,所以 <email> 標記將做爲目標名稱
    public class EmailTagHelper:TagHelper
    {
        public const string EmailDomain="qq.com";
        //能夠經過<email mail-to =「...」/>傳遞

        public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
        {
            output.TagName="a";//用<a>標籤替換<email>

            var content=await output.GetChildContentAsync();//獲取標籤裏的內容
            var tagter=content.GetContent()+"@"+EmailDomain;

            //給標籤添加屬性
            output.Attributes.SetAttribute("href",tagter);
            //設置<email></email>裏面的內容
            output.Content.SetContent(tagter);
        }

    }
}
EmailTagHelper

⑥將頁面中的 <bold>bbbb</bold> 替換爲 <strong>bbbb</strong>  

using Microsoft.AspNetCore.Razor.TagHelpers;
namespace MvcDemo2.TagHelpers
{
    public class BoldTagHelper:TagHelper
    {
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            output.Attributes.RemoveAll("bold");
            output.PreContent.SetHtmlContent("<strong>");
            output.PostContent.SetHtmlContent("</strong>");
        }
        
    }
}
BoldTagHelper

③將model傳入標記幫助程序

using System;
namespace MvcDemo2.Models
{
    public class WebsiteContext
    {
        public Version Version{get;set;}
        public int CopyrightYear{get;set;}
        public bool Approved{get;set;}
        public int TagsToShow{get;set;}
    }
}
Model
using Microsoft.AspNetCore.Razor.TagHelpers;
using MvcDemo2.Models;
namespace MvcDemo2.TagHelpers
{

    //使用<website-information />
    public class WebsiteInformationTagHelper:TagHelper
    {
        public WebsiteContext Info{get;set;}

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            output.TagName="section";
            output.Content.SetHtmlContent(
                $@"<ul><li><strong>版本:</strong> {Info.Version}</li>
                <li><strong>版權 年:</strong> {Info.CopyrightYear}</li>
                <li><strong>是否批准:</strong> {Info.Approved}</li>
                <li><strong>顯示的標籤:</strong> {Info.TagsToShow}</li></ul>"
            );
        }
        
    }
}
WebsiteInformationTagHelper
<website-information info="new WebsiteContext(){
    Version=new Version(1,3),
    CopyrightYear=10,
    Approved=true,
    TagsToShow=131
}"></website-information>
Html

⑥.NET 類型和生成的 HTML 類型 

.NET 類型 輸入類型
Bool type=」checkbox」
String type=」text」
DateTime type=」datetime」
Byte type=」number」
Int type=」number」
Single、Double type=」number」

⑦數據註解和生成的 HTML 類型 

 

特性 輸入類型
[EmailAddress] type=」email」
[Url] type=」url」
[HiddenInput] type=」hidden」
[Phone] type=」tel」
[DataType(DataType.Password)] type=」password」
[DataType(DataType.Date)] type=」date」
[DataType(DataType.Time)] type=」time」

⑧驗證標記幫助程序

 <span asp-validation-for="Email"></span> 

針對具備 asp-validation-summary 屬性的 <div> 元素

asp-validation-summary 顯示的驗證消息
ValidationSummary.All 屬性和模型級別
ValidationSummary.ModelOnly 模型
ValidationSummary.None

實例: 

@model RegisterViewModel
@{
    ViewData["Title"] = "Home Page";
}

<a bold>aaa</a>
<bold>bbbb</bold>
<!--Razor 知道 info 屬性是一個類,而不是字符串,而且你想要編寫 C# 代碼。 編寫任何非字符串標記幫助程序屬性時,都不該使用 @@ 字符。-->


<website-information info="new WebsiteContext(){
    Version=new Version(1,3),
    CopyrightYear=10,
    Approved=true,
    TagsToShow=131
}"></website-information>



<form asp-action="Register" method="POST" role="form">
    <legend>註冊</legend>

    <div asp-validation-summary="ModelOnly"></div>

    <div class="form-group">
        <input asp-for="Email" class="form-control" placeholder="Input field">
        <span asp-validation-for="Email"></span>
    </div>

     <div class="form-group">
        <input asp-for="Password" class="form-control" placeholder="Input field">
        <span asp-validation-for="Password"></span>
    </div>

    <button type="submit" class="btn btn-primary">Submit</button>
</form>
Index.cshtml
        [HttpPost]
        public IActionResult Register(RegisterViewModel model)
        {
            return View("Index");
        }
Controller

⑨選擇標記幫助程序

using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace MvcDemo2.Models
{
    public class CountryViewModel
    {
        public string Country{get;set;}
        public List<SelectListItem> Countries {get;}=new List<SelectListItem>(){
            new SelectListItem(){Value="MX",Text="墨西哥"},
            new SelectListItem(){Value="CA",Text="加拿大"},
            new SelectListItem(){Value="US",Text="美國"}
        };
    }
}
CountryViewModel
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using MvcDemo2.Models;

namespace MvcDemo2.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            var country=new CountryViewModel();
            country.Country="US";
            return View(country);
        }

        [HttpPost]
        public IActionResult Index(CountryViewModel model)
        {
            return View(model);
        }
        
    }
}
HomeController
@model CountryViewModel


<form method="POST" asp-action="Index">

    <select asp-for="Country" asp-items="Model.Countries"></select>

    <input type="submit" value="提交" />
</form>
Index

⑩枚舉綁定

public enum CountryEnum
        {
            [Display(Name = "墨西哥合衆國")]
            Mexico,
            [Display(Name = "美國")]
            USA,
            Canada,
            France,
            Germany,
            Spain
        }
定義枚舉

 <select asp-for="Country" asp-items="Html.GetEnumSelectList<CountryEnum>()"></select> 

⑩選項分組

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace MvcDemo2.Models
{
    public class CountryViewModel
    {
        public string Country{get;set;}

        public List<SelectListItem> Countries {get;}=new List<SelectListItem>(){
            new SelectListItem(){Value="MX",Text="墨西哥",Group=new SelectListGroup(){Name="分組一"}},
            new SelectListItem(){Value="CA",Text="加拿大",Group=new SelectListGroup(){Name="分組二"}},
            new SelectListItem(){Value="US",Text="美國",Group=new SelectListGroup(){Name="分組三"}}
        };

        
    }
      
}
CountryViewModel
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using MvcDemo2.Models;

namespace MvcDemo2.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            var country=new CountryViewModel();
            country.Country="US";
            return View(country);
        }

        [HttpPost]
        public IActionResult Index(CountryViewModel model)
        {
            return View(model);
        }
        
    }
}
HomeController

 <select asp-for="Country" asp-items="Model.Countries"></select> 

 

 ⑩多重選擇

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace MvcDemo2.Models
{
    public class CountryViewModel
    {
        public IEnumerable<string> Countrys{get;set;}

        public List<SelectListItem> Countries {get;}=new List<SelectListItem>(){
            new SelectListItem(){Value="MX",Text="墨西哥"},
            new SelectListItem(){Value="CA",Text="加拿大"},
            new SelectListItem(){Value="US",Text="美國"}
        };

        
    }
      
}
CountryViewModel
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using MvcDemo2.Models;

namespace MvcDemo2.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            var country=new CountryViewModel();
            country.Countrys=new []{"US","MX"};
            return View(country);
        }

        [HttpPost]
        public IActionResult Index(CountryViewModel model)
        {
            return View(model);
        }
        
    }
}
HomeController
@model CountryViewModel


<form method="POST" asp-action="Index">

    <select asp-for="Countrys" asp-items="Model.Countries"></select>

    <input type="submit" value="提交" />
</form>
index

⑩無選定內容

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace MvcDemo2.Models
{
    public class CountryViewModel
    {
        public string Country{get;set;}

        public List<SelectListItem> Countries {get;}=new List<SelectListItem>(){
            new SelectListItem(){Value="MX",Text="墨西哥"},
            new SelectListItem(){Value="CA",Text="加拿大"},
            new SelectListItem(){Value="US",Text="美國"}
        };

        
    }
      
}
CountryViewModel
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using MvcDemo2.Models;

namespace MvcDemo2.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            var country=new CountryViewModel();
            return View(country);
        }

        [HttpPost]
        public IActionResult Index(CountryViewModel model)
        {
            return View(model);
        }
        
    }
}
HomeController
@model CountryViewModel


<form method="POST" asp-action="Index">

    <select asp-for="Country" asp-items="Model.Countries">
        <option value="">--none--</option>
    </select>

    <input type="submit" value="提交" />
</form>
index

 

4,內置標記幫助程序

asp-all-route-data

@{
var parms = new Dictionary<string, string>
            {
                { "speakerId", "11" },
                { "currentYear", "true" }
            };
}

<a asp-route="speakerevalscurrent"
   asp-all-route-data="parms">Speaker Evaluations</a>
試圖
<a href="/Speaker/EvaluationsCurrent?speakerId=11&currentYear=true">Speaker Evaluations</a>
前面的代碼生成如下 HTML:
[Route("/Speaker/EvaluationsCurrent",
       Name = "speakerevalscurrent")]
public IActionResult Evaluations(
    int speakerId,
    bool currentYear) => View();
Controller

asp-fragment

可定義要追加到 URL 的 URL 片斷

<a asp-controller="Speaker"
   asp-action="Evaluations"
   asp-fragment="SpeakerEvaluations">Speaker Evaluations</a>
試圖
<a href="/Speaker/Evaluations#SpeakerEvaluations">Speaker Evaluations</a>
生成的 HTML:

asp-area

設置相應路由的區域名稱

<a asp-area="Blogs"
   asp-controller="Home"
   asp-action="AboutBlog">About Blog</a>
試圖
<a href="/Blogs/Home/AboutBlog">About Blog</a>
生成的 HTML:

asp-protocol

在URL 中指定協議(好比 https

<a asp-protocol="https"
   asp-controller="Home"
   asp-action="About">About</a>
試圖
<a href="https://localhost/Home/About">About</a>
生成的 HTML:

asp-host

在 URL 中指定主機名

<a asp-protocol="https"
   asp-host="microsoft.com"
   asp-controller="Home"
   asp-action="About">About</a>
試圖
<a href="https://microsoft.com/Home/About">About</a>
生成的 HTML:

 ⑥緩存標記幫助程序

 <cache enabled="true">@DateTime.Now</cache> 

 屬性expires-after:設置過時時間

<cache expires-after="@TimeSpan.FromSeconds(120)">
    Current Time Inside Cache Tag Helper: @DateTime.Now
</cache>
View Code

 屬性expires-sliding:設置多久未被訪問過時設置

<cache expires-sliding="@TimeSpan.FromSeconds(60)">
    Current Time Inside Cache Tag Helper: @DateTime.Now
</cache>
View Code

 ⑦環境標記幫助程序

<environment include="Development">Development</environment>
<environment include="Staging">Staging</environment>
<environment include="Production">Production</environment>
不一樣的環境顯示不一樣的標籤

⑧圖像標記幫助程序

<img src="~/images/1.jpg"  asp-append-version="true"/>
View Code

asp-append-version:追加版本號

 

5,分部視圖

@await Html.PartialAsync("ViewName")
@await Html.PartialAsync("ViewName.cshtml")
@await Html.PartialAsync("~/Views/Folder/ViewName.cshtml")
@await Html.PartialAsync("/Views/Folder/ViewName.cshtml")
@await Html.PartialAsync("../Account/LoginPartial.cshtml")
@model string
姓名:@Model
分佈頁面Person.cshtml
@await Html.PartialAsync("Person","Hunter")
調用

 

6,視圖組件

①添加 ViewComponent 類

在根目錄新建一個ViewComponents文件夾,建ViewComponent類放在此文件夾中

using MvcDemo2.Models;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;

namespace MvcDemo2.ViewComponents
{
    public class ProductListViewComponent:ViewComponent
    { 
        public async Task<IViewComponentResult> InvokeAsync(bool ischecked,string name)
        {
            var list=new List<Product>(){
                new Product(){IsChecked=true,Name="iphone x",Price=10000},
                new Product(){IsChecked=false,Name="iphone 8p",Price=6600},
            };
             var data= list.Where(m=>m.IsChecked==ischecked&&m.Name.Contains(name));
             return View(data);          
        }
        
    }
}
ProductListViewComponent

②建立視圖組件 Razor 視圖

 建立 Views/Shared/Components 文件夾。 此文件夾 必須 命名爲 Components

@model IEnumerable<Product>

@foreach(var item in Model)
{
    <p>@item.Name</p>
}
Default.cshtml
@await Component.InvokeAsync("ProductList",new {ischecked=true,name="iphone"})
視圖頁面調用

 

7,上傳文件

①使用模型綁定上傳小文件

using System.Collections.Generic;
using Microsoft.AspNetCore.Http;

namespace MvcDemo2.Models
{
    public class FileUpViewModel
    {
        public IEnumerable<IFormFile> files {get;set;}
        public string name{get;set;}
    }
}
FileUpViewModel
        public IActionResult FileUp(FileUpViewModel model)
        {
            return View();
        }
        
Controller
<form asp-action="FileUp" enctype="multipart/form-data" method="POST" role="form">
    <legend>提交</legend>

        <input type="file" name="files" class="form-control" multiple/>
        <input type="text" name="name" class="form-control"/>
    
    
    <button type="submit" class="btn btn-primary">Submit</button>
</form>
View

 

8,篩選器

每種篩選器類型都在篩選器管道中的不一樣階段執行。

  • 受權篩選器最早運行,用於肯定是否已針對當前請求爲當前用戶受權。 若是請求未獲受權,它們可讓管道短路。

  • 資源篩選器是受權後最早處理請求的篩選器。 它們能夠在篩選器管道的其他階段運行以前以及管道的其他階段完成以後運行代碼。 出於性能方面的考慮,可使用它們來實現緩存或以其餘方式讓篩選器管道短路。它們在模型綁定以前運行,因此能夠影響模型綁定。

  • 操做篩選器能夠在調用單個操做方法以前和以後當即運行代碼。 它們可用於處理傳入某個操做的參數以及從該操做返回的結果。

  • 異常篩選器用於在向響應正文寫入任何內容以前,對未經處理的異常應用全局策略。

  • 結果篩選器能夠在執行單個操做結果以前和以後當即運行代碼。 僅當操做方法成功執行時,它們纔會運行。對於必須圍繞視圖或格式化程序的執行的邏輯,它們頗有用。

下圖展現了這些篩選器類型在篩選器管道中的交互方式:

①篩選器經過不一樣的接口定義支持同步和異步實現

using FiltersSample.Helper;
using Microsoft.AspNetCore.Mvc.Filters;

namespace FiltersSample.Filters
{
    public class SampleActionFilter : IActionFilter
    {
        public void OnActionExecuting(ActionExecutingContext context)
        {
            // do something before the action executes
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            // do something after the action executes
        }
    }
}
同步實現
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Filters;

namespace FiltersSample.Filters
{
    public class SampleAsyncActionFilter : IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(
            ActionExecutingContext context,
            ActionExecutionDelegate next)
        {
            // 在行動執行以前作一些事情
            var resultContext = await next();
            // 在執行操做後執行某些操做; resultContext.Result將被設置
        }
    }
}
異步實現

②添加爲全局篩選器

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        options.Filters.Add(new AddHeaderAttribute("GlobalAddHeader", 
            "Result filter added to MvcOptions.Filters")); // an instance
        options.Filters.Add(typeof(SampleActionFilter)); // by type
        options.Filters.Add(new SampleGlobalActionFilter()); // an instance
    });

    services.AddScoped<AddHeaderFilterWithDi>();
}
ConfigureServices

取消和設置短路

 經過設置提供給篩選器方法的 context 參數上的 Result 屬性,能夠在篩選器管道的任意位置設置短路。 例如,如下資源篩選器將阻止執行管道的其他階段

using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace FiltersSample.Filters
{
    public class ShortCircuitingResourceFilterAttribute : Attribute,
            IResourceFilter
    {
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            context.Result = new ContentResult()
            {
                Content = "Resource unavailable - header should not be set"
            };
        }

        public void OnResourceExecuted(ResourceExecutedContext context)
        {
        }
    }
}
ShortCircuitingResourceFilterAttribute

 

9,綁定與壓縮

[
  {
    "outputFileName": "wwwroot/css/site.min.css",
    "inputFiles": [
      "wwwroot/css/site.css"
    ]
  },
  {
    "outputFileName": "wwwroot/js/site.min.js",
    "inputFiles": [
      "wwwroot/js/site.js"
    ],
    "minify": {
      "enabled": true,
      "renameLocals": true
    },
    "sourceMap": false
  }
]
bundleconfig.json
outputFileName:要輸出的捆綁文件名稱。能夠包含中的相對路徑 bundleconfig.json文件(必填)
inputFiles: 要將捆綁在一塊兒的文件的數組。 這些是配置文件的相對路徑(可選)
minify:輸出類型縮減選項
sourceMap:指示是否生成捆綁的文件的源映射的標誌

①須要引用: <DotNetCliToolReference Include="BundlerMinifier.Core" Version="2.6.362" />  

②執行命令:  dotnet bundle 會合並並壓縮inputFiles裏的文件到outputFileName

 

 

5、Model

1,數據註解

①DisplayFormat

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]

Column 

 [Column("FirstName")]
 public string FirstMidName { get; set; }

實體屬性表字段映射

 

2,DatabaseGenerated標記主鍵

實體

 

 

 

6、配置

相關文章
相關標籤/搜索