欢迎来到【一个大西瓜】的博客

不曾为梦想奋斗,拿什么去燃烧青春。有梦之人亦终将老去,但少年心气如昨。
太阳每一个时刻都同时是夕阳和朝阳,每天她沉入西边,意味着她同时从另一面土地升起。
扩大
缩小

ASP.NET Core 2.1的配置、AOP、缓存、部署、ORM、进程守护、Nginx、Polly【源码】

ps:废话不多说。直接上代码:源码地址:https://github.com/786744873/Asp.Net-Core-2.1-All-Demos/tree/master/src

Configuration的配置

说明:基于三种方式的读取配置文件以及自定义读取自定义配置文件 

文件结构

代码

PropertiesConfigurationProvider.cs

public class PropertiesConfigurationProvider:ConfigurationProvider
{
    string _path = string.Empty;
    public PropertiesConfigurationProvider(string path)
    {
        this._path = path;
    }

    /// <summary>
    /// 用于解析1.properties
    /// </summary>
    public override void Load()
    {
        var lines = File.ReadAllLines(this._path);

        var dict = new Dictionary<string, string>();

        foreach (var line in lines)
        {
            var items = line.Split('=');
            dict.Add(items[0], items[1]);
        }

        this.Data = dict;
    }
}
View Code

PropertiesConfigurationSource.cs

public class PropertiesConfigurationSource : IConfigurationSource
{

    string _path = string.Empty;
    public PropertiesConfigurationSource(string path)
    {
        this._path = path;
    }

    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new PropertiesConfigurationProvider(_path);
    }
}
View Code

PropertiesConfigurationExtensions.cs

public static class PropertiesConfigurationExtensions
{
    public static IConfigurationBuilder AddPropertiesFile(this IConfigurationBuilder builder, string path)
    {
        builder.Add(new PropertiesConfigurationSource(path));
        return builder;
    }
}
View Code

1.properties

port=8080
host=127.0.0.1
View Code

appsettings.json

{
  "mysql": {
    "host": "127.0.0.1",
    "port": 3306
  },
  "shopidlist": [
    { "entid": 20 },
    { "entid": 25 }
  ]
}
View Code

Program.cs

class Program
{
    static void Main(string[] args)
    {
        IConfiguration Configuration = new ConfigurationBuilder()
            .SetBasePath(Environment.CurrentDirectory)
            .AddJsonFile("appsettings.json", optional:true,reloadOnChange:true)
            .AddPropertiesFile("1.properties")//加载自定义文件
            .Build();

        Appsettings appsettings = new Appsettings();
        Configuration.Bind(appsettings);

        Console.WriteLine(appsettings.mysql.port);

        Console.WriteLine(Configuration["mysql:port"]);

        Console.WriteLine(Configuration.GetValue<int>("mysql:port"));

        Console.WriteLine(Configuration.GetSection("mysql").GetSection("port").Value);
        //读取自定义文件
        Console.WriteLine(Configuration["host"]);

        Console.Read();
    }
}


public class Appsettings
{
    public Mysql mysql { get; set; }
    public Shopidlist[] shopidlist { get; set; }
}

public class Mysql
{
    public string host { get; set; }
    public int port { get; set; }
}

public class Shopidlist
{
    public int entid { get; set; }
}
View Code

 

CollectionService注入

文件结构

 

代码

Program.cs

class Program
{
    static void Main(string[] args)
    {
        //IOC容器
        ServiceCollection services = new ServiceCollection();

        //注册服务
        services.AddScoped<IFlay, Pig>();

        //注册日志服务
        services.AddLogging();

        var provider = services.BuildServiceProvider();

        provider.GetService<ILoggerFactory>().AddConsole(LogLevel.Debug);

        var fly = provider.GetService<IFlay>();

        fly.Flay();

    }
}

public interface IFlay
{
    void Flay();
}

public class Pig : IFlay
{
    ILogger<Pig> logger = null;

    public Pig(ILoggerFactory loggerFactory)
    {
        logger=loggerFactory.CreateLogger<Pig>();
    }

    public void Flay()
    {
        logger.LogInformation("这是Console日志");
        Console.WriteLine("风口来了,猪都会飞了!");
    }
}
View Code

 

AOP AspectCore

文件结构

代码

Program.cs

//https://github.com/dotnetcore/AspectCore-Framework
class Program
{
    static void Main(string[] args)
    {
        ServiceCollection services = new ServiceCollection();

        //注册AspectCore动态代理服务
        services.AddDynamicProxy();

        services.AddTransient<IMySql, MySql>();

        var provider= services.BuildDynamicProxyServiceProvider();

        var mysql = provider.GetService<IMySql>();

        //走业务逻辑
        var msg= mysql.GetData(10);
        Console.WriteLine(msg);

        //走缓存
        msg = mysql.GetData(10);
        Console.WriteLine(msg);

    }
}

public class MysqlInterceptorAttribute : AbstractInterceptorAttribute
{
    private Dictionary<string, string> cacheDict = new Dictionary<string, string>();

    public override Task Invoke(AspectContext context, AspectDelegate next)
    {

        //用id作为cachekey
        var cacheKey = string.Join(",", context.Parameters);
        if (cacheDict.ContainsKey(cacheKey))
        {
            context.ReturnValue = cacheDict[cacheKey];
            return Task.CompletedTask;
        }

        var task = next(context);
        //ReturnValue实际上就是一个传递值的媒介
        var cacheValue = context.ReturnValue;

        cacheDict.Add(cacheKey, $"from Cache:{cacheValue.ToString()}");

        return task;

        //Console.WriteLine("开始记录日志。。。。");
        //var task = next(context);
        //Console.WriteLine("结束记录日志。。。。");
        //return task;
    }
}

public interface IMySql
{
    [MysqlInterceptor]
    string GetData(int id);
}

public class MySql : IMySql
{
    public string GetData(int id)
    {
        var msg = $"已经获取到id={id}的数据";
        //Console.WriteLine(msg);
        return msg;
    }
}
View Code

 

MemoryCache

文件结构

代码

Program.cs

class Program
{
    static void Main(string[] args)
    {

        {//cache的最大限度为100


            MemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions()
            {
                SizeLimit = 100
            });

            for (int i = 0; i < 1000; i++)
            {
                memoryCache.Set<string>(i.ToString(), i.ToString(), new MemoryCacheEntryOptions()
                {
                    Size = 1
                });

                Console.WriteLine(memoryCache.Count);
            }
        }

        {//被动过期,设置过期回调

            MemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions()
            {

            });

            var cacheOptions = new MemoryCacheEntryOptions
            {
                AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(3),//3秒过期
            };
            cacheOptions.RegisterPostEvictionCallback((key, value, reason, obj) =>
            {
                Console.WriteLine(reason);
                Console.WriteLine("执行过期回调");
            });

            memoryCache.Set("key", "value", cacheOptions);

            Console.WriteLine("3秒后过期将执行回调");
            while (true)
            {
                Thread.Sleep(1000);
                Console.WriteLine(memoryCache.Get<string>("key"));
            }
            Console.ReadKey();
        }


        {//主动过期(10秒被动过期,2秒主动使用token让他过期)


            CancellationTokenSource tokenSource = new CancellationTokenSource();
            MemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions()
            {

            });

            var cacheOptions = new MemoryCacheEntryOptions
            {
                AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(10),//10秒过期
            };
            cacheOptions.AddExpirationToken(new CancellationChangeToken(tokenSource.Token));//加入Token
            cacheOptions.RegisterPostEvictionCallback((key, value, reason, obj) =>
            {
                Console.WriteLine(reason);
                Console.WriteLine("执行过期回调");
            });

            memoryCache.Set("key", "value", cacheOptions);

            Console.WriteLine("10秒后过期将执行回调");

            tokenSource.CancelAfter(TimeSpan.FromSeconds(2));
            while (true)
            {
                Thread.Sleep(1000);
                Console.WriteLine(memoryCache.Get<string>("key"));
            }
            Console.ReadKey();
        }
    }
}
View Code

Redis MongoDB

文件结构

代码

Program.cs

class Program
{
    static void Main(string[] args)
    {
        //Redis
        {
            RedisCache redisCache = new RedisCache(new RedisCacheOptions()
            {
                Configuration = "127.0.0.1:6379",
                InstanceName = "test"
            });

            //在Redis中是以Hash的模式存放的
            redisCache.SetString("username", "jack", new DistributedCacheEntryOptions
            {
                AbsoluteExpiration = DateTime.Now.AddDays(1),
            });

            var info = redisCache.GetString("username");

            Console.WriteLine(info);
        }

        //MongoDB
        {
            MongoDBCache mongoDBCache = new MongoDBCache(new MongoDBCacheOptions()
            {
                ConnectionString = "mongodb://127.0.0.1:27017",
                DatabaseName = "mydb",
                CollectionName = "mytest"
            });

            mongoDBCache.Set("username", Encoding.UTF8.GetBytes("jack"), new DistributedCacheEntryOptions {
                AbsoluteExpiration = DateTime.Now.AddDays(1)
            });

            var info= Encoding.UTF8.GetString(mongoDBCache.Get("username"));
            Console.WriteLine(info);
        }


    }
}
View Code

Mysql.Data Dapper

文件结构

 

代码

class Program
{
    static void Main(string[] args)
    {
        //MySql.Data
        {
            var connectString = "server=127.0.0.1;por=3306;userid=root;pwd=123456;database=datamip;SslMode=none;";
            //MySqlConnection mySqlConnection = new MySqlConnection(connectString);


            //select
            var ds = MySqlHelper.ExecuteDataset(connectString, "select * from users");

            //select2
            var reader = MySqlHelper.ExecuteReader(connectString, "select * from users");
            var user = new Users();
            while (reader.Read())
            {
                user.UserId = reader.GetInt32("UserID");
                user.UserNick = reader.GetString("UserNick");
                user.LoginIP = reader.GetString("LoginIP");
                user.Email = reader.GetString("Email");
            }
            reader.Close();

            //update
            var result = MySqlHelper.ExecuteNonQuery(connectString, "update users set Email='786744873@qq.com' where UserID=1");
        }


        //Dapper
        {
            var connectString = "server=127.0.0.1;por=3306;userid=root;pwd=123456;database=datamip;SslMode=none;";
            MySqlConnection mySqlConnection = new MySqlConnection(connectString);

            //select
            var userList = mySqlConnection.Query<Users>("select * from users where UserID=@UserID",new { UserID=2 });

            //update
            var nums = mySqlConnection.Execute("update users set Email='786744873@qq.com' where UserID=1");
        }

    }

    class Users
    {
        public int UserId { get; set; }
        public string UserNick { get; set; }
        public string LoginIP { get; set; }
        public string Email { get; set; }
    }
}
View Code

nohup supervisord部署Unbuntu

不得不说Ubuntu18.04版本是个巨坑。还是老老实实用16.04吧,错了,是VirtualBox是个巨坑,这wtf软件各种问题,浪费我几天时间,艹

文件结构

代码

ConfigurationManager.cs

public class ConfigurationManager
{
    public static IConfigurationRoot Configuration
    {
        get
        {
            var configuration = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile(string.Format("appsettings.{0}.json", Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")),optional:true,reloadOnChange:true)
                .AddJsonFile(string.Format("ops.{0}.json", Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")),optional:true,reloadOnChange:true)
                .Build();
            return configuration;
        }
    }
}
View Code

Program.cs

class Program
{
    static void Main(string[] args)
    {
        var tokenSource = new CancellationTokenSource();

        Task.Factory.StartNew(() =>
        {
            while (!tokenSource.IsCancellationRequested)
            {
                Console.WriteLine($"{DateTime.Now}:业务逻辑处理中");
                Thread.Sleep(1000);
            }
        }).ContinueWith(t =>
        {
            Console.WriteLine("服务安全退出!");
            Environment.Exit(0);//强制退出
        });

        Console.WriteLine("服务成功开启");

        while (!"Y".Equals(ConfigurationManager.Configuration["isquit"],StringComparison.InvariantCultureIgnoreCase))
        {
            Thread.Sleep(1000);
        }

        tokenSource.Cancel();
    }
}
View Code

ops.Development.json  ||  ops.Production.json

{
  "isquit": "N"
}
View Code

部署过程

直接发布,发布以及虚拟机安装参照之前的博客:Virtual Box虚拟机Ubuntu18.X系统安装及Mysql基本开发配置,这里主要讲如何进行持久化

ubuntu16.04开机提示:检测到系统程序出现问题

打开终端,输入 sudo gedit /etc/default/apport 

把enabled=1改成enabled=0

方案一:nohub部署

先执行 nohup dotnet 程序集名称 & 

nohup dotnet ConsoleApp7.dll &  #(符号&使程序在后台运行)
exit #(退出nohup模式)

然后输入 exit 进行退出,不然的话后台进程会被终结

启动后,会将程序运行输出记录在当前目录下的nohup.out文件下,如果当前目录不可写,则会被记录在Home目录下的nohup.out文件中

nohup dotnet ConsoleApp7.dll > my_nohup.log 2>&1 & #(将日志输出在my_nohup.log文件中,并将stderr重定向至stdout)

查看dotnet进程

ps -ef |grep dotnet

查看后10行nohup输出

tail /home/wyt/nohup.out

查看运行的后台进程

ps -ef | grep dotnet

停止程序

kill -9 12462 #(根据进程号关闭程序)

方案二:supervisord部署

安装

ubuntu安装: 
sudo apt-get install supervisor 
centos安装: 
yum install -y supervisor 

安装成功后,会在 /etc/supervisor 目录下,生成 supervisord.conf 配置文件。

你也可以使用 echo_supervisord_conf > supervisord.conf 命令,生成默认的配置文件(不建议,内容比较多)。

 supervisord.conf 示例配置:

; supervisor config file

[unix_http_server]
file=/var/run/supervisor.sock   ; (the path to the socket file)
chmod=0700                       ; sockef file mode (default 0700)

[supervisord]
logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
childlogdir=/var/log/supervisor            ; ('AUTO' child log dir, default $TEMP)

; the below section must remain in the config file for RPC
; (supervisorctl/web interface) to work, additional interfaces may be
; added by defining them in separate rpcinterface: sections
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL  for a unix socket

; The [include] section can just contain the "files" setting.  This
; setting can list multiple files (separated by whitespace or
; newlines).  It can also contain wildcards.  The filenames are
; interpreted as relative to this file.  Included files *cannot*
; include files themselves.

[include]
files = /etc/supervisor/conf.d/*.conf
View Code

进程配置会读取 /etc/supervisor/conf.d 目录下的 *.conf 配置文件,我们在此目录下创建一个 ConsoleApp7.conf 进程配置文件:

[program:ConsoleApp7]
directory=/data/output
command=/usr/bin/dotnet /data/output/ConsoleApp7.dll
autostart=true
autorestart=true
startretries=10
redirect_stderr=true
stdout_logfile=/data/output/logs/out.log
stderr_logfile=/data/output/logs/out.log
environment=ASPNETCORE_ENVIRONMENT="Development"

需要注意的是,如果不是 root 账号,需要对这些目录进行权限设置,要不然会报一些错误(一定要在 root 账号下进行配置,要不然一系列权限引起的问题😂)。

sudo chmod 777 /var/run
sudo chmod 777 /etc/supervisor

接着就可以启动 Supervisord 了:

sudo supervisorctl reload
sudo supervisord
sudo supervisorctl ConsoleApp7

 supervisorctl  常用命令:

命令说明
sudo supervisorctl stop program_name 停止某个进程
sudo supervisorctl start program_name 启动某个进程
sudo supervisorctl restart program_name 重启某个进程
sudo supervisorctl stop all 停止全部进程
sudo supervisorctl reload 载入最新的配置文件,停止原有进程并按新的配置启动、管理所有进程
sudo supervisorctl update 根据最新的配置文件,启动新配置或有改动的进程,配置没有改动的进程不会受影响而重启

运行成功后查看守护进程信息

sudo supervisorctl status all

使用NSSM进行Windows部署

NSSM是一款可将Nodejs项目注册为Windows系统服务的工具。当你的Node.js项目需要部署在Windows Server上时,NSSM是一个不错的选择。

使用

  1. 下载NSSM       download.
  2. 根据自己的平台,将32/64位nssm.exe文件解压至任意文件夹。
  3. cmd定位至nssm.exe所在目录。
  4. 输入 nssm install {服务名称},即注册服务的名称。注册服务弹出如下NSSM界面。

Socket实现简单Web服务器

文件结构

代码

WebServer.cs

 1     public class WebServer
 2     {
 3         static Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 4 
 5         public static void Start()
 6         {
 7             socket.Bind(new IPEndPoint(IPAddress.Any, 8200));
 8             socket.Listen(100);
 9 
10             //接收客户端的Socket请求
11             socket.BeginAccept(OnAccept, socket);
12 
13             Console.WriteLine("当前Web服务器启动成功,端口号为8200");
14         }
15 
16         //接收请求
17         public static void OnAccept(IAsyncResult async)
18         {
19             var serverSocket = async.AsyncState as Socket;
20 
21             //获取到客户端的Socket
22             var clientSocket = serverSocket.EndAccept(async);
23 
24             //进行下一步监听
25             serverSocket.BeginAccept(OnAccept, socket);
26 
27             //获取其内容
28             var bytes = new byte[10240];
29             var len = clientSocket.Receive(bytes);
30             var request = Encoding.UTF8.GetString(bytes, 0, len);
31 
32             var response = string.Empty;
33 
34             if (!string.IsNullOrEmpty(request)&&!request.Contains("favicon.ico"))
35             {
36                 //1.html
37                 var filePath = request.Split("\r\n")[0].Split(" ")[1].Replace("/", "");
38 
39                 //获取文件内容
40                 response = File.ReadAllText(filePath, Encoding.UTF8);
41             }
42 
43             //按照Http响应码返回
44             var responseHeader = string.Format(@"HTTP/1.1 200 OK
45 Date: Tue, 11 Dec 2018 07:08:44 GMT
46 Content-Type: text/html; charset=utf-8
47 Content-Length: {0}
48 Connection: keep-alive
49 Vary: Accept-Encoding
50 Cache-Control: private, max-age=10
51 Expires: Tue, 11 Dec 2018 07:08:54 GMT
52 Last-Modified: Tue, 11 Dec 2018 07:08:44 GMT
53 X-UA-Compatible: IE=10
54 X-Frame-Options: SAMEORIGIN
55 
56 ", Encoding.UTF8.GetByteCount(response));
57 
58             //返回给客户端
59             clientSocket.Send(Encoding.UTF8.GetBytes(responseHeader));
60             clientSocket.Send(Encoding.UTF8.GetBytes(response));
61 
62             clientSocket.Close(); 
63         }
64 
65     }
View Code

Program.cs

class Program
{
    static void Main(string[] args)
    {
        //浏览器访问127.0.0.1:8200/1.html
        WebServer.Start();

        Console.ReadKey();
    }
}
View Code

1.html

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <h1>这是1.html的内容</h1>
</body>
</html>
View Code

2.html

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <h1>这是2.html的内容</h1>
</body>
</html>
View Code

效果:

自定义Middleware

文件结构

代码

 MyStaticFileMiddleware.cs

public class MyStaticFileMiddleware
{
    private readonly RequestDelegate _next;

    public MyStaticFileMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public Task Invoke(HttpContext context)
    {
        //1.logic   如果我当前的Context中有png,那么就直接从文件中读取,否则放下传递
        var path = context.Request.Path.Value;
        if (path.Contains(".png"))
        {
            var mypath = path.Trim('/');
            return context.Response.SendFileAsync(mypath);
        }

        var task = _next(context);
        return task;
    }
}
View Code

Nginx反向代理

安装

命令:

sudo apt-get install nginx

因为是首次安装 Nginx,通过运行以下命令显式启动

sudo service nginx start

在浏览器地址栏中输入类似于 http://192.168.XXX.XXX的IP地址或 http://域名就可以显示 Nginx 的默认登陆页了。

配置 Nginx

若要将 Nginx 配置为转发请求向 ASP.NET Core 应用程序的反向代理,修改  /etc/nginx/sites-available/default 。 在文本编辑器中打开它,并将内容替换为以下内容:

server {
    listen        80;
    server_name   test.com *.test.com;
    location / {
        proxy_pass         http://localhost:5000;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection keep-alive;
        proxy_set_header   Host $http_host;
        proxy_cache_bypass $http_upgrade;
    }
}

Nginx 接受主机标头使用的端口 80 上的公共流量, Nginx 将匹配的请求转发到在 Kestrel http://localhost:5000
测试配置:

sudo nginx -t

显示结果如下所示:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

重新加载配置:

sudo nginx -s reload

Polly

github地址:https://github.com/App-vNext/Polly

使用

Install-Package Polly

代码

重试:RetryTest.cs

public class RetryTest
{
    //重试策略的设定
    public static void Run()
    {
        var retrayPloicy = Policy.Handle<WebException>()
            .WaitAndRetry(new List<TimeSpan>() {
                TimeSpan.FromSeconds(1),
                                    TimeSpan.FromSeconds(3),
                                    TimeSpan.FromSeconds(5)
            }, (ex, dt) =>
            {
                Console.WriteLine($"{DateTime.Now} {ex.Message}  {dt} ");
            });

        int count = 0;

        var html = retrayPloicy.Execute(() =>
        {
            var url = "http://1cnblogs.com";

            if (count == 3) url = "http://cnblogs.com";

            return GetHtml(url, ref count);
        });

        //这个是我调用第三次获取到的内容。。
        Console.WriteLine(html);
    }


    /// <summary>
    /// 获取页面内容
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    public static string GetHtml(string url, ref int count)
    {
        var html = string.Empty;
        try
        {
            var webClient = new WebClient();

            html = webClient.DownloadString(url);
        }
        catch (Exception ex)
        {
            count++;
            throw;
        }

        return html;
    }
}
View Code

熔断:CircuitBreakderTest.cs

public class CircuitBreakderTest
{
    public static void Run()
    {
        //如果当前连续有两个异常,那么触发熔断,10s内不能调用,10s之后重新调用。
        //一旦调用成功了,熔断就解除了。
        var policy = Policy.Handle<WebException>()
            .CircuitBreaker(2, TimeSpan.FromSeconds(10), (ex, timespan, context) =>
            {
                //触发熔断
                Console.WriteLine($"{DateTime.Now} 熔断触发:{timespan}");
            }, (context) =>
            {
                //恢复
                Console.WriteLine($"{DateTime.Now} 熔断恢复");
            });

        var errCount = 1;

        for (int i = 0; i < 100; i++)
        {
            try
            {
                var msg = policy.Execute<string>((context, token) =>
                {
                    var url = "http://cnblogs1.com";

                    //模拟,当一定的时间后,恢复正常
                    if (errCount > 10)
                    {
                        url = "http://cnblogs.com";
                    }

                    return GetHtml(url);

                }, new Dictionary<string, object>() { { i.ToString(), i.ToString() } }, CancellationToken.None);

                Console.WriteLine("logic:" + msg);
            }
            catch (Exception ex)
            {
                Console.WriteLine(string.Format("{0} 业务逻辑异常:'{1}'", DateTime.Now, ex.Message));

                System.Threading.Thread.Sleep(2000);

                errCount++;
            }
        }
    }

    /// <summary>
    /// 获取页面内容
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    public static string GetHtml(string url)
    {
        var html = string.Empty;
        try
        {
            var webClient = new WebClient();

            html = webClient.DownloadString(url).Substring(0, 10);

        }
        catch (Exception ex)
        {
            throw;
        }

        return html;
    }
}
View Code

超时:TimeoutTest.cs

public class TimeoutTest
{
    public static void Run()
    {
        var cancellationToken = new CancellationToken();

        //10s后 cancellationToken过期
        var policy = Policy.Timeout(10);

        //通过cancellationToken进行传值,如果10s过去,IsCancellationRequested 自动变成取消状态
        policy.Execute((token) =>
        {
            for (int i = 0; i < 1000; i++)
            {
                //大家需要根据这个状态来做具体的业务逻辑
                Console.WriteLine(token.IsCancellationRequested);
                System.Threading.Thread.Sleep(1000);
            }
        }, cancellationToken);

        Console.Read();
    }

    /// <summary>
    /// 获取页面内容
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    public static string GetHtml(string url)
    {
        var html = string.Empty;

        Thread.Sleep(20);

        return html;
    }
}
View Code

隔离:BulkheadTest.cs

public class BulkheadTest
{
    public static void Run()
    {
        var policy = Policy.Bulkhead(5, 1000);

        Parallel.For(0, 100, (i) =>
        {
            //这里只能做一次调用
            var result = policy.Execute<string>(() =>
            {
                return GetHtml("http://cnblogs.com");
            });

            Console.WriteLine("已成功获取到数据:{0}", result);
        });


        Console.Read();
    }

    /// <summary>
    /// 获取页面内容
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    public static string GetHtml(string url)
    {
        var html = string.Empty;

        try
        {
            var webClient = new WebClient();

            html = webClient.DownloadString(url);

            html = html.Substring(0, 17);

            Console.WriteLine($"当前线程ID={Thread.CurrentThread.ManagedThreadId}");

            System.Threading.Thread.Sleep(2000);
        }
        catch (Exception ex)
        {
            throw;
        }

        return html;
    }
}
View Code

回退:FallbackTest.cs

public class FallbackTest
{
    public static void Run()
    {
        var result = Policy<string>.Handle<WebException>()
                                .Fallback(() =>
                                {
                                    return "接口失败,这个fake的值给你!";
                                })
                                .Execute(() =>
                                {
                                    return GetHtml("http://1cnblogs.com");
                                });

        Console.WriteLine(result);

        Console.Read();
    }

    /// <summary>
    /// 获取页面内容
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    public static string GetHtml(string url)
    {
        var html = string.Empty;

        try
        {
            var webClient = new WebClient();

            html = webClient.DownloadString(url);
        }
        catch (Exception ex)
        {
            throw;
        }

        return html;
    }
}
View Code

c#7.0

out语法

//out
{
    {//old
        string val = "10";
        int result;
        int.TryParse(val, out result);
        Console.WriteLine(result);
    }

    {//new
        string val = "10";
        int.TryParse(val, out int result);
        Console.WriteLine(result);
    }
}
View Code

Tuple/ValueTuple

public static Tuple<bool, string> GetData()
{
    return Tuple.Create(true, "操作成功");
}

public static (bool, string) GetDataNew()
{
    return (true, "操作成功");
}




//Tuple
{
    var tuple = GetData();
    Console.WriteLine(tuple.Item1+" "+tuple.Item2);

    var (isSuccess, msg) = GetDataNew();
    Console.WriteLine(isSuccess.ToString(),msg);
}
View Code

Deconstruct(解构函数)

public class Person
{
    private string _name;
    private int _age;

    public Person(string name, int age)
    {
        this._name = name;
        this._age = age;
    }

    public void Deconstruct(out string name, out int age)
    {
        name = this._name;
        age = this._age;
    }
}


//Deconstruct
{
    var (Name, Age) = new Person("jack", 18);

    Console.WriteLine(Name + " " + Age);
}
View Code

Local

//Local内部方法
{
    Console.WriteLine(GetLength("hello world"));

    int GetLength(string str)
    {
        return str.Length;
    }
}
View Code

switch增强

//switch增强
{
    var list = new List<object>() { 1, "2" };
    foreach (var item in list)
    {
        switch (item)
        {
            //如果当前item是int类型,那么执行
            case int val:
                Console.WriteLine(val);
                break;
            //如果当前item是string类型,那么转成int
            case string str when int.TryParse(str, out int ival):
                Console.WriteLine(ival);
                break;
            default:
                break;
        }
    }
}
View Code

 

posted on 2018-12-12 11:04  一个大西瓜咚咚咚  阅读(1468)  评论(0编辑  收藏  举报

导航