初始化项目

  本来想详细讲一讲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的配置如下:

{
    "version": "1.0.0-*",
    "buildOptions": {
        "debugType": "portable",
        "emitEntryPoint": true,
        "copyToOutPut": "appconfig.json"
    },
    "dependencies": {
        "Newtonsoft.Json": "9.0.1",
        "Dapper": "1.50.2",
        "System.Data.SqlClient": "4.1.0",
        "Microsoft.Extensions.Configuration": "1.0.0-rc2-final",
        "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0-rc2-final",
        "Microsoft.Extensions.Configuration.Json": "1.0.0-rc2-final",
        "System.Text.Encoding.CodePages": "4.0.1"
    },
    "frameworks": {
        "netcoreapp1.0": {
            "dependencies": {
                "Microsoft.NETCore.App": {
                    "version": "1.0.0"
                }
            },
            "imports": "dnxcore50"
        }
    },
    "runtimes": {
        "win7-x64": {},
        "osx.10.11-x64": {}
    },
    "publishOptions": {
        "include": [
            "appconfig.json"
        ]
    }
}

我们可以看到在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数据库,并执行脚本如下:

    USE [Lotto]
    CREATE TABLE [dbo].[UnionLotto](
    ,) NOT NULL,
    [SN] [bigint] NOT NULL,
    [PublishDate] [datetime] NOT NULL,
    [Red1] [int] NOT NULL,
    [Red2] [int] NOT NULL,
    [Red3] [int] NOT NULL,
    [Red4] [int] NOT NULL,
    [Red5] [int] NOT NULL,
    [Red6] [int] NOT NULL,
    [Blue1] [int] NOT NULL,
 CONSTRAINT [PK_UnionLotto] PRIMARY KEY CLUSTERED
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

编码实现

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

using System;
using System.IO;
using System.Net;
using System.Threading;

namespace JokeBuy.Common
{
    /// <summary>
    /// Http请求工具类。
    /// </summary>
    public class QuickBrowser
    {
        public static string BrowseByGet(string url)
        {
            );
        }

        public static string BrowseByPost(string url)
        {
            );
        }

        static ManualResetEvent allDone = new ManualResetEvent(false);

        static string Browse(string url, string method, int timeout, string contenttype = "application/x-www-form-urlencoded")
        {
            HttpWebRequest hwr = (HttpWebRequest)WebRequest.Create(url);
            hwr.Method = method.ToLower();
            hwr.ContinueTimeout = timeout;
            hwr.ContentType = contenttype;
            BrowserContext bc = new BrowserContext();
            bc.BrowseRequest = hwr;
            var asyncR = hwr.BeginGetResponse(new AsyncCallback(ResponseCallback), bc);
            allDone.WaitOne();
            using (Stream repStream = bc.BrowseResponse.GetResponseStream())
            {
                using (StreamReader sr = new StreamReader(repStream))
                {
                    return sr.ReadToEnd();
                }
            }
        }

        static void ResponseCallback(IAsyncResult asyncR)
        {
            try
            {
                var bc = (BrowserContext)asyncR.AsyncState;
                bc.BrowseResponse = (HttpWebResponse)bc.BrowseRequest.EndGetResponse(asyncR);
                Stream repStream = bc.BrowseResponse.GetResponseStream();
                return;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                allDone.Set();
            }
        }
    }

    public class BrowserContext
    {
        public HttpWebRequest BrowseRequest { get; set; }

        public HttpWebResponse BrowseResponse { get; set; }
    }
}

QuickBrowser

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

using System;
using Microsoft.Extensions.Configuration;

namespace JokeBuy.Common
{
    public class QuickConfig
    {

        static IConfiguration AppConfig;
        static object Lock = new object();

        public static string GetConfig(string key)
        {
            key = string.Format("AppSettings:{0}", key);
            if (string.IsNullOrEmpty(key))
                throw new ArgumentNullException("配置键不能为空值!");
            if (AppConfig == null)
            {
                lock (Lock)
                {
                    if (AppConfig == null)
                    {
                        AppConfig = new ConfigurationBuilder().AddJsonFile(@"appconfig.json").Build();
                    }
                }
            }
            return AppConfig[key];
        }
    }
}

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类:

using System;

namespace JokeBuy.Presistent
{
    /// <summary>
    /// 双色球实体。
    /// </summary>
    public class UnionLotto
    {
        /// <summary>
        /// 标识。
        /// </summary>
        public long Id { get; set; }

        /// <summary>
        /// 批次号。
        /// </summary>
        public long SN { get; set; }

        /// <summary>
        /// 公布日期。
        /// </summary>

        public DateTime PublishDate { get; set; }

        /// <summary>
        /// 红球1。
        /// </summary>
        public int Red1 { get; set; }

        /// <summary>
        /// 红球1。
        /// </summary>
        public int Red2 { get; set; }

        /// <summary>
        /// 红球1。
        /// </summary>
        public int Red3 { get; set; }

        /// <summary>
        /// 红球1。
        /// </summary>
        public int Red4 { get; set; }

        /// <summary>
        /// 红球1。
        /// </summary>
        public int Red5 { get; set; }

        /// <summary>
        /// 红球1。
        /// </summary>
        public int Red6 { get; set; }

        /// <summary>
        /// 蓝球1。
        /// </summary>
        public int Blue1 { get; set; }
    }
}

UnionLotto

using System;

namespace JokeBuy.Presistent
{
    /// <summary>
    /// 双色球实体操作工厂。
    /// </summary>
    public class UnionLottoFactory
    {
        /// <summary>
        /// 创建双色球。
        /// </summary>
        /// <returns>双色球实体。</returns>
        public static UnionLotto CreateUnionLotto(
            long sn,
            DateTime pd,
            int red1,
            int red2,
            int red3,
            int red4,
            int red5,
            int red6,
            int blue1
        )
        {
             || red2 <  || red3 <  || red4 <  || red5 <  || red6 <  || blue1 < )
                throw new Exception("Create failed,wrong number!");
             || red2 >  || red3 >  || red4 >  || red5 >  || red6 >  || blue1 > )
                throw new Exception("Create failed,wrong number!");

            return new UnionLotto
            {
                SN = sn,
                PublishDate = pd,
                Red1 = red1,
                Red2 = red2,
                Red3 = red3,
                Red4 = red4,
                Red5 = red5,
                Red6 = red6,
                Blue1 = blue1
            };
        }
    }
}

UnionLottoFactory

using System.Collections.Generic;
using System.Data.Common;
using System.Data.SqlClient;
using System.Linq;
using Dapper;
using JokeBuy.Common;

namespace JokeBuy.Presistent
{
    /// <summary>
    ///
    /// </summary>
    public class UnionLottoDbWork
    {
        public static void AddUnionLotto(UnionLotto entity)
        {
            using (DbConnection conn = (DbConnection)new SqlConnection(QuickConfig.GetConfig("DbConnStr")))
            {
                conn.Open();
                string insertSql = "INSERT INTO UnionLotto(SN,PublishDate,Red1,Red2,Red3,Red4,Red5,Red6,Blue1)VALUES(@SN,@PublishDate,@Red1,@Red2,@Red3,@Red4,@Red5,@Red6,@Blue1)";
                conn.Execute(insertSql, entity);
                conn.Close();
            }
        }

        public static UnionLotto GetUnionLottoBySN(long sn)
        {

            using (DbConnection conn = (DbConnection)new SqlConnection(QuickConfig.GetConfig("DbConnStr")))
            {
                conn.Open();
                string querySql = "select * from UnionLotto where SN=@sn";
                var info = conn.Query<UnionLotto>(querySql, new { sn = sn }).SingleOrDefault();
                conn.Close();
                return info;
            }
        }

        public static void BatchAddUnionLotto(List<UnionLotto> entities)
        {
            foreach (var entity in entities)
            {
                if (GetUnionLottoBySN(entity.SN) == null)
                {
                    AddUnionLotto(entity);
                }
            }
        }
    }
}

UnionLottoDbWork

在Servie下新建DataSpiderService和UnionLottoService类:

using System;
using System.Collections.Generic;
using JokeBuy.Common;
using JokeBuy.Presistent;
using Newtonsoft.Json;

namespace JokeBuy.Service
{

    internal class DataSpiderService
    {

        /// <summary>
        /// 从百度抓取数据。
        /// </summary>
        /// <returns>数据集合。</returns>
        public static List<UnionLotto> BaiduSpider()
        {
            List<UnionLotto> lottos = new List<UnionLotto>();

            return lottos;
        }

        /// <summary>
        /// 从Api抓取数据。
        /// </summary>
        /// <returns>数据集合。</returns>
        public static List<UnionLotto> ApiPlusSpider()
        {
            List<UnionLotto> lottos = new List<UnionLotto>();
            try
            {
                var json = QuickBrowser.BrowseByGet(QuickConfig.GetConfig("PlusApi"));
                var jsonObj = JsonConvert.DeserializeObject<dynamic>(json);
                )
                {
                    List<PlusSSQ> ssqs = JsonConvert.DeserializeObject<List<PlusSSQ>>(jsonObj.data.ToString());
                    ; i < ssqs.Count; i++)
                    {
                        var nums = ssqs[i].opencode.Split(new char[] { ',', '+' }, StringSplitOptions.RemoveEmptyEntries);
                        lottos.Add(UnionLottoFactory.CreateUnionLotto(
                                                     ssqs[i].expect,
                                                     ssqs[i].opentime,
                                                     ]), ]), ]), ]), ]), ]), ])));

                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            return lottos;
        }
    }

    internal class PlusSSQ
    {
        public long expect;
        public string opencode;
        public DateTime opentime;
    }
}

DataSpiderService

using JokeBuy.Presistent;

namespace JokeBuy.Service
{
    public class UnionLottoService
    {
        public static void DataInitial()
        {

        }

        /// <summary>
        /// 从API中同步数据。
        /// </summary>
        public static void DataSync()
        {
            var lottos = DataSpiderService.ApiPlusSpider();
            UnionLottoDbWork.BatchAddUnionLotto(lottos);
        }
    }
}

UnionLottoService

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

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

appconfig.json

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

执行

  最后在Program中调用:

using System;
using System.Text;
using JokeBuy.Service;

namespace ConsoleApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);             //主要用于解决控制台中文输出乱码问题
            UnionLottoService.DataSync();
            Console.WriteLine("执行完毕!");
            Console.ReadLine();
        }
    }
}

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. hibernate dao 公共方法

    package com.dao.impl; import java.lang.reflect.ParameterizedType; import java.util.Collection; impor ...

  2. Spark Streaming 整合 Kafka

    一:通过设置检查点,实现单词计数的累加功能 object StatefulKafkaWCnt { /** * 第一个参数:聚合的key,就是单词 * 第二个参数:当前批次产生批次该单词在每一个分区出现 ...

  3. 【Oracle】RAC控制文件多路复用

    1.—关闭数据库,各个节点都要关闭: [oracle@rac1 ~]$ srvctl stop database -d racdb -o immediate 2.—启动任一节点到nomount状态: ...

  4. [Intermediate Algorithm] - Sum All Primes

    题目 求小于等于给定数值的质数之和. 只有 1 和它本身两个约数的数叫质数.例如,2 是质数,因为它只能被 1 和 2 整除.1 不是质数,因为它只能被自身整除. 给定的数不一定是质数. 提示 For ...

  5. 查看Linux系统版本信息的几种方法

    一.查看Linux内核版本命令(两种方法): 1.cat /proc/version 2.uname -a 二.查看Linux系统版本的命令(3种方法): 1.lsb_release -a,即可列出所 ...

  6. [luogu4037 JSOI2008] 魔兽地图 (树形dp)

    传送门 Description DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA (Defense of the ...

  7. weex手机端安全键盘

    github地址:weexSafeKeyboard 效果图: 技术依赖:框架:weex+vue 弹出层:weex-ui 图标:iconfont 说明:1.如果不想用到weex-ui,可以把inputk ...

  8. Python - def 函数

    1.def 函数 如果我们用代码实现了一个小功能,但想要在程序代码中重复使用,不能在代码中到处粘贴这些代码,因为这样做违反了软件工程中 DRY原则. Python 提供了 函数功能,可以将我们这部分功 ...

  9. Django入门--模型系统(一):模型基础

    1.Django的ORM介绍 对象关系映射(英语:(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不 ...

  10. 【ACM-ICPC 2018 沈阳赛区网络预赛 I】Lattice's basics in digital electronics

    [链接] 我是链接,点我呀:) [题意] [题解] 每个单词的前缀都不同. 不能更明示了... 裸的字典树. 模拟一下.输出一下就ojbk了. [代码] #include <bits/stdc+ ...