.NET CORE 2.1:一个跨平台的高性能开源框架,用于生成启用云且连接 Internet 的新式应用
ASP.NET MVC:一种使用“模型-视图-控制器”设计模式构建 Web 应用和 API 的框架
ASP Razor Page:一种混合HTML和.NET语言而开发的服务端页面
SQL Server:一种关系型数据库
EF Code First:代码优先实体框架,一种迁移脚手架工具,以代码模型类为驱动的数据库表结构自动构建与更新同步工具。
BootStrap/EChart/jQuery: JS框架,内置丰富的web功能组件,拿来即用
通过HTTP请求调取基金接口数据,经过处理结构化后保存至数据库,开发数据增删改的WEB页面,利用URL传参嵌入其他web页面查看基金走势。
基金查询页面
根据页面设置的筛选条件,读取并展示数据库保存的数据内容
使用分页查询,一次最多展示12条数据
如果基金类型为货币基金 ,由内嵌页面不支持货币基金查询,故将Details链接移除
编辑页面
利用脚手架工具自动生成的后台代码和页面
使用基金代码作为主键,更新数据库信息
明细查询
主要步骤及解释
1.新建一个基于ASP.NET CORE的Web应用项目
选择一个模板,不同的模板会集成各自的JS技术框架,便于后面使用对应的框架语法和项目结构进行web开发
2.创建基金数据的模型类,并设置注解,方便EF工具自动创建表,其中,类名就是表名,类属性就是字段名,注解与字段属性一一对应
public class Fund
{
[Display(Name = "基金代码")]
[RegularExpression(@"^[0-9]+$")]
[StringLength(6)]
[Required]
[Key]
public string Code { get; set; }
[Display(Name = "基金名称")]
[Required]
public string Name { get; set; }
[Display(Name = "基金种类")]
[Required]
public string Type { get; set; }
}
3.创建数据库上下文类,EF工具会根据该类的类名自动创建数据库和生成相关的文件,后面与数据库的交互(访问数据,更新数据,删除数据)也会使用该类,而不是直接编写SQL语言。总之,使用该类之后,系统已经帮你完成了绝大部分工作,而不用担心数据更新异常,数据校验,并发的问题。
public class FundContext : DbContext
{
public FundContext (DbContextOptions options)
: base(options)
{
}
public DbSet Fund { get; set; }
}
3,安装并使用迁移工具EF first Core
Install-Package Microsoft.EntityFrameworkCore.SqlServer
4.使用脚手架自动生成增删改页面
选择自动生成的方式,这里使用MVC
选择需要生成的模型类,数据库上下文类(如果之前步骤没有创建该类,这里也可以自动生成,只要点击加号,指定类名称即可)
最下面是需要生成的MVC的控制器类,视图类,也可以指定页面的公共布局页面等
自动生成目录文件和代码依赖注入
5.使用EF迁移工具
在NuGet Package Manager中打开包管理工具控制台(Package Manager Console (PMC))
键入如下命令
Add-Migration InitialCreate
Update-Database
第一个命令,系统会自动根据数据库上下文类,生成数据库构建类,上载类和撤销上载类等文件,
第二个命令,是确认执行命令
[DbContext(typeof(FundContext))]
partial class FundContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.1.14-servicing-32113")
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("WebTest.Models.Fund", b =>
{
b.Property("Code")
.ValueGeneratedOnAdd()
.HasMaxLength(6);
b.Property("Name")
.IsRequired();
b.Property("Type")
.IsRequired();
b.HasKey("Code");
b.ToTable("Fund");
});
#pragma warning restore 612, 618
}
}
该类保存创建数据库以及数据库和表之间关系的必要信息
public partial class InitialCreateFund : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Fund",
columns: table => new
{
Code = table.Column(maxLength: 6, nullable: false),
Name = table.Column(nullable: false),
Type = table.Column(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Fund", x => x.Code);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Fund");
}
}
该类保存了建表语句与撤销建表语句的必要信息
如果后面涉及了表更新,需要重复上述命令,EF工具会自动新增迁移类,以下是增加模型类属性后EF迁移类自动生成的内容
public partial class Rating : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn(
name: "Rating",
table: "Movie",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Rating",
table: "Movie");
}
}
EF工具会比较数据库表和模型类之间的差异,如果发现不同,它就会新增迁移类文件,Up方法记录了改表语句,Down方法记录了撤销改表的动作,生成的类允许再次修改,当使用包命令时,实际就是调用了生成的方法间接操作数据库
更新完成之后,数据库自动增加了一个Schema和两张表
向表里增加数据或查询内容
以上步骤完成之后即可在IIS Express中访问增删改查页面
使用基金接口想数据库中写入数据
在Main方法前初始化数据,调用SeedData.Initialize方法
public static void Main(string[] args)
{
IWebHost webHost = CreateWebHostBuilder(args).Build();
using (var scope = webHost.Services.CreateScope())
{
IServiceProvider services = scope.ServiceProvider;
try
{
SeedData.Initialize(services);
}
catch (Exception ex)
{
var logger = services.GetRequiredService>();
logger.LogError(ex, "An error occurred seeding the DB.");
}
}
webHost.Run();
}
在初始化方法中通过服务器端发送HTTP GET请求获取基金数据
解析JS文本内容,编写LINQ语句,延时执行,防止卡顿
public class SeedData
{
public static void Initialize(IServiceProvider serviceProvider)
{
using(var context = new FundContext(
serviceProvider.GetRequiredService<
DbContextOptions>()))
{
// Look for any movies.
if (!context.Fund.Any())
{
string resultstr = Utils.HttpCommon.HttpGet(@"http://fund.eastmoney.com/js/fundcode_search.js?v=" + DateTime.Now.ToString("yyyyMMddHHmmss"));
//Regex regex = new Regex("var r = (?\\[\\[\"(?[0-9]{6})\",\".*?\",\"(?.*?)\",\"(?.*?)\".*?\\],{0,1})*\\]");
Regex regex = new Regex("var r = (?\\[(\\[\"(?[0-9]{6})\"\\,\".*?\"\\,\"(?.*?)\"\\,\"(?.*?)\".*?\\][\\,]{0,1})+\\])");
Match match = regex.Match(resultstr);
int matchSize = match.Groups["Code"].Captures.Count;
System.Collections.Generic.IEnumerable s = match.Groups["Code"].Captures.Select((v, i) => new { value = v.Value, index = i }).Join(match.Groups["Name"].Captures.Select((v, i) => new { value = v.Value, index = i }), a => a.index, b => b.index, (a, b) => new { Code = a.value, Name = b.value, a.index }).Join(match.Groups["Type"].Captures.Select((v, i) => new { value = v.Value, index = i }), a => a.index, b => b.index, (a, b) => new Fund { Code = a.Code, Name = a.Name, Type = b.value });
//var SS = (from code in match.Groups["Code"].Captures select new { VALUE = code.Value, CODE = code.Index }).ToList();
context.Fund.AddRange(s);
context.SaveChanges();
}
}
}
}
调用SaveChanges方法后,自动完成数据库更新
货币基金移除Details链接
使用Razor Page语法,其中@后面接的是.NET语言,如果使用C#开发,则接C#语言,如果是Visual Basic语言开发,则可以接Visual Basic。该语句仅在服务器端运行,系统会根据编写的语法糖输出符合HTML语法的替换内容,并发送到broswer端渲染并展示
注意到@后的循环语句和条件判断语句,用于生成相应的HTML替换文本
@Html.DisplayNameFor(model => model.Funds[0].Code)
@Html.DisplayNameFor(model => model.Funds[0].Name)
@Html.DisplayNameFor(model => model.Funds[0].Type)
@foreach (var item in Model.Funds) {
@Html.DisplayFor(modelItem => item.Code)
@Html.DisplayFor(modelItem => item.Name)
@Html.DisplayFor(modelItem => item.Type)
@if (item.Type == "货币型")
{
Edit |
Delete
}
else
{
Edit |
Details |
Delete
}
}
Detail页面内容修改,嵌入基金明细页面
HTML CS混合编程,嵌入一个iframe标签,地址参数使用控制器类的变量ViewData["DetailURL"]
ViewData是一个键值对表,可以在MVC任何地方使用
在View中,对DetailURL赋值,调用了以前开发好的Echart页面,并传递URL参数基金代码
@{
ViewData["Title"] = "Details";
ViewData["DetailURL"] = "http://localhost/Works/Echart/%E5%9F%BA%E9%87%91%E6%95%B0%E6%8D%AE.html?fundcode=" + Model.Code;
}
自开发明细WEB页面的处理内容
获取URL参数
// 获取url中的参数
function getUrlParam(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if (r != null) {
return unescape(r[2]);
} else {
return null;
}
}
发送AJAX请求访问基金走势的散点数据
所谓AJAX 就是异步js xml技术,相当于对HTTP请求的封装类,使用它方便从浏览器端发送HTTP请求,并异步处理返回的结果
getScript 方法不仅获取服务器的JS文件资源,而且对对其进行了执行
function viewfunddata(fundcode) {
var sourcedata = [];
var time = dateFormat("YYYYmmddHHMMSS", new Date());
$.getScript('https://fund.eastmoney.com/pingzhongdata/' + fundcode + '.js?v=' + time, function () {
for (var i = 0; i < Data_netWorthTrend.length; i++) { sourcedata[i] = [Data_netWorthTrend[i].x, Data_netWorthTrend[i].y]; }
refreshEchardata(fS_name, fS_code, syl_1n, syl_6y, syl_3y, syl_1y, sourcedata);
});
}
执行完后,将JS中的变量值通过refreshEchardata方法传递给Echart组件
注意option中的sourcedata关键数据
option = {
title: {
text: fundname + '(' + fundcode + ')'
},
visualMap: [{
show: true,
type: 'continuous',
min: 0,
max: 5
}],
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
xAxis: {
min: 1469225600000,
type: 'time'
},
yAxis: {
type: 'value'
},
dataZoom: [{
show: true,
type: 'inside',
filterMode: 'none',
xAxisIndex: [0],
}, {
show: true,
type: 'inside',
filterMode: 'none',
}],
series: [{
symbolSize: 2,
data: sourcedata,
type: 'line',
showSymbol: false,
smooth: true,
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgb(255, 255, 255,10)'
}, {
offset: 1,
color: 'rgb(255, 200, 231,0)'
}])
},
label: {
show: true,
position: 'top'
},
lineStyle: {
width: 1,
shadowColor: 'rgba(0,0,0,0.3)',
shadowBlur: 10,
shadowOffsetY: 8
},
}]
};
if (option && typeof option === 'object') {
myChart.setOption(option);
}
EF应用一:Code First模式 - .NET开发菜鸟 - 博客园
Install-Package Pomelo.EntityFrameworkCore.MySql -Version 2.1.1
Install-Package System.Data.SQLite
install-package npgsql -version 3.1.1 Install-Package EntityFramework6.Npgsql -Version 3.1.1