初始化项目

  本来想详细讲一讲dotnet core的,但我对于dotnet core的研究还不到一星期,半吊子,脑子又笨,就不写那些理论出来误人子弟了,还是直接来一篇实践给大家做个参考。废话不多说,直接上项目,这里我设计了一个简单的控制台应用程序,抓取

  http://f.apiplus.cn

的双色球信息,并持久化到SQL Server,同时还引用了Json.NET和Dapper两个外部组件。

  使用dotnet new新建项目,并入下图所示新建Common、Persistent、Service三个文件夹:

  

  • Common文件夹中用于存放公共组件类;
  • Persistent用于存放实体和实体操作类;
  • Service用于处理实现抓取业务并将数据通过Common将数据插入到数据库总。

  接着,我们需要引入Json.NET和Dapper两个外部组件,传统的.net项目可以通过nuget来管理,.net core项目也是如此,但是他并不会像.net项目那样把package下载到项目的根目录下,而是package下载到用户根目录下集中管理(例:C:\Users\Administrator\.nuget),不得不说,这一套和maven很像,这样的好处是管理起来方便,实现了依赖包的复用,项目看起来也更为清爽,不过如果你需要引入自己开发的项目,就需要使用dotnet pack先对项目进行打包后再做本地引入,project.json的配置如下:

  1. {
  2. "version": "1.0.0-*",
  3. "buildOptions": {
  4. "debugType": "portable",
  5. "emitEntryPoint": true,
  6. "copyToOutPut": "appconfig.json"
  7. },
  8. "dependencies": {
  9. "Newtonsoft.Json": "9.0.1",
  10. "Dapper": "1.50.2",
  11. "System.Data.SqlClient": "4.1.0",
  12. "Microsoft.Extensions.Configuration": "1.0.0-rc2-final",
  13. "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0-rc2-final",
  14. "Microsoft.Extensions.Configuration.Json": "1.0.0-rc2-final",
  15. "System.Text.Encoding.CodePages": "4.0.1"
  16. },
  17. "frameworks": {
  18. "netcoreapp1.0": {
  19. "dependencies": {
  20. "Microsoft.NETCore.App": {
  21. "version": "1.0.0"
  22. }
  23. },
  24. "imports": "dnxcore50"
  25. }
  26. },
  27. "runtimes": {
  28. "win7-x64": {},
  29. "osx.10.11-x64": {}
  30. },
  31. "publishOptions": {
  32. "include": [
  33. "appconfig.json"
  34. ]
  35. }
  36. }

我们可以看到在project.json的dependencies节点中定义了项目依赖,以"Dapper": "1.50.2"为例,Dapper是我们需要引用的包的名称,1.50.2是引入的版本号,不过请务必使用 https://www.nuget.org 上的名称和版本号,并确认当前包包是否支持.net core。按照微软的官方说法是他们打算在未来启用这个project.json,不过有兴趣的同学可以访问:

  https://docs.microsoft.com/en-us/dotnet/articles/core/tools/project-json

查看有关它的详细介绍。

  

数据库设计

  创建Lotto数据库,并执行脚本如下:

  1. USE [Lotto]
  2. CREATE TABLE [dbo].[UnionLotto](
  3. ,) NOT NULL,
  4. [SN] [bigint] NOT NULL,
  5. [PublishDate] [datetime] NOT NULL,
  6. [Red1] [int] NOT NULL,
  7. [Red2] [int] NOT NULL,
  8. [Red3] [int] NOT NULL,
  9. [Red4] [int] NOT NULL,
  10. [Red5] [int] NOT NULL,
  11. [Red6] [int] NOT NULL,
  12. [Blue1] [int] NOT NULL,
  13. CONSTRAINT [PK_UnionLotto] PRIMARY KEY CLUSTERED
  14. (
  15. [Id] ASC
  16. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
  17. ) ON [PRIMARY]

编码实现

  在Common文件夹下新建QuickConfig和QuickBrowser类,QuickBrowser用于发起Http请求抓取数据,QuickConfig用于获取系统配置: 

  1. using System;
  2. using System.IO;
  3. using System.Net;
  4. using System.Threading;
  5.  
  6. namespace JokeBuy.Common
  7. {
  8. /// <summary>
  9. /// Http请求工具类。
  10. /// </summary>
  11. public class QuickBrowser
  12. {
  13. public static string BrowseByGet(string url)
  14. {
  15. );
  16. }
  17.  
  18. public static string BrowseByPost(string url)
  19. {
  20. );
  21. }
  22.  
  23. static ManualResetEvent allDone = new ManualResetEvent(false);
  24.  
  25. static string Browse(string url, string method, int timeout, string contenttype = "application/x-www-form-urlencoded")
  26. {
  27. HttpWebRequest hwr = (HttpWebRequest)WebRequest.Create(url);
  28. hwr.Method = method.ToLower();
  29. hwr.ContinueTimeout = timeout;
  30. hwr.ContentType = contenttype;
  31. BrowserContext bc = new BrowserContext();
  32. bc.BrowseRequest = hwr;
  33. var asyncR = hwr.BeginGetResponse(new AsyncCallback(ResponseCallback), bc);
  34. allDone.WaitOne();
  35. using (Stream repStream = bc.BrowseResponse.GetResponseStream())
  36. {
  37. using (StreamReader sr = new StreamReader(repStream))
  38. {
  39. return sr.ReadToEnd();
  40. }
  41. }
  42. }
  43.  
  44. static void ResponseCallback(IAsyncResult asyncR)
  45. {
  46. try
  47. {
  48. var bc = (BrowserContext)asyncR.AsyncState;
  49. bc.BrowseResponse = (HttpWebResponse)bc.BrowseRequest.EndGetResponse(asyncR);
  50. Stream repStream = bc.BrowseResponse.GetResponseStream();
  51. return;
  52. }
  53. catch (Exception ex)
  54. {
  55. Console.WriteLine(ex.Message);
  56. }
  57. finally
  58. {
  59. allDone.Set();
  60. }
  61. }
  62. }
  63.  
  64. public class BrowserContext
  65. {
  66. public HttpWebRequest BrowseRequest { get; set; }
  67.  
  68. public HttpWebResponse BrowseResponse { get; set; }
  69. }
  70. }

QuickBrowser

在QuickBrowser中,可以看到我并未使用WebRequest.GetResponse()去抓取使用,而是使用了BeginGetResponse的异步方法进行操作,因为.net core中并未发现GetResponse()方法,看来微软在重新设计.net core时,该方法被摒弃了,所以在使用.net core时还是小心为好。 

  1. using System;
  2. using Microsoft.Extensions.Configuration;
  3.  
  4. namespace JokeBuy.Common
  5. {
  6. public class QuickConfig
  7. {
  8.  
  9. static IConfiguration AppConfig;
  10. static object Lock = new object();
  11.  
  12. public static string GetConfig(string key)
  13. {
  14. key = string.Format("AppSettings:{0}", key);
  15. if (string.IsNullOrEmpty(key))
  16. throw new ArgumentNullException("配置键不能为空值!");
  17. if (AppConfig == null)
  18. {
  19. lock (Lock)
  20. {
  21. if (AppConfig == null)
  22. {
  23. AppConfig = new ConfigurationBuilder().AddJsonFile(@"appconfig.json").Build();
  24. }
  25. }
  26. }
  27. return AppConfig[key];
  28. }
  29. }
  30. }

QuickConfig

在QuickConfig中,我们可以看到配置文件的获取方式也和.net有了很大的不同,可以使用mermory、json、xml等多种方式,具体可以参考博客园大神

  http://www.cnblogs.com/artech/p/new-config-system-01.html

的文章,本例中会去加载自定义的appconfig.josn文件。

  使用VS Code新建Class真的很麻烦,namespace和class的声明均需要自己去拼写,不知道有没有人知道什么简便的方法。

  在Presistent下新建UnionLotto、UnionLottoFactory和UnionLottoDbWork类:

  1. using System;
  2.  
  3. namespace JokeBuy.Presistent
  4. {
  5. /// <summary>
  6. /// 双色球实体。
  7. /// </summary>
  8. public class UnionLotto
  9. {
  10. /// <summary>
  11. /// 标识。
  12. /// </summary>
  13. public long Id { get; set; }
  14.  
  15. /// <summary>
  16. /// 批次号。
  17. /// </summary>
  18. public long SN { get; set; }
  19.  
  20. /// <summary>
  21. /// 公布日期。
  22. /// </summary>
  23.  
  24. public DateTime PublishDate { get; set; }
  25.  
  26. /// <summary>
  27. /// 红球1。
  28. /// </summary>
  29. public int Red1 { get; set; }
  30.  
  31. /// <summary>
  32. /// 红球1。
  33. /// </summary>
  34. public int Red2 { get; set; }
  35.  
  36. /// <summary>
  37. /// 红球1。
  38. /// </summary>
  39. public int Red3 { get; set; }
  40.  
  41. /// <summary>
  42. /// 红球1。
  43. /// </summary>
  44. public int Red4 { get; set; }
  45.  
  46. /// <summary>
  47. /// 红球1。
  48. /// </summary>
  49. public int Red5 { get; set; }
  50.  
  51. /// <summary>
  52. /// 红球1。
  53. /// </summary>
  54. public int Red6 { get; set; }
  55.  
  56. /// <summary>
  57. /// 蓝球1。
  58. /// </summary>
  59. public int Blue1 { get; set; }
  60. }
  61. }

UnionLotto

  1. using System;
  2.  
  3. namespace JokeBuy.Presistent
  4. {
  5. /// <summary>
  6. /// 双色球实体操作工厂。
  7. /// </summary>
  8. public class UnionLottoFactory
  9. {
  10. /// <summary>
  11. /// 创建双色球。
  12. /// </summary>
  13. /// <returns>双色球实体。</returns>
  14. public static UnionLotto CreateUnionLotto(
  15. long sn,
  16. DateTime pd,
  17. int red1,
  18. int red2,
  19. int red3,
  20. int red4,
  21. int red5,
  22. int red6,
  23. int blue1
  24. )
  25. {
  26. || red2 < || red3 < || red4 < || red5 < || red6 < || blue1 < )
  27. throw new Exception("Create failed,wrong number!");
  28. || red2 > || red3 > || red4 > || red5 > || red6 > || blue1 > )
  29. throw new Exception("Create failed,wrong number!");
  30.  
  31. return new UnionLotto
  32. {
  33. SN = sn,
  34. PublishDate = pd,
  35. Red1 = red1,
  36. Red2 = red2,
  37. Red3 = red3,
  38. Red4 = red4,
  39. Red5 = red5,
  40. Red6 = red6,
  41. Blue1 = blue1
  42. };
  43. }
  44. }
  45. }

UnionLottoFactory

  1. using System.Collections.Generic;
  2. using System.Data.Common;
  3. using System.Data.SqlClient;
  4. using System.Linq;
  5. using Dapper;
  6. using JokeBuy.Common;
  7.  
  8. namespace JokeBuy.Presistent
  9. {
  10. /// <summary>
  11. ///
  12. /// </summary>
  13. public class UnionLottoDbWork
  14. {
  15. public static void AddUnionLotto(UnionLotto entity)
  16. {
  17. using (DbConnection conn = (DbConnection)new SqlConnection(QuickConfig.GetConfig("DbConnStr")))
  18. {
  19. conn.Open();
  20. string insertSql = "INSERT INTO UnionLotto(SN,PublishDate,Red1,Red2,Red3,Red4,Red5,Red6,Blue1)VALUES(@SN,@PublishDate,@Red1,@Red2,@Red3,@Red4,@Red5,@Red6,@Blue1)";
  21. conn.Execute(insertSql, entity);
  22. conn.Close();
  23. }
  24. }
  25.  
  26. public static UnionLotto GetUnionLottoBySN(long sn)
  27. {
  28.  
  29. using (DbConnection conn = (DbConnection)new SqlConnection(QuickConfig.GetConfig("DbConnStr")))
  30. {
  31. conn.Open();
  32. string querySql = "select * from UnionLotto where SN=@sn";
  33. var info = conn.Query<UnionLotto>(querySql, new { sn = sn }).SingleOrDefault();
  34. conn.Close();
  35. return info;
  36. }
  37. }
  38.  
  39. public static void BatchAddUnionLotto(List<UnionLotto> entities)
  40. {
  41. foreach (var entity in entities)
  42. {
  43. if (GetUnionLottoBySN(entity.SN) == null)
  44. {
  45. AddUnionLotto(entity);
  46. }
  47. }
  48. }
  49. }
  50. }

UnionLottoDbWork

在Servie下新建DataSpiderService和UnionLottoService类:

  1. using System;
  2. using System.Collections.Generic;
  3. using JokeBuy.Common;
  4. using JokeBuy.Presistent;
  5. using Newtonsoft.Json;
  6.  
  7. namespace JokeBuy.Service
  8. {
  9.  
  10. internal class DataSpiderService
  11. {
  12.  
  13. /// <summary>
  14. /// 从百度抓取数据。
  15. /// </summary>
  16. /// <returns>数据集合。</returns>
  17. public static List<UnionLotto> BaiduSpider()
  18. {
  19. List<UnionLotto> lottos = new List<UnionLotto>();
  20.  
  21. return lottos;
  22. }
  23.  
  24. /// <summary>
  25. /// 从Api抓取数据。
  26. /// </summary>
  27. /// <returns>数据集合。</returns>
  28. public static List<UnionLotto> ApiPlusSpider()
  29. {
  30. List<UnionLotto> lottos = new List<UnionLotto>();
  31. try
  32. {
  33. var json = QuickBrowser.BrowseByGet(QuickConfig.GetConfig("PlusApi"));
  34. var jsonObj = JsonConvert.DeserializeObject<dynamic>(json);
  35. )
  36. {
  37. List<PlusSSQ> ssqs = JsonConvert.DeserializeObject<List<PlusSSQ>>(jsonObj.data.ToString());
  38. ; i < ssqs.Count; i++)
  39. {
  40. var nums = ssqs[i].opencode.Split(new char[] { ',', '+' }, StringSplitOptions.RemoveEmptyEntries);
  41. lottos.Add(UnionLottoFactory.CreateUnionLotto(
  42. ssqs[i].expect,
  43. ssqs[i].opentime,
  44. ]), ]), ]), ]), ]), ]), ])));
  45.  
  46. }
  47. }
  48. }
  49. catch (Exception ex)
  50. {
  51. Console.WriteLine(ex.Message);
  52. }
  53. return lottos;
  54. }
  55. }
  56.  
  57. internal class PlusSSQ
  58. {
  59. public long expect;
  60. public string opencode;
  61. public DateTime opentime;
  62. }
  63. }

DataSpiderService

  1. using JokeBuy.Presistent;
  2.  
  3. namespace JokeBuy.Service
  4. {
  5. public class UnionLottoService
  6. {
  7. public static void DataInitial()
  8. {
  9.  
  10. }
  11.  
  12. /// <summary>
  13. /// 从API中同步数据。
  14. /// </summary>
  15. public static void DataSync()
  16. {
  17. var lottos = DataSpiderService.ApiPlusSpider();
  18. UnionLottoDbWork.BatchAddUnionLotto(lottos);
  19. }
  20. }
  21. }

UnionLottoService

在根目录下添加appconfig.json文件:

  1. {
  2. "AppSettings": {
  3. "DbConnStr": "Data Source=.\\SQL2012;Initial Catalog=Lotto;Persist Security Info=True;User ID=sa;Password=1234567;",
  4. "PlusApi": "http://f.apiplus.cn/ssq-1.json"
  5. }
  6. }

appconfig.json

appconfig.json中定义了项目数据库链接和api抓取地址,回顾一下project.json中的配置,我们可以发现publishOptions.include配置,因为发布时appconfig.json并不会被拷贝到发布包中,需要手动将其引入进来。

执行

  最后在Program中调用:

  1. using System;
  2. using System.Text;
  3. using JokeBuy.Service;
  4.  
  5. namespace ConsoleApplication
  6. {
  7. public class Program
  8. {
  9. public static void Main(string[] args)
  10. {
  11. Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); //主要用于解决控制台中文输出乱码问题
  12. UnionLottoService.DataSync();
  13. Console.WriteLine("执行完毕!");
  14. Console.ReadLine();
  15. }
  16. }
  17. }

Program

使用dotnet publish后,在..\bin\Debug\netcoreapp1.0\win7-x64\publish下找到JokeBuy.exe执行后,数据成功插入到数据库:

  

执行成功!

.NET Core开发:项目实践的更多相关文章

  1. 使用Asp.Net Core MVC 开发项目实践[第一篇:项目结构说明]

    先从下图看整体项目结构: Mango.Manager: 为后台管理项目 Mango.Web: 为前台项目 Mango.Framework.Core: 为常用的基础操作类项目 Mango.Framewo ...

  2. 使用Asp.Net Core MVC 开发项目实践[第五篇:缓存的使用]

    项目中我们常常会碰到一些数据,需要高频率用到但是又不会频繁变动的这类,我们就可以使用缓存把这些数据缓存起来(比如说本项目的导航数据,帖子频道数据). 我们项目中常用到有Asp.Net Core 本身提 ...

  3. 使用Asp.Net Core MVC 开发项目实践[第二篇:EF Core]

    在项目中使用EF Core还是比较容易的,在这里我们使用的版本是EF Core 2.2. 1.使用nuget获取EF Core包 这个示例项目使用的是SQLSERVER,所以还需要下载Microsof ...

  4. 使用Asp.Net Core MVC 开发项目实践[第三篇:基于EF Core的扩展]

    上篇我们说到了EFCore的基础使用,这篇我们将讲解下基于EFCore的扩展. 我们在Mango.Framework.EFCore类库项目中创建一个类名EFExtended的扩展类,并且引入相关的命名 ...

  5. 使用Asp.Net Core MVC 开发项目实践[第四篇:基于EF Core的扩展2]

    上篇我们说到了基于EFCore的基础扩展,这篇我们讲解下基于实体结合拉姆达表达式的自定义更新以及删除数据. 先说下原理:其实通过实体以及拉姆达表达式生成SQL语句去执行 第一种更新扩展: 自定义更新字 ...

  6. 基于 Vue.js 之 iView UI 框架非工程化实践记要 使用 Newtonsoft.Json 操作 JSON 字符串 基于.net core实现项目自动编译、并生成nuget包 webpack + vue 在dev和production模式下的小小区别 这样入门asp.net core 之 静态文件 这样入门asp.net core,如何

    基于 Vue.js 之 iView UI 框架非工程化实践记要   像我们平日里做惯了 Java 或者 .NET 这种后端程序员,对于前端的认识还常常停留在 jQuery 时代,包括其插件在需要时就引 ...

  7. Entity Framework Core Code First 项目实践

    Entity Framework Core Code First 实践 任何一种技术的出现都是为了解决一系列特定的问题,只有了解了技术所要解决的关键问题,才能理解它的真正用途,之后,才能在实践中用好它 ...

  8. 《ASP.NET Core应用开发入门教程》与《ASP.NET Core 应用开发项目实战》正式出版

    “全书之写印,实系初稿.有时公私琐务猬集,每写一句,三搁其笔:有时兴会淋漓,走笔疾书,絮絮不休:有时意趣萧索,执笔木坐,草草而止.每写一段,自助覆阅,辄摇其首,觉有大不妥者,即贴补重书,故剪刀浆糊乃不 ...

  9. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(四)

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

  10. 使用VS Code开发调试.NET Core 多项目

    使用Visual Studio Code(VS Code)开发调试.NET Core和ASP.NET Core 多项目multiple project. 之前讲解过如果使用Visual Studio ...

随机推荐

  1. classname在JavaScript中的应用

    <html> <head> <meta charset="utf-8"> <title>无标题文档</title> &l ...

  2. Py基础+中级

    原文 Py学习博客 1:https://www.cnblogs.com/fu-yong/p/8060198.html2:while True:just do it 三.Python的默认编码 ▷pyt ...

  3. 【Oracle】审计

    1.审计的功能:监控用户在database 的 action (操作) 2.审计分类: 1) session :在同一个session,相同的语句只产生一个审计结果(默认) 2) access : 在 ...

  4. 【技术累积】【点】【java】【8】maven常用命令(持续更新)

    建立 mvn archetype:generate -DgroupId=com.andy.test -DartifactId=test-project -Dversion=0.0.1-SNAPSHOT ...

  5. Kafka学习笔记(7)----Kafka使用Cosumer接收消息

    1. 什么是KafkaConsumer? 应用程序使用KafkaConsul'le 「向Kafka 订阅主题,并从订阅的主题上接收消息.Kafka的消息读取不同于从其他消息系统读取数据,它涉及了一些独 ...

  6. -webkit-appearance: none; 去除浏览器默认样式

    -webkit-appearance: none;    去除浏览器默认样式

  7. codeforces 468B two set(并查集)

    链接 B. Two Sets 题意 给两个集合A B,两个数a b,n个数x,分配n个数到两个集合,要求x , a-x在同一个集合,x , b-x在同一个集合,属于A集合的数输出0,B的输出1,无解输 ...

  8. python编写简单的html登陆页面(1)

    1  html 打开调式效果如下 2  用python后台编写 # coding:utf-8# 从同一个位置导入多个工具,# 这些工具之间可以用逗号隔开,同时导入# render_template渲染 ...

  9. 写shell工具类,一个常用实例

    简述: 当我们常用到某些指令时,我们就需要将这个命令进行封装.封装的设计和扩展,因人而异.但为了每个人都能够了解到这个命令,常需要写出这个类的help. 关键字: 函数.getopts 函数 通过自定 ...

  10. 路飞学城Python-Day181

    Evernote Export Nginx默认网站 当Nginx配置文件中有且仅有一个Server的时候,该Server就被Nginx认为是默认网站,所有发给Nginx服务器80端口的数据都会默认给s ...