利用ASP.NET快速开发一款Web应用

2 篇文章 0 订阅
1 篇文章 0 订阅

需要用到的技术

.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<FundContext> options)
            : base(options)
        {
        }

        public DbSet<WebTest.Models.Fund> Fund { get; set; }
    }

3,安装并使用迁移工具EF first Core

Install-Package Microsoft.EntityFrameworkCore.SqlServer

4.使用脚手架自动生成增删改页面

选择自动生成的方式,这里使用MVC

Add Scaffold dialog

 选择需要生成的模型类,数据库上下文类(如果之前步骤没有创建该类,这里也可以自动生成,只要点击加号,指定类名称即可)

最下面是需要生成的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<string>("Code")
                        .ValueGeneratedOnAdd()
                        .HasMaxLength(6);

                    b.Property<string>("Name")
                        .IsRequired();

                    b.Property<string>("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<string>(maxLength: 6, nullable: false),
                    Name = table.Column<string>(nullable: false),
                    Type = table.Column<string>(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<string>(
                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<ILogger<Program>>();
          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<FundContext>>()))
      {
        // 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 = (?<Data>\\[\\[\"(?<Code>[0-9]{6})\",\".*?\",\"(?<Name>.*?)\",\"(?<Type>.*?)\".*?\\],{0,1})*\\]");
          Regex regex = new Regex("var r = (?<Data>\\[(\\[\"(?<Code>[0-9]{6})\"\\,\".*?\"\\,\"(?<Name>.*?)\"\\,\"(?<Type>.*?)\".*?\\][\\,]{0,1})+\\])");

          Match match = regex.Match(resultstr);
          int matchSize = match.Groups["Code"].Captures.Count;

          System.Collections.Generic.IEnumerable<Fund> 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替换文本

<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Funds[0].Code)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Funds[0].Name)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Funds[0].Type)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.Funds) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Code)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Name)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Type)
            </td>
            @if (item.Type == "货币型")
            {
                <td>
                    <a asp-action="Edit" asp-route-id="@item.Code">Edit</a> |
                    <a asp-action="Delete" asp-route-id="@item.Code"> Delete </a>
                </td>
            }
            else
            {
                <td>
                    <a asp-action="Edit" asp-route-id="@item.Code">Edit</a> |
                    <a asp-action="Details" asp-route-id="@item.Code">Details </a> |
                    <a asp-action="Delete" asp-route-id="@item.Code"> Delete </a>
                </td>
            }
        </tr>
        }
    </tbody>
</table>

Detail页面内容修改,嵌入基金明细页面

HTML CS混合编程,嵌入一个iframe标签,地址参数使用控制器类的变量ViewData["DetailURL"] 

<div scrolling=auto margin=auto
    border="springgreen 10px solid">
    <iframe width=1066 height=888 frameborder=0 scrolling=auto src="@ViewData["DetailURL"]"></iframe>
</div>

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更新数据库机制,可以参考

EF应用一:Code First模式 - .NET开发菜鸟 - 博客园

  • Mysql也有相应的脚手架工具,亲测有效,用法与Sql Server相同,貌似在表字符集的映射上还存在点问题,插入中文时报错,也许是我装的版本太低,这个工具是开源的,以后有时间可以去找找原因。

Install-Package Pomelo.EntityFrameworkCore.MySql -Version 2.1.1

  • SQLite数据库也是支持的,安装语句:

Install-Package System.Data.SQLite

  • PostgreSQL数据库的EF脚手架工具安装语句
install-package npgsql -version 3.1.1
Install-Package EntityFramework6.Npgsql -Version 3.1.1
  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值