iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 20
0
Software Development

.Net微服務輕旅行30天系列 第 20

Day 20 Steeltoe OSS提供的Service Registry and Discovery (4)

繼續完成 service registry

把Fortunes跟練習專案交叉測試了

確認不是.net core 2.0的問題,所以1.1版的Service registry和discovery可以正常使用

接著Day19的後續,開始改APIGateway專案,
appsettings.json中加入 eureka的設定

  "eureka": {
    "client": {
      "serviceUrl": "http://localhost:8761/eureka/",
      "shouldRegisterWithEureka": false
    }
  }

接著在Startup.cs的Startup方法中加入下面的設定(由於我們在ConfigServer的時候已經加入相關設定, 如果重頭寫寫的時候沒有加入AddJsonFile是沒有辦法讀到appsettings.json)

    public Startup(IHostingEnvironment env)
    {
      var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
        .AddEnvironmentVariables()
        .AddConfigServer();

      Configuration = builder.Build();
    }

在ConfigureServices裡面加入了AddDiscoveryClient, 同時為後面要調用的IProductService設定singleton注入

   // This method gets called by the runtime. Use this method to add services to the container.
   public void ConfigureServices(IServiceCollection services)
   {
     services.AddOptions();

     services.AddDiscoveryClient(Configuration);

     services.AddSingleton<IProductService, ProductService>();

     services.Configure<ConfigServerData>(Configuration);

     services.AddMvc();
   }

Program.cs 維持原狀(其實這邊設定有誤造成service discovery無法解析名字,此地雷後述~)

切換到ProdcutService專案裡面controller 看一下有哪些API ,等等要在APIGateway專案裡調用

namespace ProductService.Controllers
{
    [Route("api/[controller]")]
    public class ProductController : Controller
    {
        // GET api/values
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return new string[] { "Product1", "Product2" };
        }

        // GET api/values/5
        [HttpGet("{id}")]
        public string Get(int id)
        {
            return "Product"+id;
        }

    }
}

在APIGateway專案新增一個Service資料夾 增加IProductService定義需要調用的ProductService介面

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

namespace APIGateway.Services
{
    public interface IProductService
    {
        string GetValue(int id);
        string[] GetValues();
    }
}

增加ProductService 實作IProduceService規定的方法, service discovery會在這邊注入使用,

using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Pivotal.Discovery.Client;
using System.Collections.Generic;
using System.Net.Http;

namespace APIGateway.Services
{
  public class ProductService : IProductService
    {
        DiscoveryHttpClientHandler _handler;
        private const string ProductServiceAPI_URL = "http://ProductService/api/values";
        public ProductService(IDiscoveryClient client, ILoggerFactory logFactory) {
            _handler = new DiscoveryHttpClientHandler(client);
        }

        public string GetValue(int id) {
            var client = new HttpClient(_handler, false);
            var result = client.GetStringAsync($"{ProductServiceAPI_URL}/{id}").Result;
            return result;
        }

        public string[] GetValues() {
            var client = new HttpClient(_handler, false);
            var response = client.GetAsync(ProductServiceAPI_URL).Result;
            var responseBody = response.Content.ReadAsStringAsync().Result;
            var result = JsonConvert.DeserializeObject<List<string>>(responseBody);

            return result.ToArray();
        }
    }
}

到APIGateway對應的controller下調用IProductService

using System.Collections.Generic;
using APIGateway.Services;
using Microsoft.AspNetCore.Mvc;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace APIGateway
{
  [Route("api/[controller]")]
    public class ProductController : Controller
    {
        // GET: api/values
        public ProductController(IProductService service) {
            _productService = service;
        }
        IProductService _productService;

        [HttpGet]
        public IEnumerable<string> Get() {

            return _productService.GetValues();
        }

        // GET api/values/5
        [HttpGet("{id}")]
        public string Get(int id) {
            return _productService.GetValue(id);
        }


    }
}

到這邊應該就完成了

Service registry時,位址設定上的要注意的地方(雷?)

執行後會發現HttpClient那邊會拋出錯誤,但是會發現交叉比對之下FortuneService-Teller-UI跟APIGateway都無法解析ProductService在Eureka對應的資源名稱,結果是HttpClient發request時找不到伺服器,

最後發現是Program.cs裡面啟動程式的位址寫法對service discovery有影響,注意這兩行

                .UseUrls("http://*:1234")
                //.UseUrls("http://localhost:1234")  // service discovery can't work

這兩個設定程式都能跑 而且都會在localhost:1234啟動,在Eureka也可以註冊,
但是第二行的service discovery是無法找到服務的位置的,我在官方文件沒看到說明,可能要看source code或是發issue問一下了....

    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();            
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .UseUrls("http://*:1234")
                //.UseUrls("http://localhost:1234")  // service discovery can't work
                .Build();
    }

短短一行 幾個小時就掰了..............


上一篇
Day 19 Steeltoe OSS提供的Service Registry and Discovery (3)
下一篇
Day 21: Steeltoe OSS提供的Circuit Breaker - Hystrix Netflix (1)
系列文
.Net微服務輕旅行30天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言