Asp.Net Core API网关Ocelot

本文涉及的产品
云原生 API 网关,700元额度,多规格可选
简介: 首先,让我们简单了解下什么是API网关?      API网关是一个服务器,是系统的唯一入口。从面向对象设计的角度看,它与外观模式类似。API网关封装了系统内部架构,为每个客户端提供一个定制的API。

首先,让我们简单了解下什么是API网关?

      API网关是一个服务器,是系统的唯一入口。从面向对象设计的角度看,它与外观模式类似。API网关封装了系统内部架构,为每个客户端提供一个定制的API。它可能还具有其它职责,如身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理。
    API网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。通常,网关也是提供REST/HTTP的访问API。服务端通过API-GW注册和管理服务。

其次,我们了解下Ocelot框架

 Ocelot的目标是使用.NET运行微服务/面向服务架构,我们需要一个统一的入口进入我们的服务,提供监控、鉴权、负载均衡等机制,也可以通过编写中间件的形式,来扩展Ocelot的功能。  Ocelot是一堆特定顺序的中间件。

 Ocelot框架内部集成了IdentityServer和Consul(服务注册发现),还引入了Polly来处理进行故障处理,关于Polly,可以在这篇博客中了解更多《已被.NET基金会认可的弹性和瞬态故障处理库Polly介绍》

 Ocelot开源地址:https://github.com/TomPallister/Ocelot

接下来,我们就针对Ocelot的具体用法展开介绍。

这里使用的Ocelot版本为2.0,.Net Core版本2.0

1、搭建Asp.net Core WebApi项目,引用Ocelot.dll。

Nuget控制台,执行Ocelot安装。

PM>Install-Package Ocelot

  

GET https://api.nuget.org/v3/registration3-gz-semver2/ocelot/index.json
  OK https://api.nuget.org/v3/registration3-gz-semver2/ocelot/index.json 104 毫秒
  GET https://api.nuget.org/v3/registration3-gz-semver2/ocelot/page/1.5.0-unstable0134/2.0.0.json
  OK https://api.nuget.org/v3/registration3-gz-semver2/ocelot/page/1.5.0-unstable0134/2.0.0.json 108 毫秒
正在还原 J:\Demo\RichCodeBox\APIGatewayApp\APIGatewayApp.csproj 的包...
  GET https://api.nuget.org/v3-flatcontainer/ocelot/index.json
  OK https://api.nuget.org/v3-flatcontainer/ocelot/index.json 476 毫秒
  GET https://api.nuget.org/v3-flatcontainer/ocelot/2.0.0/ocelot.2.0.0.nupkg
  OK https://api.nuget.org/v3-flatcontainer/ocelot/2.0.0/ocelot.2.0.0.nupkg 125 毫秒
  GET https://api.nuget.org/v3-flatcontainer/identityserver4.accesstokenvalidation/index.json
  GET https://api.nuget.org/v3-flatcontainer/cachemanager.core/index.json
  GET https://api.nuget.org/v3-flatcontainer/cachemanager.microsoft.extensions.configuration/index.json
  GET https://api.nuget.org/v3-flatcontainer/cachemanager.microsoft.extensions.logging/index.json
  GET https://api.nuget.org/v3-flatcontainer/consul/index.json
  GET https://api.nuget.org/v3-flatcontainer/polly/index.json
  GET https://api.nuget.org/v3-flatcontainer/identityserver4/index.json
  OK https://api.nuget.org/v3-flatcontainer/identityserver4.accesstokenvalidation/index.json 133 毫秒
  GET https://api.nuget.org/v3-flatcontainer/identityserver4.accesstokenvalidation/2.1.0/identityserver4.accesstokenvalidation.2.1.0.nupkg
  OK https://api.nuget.org/v3-flatcontainer/cachemanager.microsoft.extensions.logging/index.json 286 毫秒
  OK https://api.nuget.org/v3-flatcontainer/polly/index.json 287 毫秒
  OK https://api.nuget.org/v3-flatcontainer/identityserver4.accesstokenvalidation/2.1.0/identityserver4.accesstokenvalidation.2.1.0.nupkg 160 毫秒
  GET https://api.nuget.org/v3-flatcontainer/cachemanager.microsoft.extensions.logging/1.1.1/cachemanager.microsoft.extensions.logging.1.1.1.nupkg

  2、修改Startup程序。

   /// <summary>
        /// 
        /// </summary>
        /// <param name="environment"></param>
        public Startup(IHostingEnvironment environment)
        {
            var builder = new Microsoft.Extensions.Configuration.ConfigurationBuilder();
            builder.SetBasePath(environment.ContentRootPath)
                   .AddJsonFile("appsettings.json", false, reloadOnChange: true)
                   .AddJsonFile($"appsettings.{environment.EnvironmentName}.json", optional: false, reloadOnChange: true)
                   .AddJsonFile("configuration.json", optional: false, reloadOnChange: true)
                   .AddEnvironmentVariables();


            Configuration = builder.Build();
        }

  

        /// <summary>
        ///modified:配置
        /// </summary>
        public IConfigurationRoot Configuration { get; }

        /// <summary>
        /// 配置服务
        /// </summary>
        /// <param name="services"></param>
        public void ConfigureServices(IServiceCollection services)
        {
            Action<ConfigurationBuilderCachePart> settings = (x) =>
            {
                x.WithMicrosoftLogging(log =>
                {
                    log.AddConsole(LogLevel.Debug);

                }).WithDictionaryHandle();
            };
            services.AddOcelot(Configuration, settings);
            //services.AddMvc();
        }

        /// <summary>
        /// 配置Ocelot
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        public async void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            //if (env.IsDevelopment())
            //{
            //    app.UseDeveloperExceptionPage();
            //}
            await app.UseOcelot();
            //app.UseMvc();
        }
        /// <summary>
        /// 入口程序
        /// </summary>
        /// <param name="args"></param>
        public static void Main(string[] args)
        {
            IWebHostBuilder builder = new WebHostBuilder();
            builder.ConfigureServices(s =>
            {
                s.AddSingleton(builder);
            });
            builder.UseKestrel()
                   .UseContentRoot(Directory.GetCurrentDirectory())
                   .UseIISIntegration()
                   .UseStartup<Startup>()
                   .UseApplicationInsights();
            var host = builder.Build();
            host.Run();
        }

  

3、配置Ocelot。

我们新建一个名为configuration的json文件,配置如下:

{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/api/values",
      "DownstreamScheme": "http",
      "DownstreamHost": "localhost",
      "DownstreamPort": 8801,
      "UpstreamPathTemplate": "/api/values",
      "UpstreamHttpMethod": [ "Get" ],
      "QoSOptions": {
        "ExceptionsAllowedBeforeBreaking": 3,
        "DurationOfBreak": 10,
        "TimeoutValue": 5000
      },
      "HttpHandlerOptions": {
        "AllowAutoRedirect": false,
        "UseCookieContainer": false
      },
      "AuthenticationOptions": {

      }
    },
    {
      "DownstreamPathTemplate": "/api/product",
      "DownstreamScheme": "http",
      "DownstreamPort": 8802,
      "DownstreamHost": "localhost",
      "UpstreamPathTemplate": "/api/product",
      "UpstreamHttpMethod": [ "Get" ],
      "QoSOptions": {
        "ExceptionsAllowedBeforeBreaking": 3,
        "DurationOfBreak": 10,
        "TimeoutValue": 5000
      },
      "AuthenticationOptions": {

      }
    }
  ],
  "GlobalConfiguration": {
    "RequestIdKey": "OcRequestId",
    "AdministrationPath": "/admin"
  }
}

  

在这里,我们配置了两个服务,端口分别为8801和8802的。

Ocelot支持负载均衡(提供轮询、最少访问)。Ocelot大部分功能,都可以通过中间件来完成,也可以实现和重写中间件。

Ocelot原理非常简单,这里的配置文件,体现了上游请求和下游服务间的映射关系,你可以理解为,上游是客户端直接调用的URL ,下游,则是对应我们开发的服务。

4、新增两个WebApi项目,分别为APIUserServiec和APIProductService。

API服务 端口(Port)
APIUserServiec 8801
APIProductService 8802

解决方案如下:

5、配置VS启动端口:

依次类推,分别设置端口。

6、启动项目。

配置多个项目启动。

F5启动项目。

再通过API网关,访问商品服务:http://localhost:5000/api/product。

常见问题:

首次在启动API网关时,触发以下错误。

Sequence contains no matching element

 

根据错误详细信息,可知原因是由于系统调用AddIdentityServer方法时,触发异常。

刚开始,怀疑是配置文件configuration.json文件配置导致的,Ocelot2.0版,采用官方配置仍然触发该异常,由此排除这种可能。接下来,直接从github上克隆源代码,查看。

找到触发错误的地方,

private static void AddIdentityServer(this IServiceCollection services, IIdentityServerConfiguration identityServerConfiguration, IConfigurationRoot configurationRoot) 
        {
            services.TryAddSingleton<IIdentityServerConfiguration>(identityServerConfiguration);
            services.TryAddSingleton<IHashMatcher, HashMatcher>();
            var identityServerBuilder = services
                .AddIdentityServer(o => {
                    o.IssuerUri = "Ocelot";
                })
                .AddInMemoryApiResources(Resources(identityServerConfiguration))
                .AddInMemoryClients(Client(identityServerConfiguration))
                .AddResourceOwnerValidator<OcelotResourceOwnerPasswordValidator>();

            //todo - refactor a method so we know why this is happening
            var whb = services.First(x => x.ServiceType == typeof(IWebHostBuilder));//这个地方触发了错误
            var urlFinder = new BaseUrlFinder((IWebHostBuilder)whb.ImplementationInstance);
            var baseSchemeUrlAndPort = urlFinder.Find();
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

            services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
                .AddIdentityServerAuthentication(o =>
                {
                    var adminPath = configurationRoot.GetValue("GlobalConfiguration:AdministrationPath", string.Empty);
                    o.Authority = baseSchemeUrlAndPort + adminPath;
                    o.ApiName = identityServerConfiguration.ApiName;
                    o.RequireHttpsMetadata = identityServerConfiguration.RequireHttps;
                    o.SupportedTokens = SupportedTokens.Both;
                    o.ApiSecret = identityServerConfiguration.ApiSecret;
                });

                //todo - refactor naming..
                if (string.IsNullOrEmpty(identityServerConfiguration.CredentialsSigningCertificateLocation) || string.IsNullOrEmpty(identityServerConfiguration.CredentialsSigningCertificatePassword))
                {
                    identityServerBuilder.AddDeveloperSigningCredential();
                }
                else
                {
                    //todo - refactor so calls method?
                    var cert = new X509Certificate2(identityServerConfiguration.CredentialsSigningCertificateLocation, identityServerConfiguration.CredentialsSigningCertificatePassword);
                    identityServerBuilder.AddSigningCredential(cert);
                }
var whb = services.First(x => x.ServiceType == typeof(IWebHostBuilder));

这就代码触发了错误,是由于表达式条件不成立,导致First发生异常,这就简单了,我们修改Main函数,

把这句代码:

 var builder = new WebHostBuilder();

改成:

IWebHostBuilder builder = new WebHostBuilder();

这样,就解决了问题,API网关启动成功。另外,官方例子https://github.com/TomPallister/Ocelot/blob/develop/test/Ocelot.ManualTest/Program.cs中,写法是正确的,大家自己写的时候,注意把IWebHostBuilder换成var会引发错误。

这样,使用Ocelot框架搭建API网关的工作已经完成,尝试通过访问API网关,来访问下游的服务。

此实例源码:https://gitee.com/lichaoqiang/RichCodeBox.git

欢迎大家一起研究探讨,开启你的微服务之路。

 

目录
相关文章
|
1月前
|
存储 开发框架 JSON
ASP.NET Core OData 9 正式发布
【10月更文挑战第8天】Microsoft 在 2024 年 8 月 30 日宣布推出 ASP.NET Core OData 9,此版本与 .NET 8 的 OData 库保持一致,改进了数据编码以符合 OData 规范,并放弃了对旧版 .NET Framework 的支持,仅支持 .NET 8 及更高版本。新版本引入了更快的 JSON 编写器 `System.Text.UTF8JsonWriter`,优化了内存使用和序列化速度。
|
9天前
|
负载均衡 监控 API
dotnet微服务之API网关Ocelot
Ocelot 是一个基于 .NET 的 API 网关,适用于微服务架构。本文介绍了如何创建一个 Web API 项目并使用 Ocelot 进行 API 请求路由、负载均衡等。通过配置 `ocelot.json` 和修改 `Program.cs`,实现对 `GoodApi` 和 `OrderApi` 两个项目的路由管理。最终,通过访问 `https://localhost:7122/good/Hello` 和 `https://localhost:7122/order/Hello` 验证配置成功。
19 1
dotnet微服务之API网关Ocelot
|
1月前
|
开发框架 .NET API
Windows Forms应用程序中集成一个ASP.NET API服务
Windows Forms应用程序中集成一个ASP.NET API服务
96 9
|
1月前
|
存储 开发框架 .NET
.NET 8 实现无实体库表 API 部署服务
【10月更文挑战第12天】在.NET 8中,可通过以下步骤实现无实体库表的API部署:首先安装.NET 8 SDK及开发工具,并选用轻量级Web API框架如ASP.NET Core;接着创建新项目并设计API,利用内存数据结构模拟数据存储;最后配置项目设置并进行测试与部署。此方法适用于小型项目或临时解决方案,但对于大规模应用仍需考虑持久化存储以确保数据可靠性与可扩展性。
|
1月前
|
数据采集 传感器 监控
.NET 工控网关 轻量级组态软件
【10月更文挑战第10天】.NET 工控网关是一种基于 .NET 平台开发的设备,用于连接工业控制系统中的不同网络和设备,实现数据传输和协议转换。它能统一处理多种协议(如 Modbus、Profibus)的数据,便于后续系统处理。.NET 平台的优势包括开发效率高、跨平台能力强及安全性高,适用于工业物联网环境。此外,轻量级组态软件具备体积小、资源占用少的特点,可在资源受限的设备上运行,提供数据采集、监控、报警及数据分析等功能,简化工业自动化过程。
|
1月前
mcr.microsoft.com/dotnet/core/aspnet:2.1安装libgdiplus
mcr.microsoft.com/dotnet/core/aspnet:2.1安装libgdiplus
29 1
|
2月前
|
开发框架 监控 前端开发
在 ASP.NET Core Web API 中使用操作筛选器统一处理通用操作
【9月更文挑战第27天】操作筛选器是ASP.NET Core MVC和Web API中的一种过滤器,可在操作方法执行前后运行代码,适用于日志记录、性能监控和验证等场景。通过实现`IActionFilter`接口的`OnActionExecuting`和`OnActionExecuted`方法,可以统一处理日志、验证及异常。创建并注册自定义筛选器类,能提升代码的可维护性和复用性。
|
2月前
|
开发框架 .NET 中间件
ASP.NET Core Web 开发浅谈
本文介绍ASP.NET Core,一个轻量级、开源的跨平台框架,专为构建高性能Web应用设计。通过简单步骤,你将学会创建首个Web应用。文章还深入探讨了路由配置、依赖注入及安全性配置等常见问题,并提供了实用示例代码以助于理解与避免错误,帮助开发者更好地掌握ASP.NET Core的核心概念。
99 3
|
2月前
|
存储 安全 物联网
.NET 跨平台工业物联网网关解决方案
【9月更文挑战第28天】本文介绍了利用 .NET 构建跨平台工业物联网网关的解决方案。通过 .NET Core 和多种通信协议(如 MQTT 和 Modbus),实现工业设备的高效接入和数据采集。系统架构包括设备接入层、数据处理层、通信层、应用层和数据库层,确保数据的准确采集、实时处理和安全传输。此外,还详细阐述了设备身份认证、数据加密及安全审计等机制,确保系统的安全性。该方案适用于不同操作系统和工业环境,具备高度灵活性和扩展性。
|
1月前
|
开发框架 JavaScript 前端开发
一个适用于 ASP.NET Core 的轻量级插件框架
一个适用于 ASP.NET Core 的轻量级插件框架