• 微服务网关从零搭建——(一)创建测试api以及api自动注入consul


    本系列编写目的纯属个人开发记录  以下代码均为demo级 如有需要 请自行优化 代码完整包由于公司电脑加密 无法上传整包的demo文件

    consul 开发环境简易处理

    consul 下载地址 : https://www.consul.io/downloads.html

    此处使用windows 64版本 

    为方便使用在创建一个bat文件 命令如下:

    cd C:UsersLenovoDesktop    
    consul.exe agent -dev

    第一行为进入桌面

    第二行为 执行consul开发模式

    运行后可在 localhost:8500 地址处看到consul 后台服务管理页面

    搭建测试API

    由于 使用了consul 最新nuget包 所以 在创建的时候需要使用 .netcore 2.1 

    由于已经搭建了demo1 这里演示截图会是demo2 创建方式一样

    创建一个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:ServerApiOcelotGetWayDemoApi_IIinDebug
    etcoreapp2.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

  • 相关阅读:
    软件工程作业-结对实验
    软件工程实践作业2
    UNIX线程之间的关系
    c中计时的几种方法
    调试器工作原理(3):调试信息
    调试器工作原理(2):实现断点
    调试器工作原理(1):基础篇
    linux的终端,网络虚拟终端,伪终端(转)
    asterisk webrtc使用SIPML5初体验
    初次使用nodejs的问题
  • 原文地址:https://www.cnblogs.com/nontracey/p/9962505.html
Copyright © 2020-2023  润新知