ASP.NET Core 2.1的配置、AOP、緩存、部署、ORM、進程守護、Nginx、Polly【源碼】

ps:廢話很少說。直接上代碼:源碼地址:https://github.com/786744873/Asp.Net-Core-2.1-All-Demos/tree/master/srchtml

Configuration的配置

說明:基於三種方式的讀取配置文件以及自定義讀取自定義配置文件mysql

文件結構

代碼

PropertiesConfigurationProvider.csnginx

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.csgit

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.csgithub

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

1.propertiesweb

port=8080
host=127.0.0.1
View Code

appsettings.jsonredis

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

Program.cssql

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.csmongodb

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.csjson

//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
相關文章
相關標籤/搜索