微服務網關從零搭建——(一)建立測試api以及api自動注入consul

本系列編寫目的純屬我的開發記錄  如下代碼均爲demo級 若有須要 請自行優化 代碼完整包因爲公司電腦加密 沒法上傳整包的demo文件html

consul 開發環境簡易處理

consul 下載地址 : https://www.consul.io/downloads.htmljson

此處使用windows 64版本 windows

爲方便使用在建立一個bat文件 命令以下:api

cd C:\Users\Lenovo\Desktop\    
consul.exe agent -devapp

第一行爲進入桌面dom

第二行爲 執行consul開發模式tcp

運行後可在 localhost:8500 地址處看到consul 後臺服務管理頁面ide

搭建測試API

因爲 使用了consul 最新nuget包 因此 在建立的時候須要使用 .netcore 2.1 微服務

因爲已經搭建了demo1 這裏演示截圖會是demo2 建立方式同樣oop

建立一個core 2.1的API空項目

 

建立一個BaseController 用來保存配置信息

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;

namespace DemoApi_I.Controllers
{
    public class BaseController : ControllerBase
    {
        public static Setting Config;
        public BaseController(IOptions<Setting> setting)
        {
            Config = setting.Value;
        }
    }
}
BaseController

再添加一個健康檢查的控制器

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;

namespace DemoApi_II.Controllers
{
    [Route("api/[controller]")]
    public class HealthController : BaseController
    {
        public HealthController(IOptions<Setting> setting) : base(setting)
        {
        }

        // GET api/values
        [HttpGet]
        public string Get()
        {
            return "ok";
        }
    }
}
HealthController.cs

爲了統一顯示 能夠更改默認values控制器爲

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;

namespace DemoApi_II.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : BaseController
    {
        public ValuesController(IOptions<Setting> setting) : base(setting)
        {
        }
        // GET api/values
        [HttpGet]
        public string Get()
        {
            var aaa = Config.ServiceName;
            return "二號測試API";
        }
    }
}
ValuesController

 接下來 增長 一個配置類

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace DemoApi_II
{
    public class Setting
    {
        /// <summary>
        /// 端口號
        /// </summary>
        public int Port { get; set; }
        /// <summary>
        /// 服務名稱
        /// </summary>
        public string ServiceName { get; set; }
        /// <summary>
        /// 服務發現IP
        /// </summary>
        public string ConsulIP { get; set; }
        /// <summary>
        /// 服務發現端口號
        /// </summary>
        public int ConsulPort { get; set; }

    }
}
Setting.cs

在appsettings.json 內新增節點 

測試地址中只須要改端口號和服務名稱便可 會自動讀取本機ip到注入到consul中

 "Setting": {
    "Port": "1001",
    "ServiceName": "demoAPi",
    "ConsulIP": "localhost",
    "ConsulPort": "8500"
  }
新增部分

注意 須要修改成 始終複製或者較新複製

 

修改 Program.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace DemoApi_II
{
    public class Program
    {
        public static string StartPort;
        public static void Main(string[] args)
        {
            var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true)
.Build();
            StartPort = config.GetSection("Setting")["Port"];
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
              .UseUrls($"http://*:{StartPort}")
                .UseStartup<Startup>();
    }
}
Program.cs

修改startup.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ConsulRegisterHelper;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace DemoApi_II
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<Setting>(Configuration.GetSection("Setting"));
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime lifetime)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseMvc();
            app.RegisterConsul(lifetime, new ServiceEntity
            {
                IP = NetworkHelper.LocalIPAddress,
                Port = Convert.ToInt32(Configuration.GetSection("Setting")["Port"]),
                ServiceName = Configuration.GetSection("Setting")["ServiceName"],
                ConsulIP = Configuration.GetSection("Setting")["ConsulIP"],
                ConsulPort = Convert.ToInt32(Configuration.GetSection("Setting")["ConsulPort"])
            });
        }
    }
}
Startup.cs

建立自動注入consul服務的類庫

新建core2.1類庫項目 取名ConsulRegisterHelper

將如下3個類建立便可

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;

namespace ConsulRegisterHelper
{
    public class NetworkHelper
    {
        public static string LocalIPAddress
        {
            get
            {
                UnicastIPAddressInformation mostSuitableIp = null;
                var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();

                foreach (var network in networkInterfaces)
                {
                    if (network.OperationalStatus != OperationalStatus.Up)
                        continue;
                    var properties = network.GetIPProperties();
                    if (properties.GatewayAddresses.Count == 0)
                        continue;

                    foreach (var address in properties.UnicastAddresses)
                    {
                        if (address.Address.AddressFamily != AddressFamily.InterNetwork)
                            continue;
                        if (IPAddress.IsLoopback(address.Address))
                            continue;
                        return address.Address.ToString();
                    }
                }

                return mostSuitableIp != null
                    ? mostSuitableIp.Address.ToString()
                    : "";
            }
        }

        public static int GetRandomAvaliablePort(int minPort = 1024, int maxPort = 65535)
        {
            Random rand = new Random();
            while (true)
            {
                int port = rand.Next(minPort, maxPort);
                if (!IsPortInUsed(port))
                {
                    return port;
                }
            }
        }

        private static bool IsPortInUsed(int port)
        {
            IPGlobalProperties ipGlobalProps = IPGlobalProperties.GetIPGlobalProperties();
            IPEndPoint[] ipsTCP = ipGlobalProps.GetActiveTcpListeners();

            if (ipsTCP.Any(p => p.Port == port))
            {
                return true;
            }

            IPEndPoint[] ipsUDP = ipGlobalProps.GetActiveUdpListeners();
            if (ipsUDP.Any(p => p.Port == port))
            {
                return true;
            }

            TcpConnectionInformation[] tcpConnInfos = ipGlobalProps.GetActiveTcpConnections();
            if (tcpConnInfos.Any(conn => conn.LocalEndPoint.Port == port))
            {
                return true;
            }

            return false;
        }
    }
}
NetworkHelper.cs
using Consul;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using System;

namespace ConsulRegisterHelper
{
    public static class AppBuilderExtensions
    {
        public static IApplicationBuilder RegisterConsul(this IApplicationBuilder app, IApplicationLifetime lifetime, ServiceEntity serviceEntity)
        {
            var consulClient = new ConsulClient(x => x.Address = new Uri($"http://{serviceEntity.ConsulIP}:{serviceEntity.ConsulPort}"));//請求註冊的 Consul 地址
            var httpCheck = new AgentServiceCheck()
            {
                DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服務啓動多久後註冊
                Interval = TimeSpan.FromSeconds(3),//健康檢查時間間隔,或者稱爲心跳間隔
                HTTP = $"http://{serviceEntity.IP}:{serviceEntity.Port}{serviceEntity.HealthUrl}",//健康檢查地址
                Timeout = TimeSpan.FromSeconds(3)
            };

            // Register service with consul
            var registration = new AgentServiceRegistration()
            {
                Checks = new[] { httpCheck },
                ID = Guid.NewGuid().ToString(),
                Name = serviceEntity.ServiceName,
                Address = serviceEntity.IP,
                Port = serviceEntity.Port,
                Tags = new[] { $"urlprefix-/{serviceEntity.ServiceName}" }//添加 urlprefix-/servicename 格式的 tag 標籤,以便 Fabio 識別
            };

            consulClient.Agent.ServiceRegister(registration).Wait();//服務啓動時註冊,內部實現其實就是使用 Consul API 進行註冊(HttpClient發起)
            lifetime.ApplicationStopping.Register(() =>
            {
                consulClient.Agent.ServiceDeregister(registration.ID).Wait();//服務中止時取消註冊
            });

            return app;
        }
    }
}
Register.cs
using System;
using System.Collections.Generic;
using System.Text;

namespace ConsulRegisterHelper
{
    public class ServiceEntity
    {
        public ServiceEntity()
        {
            HealthUrl = "/api/health";
        }
        /// <summary>
        /// 服務IP
        /// </summary>
        public string IP { get; set; }
        /// <summary>
        /// 服務端口號
        /// </summary>
        public int Port { get; set; }
        /// <summary>
        /// 服務名稱
        /// </summary>
        public string ServiceName { get; set; }
        /// <summary>
        /// 服務發現地址
        /// </summary>
        public string ConsulIP { get; set; }
        /// <summary>
        /// 服務發現端口號
        /// </summary>
        public int ConsulPort { get; set; }
        /// <summary>
        /// 健康檢查地址默認爲/api/health
        /// </summary>
        public string HealthUrl { get; set; }
    }
}
ServiceEntity.cs

在須要注入的服務Startup.cs中經過以下代碼注入:

 

建立bat文件方便測試使用

E:
cd E:\ServerApi\OcelotGetWay\DemoApi_II\bin\Debug\netcoreapp2.1
dotnet DemoApi_II.dll
實例代碼

 到此 測試demoapi 準備完成

 參考內容: 

微服務系列文章

https://www.cnblogs.com/edisonchou/p/dotnetcore_microservice_foundation_blogs_index_final.html

ocelot配置特性介紹

https://blog.csdn.net/qin_yu_2010/article/details/82749414

相關文章
相關標籤/搜索