mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-22 06:42:50 +08:00
Rename all ReRoute to Route to move closer to YARP +semver: breaking
This commit is contained in:
parent
fe3e8bd23a
commit
3439be8927
@ -1,7 +1,7 @@
|
|||||||
Authentication
|
Authentication
|
||||||
==============
|
==============
|
||||||
|
|
||||||
In order to authenticate ReRoutes and subsequently use any of Ocelot's claims based features such as authorisation or modifying the request with values from the token. Users must register authentication services in their Startup.cs as usual but they provide a scheme (authentication provider key) with each registration e.g.
|
In order to authenticate Routes and subsequently use any of Ocelot's claims based features such as authorisation or modifying the request with values from the token. Users must register authentication services in their Startup.cs as usual but they provide a scheme (authentication provider key) with each registration e.g.
|
||||||
|
|
||||||
.. code-block:: csharp
|
.. code-block:: csharp
|
||||||
|
|
||||||
@ -16,11 +16,11 @@ In order to authenticate ReRoutes and subsequently use any of Ocelot's claims ba
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
In this example TestKey is the scheme that this provider has been registered with. We then map this to a ReRoute in the configuration e.g.
|
In this example TestKey is the scheme that this provider has been registered with. We then map this to a Route in the configuration e.g.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
"ReRoutes": [{
|
"Routes": [{
|
||||||
"DownstreamHostAndPorts": [
|
"DownstreamHostAndPorts": [
|
||||||
{
|
{
|
||||||
"Host": "localhost",
|
"Host": "localhost",
|
||||||
@ -30,7 +30,7 @@ In this example TestKey is the scheme that this provider has been registered wit
|
|||||||
"DownstreamPathTemplate": "/",
|
"DownstreamPathTemplate": "/",
|
||||||
"UpstreamPathTemplate": "/",
|
"UpstreamPathTemplate": "/",
|
||||||
"UpstreamHttpMethod": ["Post"],
|
"UpstreamHttpMethod": ["Post"],
|
||||||
"ReRouteIsCaseSensitive": false,
|
"RouteIsCaseSensitive": false,
|
||||||
"DownstreamScheme": "http",
|
"DownstreamScheme": "http",
|
||||||
"AuthenticationOptions": {
|
"AuthenticationOptions": {
|
||||||
"AuthenticationProviderKey": "TestKey",
|
"AuthenticationProviderKey": "TestKey",
|
||||||
@ -38,9 +38,9 @@ In this example TestKey is the scheme that this provider has been registered wit
|
|||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
|
|
||||||
When Ocelot runs it will look at this ReRoutes AuthenticationOptions.AuthenticationProviderKey and check that there is an Authentication provider registered with the given key. If there isn't then Ocelot will not start up, if there is then the ReRoute will use that provider when it executes.
|
When Ocelot runs it will look at this Routes AuthenticationOptions.AuthenticationProviderKey and check that there is an Authentication provider registered with the given key. If there isn't then Ocelot will not start up, if there is then the Route will use that provider when it executes.
|
||||||
|
|
||||||
If a ReRoute is authenticated Ocelot will invoke whatever scheme is associated with it while executing the authentication middleware. If the request fails authentication Ocelot returns a http status code 401.
|
If a Route is authenticated Ocelot will invoke whatever scheme is associated with it while executing the authentication middleware. If the request fails authentication Ocelot returns a http status code 401.
|
||||||
|
|
||||||
JWT Tokens
|
JWT Tokens
|
||||||
^^^^^^^^^^
|
^^^^^^^^^^
|
||||||
@ -63,11 +63,11 @@ If you want to authenticate using JWT tokens maybe from a provider like Auth0 yo
|
|||||||
services.AddOcelot();
|
services.AddOcelot();
|
||||||
}
|
}
|
||||||
|
|
||||||
Then map the authentication provider key to a ReRoute in your configuration e.g.
|
Then map the authentication provider key to a Route in your configuration e.g.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
"ReRoutes": [{
|
"Routes": [{
|
||||||
"DownstreamHostAndPorts": [
|
"DownstreamHostAndPorts": [
|
||||||
{
|
{
|
||||||
"Host": "localhost",
|
"Host": "localhost",
|
||||||
@ -77,7 +77,7 @@ Then map the authentication provider key to a ReRoute in your configuration e.g.
|
|||||||
"DownstreamPathTemplate": "/",
|
"DownstreamPathTemplate": "/",
|
||||||
"UpstreamPathTemplate": "/",
|
"UpstreamPathTemplate": "/",
|
||||||
"UpstreamHttpMethod": ["Post"],
|
"UpstreamHttpMethod": ["Post"],
|
||||||
"ReRouteIsCaseSensitive": false,
|
"RouteIsCaseSensitive": false,
|
||||||
"DownstreamScheme": "http",
|
"DownstreamScheme": "http",
|
||||||
"AuthenticationOptions": {
|
"AuthenticationOptions": {
|
||||||
"AuthenticationProviderKey": "TestKey",
|
"AuthenticationProviderKey": "TestKey",
|
||||||
@ -111,11 +111,11 @@ In order to use IdentityServer bearer tokens, register your IdentityServer servi
|
|||||||
services.AddOcelot();
|
services.AddOcelot();
|
||||||
}
|
}
|
||||||
|
|
||||||
Then map the authentication provider key to a ReRoute in your configuration e.g.
|
Then map the authentication provider key to a Route in your configuration e.g.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
"ReRoutes": [{
|
"Routes": [{
|
||||||
"DownstreamHostAndPorts": [
|
"DownstreamHostAndPorts": [
|
||||||
{
|
{
|
||||||
"Host": "localhost",
|
"Host": "localhost",
|
||||||
@ -125,7 +125,7 @@ Then map the authentication provider key to a ReRoute in your configuration e.g.
|
|||||||
"DownstreamPathTemplate": "/",
|
"DownstreamPathTemplate": "/",
|
||||||
"UpstreamPathTemplate": "/",
|
"UpstreamPathTemplate": "/",
|
||||||
"UpstreamHttpMethod": ["Post"],
|
"UpstreamHttpMethod": ["Post"],
|
||||||
"ReRouteIsCaseSensitive": false,
|
"RouteIsCaseSensitive": false,
|
||||||
"DownstreamScheme": "http",
|
"DownstreamScheme": "http",
|
||||||
"AuthenticationOptions": {
|
"AuthenticationOptions": {
|
||||||
"AuthenticationProviderKey": "TestKey",
|
"AuthenticationProviderKey": "TestKey",
|
||||||
@ -176,4 +176,4 @@ Allowed Scopes
|
|||||||
|
|
||||||
If you add scopes to AllowedScopes Ocelot will get all the user claims (from the token) of the type scope and make sure that the user has all of the scopes in the list.
|
If you add scopes to AllowedScopes Ocelot will get all the user claims (from the token) of the type scope and make sure that the user has all of the scopes in the list.
|
||||||
|
|
||||||
This is a way to restrict access to a ReRoute on a per scope basis.
|
This is a way to restrict access to a Route on a per scope basis.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
Authorisation
|
Authorisation
|
||||||
=============
|
=============
|
||||||
|
|
||||||
Ocelot supports claims based authorisation which is run post authentication. This means if you have a route you want to authorise you can add the following to you ReRoute configuration.
|
Ocelot supports claims based authorisation which is run post authentication. This means if you have a route you want to authorise you can add the following to you Route configuration.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ The second thing you need to do something like the following to your ConfigureSe
|
|||||||
x.WithDictionaryHandle();
|
x.WithDictionaryHandle();
|
||||||
})
|
})
|
||||||
|
|
||||||
Finally in order to use caching on a route in your ReRoute configuration add this setting.
|
Finally in order to use caching on a route in your Route configuration add this setting.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ Ocelot allows the user to access claims and transform them into headers, query s
|
|||||||
|
|
||||||
After the user is authenticated we run the claims to claims transformation middleware. This allows the user to transform claims before the authorisation middleware is called. After the user is authorised first we call the claims to headers middleware, thenthe claims to query string parameters middleware, and Finally the claims to downstream pathmiddleware.
|
After the user is authenticated we run the claims to claims transformation middleware. This allows the user to transform claims before the authorisation middleware is called. After the user is authorised first we call the claims to headers middleware, thenthe claims to query string parameters middleware, and Finally the claims to downstream pathmiddleware.
|
||||||
|
|
||||||
The syntax for performing the transforms is the same for each process. In the ReRoute configuration a json dictionary is added with a specific name either AddClaimsToRequest, AddHeadersToRequest, AddQueriesToRequest, or ChangeDownstreamPathTemplate.
|
The syntax for performing the transforms is the same for each process. In the Route configuration a json dictionary is added with a specific name either AddClaimsToRequest, AddHeadersToRequest, AddQueriesToRequest, or ChangeDownstreamPathTemplate.
|
||||||
|
|
||||||
Note: I'm not a hotshot programmer so have no idea if this syntax is good...
|
Note: I'm not a hotshot programmer so have no idea if this syntax is good...
|
||||||
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
Configuration
|
Configuration
|
||||||
============
|
============
|
||||||
|
|
||||||
An example configuration can be found `here <https://github.com/ThreeMammals/Ocelot/blob/master/test/Ocelot.ManualTest/ocelot.json>`_. There are two sections to the configuration. An array of ReRoutes and a GlobalConfiguration. The ReRoutes are the objects that tell Ocelot how to treat an upstream request. The Global configuration is a bit hacky and allows overrides of ReRoute specific settings. It's useful if you don't want to manage lots of ReRoute specific settings.
|
An example configuration can be found `here <https://github.com/ThreeMammals/Ocelot/blob/master/test/Ocelot.ManualTest/ocelot.json>`_. There are two sections to the configuration. An array of Routes and a GlobalConfiguration. The Routes are the objects that tell Ocelot how to treat an upstream request. The Global configuration is a bit hacky and allows overrides of Route specific settings. It's useful if you don't want to manage lots of Route specific settings.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"ReRoutes": [],
|
"Routes": [],
|
||||||
"GlobalConfiguration": {}
|
"GlobalConfiguration": {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Here is an example ReRoute configuration, You don't need to set all of these things but this is everything that is available at the moment:
|
Here is an example Route configuration, You don't need to set all of these things but this is everything that is available at the moment:
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ Here is an example ReRoute configuration, You don't need to set all of these thi
|
|||||||
"TtlSeconds": 0,
|
"TtlSeconds": 0,
|
||||||
"Region": ""
|
"Region": ""
|
||||||
},
|
},
|
||||||
"ReRouteIsCaseSensitive": false,
|
"RouteIsCaseSensitive": false,
|
||||||
"ServiceName": "",
|
"ServiceName": "",
|
||||||
"DownstreamScheme": "http",
|
"DownstreamScheme": "http",
|
||||||
"DownstreamHostAndPorts": [
|
"DownstreamHostAndPorts": [
|
||||||
@ -112,7 +112,7 @@ Instead of adding the configuration directly e.g. AddJsonFile("ocelot.json") you
|
|||||||
|
|
||||||
In this scenario Ocelot will look for any files that match the pattern (?i)ocelot.([a-zA-Z0-9]*).json and then merge these together. If you want to set the GlobalConfiguration property you must have a file called ocelot.global.json.
|
In this scenario Ocelot will look for any files that match the pattern (?i)ocelot.([a-zA-Z0-9]*).json and then merge these together. If you want to set the GlobalConfiguration property you must have a file called ocelot.global.json.
|
||||||
|
|
||||||
The way Ocelot merges the files is basically load them, loop over them, add any ReRoutes, add any AggregateReRoutes and if the file is called ocelot.global.json add the GlobalConfiguration aswell as any ReRoutes or AggregateReRoutes. Ocelot will then save the merged configuration to a file called ocelot.json and this will be used as the source of truth while ocelot is running.
|
The way Ocelot merges the files is basically load them, loop over them, add any Routes, add any AggregateRoutes and if the file is called ocelot.global.json add the GlobalConfiguration aswell as any Routes or AggregateRoutes. Ocelot will then save the merged configuration to a file called ocelot.json and this will be used as the source of truth while ocelot is running.
|
||||||
|
|
||||||
At the moment there is no validation at this stage it only happens when Ocelot validates the final merged configuration. This is something to be aware of when you are investigating problems. I would advise always checking what is in ocelot.json if you have any problems.
|
At the moment there is no validation at this stage it only happens when Ocelot validates the final merged configuration. This is something to be aware of when you are investigating problems. I would advise always checking what is in ocelot.json if you have any problems.
|
||||||
|
|
||||||
@ -195,7 +195,7 @@ If you do not set the ConfigurationKey Ocelot will use the string InternalConfig
|
|||||||
Follow Redirects / Use CookieContainer
|
Follow Redirects / Use CookieContainer
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Use HttpHandlerOptions in ReRoute configuration to set up HttpHandler behavior:
|
Use HttpHandlerOptions in Route configuration to set up HttpHandler behavior:
|
||||||
|
|
||||||
1. AllowAutoRedirect is a value that indicates whether the request should follow redirection responses. Set it true if the request should automatically follow redirection responses from the Downstream resource; otherwise false. The default value is false.
|
1. AllowAutoRedirect is a value that indicates whether the request should follow redirection responses. Set it true if the request should automatically follow redirection responses from the Downstream resource; otherwise false. The default value is false.
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ Use HttpHandlerOptions in ReRoute configuration to set up HttpHandler behavior:
|
|||||||
SSL Errors
|
SSL Errors
|
||||||
^^^^^^^^^^
|
^^^^^^^^^^
|
||||||
|
|
||||||
If you want to ignore SSL warnings / errors set the following in your ReRoute config.
|
If you want to ignore SSL warnings / errors set the following in your Route config.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ I don't recommend doing this, I suggest creating your own certificate and then g
|
|||||||
MaxConnectionsPerServer
|
MaxConnectionsPerServer
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
This controls how many connections the internal HttpClient will open. This can be set at ReRoute or global level.
|
This controls how many connections the internal HttpClient will open. This can be set at Route or global level.
|
||||||
|
|
||||||
React to Configuration Changes
|
React to Configuration Changes
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -31,8 +31,8 @@ Next you must add the handlers to Ocelot's container like below...
|
|||||||
.AddDelegatingHandler<FakeHandler>()
|
.AddDelegatingHandler<FakeHandler>()
|
||||||
.AddDelegatingHandler<FakeHandlerTwo>()
|
.AddDelegatingHandler<FakeHandlerTwo>()
|
||||||
|
|
||||||
Both of these Add methods have a default parameter called global which is set to false. If it is false then the intent of the DelegatingHandler is to be applied to specific ReRoutes via ocelot.json (more on that later). If it is set to true
|
Both of these Add methods have a default parameter called global which is set to false. If it is false then the intent of the DelegatingHandler is to be applied to specific Routes via ocelot.json (more on that later). If it is set to true
|
||||||
then it becomes a global handler and will be applied to all ReRoutes.
|
then it becomes a global handler and will be applied to all Routes.
|
||||||
|
|
||||||
e.g.
|
e.g.
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ As below...
|
|||||||
services.AddOcelot()
|
services.AddOcelot()
|
||||||
.AddDelegatingHandler<FakeHandler>(true)
|
.AddDelegatingHandler<FakeHandler>(true)
|
||||||
|
|
||||||
Finally if you want ReRoute specific DelegatingHandlers or to order your specific and / or global (more on this later) DelegatingHandlers then you must add the following json to the specific ReRoute in ocelot.json. The names in the array must match the class names of your
|
Finally if you want Route specific DelegatingHandlers or to order your specific and / or global (more on this later) DelegatingHandlers then you must add the following json to the specific Route in ocelot.json. The names in the array must match the class names of your
|
||||||
DelegatingHandlers for Ocelot to match them together.
|
DelegatingHandlers for Ocelot to match them together.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
@ -8,7 +8,7 @@ Add to Request
|
|||||||
|
|
||||||
This feature was requestes in `GitHub #313 <https://github.com/ThreeMammals/Ocelot/issues/313>`_.
|
This feature was requestes in `GitHub #313 <https://github.com/ThreeMammals/Ocelot/issues/313>`_.
|
||||||
|
|
||||||
If you want to add a header to your upstream request please add the following to a ReRoute in your ocelot.json:
|
If you want to add a header to your upstream request please add the following to a Route in your ocelot.json:
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ Add to Response
|
|||||||
|
|
||||||
This feature was requested in `GitHub #280 <https://github.com/ThreeMammals/Ocelot/issues/280>`_.
|
This feature was requested in `GitHub #280 <https://github.com/ThreeMammals/Ocelot/issues/280>`_.
|
||||||
|
|
||||||
If you want to add a header to your downstream response please add the following to a ReRoute in ocelot.json..
|
If you want to add a header to your downstream response please add the following to a Route in ocelot.json..
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ If you want to add a header to your downstream response please add the following
|
|||||||
"Uncle": "Bob"
|
"Uncle": "Bob"
|
||||||
},
|
},
|
||||||
|
|
||||||
In the example above a header with the key Uncle and value Bob would be returned by Ocelot when requesting the specific ReRoute.
|
In the example above a header with the key Uncle and value Bob would be returned by Ocelot when requesting the specific Route.
|
||||||
|
|
||||||
If you want to return the Butterfly APM trace id then do something like the following..
|
If you want to return the Butterfly APM trace id then do something like the following..
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ The key is "Test" and the value is "http://www.bbc.co.uk/, http://ocelot.com/".
|
|||||||
Pre Downstream Request
|
Pre Downstream Request
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Add the following to a ReRoute in ocelot.json in order to replace http://www.bbc.co.uk/ with http://ocelot.com/. This header will be changed before the request downstream and will be sent to the downstream server.
|
Add the following to a Route in ocelot.json in order to replace http://www.bbc.co.uk/ with http://ocelot.com/. This header will be changed before the request downstream and will be sent to the downstream server.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ Add the following to a ReRoute in ocelot.json in order to replace http://www.bbc
|
|||||||
Post Downstream Request
|
Post Downstream Request
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Add the following to a ReRoute in ocelot.json in order to replace http://www.bbc.co.uk/ with http://ocelot.com/. This transformation will take place after Ocelot has received the response from the downstream service.
|
Add the following to a Route in ocelot.json in order to replace http://www.bbc.co.uk/ with http://ocelot.com/. This transformation will take place after Ocelot has received the response from the downstream service.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
|
@ -30,13 +30,13 @@ You can replicate a Permissive. Using RBAC role bindings.
|
|||||||
.. code-block::bash
|
.. code-block::bash
|
||||||
kubectl create clusterrolebinding permissive-binding --clusterrole=cluster-admin --user=admin --user=kubelet --group=system:serviceaccounts
|
kubectl create clusterrolebinding permissive-binding --clusterrole=cluster-admin --user=admin --user=kubelet --group=system:serviceaccounts
|
||||||
|
|
||||||
The following example shows how to set up a ReRoute that will work in kubernetes. The most important thing is the ServiceName which is made up of the kubernetes service name. We also need to set up the ServiceDiscoveryProvider in GlobalConfiguration. The example here shows a typical configuration.
|
The following example shows how to set up a Route that will work in kubernetes. The most important thing is the ServiceName which is made up of the kubernetes service name. We also need to set up the ServiceDiscoveryProvider in GlobalConfiguration. The example here shows a typical configuration.
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"ReRoutes": [
|
"Routes": [
|
||||||
{
|
{
|
||||||
"DownstreamPathTemplate": "/api/values",
|
"DownstreamPathTemplate": "/api/values",
|
||||||
"DownstreamScheme": "http",
|
"DownstreamScheme": "http",
|
||||||
@ -76,13 +76,13 @@ The polling interval is in milliseconds and tells Ocelot how often to call kuber
|
|||||||
|
|
||||||
Please note there are tradeoffs here. If you poll kubernetes it is possible Ocelot will not know if a service is down depending on your polling interval and you might get more errors than if you get the latest services per request. This really depends on how volatile your services are. I doubt it will matter for most people and polling may give a tiny performance improvement over calling kubernetes per request. There is no way for Ocelot to work these out for you.
|
Please note there are tradeoffs here. If you poll kubernetes it is possible Ocelot will not know if a service is down depending on your polling interval and you might get more errors than if you get the latest services per request. This really depends on how volatile your services are. I doubt it will matter for most people and polling may give a tiny performance improvement over calling kubernetes per request. There is no way for Ocelot to work these out for you.
|
||||||
|
|
||||||
If your downstream service resides in a different namespace you can override the global setting at the ReRoute level by specifying a ServiceNamespace.
|
If your downstream service resides in a different namespace you can override the global setting at the Route level by specifying a ServiceNamespace.
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"ReRoutes": [
|
"Routes": [
|
||||||
{
|
{
|
||||||
"DownstreamPathTemplate": "/api/values",
|
"DownstreamPathTemplate": "/api/values",
|
||||||
"DownstreamScheme": "http",
|
"DownstreamScheme": "http",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
Load Balancer
|
Load Balancer
|
||||||
=============
|
=============
|
||||||
|
|
||||||
Ocelot can load balance across available downstream services for each ReRoute. This means you can scale your downstream services and Ocelot can use them effectively.
|
Ocelot can load balance across available downstream services for each Route. This means you can scale your downstream services and Ocelot can use them effectively.
|
||||||
|
|
||||||
The type of load balancer available are:
|
The type of load balancer available are:
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ You must choose in your configuration which load balancer to use.
|
|||||||
Configuration
|
Configuration
|
||||||
^^^^^^^^^^^^^
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
The following shows how to set up multiple downstream services for a ReRoute using ocelot.json and then select the LeastConnection load balancer. This is the simplest way to get load balancing set up.
|
The following shows how to set up multiple downstream services for a Route using ocelot.json and then select the LeastConnection load balancer. This is the simplest way to get load balancing set up.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ The following shows how to set up multiple downstream services for a ReRoute usi
|
|||||||
Service Discovery
|
Service Discovery
|
||||||
^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
The following shows how to set up a ReRoute using service discovery then select the LeastConnection load balancer.
|
The following shows how to set up a Route using service discovery then select the LeastConnection load balancer.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ In order to set up CookieStickySessions load balancer you need to do something l
|
|||||||
|
|
||||||
The LoadBalancerOptions are Type this needs to be CookieStickySessions, Key this is the key of the cookie you wish to use for the sticky sessions, Expiry this is how long in milliseconds you want to the session to be stuck for. Remember this refreshes on every request which is meant to mimick how sessions work usually.
|
The LoadBalancerOptions are Type this needs to be CookieStickySessions, Key this is the key of the cookie you wish to use for the sticky sessions, Expiry this is how long in milliseconds you want to the session to be stuck for. Remember this refreshes on every request which is meant to mimick how sessions work usually.
|
||||||
|
|
||||||
If you have multiple ReRoutes with the same LoadBalancerOptions then all of those ReRoutes will use the same load balancer for there subsequent requests. This means the sessions will be stuck across ReRoutes.
|
If you have multiple Routes with the same LoadBalancerOptions then all of those Routes will use the same load balancer for there subsequent requests. This means the sessions will be stuck across Routes.
|
||||||
|
|
||||||
Please note that if you give more than one DownstreamHostAndPort or you are using a Service Discovery provider such as Consul and this returns more than one service then CookieStickySessions uses round robin to select the next server. This is hard coded at the moment but could be changed.
|
Please note that if you give more than one DownstreamHostAndPort or you are using a Service Discovery provider such as Consul and this returns more than one service then CookieStickySessions uses round robin to select the next server. This is hard coded at the moment but could be changed.
|
||||||
|
|
||||||
@ -172,7 +172,7 @@ Finally you need to register this class with Ocelot. I have used the most comple
|
|||||||
|
|
||||||
.. code-block:: csharp
|
.. code-block:: csharp
|
||||||
|
|
||||||
Func<IServiceProvider, DownstreamReRoute, IServiceDiscoveryProvider, CustomLoadBalancer> loadBalancerFactoryFunc = (serviceProvider, reRoute, serviceDiscoveryProvider) => new CustomLoadBalancer(serviceDiscoveryProvider.Get);
|
Func<IServiceProvider, DownstreamRoute, IServiceDiscoveryProvider, CustomLoadBalancer> loadBalancerFactoryFunc = (serviceProvider, Route, serviceDiscoveryProvider) => new CustomLoadBalancer(serviceDiscoveryProvider.Get);
|
||||||
|
|
||||||
s.AddOcelot()
|
s.AddOcelot()
|
||||||
.AddCustomLoadBalancer(loadBalancerFactoryFunc);
|
.AddCustomLoadBalancer(loadBalancerFactoryFunc);
|
||||||
@ -198,11 +198,11 @@ There are numerous extension methods to add a custom load balancer and the inter
|
|||||||
where T : ILoadBalancer;
|
where T : ILoadBalancer;
|
||||||
|
|
||||||
IOcelotBuilder AddCustomLoadBalancer<T>(
|
IOcelotBuilder AddCustomLoadBalancer<T>(
|
||||||
Func<DownstreamReRoute, IServiceDiscoveryProvider, T> loadBalancerFactoryFunc)
|
Func<DownstreamRoute, IServiceDiscoveryProvider, T> loadBalancerFactoryFunc)
|
||||||
where T : ILoadBalancer;
|
where T : ILoadBalancer;
|
||||||
|
|
||||||
IOcelotBuilder AddCustomLoadBalancer<T>(
|
IOcelotBuilder AddCustomLoadBalancer<T>(
|
||||||
Func<IServiceProvider, DownstreamReRoute, IServiceDiscoveryProvider, T> loadBalancerFactoryFunc)
|
Func<IServiceProvider, DownstreamRoute, IServiceDiscoveryProvider, T> loadBalancerFactoryFunc)
|
||||||
where T : ILoadBalancer;
|
where T : ILoadBalancer;
|
||||||
|
|
||||||
When you enable custom load balancers Ocelot looks up your load balancer by its class name when it decides if it should do load balancing. If it finds a match it will use your load balaner to load balance. If Ocelot cannot match the load balancer type in your configuration with the name of registered load balancer class then you will receive a HTTP 500 internal server error. If your load balancer factory throw an exception when Ocelot calls it you will receive a HTTP 500 internal server error.
|
When you enable custom load balancers Ocelot looks up your load balancer by its class name when it decides if it should do load balancing. If it finds a match it will use your load balaner to load balance. If Ocelot cannot match the load balancer type in your configuration with the name of registered load balancer class then you will receive a HTTP 500 internal server error. If your load balancer factory throw an exception when Ocelot calls it you will receive a HTTP 500 internal server error.
|
||||||
|
@ -3,7 +3,7 @@ HTTP Method Transformation
|
|||||||
|
|
||||||
Ocelot allows the user to change the HTTP request method that will be used when making a request to a downstream service.
|
Ocelot allows the user to change the HTTP request method that will be used when making a request to a downstream service.
|
||||||
|
|
||||||
This achieved by setting the following ReRoute configuration:
|
This achieved by setting the following Route configuration:
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
@ -23,6 +23,6 @@ This achieved by setting the following ReRoute configuration:
|
|||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
The key property here is DownstreamHttpMethod which is set as POST and the ReRoute will only match on GET as set by UpstreamHttpMethod.
|
The key property here is DownstreamHttpMethod which is set as POST and the Route will only match on GET as set by UpstreamHttpMethod.
|
||||||
|
|
||||||
This feature can be useful when interacting with downstream apis that only support POST and you want to present some kind of RESTful interface.
|
This feature can be useful when interacting with downstream apis that only support POST and you want to present some kind of RESTful interface.
|
@ -1,7 +1,7 @@
|
|||||||
Quality of Service
|
Quality of Service
|
||||||
==================
|
==================
|
||||||
|
|
||||||
Ocelot supports one QoS capability at the current time. You can set on a per ReRoute basis if you want to use a circuit breaker when making requests to a downstream service. This uses an awesome
|
Ocelot supports one QoS capability at the current time. You can set on a per Route basis if you want to use a circuit breaker when making requests to a downstream service. This uses an awesome
|
||||||
.NET library called Polly check them out `here <https://github.com/App-vNext/Polly>`_.
|
.NET library called Polly check them out `here <https://github.com/App-vNext/Polly>`_.
|
||||||
|
|
||||||
The first thing you need to do if you want to use the administration API is bring in the relevant NuGet package..
|
The first thing you need to do if you want to use the administration API is bring in the relevant NuGet package..
|
||||||
@ -19,7 +19,7 @@ Then in your ConfigureServices method
|
|||||||
.AddPolly();
|
.AddPolly();
|
||||||
}
|
}
|
||||||
|
|
||||||
Then add the following section to a ReRoute configuration.
|
Then add the following section to a Route configuration.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ Thanks to `@catcherwong article <http://www.c-sharpcorner.com/article/building-a
|
|||||||
|
|
||||||
Ocelot supports rate limiting of upstream requests so that your downstream services do not become overloaded. This feature was added by @geffzhang on GitHub! Thanks very much.
|
Ocelot supports rate limiting of upstream requests so that your downstream services do not become overloaded. This feature was added by @geffzhang on GitHub! Thanks very much.
|
||||||
|
|
||||||
OK so to get rate limiting working for a ReRoute you need to add the following json to it.
|
OK so to get rate limiting working for a Route you need to add the following json to it.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
Request Aggregation
|
Request Aggregation
|
||||||
===================
|
===================
|
||||||
|
|
||||||
Ocelot allows you to specify Aggregate ReRoutes that compose multiple normal ReRoutes and map their responses into one object. This is usually where you have
|
Ocelot allows you to specify Aggregate Routes that compose multiple normal Routes and map their responses into one object. This is usually where you have
|
||||||
a client that is making multiple requests to a server where it could just be one. This feature allows you to start implementing back end for a front end type
|
a client that is making multiple requests to a server where it could just be one. This feature allows you to start implementing back end for a front end type
|
||||||
architecture with Ocelot.
|
architecture with Ocelot.
|
||||||
|
|
||||||
This feature was requested as part of `Issue 79 <https://github.com/ThreeMammals/Ocelot/pull/79>`_ and further improvements were made as part of `Issue 298 <https://github.com/ThreeMammals/Ocelot/issue/298>`_.
|
This feature was requested as part of `Issue 79 <https://github.com/ThreeMammals/Ocelot/pull/79>`_ and further improvements were made as part of `Issue 298 <https://github.com/ThreeMammals/Ocelot/issue/298>`_.
|
||||||
|
|
||||||
In order to set this up you must do something like the following in your ocelot.json. Here we have specified two normal ReRoutes and each one has a Key property.
|
In order to set this up you must do something like the following in your ocelot.json. Here we have specified two normal Routes and each one has a Key property.
|
||||||
We then specify an Aggregate that composes the two ReRoutes using their keys in the ReRouteKeys list and says then we have the UpstreamPathTemplate which works like a normal ReRoute.
|
We then specify an Aggregate that composes the two Routes using their keys in the RouteKeys list and says then we have the UpstreamPathTemplate which works like a normal Route.
|
||||||
Obviously you cannot have duplicate UpstreamPathTemplates between ReRoutes and Aggregates. You can use all of Ocelot's normal ReRoute options apart from RequestIdKey (explained in gotchas below).
|
Obviously you cannot have duplicate UpstreamPathTemplates between Routes and Aggregates. You can use all of Ocelot's normal Route options apart from RequestIdKey (explained in gotchas below).
|
||||||
|
|
||||||
Advanced register your own Aggregators
|
Advanced register your own Aggregators
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -22,7 +22,7 @@ The ocelot.json setup is pretty much the same as the basic aggregation approach
|
|||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"ReRoutes": [
|
"Routes": [
|
||||||
{
|
{
|
||||||
"DownstreamPathTemplate": "/",
|
"DownstreamPathTemplate": "/",
|
||||||
"UpstreamPathTemplate": "/laura",
|
"UpstreamPathTemplate": "/laura",
|
||||||
@ -56,7 +56,7 @@ The ocelot.json setup is pretty much the same as the basic aggregation approach
|
|||||||
],
|
],
|
||||||
"Aggregates": [
|
"Aggregates": [
|
||||||
{
|
{
|
||||||
"ReRouteKeys": [
|
"RouteKeys": [
|
||||||
"Tom",
|
"Tom",
|
||||||
"Laura"
|
"Laura"
|
||||||
],
|
],
|
||||||
@ -66,7 +66,7 @@ The ocelot.json setup is pretty much the same as the basic aggregation approach
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
Here we have added an aggregator called FakeDefinedAggregator. Ocelot is going to look for this aggregator when it tries to aggregate this ReRoute.
|
Here we have added an aggregator called FakeDefinedAggregator. Ocelot is going to look for this aggregator when it tries to aggregate this Route.
|
||||||
|
|
||||||
In order to make the aggregator available we must add the FakeDefinedAggregator to the OcelotBuilder like below.
|
In order to make the aggregator available we must add the FakeDefinedAggregator to the OcelotBuilder like below.
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ In order to make the aggregator available we must add the FakeDefinedAggregator
|
|||||||
.AddOcelot()
|
.AddOcelot()
|
||||||
.AddSingletonDefinedAggregator<FakeDefinedAggregator>();
|
.AddSingletonDefinedAggregator<FakeDefinedAggregator>();
|
||||||
|
|
||||||
Now when Ocelot tries to aggregate the ReRoute above it will find the FakeDefinedAggregator in the container and use it to aggregate the ReRoute.
|
Now when Ocelot tries to aggregate the Route above it will find the FakeDefinedAggregator in the container and use it to aggregate the Route.
|
||||||
Because the FakeDefinedAggregator is registered in the container you can add any dependencies it needs into the container like below.
|
Because the FakeDefinedAggregator is registered in the container you can add any dependencies it needs into the container like below.
|
||||||
|
|
||||||
.. code-block:: csharp
|
.. code-block:: csharp
|
||||||
@ -106,7 +106,7 @@ In order to make an Aggregator you must implement this interface.
|
|||||||
Task<DownstreamResponse> Aggregate(List<HttpContext> responses);
|
Task<DownstreamResponse> Aggregate(List<HttpContext> responses);
|
||||||
}
|
}
|
||||||
|
|
||||||
With this feature you can pretty much do whatever you want because the HttpContext objects contain the results of all the aggregate requests. Please note if the HttpClient throws an exception when making a request to a ReRoute in the aggregate then you will not get a HttpContext for it but you would for any that succeed. If it does throw an exception this will be logged.
|
With this feature you can pretty much do whatever you want because the HttpContext objects contain the results of all the aggregate requests. Please note if the HttpClient throws an exception when making a request to a Route in the aggregate then you will not get a HttpContext for it but you would for any that succeed. If it does throw an exception this will be logged.
|
||||||
|
|
||||||
Basic expecting JSON from Downstream Services
|
Basic expecting JSON from Downstream Services
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -114,7 +114,7 @@ Basic expecting JSON from Downstream Services
|
|||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"ReRoutes": [
|
"Routes": [
|
||||||
{
|
{
|
||||||
"DownstreamPathTemplate": "/",
|
"DownstreamPathTemplate": "/",
|
||||||
"UpstreamPathTemplate": "/laura",
|
"UpstreamPathTemplate": "/laura",
|
||||||
@ -148,7 +148,7 @@ Basic expecting JSON from Downstream Services
|
|||||||
],
|
],
|
||||||
"Aggregates": [
|
"Aggregates": [
|
||||||
{
|
{
|
||||||
"ReRouteKeys": [
|
"RouteKeys": [
|
||||||
"Tom",
|
"Tom",
|
||||||
"Laura"
|
"Laura"
|
||||||
],
|
],
|
||||||
@ -157,16 +157,16 @@ Basic expecting JSON from Downstream Services
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
You can also set UpstreamHost and ReRouteIsCaseSensitive in the Aggregate configuration. These behave the same as any other ReRoutes.
|
You can also set UpstreamHost and RouteIsCaseSensitive in the Aggregate configuration. These behave the same as any other Routes.
|
||||||
|
|
||||||
If the ReRoute /tom returned a body of {"Age": 19} and /laura returned {"Age": 25} the the response after aggregation would be as follows.
|
If the Route /tom returned a body of {"Age": 19} and /laura returned {"Age": 25} the the response after aggregation would be as follows.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
{"Tom":{"Age": 19},"Laura":{"Age": 25}}
|
{"Tom":{"Age": 19},"Laura":{"Age": 25}}
|
||||||
|
|
||||||
At the moment the aggregation is very simple. Ocelot just gets the response from your downstream service and sticks it into a json dictionary
|
At the moment the aggregation is very simple. Ocelot just gets the response from your downstream service and sticks it into a json dictionary
|
||||||
as above. With the ReRoute key being the key of the dictionary and the value the response body from your downstream service. You can see that the object is just
|
as above. With the Route key being the key of the dictionary and the value the response body from your downstream service. You can see that the object is just
|
||||||
JSON without any pretty spaces etc.
|
JSON without any pretty spaces etc.
|
||||||
|
|
||||||
All headers will be lost from the downstream services response.
|
All headers will be lost from the downstream services response.
|
||||||
@ -179,7 +179,7 @@ It will not change the aggregate response into a 404 even if all the downstreams
|
|||||||
Gotcha's / Further info
|
Gotcha's / Further info
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
You cannot use ReRoutes with specific RequestIdKeys as this would be crazy complicated to track.
|
You cannot use Routes with specific RequestIdKeys as this would be crazy complicated to track.
|
||||||
|
|
||||||
Aggregation only supports the GET HTTP Verb.
|
Aggregation only supports the GET HTTP Verb.
|
||||||
|
|
||||||
|
@ -18,19 +18,19 @@ In your ocelot.json set the following in the GlobalConfiguration section. This w
|
|||||||
"RequestIdKey": "OcRequestId"
|
"RequestIdKey": "OcRequestId"
|
||||||
}
|
}
|
||||||
|
|
||||||
I recommend using the GlobalConfiguration unless you really need it to be ReRoute specific.
|
I recommend using the GlobalConfiguration unless you really need it to be Route specific.
|
||||||
|
|
||||||
*ReRoute*
|
*Route*
|
||||||
|
|
||||||
If you want to override this for a specific ReRoute add the following to ocelot.json for the specific ReRoute.
|
If you want to override this for a specific Route add the following to ocelot.json for the specific Route.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
"RequestIdKey": "OcRequestId"
|
"RequestIdKey": "OcRequestId"
|
||||||
|
|
||||||
Once Ocelot has identified the incoming requests matching ReRoute object it will set the request id based on the ReRoute configuration.
|
Once Ocelot has identified the incoming requests matching Route object it will set the request id based on the Route configuration.
|
||||||
|
|
||||||
This can lead to a small gotcha. If you set a GlobalConfiguration it is possible to get one request id until the ReRoute is identified and then another after that because the request id key can change. This is by design and is the best solution I can think of at the moment. In this case the OcelotLogger will show the request id and previous request id in the logs.
|
This can lead to a small gotcha. If you set a GlobalConfiguration it is possible to get one request id until the Route is identified and then another after that because the request id key can change. This is by design and is the best solution I can think of at the moment. In this case the OcelotLogger will show the request id and previous request id in the logs.
|
||||||
|
|
||||||
Below is an example of the logging when set at Debug level for a normal request..
|
Below is an example of the logging when set at Debug level for a normal request..
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ Below is an example of the logging when set at Debug level for a normal request.
|
|||||||
dbug: Ocelot.DownstreamRouteFinder.Middleware.DownstreamRouteFinderMiddleware[0]
|
dbug: Ocelot.DownstreamRouteFinder.Middleware.DownstreamRouteFinderMiddleware[0]
|
||||||
requestId: asdf, previousRequestId: no previous request id, message: upstream url path is {upstreamUrlPath},
|
requestId: asdf, previousRequestId: no previous request id, message: upstream url path is {upstreamUrlPath},
|
||||||
dbug: Ocelot.DownstreamRouteFinder.Middleware.DownstreamRouteFinderMiddleware[0]
|
dbug: Ocelot.DownstreamRouteFinder.Middleware.DownstreamRouteFinderMiddleware[0]
|
||||||
requestId: asdf, previousRequestId: no previous request id, message: downstream template is {downstreamRoute.Data.ReRoute.DownstreamPath},
|
requestId: asdf, previousRequestId: no previous request id, message: downstream template is {downstreamRoute.Data.Route.DownstreamPath},
|
||||||
dbug: Ocelot.RateLimit.Middleware.ClientRateLimitMiddleware[0]
|
dbug: Ocelot.RateLimit.Middleware.ClientRateLimitMiddleware[0]
|
||||||
requestId: asdf, previousRequestId: no previous request id, message: EndpointRateLimiting is not enabled for Ocelot.Values.PathTemplate,
|
requestId: asdf, previousRequestId: no previous request id, message: EndpointRateLimiting is not enabled for Ocelot.Values.PathTemplate,
|
||||||
dbug: Ocelot.Authorisation.Middleware.AuthorisationMiddleware[0]
|
dbug: Ocelot.Authorisation.Middleware.AuthorisationMiddleware[0]
|
||||||
|
@ -4,16 +4,16 @@ Routing
|
|||||||
Ocelot's primary functionality is to take incoming http requests and forward them on to a downstream service. Ocelot currently only supports this in the form of another http request (in the future
|
Ocelot's primary functionality is to take incoming http requests and forward them on to a downstream service. Ocelot currently only supports this in the form of another http request (in the future
|
||||||
this could be any transport mechanism).
|
this could be any transport mechanism).
|
||||||
|
|
||||||
Ocelot's describes the routing of one request to another as a ReRoute. In order to get anything working in Ocelot you need to set up a ReRoute in the configuration.
|
Ocelot's describes the routing of one request to another as a Route. In order to get anything working in Ocelot you need to set up a Route in the configuration.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"ReRoutes": [
|
"Routes": [
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
To configure a ReRoute you need to add one to the ReRoutes json array.
|
To configure a Route you need to add one to the Routes json array.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ The UpstreamPathTemplate is the URL that Ocelot will use to identify which Downs
|
|||||||
|
|
||||||
In Ocelot you can add placeholders for variables to your Templates in the form of {something}. The placeholder variable needs to be present in both the DownstreamPathTemplate and UpstreamPathTemplate properties. When it is Ocelot will attempt to substitute the value in the UpstreamPathTemplate placeholder into the DownstreamPathTemplate for each request Ocelot processes.
|
In Ocelot you can add placeholders for variables to your Templates in the form of {something}. The placeholder variable needs to be present in both the DownstreamPathTemplate and UpstreamPathTemplate properties. When it is Ocelot will attempt to substitute the value in the UpstreamPathTemplate placeholder into the DownstreamPathTemplate for each request Ocelot processes.
|
||||||
|
|
||||||
You can also do a catch all type of ReRoute e.g.
|
You can also do a catch all type of Route e.g.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
@ -60,11 +60,11 @@ This will forward any path + query string combinations to the downstream service
|
|||||||
|
|
||||||
The default ReRouting configuration is case insensitive!
|
The default ReRouting configuration is case insensitive!
|
||||||
|
|
||||||
In order to change this you can specify on a per ReRoute basis the following setting.
|
In order to change this you can specify on a per Route basis the following setting.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
"ReRouteIsCaseSensitive": true
|
"RouteIsCaseSensitive": true
|
||||||
|
|
||||||
This means that when Ocelot tries to match the incoming upstream url with an upstream template the
|
This means that when Ocelot tries to match the incoming upstream url with an upstream template the
|
||||||
evaluation will be case sensitive.
|
evaluation will be case sensitive.
|
||||||
@ -91,7 +91,7 @@ If you set up your config like below, all requests will be proxied straight thro
|
|||||||
"UpstreamHttpMethod": [ "Get" ]
|
"UpstreamHttpMethod": [ "Get" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
The catch all has a lower priority than any other ReRoute. If you also have the ReRoute below in your config then Ocelot would match it before the catch all.
|
The catch all has a lower priority than any other Route. If you also have the Route below in your config then Ocelot would match it before the catch all.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ The catch all has a lower priority than any other ReRoute. If you also have the
|
|||||||
Upstream Host
|
Upstream Host
|
||||||
^^^^^^^^^^^^^
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
This feature allows you to have ReRoutes based on the upstream host. This works by looking at the host header the client has used and then using this as part of the information we use to identify a ReRoute.
|
This feature allows you to have Routes based on the upstream host. This works by looking at the host header the client has used and then using this as part of the information we use to identify a Route.
|
||||||
|
|
||||||
In order to use this feature please add the following to your config.
|
In order to use this feature please add the following to your config.
|
||||||
|
|
||||||
@ -131,16 +131,16 @@ In order to use this feature please add the following to your config.
|
|||||||
"UpstreamHost": "somedomain.com"
|
"UpstreamHost": "somedomain.com"
|
||||||
}
|
}
|
||||||
|
|
||||||
The ReRoute above will only be matched when the host header value is somedomain.com.
|
The Route above will only be matched when the host header value is somedomain.com.
|
||||||
|
|
||||||
If you do not set UpstreamHost on a ReRoute then any host header will match it. This means that if you have two ReRoutes that are the same, apart from the UpstreamHost, where one is null and the other set Ocelot will favour the one that has been set.
|
If you do not set UpstreamHost on a Route then any host header will match it. This means that if you have two Routes that are the same, apart from the UpstreamHost, where one is null and the other set Ocelot will favour the one that has been set.
|
||||||
|
|
||||||
This feature was requested as part of `Issue 216 <https://github.com/ThreeMammals/Ocelot/pull/216>`_ .
|
This feature was requested as part of `Issue 216 <https://github.com/ThreeMammals/Ocelot/pull/216>`_ .
|
||||||
|
|
||||||
Priority
|
Priority
|
||||||
^^^^^^^^
|
^^^^^^^^
|
||||||
|
|
||||||
You can define the order you want your ReRoutes to match the Upstream HttpRequest by including a "Priority" property in ocelot.json
|
You can define the order you want your Routes to match the Upstream HttpRequest by including a "Priority" property in ocelot.json
|
||||||
See `Issue 270 <https://github.com/ThreeMammals/Ocelot/pull/270>`_ for reference
|
See `Issue 270 <https://github.com/ThreeMammals/Ocelot/pull/270>`_ for reference
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
@ -149,7 +149,7 @@ See `Issue 270 <https://github.com/ThreeMammals/Ocelot/pull/270>`_ for reference
|
|||||||
"Priority": 0
|
"Priority": 0
|
||||||
}
|
}
|
||||||
|
|
||||||
0 is the lowest priority, Ocelot will always use 0 for /{catchAll} ReRoutes and this is still hardcoded. After that you are free to set any priority you wish.
|
0 is the lowest priority, Ocelot will always use 0 for /{catchAll} Routes and this is still hardcoded. After that you are free to set any priority you wish.
|
||||||
|
|
||||||
e.g. you could have
|
e.g. you could have
|
||||||
|
|
||||||
@ -169,14 +169,14 @@ and
|
|||||||
"Priority": 1
|
"Priority": 1
|
||||||
}
|
}
|
||||||
|
|
||||||
In the example above if you make a request into Ocelot on /goods/delete Ocelot will match /goods/delete ReRoute. Previously it would have matched /goods/{catchAll} (because this is the first ReRoute in the list!).
|
In the example above if you make a request into Ocelot on /goods/delete Ocelot will match /goods/delete Route. Previously it would have matched /goods/{catchAll} (because this is the first Route in the list!).
|
||||||
|
|
||||||
Dynamic Routing
|
Dynamic Routing
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
This feature was requested in `issue 340 <https://github.com/ThreeMammals/Ocelot/issues/340>`_.
|
This feature was requested in `issue 340 <https://github.com/ThreeMammals/Ocelot/issues/340>`_.
|
||||||
|
|
||||||
The idea is to enable dynamic routing when using a service discovery provider so you don't have to provide the ReRoute config. See the docs :ref:`service-discovery` if
|
The idea is to enable dynamic routing when using a service discovery provider so you don't have to provide the Route config. See the docs :ref:`service-discovery` if
|
||||||
this sounds interesting to you.
|
this sounds interesting to you.
|
||||||
|
|
||||||
Query Strings
|
Query Strings
|
||||||
@ -187,7 +187,7 @@ Ocelot allows you to specify a query string as part of the DownstreamPathTemplat
|
|||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"ReRoutes": [
|
"Routes": [
|
||||||
{
|
{
|
||||||
"DownstreamPathTemplate": "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
|
"DownstreamPathTemplate": "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
|
||||||
"UpstreamPathTemplate": "/api/units/{subscriptionId}/{unitId}/updates",
|
"UpstreamPathTemplate": "/api/units/{subscriptionId}/{unitId}/updates",
|
||||||
@ -214,7 +214,7 @@ Ocelot will also allow you to put query string parameters in the UpstreamPathTem
|
|||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"ReRoutes": [
|
"Routes": [
|
||||||
{
|
{
|
||||||
"DownstreamPathTemplate": "/api/units/{subscriptionId}/{unitId}/updates",
|
"DownstreamPathTemplate": "/api/units/{subscriptionId}/{unitId}/updates",
|
||||||
"UpstreamPathTemplate": "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
|
"UpstreamPathTemplate": "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
|
||||||
|
@ -4,7 +4,7 @@ Service Discovery
|
|||||||
=================
|
=================
|
||||||
|
|
||||||
Ocelot allows you to specify a service discovery provider and will use this to find the host and port for the downstream service Ocelot is forwarding a request to. At the moment this is only supported in the
|
Ocelot allows you to specify a service discovery provider and will use this to find the host and port for the downstream service Ocelot is forwarding a request to. At the moment this is only supported in the
|
||||||
GlobalConfiguration section which means the same service discovery provider will be used for all ReRoutes you specify a ServiceName for at ReRoute level.
|
GlobalConfiguration section which means the same service discovery provider will be used for all Routes you specify a ServiceName for at Route level.
|
||||||
|
|
||||||
Consul
|
Consul
|
||||||
^^^^^^
|
^^^^^^
|
||||||
@ -34,9 +34,9 @@ Please note the Scheme option defauls to HTTP. It was added in this `PR <https:/
|
|||||||
"Type": "Consul"
|
"Type": "Consul"
|
||||||
}
|
}
|
||||||
|
|
||||||
In the future we can add a feature that allows ReRoute specfic configuration.
|
In the future we can add a feature that allows Route specfic configuration.
|
||||||
|
|
||||||
In order to tell Ocelot a ReRoute is to use the service discovery provider for its host and port you must add the ServiceName and load balancer you wish to use when making requests downstream. At the moment Ocelot has a RoundRobin and LeastConnection algorithm you can use. If no load balancer is specified Ocelot will not load balance requests.
|
In order to tell Ocelot a Route is to use the service discovery provider for its host and port you must add the ServiceName and load balancer you wish to use when making requests downstream. At the moment Ocelot has a RoundRobin and LeastConnection algorithm you can use. If no load balancer is specified Ocelot will not load balance requests.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
@ -157,16 +157,16 @@ This feature was requested in `issue 340 <https://github.com/ThreeMammals/Ocelot
|
|||||||
An example of this would be calling Ocelot with a url like https://api.mywebsite.com/product/products. Ocelot will take the first segment of
|
An example of this would be calling Ocelot with a url like https://api.mywebsite.com/product/products. Ocelot will take the first segment of
|
||||||
the path which is product and use it as a key to look up the service in Consul. If Consul returns a service Ocelot will request it on whatever host and port comes back from Consul plus the remaining path segments in this case products thus making the downstream call http://hostfromconsul:portfromconsul/products. Ocelot will apprend any query string to the downstream url as normal.
|
the path which is product and use it as a key to look up the service in Consul. If Consul returns a service Ocelot will request it on whatever host and port comes back from Consul plus the remaining path segments in this case products thus making the downstream call http://hostfromconsul:portfromconsul/products. Ocelot will apprend any query string to the downstream url as normal.
|
||||||
|
|
||||||
In order to enable dynamic routing you need to have 0 ReRoutes in your config. At the moment you cannot mix dynamic and configuration ReRoutes. In addition to this you need to specify the Service Discovery provider details as outlined above and the downstream http/https scheme as DownstreamScheme.
|
In order to enable dynamic routing you need to have 0 Routes in your config. At the moment you cannot mix dynamic and configuration Routes. In addition to this you need to specify the Service Discovery provider details as outlined above and the downstream http/https scheme as DownstreamScheme.
|
||||||
|
|
||||||
In addition to that you can set RateLimitOptions, QoSOptions, LoadBalancerOptions and HttpHandlerOptions, DownstreamScheme (You might want to call Ocelot on https but talk to private services over http) that will be applied to all of the dynamic ReRoutes.
|
In addition to that you can set RateLimitOptions, QoSOptions, LoadBalancerOptions and HttpHandlerOptions, DownstreamScheme (You might want to call Ocelot on https but talk to private services over http) that will be applied to all of the dynamic Routes.
|
||||||
|
|
||||||
The config might look something like
|
The config might look something like
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"ReRoutes": [],
|
"Routes": [],
|
||||||
"Aggregates": [],
|
"Aggregates": [],
|
||||||
"GlobalConfiguration": {
|
"GlobalConfiguration": {
|
||||||
"RequestIdKey": null,
|
"RequestIdKey": null,
|
||||||
@ -204,12 +204,12 @@ The config might look something like
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ocelot also allows you to set DynamicReRoutes which lets you set rate limiting rules per downstream service. This is useful if you have for example a product and search service and you want to rate limit one more than the other. An example of this would be as follows.
|
Ocelot also allows you to set DynamicRoutes which lets you set rate limiting rules per downstream service. This is useful if you have for example a product and search service and you want to rate limit one more than the other. An example of this would be as follows.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"DynamicReRoutes": [
|
"DynamicRoutes": [
|
||||||
{
|
{
|
||||||
"ServiceName": "product",
|
"ServiceName": "product",
|
||||||
"RateLimitRule": {
|
"RateLimitRule": {
|
||||||
@ -239,6 +239,6 @@ Ocelot also allows you to set DynamicReRoutes which lets you set rate limiting r
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
This configuration means that if you have a request come into Ocelot on /product/* then dynamic routing will kick in and ocelot will use the rate limiting set against the product service in the DynamicReRoutes section.
|
This configuration means that if you have a request come into Ocelot on /product/* then dynamic routing will kick in and ocelot will use the rate limiting set against the product service in the DynamicRoutes section.
|
||||||
|
|
||||||
Please take a look through all of the docs to understand these options.
|
Please take a look through all of the docs to understand these options.
|
||||||
|
@ -3,14 +3,14 @@ Service Fabric
|
|||||||
|
|
||||||
If you have services deployed in Service Fabric you will normally use the naming service to access them.
|
If you have services deployed in Service Fabric you will normally use the naming service to access them.
|
||||||
|
|
||||||
The following example shows how to set up a ReRoute that will work in Service Fabric. The most important thing is the ServiceName which is made up of the Service Fabric application name then the specific service name. We also need to set up the ServiceDiscoveryProvider in GlobalConfiguration. The example here shows a typical configuration. It assumes service fabric is running on localhost and that the naming service is on port 19081.
|
The following example shows how to set up a Route that will work in Service Fabric. The most important thing is the ServiceName which is made up of the Service Fabric application name then the specific service name. We also need to set up the ServiceDiscoveryProvider in GlobalConfiguration. The example here shows a typical configuration. It assumes service fabric is running on localhost and that the naming service is on port 19081.
|
||||||
|
|
||||||
The example below is taken from the samples folder so please check it if this doesnt make sense!
|
The example below is taken from the samples folder so please check it if this doesnt make sense!
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"ReRoutes": [
|
"Routes": [
|
||||||
{
|
{
|
||||||
"DownstreamPathTemplate": "/api/values",
|
"DownstreamPathTemplate": "/api/values",
|
||||||
"UpstreamPathTemplate": "/EquipmentInterfaces",
|
"UpstreamPathTemplate": "/EquipmentInterfaces",
|
||||||
|
@ -12,7 +12,7 @@ can be found `here <https://github.com/ThreeMammals/Ocelot.Tracing.Butterfly>`_.
|
|||||||
|
|
||||||
In order to use the tracing please read the Butterfly documentation.
|
In order to use the tracing please read the Butterfly documentation.
|
||||||
|
|
||||||
In ocelot you need to do the following if you wish to trace a ReRoute.
|
In ocelot you need to do the following if you wish to trace a Route.
|
||||||
|
|
||||||
``Install-Package Ocelot.Tracing.Butterfly``
|
``Install-Package Ocelot.Tracing.Butterfly``
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ In your ConfigureServices method
|
|||||||
option.Service = "Ocelot";
|
option.Service = "Ocelot";
|
||||||
});
|
});
|
||||||
|
|
||||||
Then in your ocelot.json add the following to the ReRoute you want to trace..
|
Then in your ocelot.json add the following to the Route you want to trace..
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
@ -38,4 +38,4 @@ Then in your ocelot.json add the following to the ReRoute you want to trace..
|
|||||||
"UseTracing": true
|
"UseTracing": true
|
||||||
},
|
},
|
||||||
|
|
||||||
Ocelot will now send tracing information to Butterfly when this ReRoute is called.
|
Ocelot will now send tracing information to Butterfly when this Route is called.
|
||||||
|
@ -15,7 +15,7 @@ In your Configure method you need to tell your application to use WebSockets.
|
|||||||
app.UseOcelot().Wait();
|
app.UseOcelot().Wait();
|
||||||
})
|
})
|
||||||
|
|
||||||
Then in your ocelot.json add the following to proxy a ReRoute using websockets.
|
Then in your ocelot.json add the following to proxy a Route using websockets.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
@ -54,12 +54,12 @@ In your Configure method you need to tell your application to use SignalR.
|
|||||||
app.UseOcelot().Wait();
|
app.UseOcelot().Wait();
|
||||||
})
|
})
|
||||||
|
|
||||||
Then in your ocelot.json add the following to proxy a ReRoute using SignalR. Note normal Ocelot routing rules apply the main thing is the scheme which is set to "ws".
|
Then in your ocelot.json add the following to proxy a Route using SignalR. Note normal Ocelot routing rules apply the main thing is the scheme which is set to "ws".
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"ReRoutes": [
|
"Routes": [
|
||||||
{
|
{
|
||||||
"DownstreamPathTemplate": "/{catchAll}",
|
"DownstreamPathTemplate": "/{catchAll}",
|
||||||
"DownstreamScheme": "ws",
|
"DownstreamScheme": "ws",
|
||||||
@ -84,7 +84,7 @@ Supported
|
|||||||
2. Routing
|
2. Routing
|
||||||
3. Service Discovery
|
3. Service Discovery
|
||||||
|
|
||||||
This means that you can set up your downstream services running websockets and either have multiple DownstreamHostAndPorts in your ReRoute config or hook your ReRoute into a service discovery provider and then load balance requests...Which I think is pretty cool :)
|
This means that you can set up your downstream services running websockets and either have multiple DownstreamHostAndPorts in your Route config or hook your Route into a service discovery provider and then load balance requests...Which I think is pretty cool :)
|
||||||
|
|
||||||
Not Supported
|
Not Supported
|
||||||
^^^^^^^^^^^^^
|
^^^^^^^^^^^^^
|
||||||
|
@ -22,7 +22,7 @@ The following is a very basic ocelot.json. It won't do anything but should get O
|
|||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"ReRoutes": [],
|
"Routes": [],
|
||||||
"GlobalConfiguration": {
|
"GlobalConfiguration": {
|
||||||
"BaseUrl": "https://api.mybusiness.com"
|
"BaseUrl": "https://api.mybusiness.com"
|
||||||
}
|
}
|
||||||
@ -33,7 +33,7 @@ If you want some example that actually does something use the following:
|
|||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"ReRoutes": [
|
"Routes": [
|
||||||
{
|
{
|
||||||
"DownstreamPathTemplate": "/todos/{id}",
|
"DownstreamPathTemplate": "/todos/{id}",
|
||||||
"DownstreamScheme": "https",
|
"DownstreamScheme": "https",
|
||||||
@ -124,7 +124,7 @@ The following is a very basic ocelot.json. It won't do anything but should get O
|
|||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
"ReRoutes": [],
|
"Routes": [],
|
||||||
"GlobalConfiguration": {}
|
"GlobalConfiguration": {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
11
helpers.txt
11
helpers.txt
@ -1,11 +0,0 @@
|
|||||||
var downstreamReRoute = RequestScopedDataRepository.Get<DownstreamReRoute>("DownstreamReRoute");
|
|
||||||
// todo check downstreamReRoute is ok
|
|
||||||
|
|
||||||
var errors = RequestScopedDataRepository.Get<List<Error>>("Errors");
|
|
||||||
// todo check errors is ok
|
|
||||||
|
|
||||||
var downstreamResponse = RequestScopedDataRepository.Get<DownstreamResponse>("DownstreamResponse");
|
|
||||||
// todo check downstreamResponse is ok
|
|
||||||
|
|
||||||
var context = RequestScopedDataRepository.Get<DownstreamContext>("DownstreamContext").Data;
|
|
||||||
// todo check downstreamcontext is ok
|
|
@ -48,7 +48,7 @@
|
|||||||
],
|
],
|
||||||
"body": {
|
"body": {
|
||||||
"mode": "raw",
|
"mode": "raw",
|
||||||
"raw": "{\r\n \"reRoutes\": [\r\n {\r\n \"downstreamPathTemplate\": \"/{everything}\",\r\n \"upstreamPathTemplate\": \"/templates/{everything}\",\r\n \"upstreamHttpMethod\": [\r\n \"GET\"\r\n ],\r\n \"addHeadersToRequest\": {},\r\n \"upstreamHeaderTransform\": {},\r\n \"downstreamHeaderTransform\": {},\r\n \"addClaimsToRequest\": {},\r\n \"routeClaimsRequirement\": {},\r\n \"addQueriesToRequest\": {},\r\n \"requestIdKey\": null,\r\n \"fileCacheOptions\": {\r\n \"ttlSeconds\": 0,\r\n \"region\": null\r\n },\r\n \"reRouteIsCaseSensitive\": false,\r\n \"downstreamScheme\": \"http\",\r\n \"qoSOptions\": {\r\n \"exceptionsAllowedBeforeBreaking\": 0,\r\n \"durationOfBreak\": 0,\r\n \"timeoutValue\": 0\r\n },\r\n \"loadBalancerOptions\": {\r\n \"type\": null,\r\n \"key\": null,\r\n \"expiry\": 0\r\n },\r\n \"rateLimitOptions\": {\r\n \"clientWhitelist\": [],\r\n \"enableRateLimiting\": false,\r\n \"period\": null,\r\n \"periodTimespan\": 0,\r\n \"limit\": 0\r\n },\r\n \"authenticationOptions\": {\r\n \"authenticationProviderKey\": null,\r\n \"allowedScopes\": []\r\n },\r\n \"httpHandlerOptions\": {\r\n \"allowAutoRedirect\": false,\r\n \"useCookieContainer\": false,\r\n \"useTracing\": false,\r\n \"useProxy\": true\r\n },\r\n \"downstreamHostAndPorts\": [\r\n {\r\n \"host\": \"localhost\",\r\n \"port\": 50689\r\n }\r\n ],\r\n \"upstreamHost\": null,\r\n \"key\": null,\r\n \"delegatingHandlers\": [],\r\n \"priority\": 1,\r\n \"timeout\": 0,\r\n \"dangerousAcceptAnyServerCertificateValidator\": false\r\n }\r\n ],\r\n \"aggregates\": [],\r\n \"globalConfiguration\": {\r\n \"requestIdKey\": \"Request-Id\",\r\n \"rateLimitOptions\": {\r\n \"clientIdHeader\": \"ClientId\",\r\n \"quotaExceededMessage\": null,\r\n \"rateLimitCounterPrefix\": \"ocelot\",\r\n \"disableRateLimitHeaders\": false,\r\n \"httpStatusCode\": 429\r\n },\r\n \"qoSOptions\": {\r\n \"exceptionsAllowedBeforeBreaking\": 0,\r\n \"durationOfBreak\": 0,\r\n \"timeoutValue\": 0\r\n },\r\n \"baseUrl\": \"http://localhost:55580\",\r\n \"loadBalancerOptions\": {\r\n \"type\": null,\r\n \"key\": null,\r\n \"expiry\": 0\r\n },\r\n \"downstreamScheme\": null,\r\n \"httpHandlerOptions\": {\r\n \"allowAutoRedirect\": false,\r\n \"useCookieContainer\": false,\r\n \"useTracing\": false,\r\n \"useProxy\": true\r\n }\r\n }\r\n}"
|
"raw": "{\r\n \"routes\": [\r\n {\r\n \"downstreamPathTemplate\": \"/{everything}\",\r\n \"upstreamPathTemplate\": \"/templates/{everything}\",\r\n \"upstreamHttpMethod\": [\r\n \"GET\"\r\n ],\r\n \"addHeadersToRequest\": {},\r\n \"upstreamHeaderTransform\": {},\r\n \"downstreamHeaderTransform\": {},\r\n \"addClaimsToRequest\": {},\r\n \"routeClaimsRequirement\": {},\r\n \"addQueriesToRequest\": {},\r\n \"requestIdKey\": null,\r\n \"fileCacheOptions\": {\r\n \"ttlSeconds\": 0,\r\n \"region\": null\r\n },\r\n \"routeIsCaseSensitive\": false,\r\n \"downstreamScheme\": \"http\",\r\n \"qoSOptions\": {\r\n \"exceptionsAllowedBeforeBreaking\": 0,\r\n \"durationOfBreak\": 0,\r\n \"timeoutValue\": 0\r\n },\r\n \"loadBalancerOptions\": {\r\n \"type\": null,\r\n \"key\": null,\r\n \"expiry\": 0\r\n },\r\n \"rateLimitOptions\": {\r\n \"clientWhitelist\": [],\r\n \"enableRateLimiting\": false,\r\n \"period\": null,\r\n \"periodTimespan\": 0,\r\n \"limit\": 0\r\n },\r\n \"authenticationOptions\": {\r\n \"authenticationProviderKey\": null,\r\n \"allowedScopes\": []\r\n },\r\n \"httpHandlerOptions\": {\r\n \"allowAutoRedirect\": false,\r\n \"useCookieContainer\": false,\r\n \"useTracing\": false,\r\n \"useProxy\": true\r\n },\r\n \"downstreamHostAndPorts\": [\r\n {\r\n \"host\": \"localhost\",\r\n \"port\": 50689\r\n }\r\n ],\r\n \"upstreamHost\": null,\r\n \"key\": null,\r\n \"delegatingHandlers\": [],\r\n \"priority\": 1,\r\n \"timeout\": 0,\r\n \"dangerousAcceptAnyServerCertificateValidator\": false\r\n }\r\n ],\r\n \"aggregates\": [],\r\n \"globalConfiguration\": {\r\n \"requestIdKey\": \"Request-Id\",\r\n \"rateLimitOptions\": {\r\n \"clientIdHeader\": \"ClientId\",\r\n \"quotaExceededMessage\": null,\r\n \"rateLimitCounterPrefix\": \"ocelot\",\r\n \"disableRateLimitHeaders\": false,\r\n \"httpStatusCode\": 429\r\n },\r\n \"qoSOptions\": {\r\n \"exceptionsAllowedBeforeBreaking\": 0,\r\n \"durationOfBreak\": 0,\r\n \"timeoutValue\": 0\r\n },\r\n \"baseUrl\": \"http://localhost:55580\",\r\n \"loadBalancerOptions\": {\r\n \"type\": null,\r\n \"key\": null,\r\n \"expiry\": 0\r\n },\r\n \"downstreamScheme\": null,\r\n \"httpHandlerOptions\": {\r\n \"allowAutoRedirect\": false,\r\n \"useCookieContainer\": false,\r\n \"useTracing\": false,\r\n \"useProxy\": true\r\n }\r\n }\r\n}"
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
"raw": "http://localhost:5000/administration/configuration",
|
"raw": "http://localhost:5000/administration/configuration",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"reRoutes": [
|
"routes": [
|
||||||
{
|
{
|
||||||
"downstreamPathTemplate": "/{everything}",
|
"downstreamPathTemplate": "/{everything}",
|
||||||
"upstreamPathTemplate": "/templates/{everything}",
|
"upstreamPathTemplate": "/templates/{everything}",
|
||||||
@ -18,7 +18,7 @@
|
|||||||
"ttlSeconds": 0,
|
"ttlSeconds": 0,
|
||||||
"region": null
|
"region": null
|
||||||
},
|
},
|
||||||
"reRouteIsCaseSensitive": false,
|
"routeIsCaseSensitive": false,
|
||||||
"downstreamScheme": "http",
|
"downstreamScheme": "http",
|
||||||
"qoSOptions": {
|
"qoSOptions": {
|
||||||
"exceptionsAllowedBeforeBreaking": 0,
|
"exceptionsAllowedBeforeBreaking": 0,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"ReRoutes": [
|
"Routes": [
|
||||||
{
|
{
|
||||||
"DownstreamPathTemplate": "/service/stats/collected",
|
"DownstreamPathTemplate": "/service/stats/collected",
|
||||||
"DownstreamScheme": "http",
|
"DownstreamScheme": "http",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"ReRoutes": [
|
"Routes": [
|
||||||
{
|
{
|
||||||
"DownstreamPathTemplate": "/todos/{id}",
|
"DownstreamPathTemplate": "/todos/{id}",
|
||||||
"DownstreamScheme": "https",
|
"DownstreamScheme": "https",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"ReRoutes": [
|
"Routes": [
|
||||||
{
|
{
|
||||||
"DownstreamPathTemplate": "/api/Category",
|
"DownstreamPathTemplate": "/api/Category",
|
||||||
"DownstreamScheme": "http",
|
"DownstreamScheme": "http",
|
||||||
|
@ -51,7 +51,7 @@ Please note this project never goes out to another service, it just gets the dat
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"ReRoutes": [
|
"Routes": [
|
||||||
{
|
{
|
||||||
"DownstreamPathTemplate": "/graphql",
|
"DownstreamPathTemplate": "/graphql",
|
||||||
"DownstreamScheme": "http",
|
"DownstreamScheme": "http",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"ReRoutes": [
|
"Routes": [
|
||||||
{
|
{
|
||||||
"DownstreamPathTemplate": "/",
|
"DownstreamPathTemplate": "/",
|
||||||
"DownstreamScheme": "http",
|
"DownstreamScheme": "http",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"ReRoutes": [
|
"Routes": [
|
||||||
{
|
{
|
||||||
"DownstreamPathTemplate": "/api/values",
|
"DownstreamPathTemplate": "/api/values",
|
||||||
"DownstreamScheme": "http",
|
"DownstreamScheme": "http",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"ReRoutes": [
|
"Routes": [
|
||||||
{
|
{
|
||||||
"DownstreamPathTemplate": "/api/values",
|
"DownstreamPathTemplate": "/api/values",
|
||||||
"UpstreamPathTemplate": "/EquipmentInterfaces",
|
"UpstreamPathTemplate": "/EquipmentInterfaces",
|
||||||
|
@ -6,13 +6,13 @@
|
|||||||
|
|
||||||
public static class ConsulProviderFactory
|
public static class ConsulProviderFactory
|
||||||
{
|
{
|
||||||
public static ServiceDiscoveryFinderDelegate Get = (provider, config, reRoute) =>
|
public static ServiceDiscoveryFinderDelegate Get = (provider, config, route) =>
|
||||||
{
|
{
|
||||||
var factory = provider.GetService<IOcelotLoggerFactory>();
|
var factory = provider.GetService<IOcelotLoggerFactory>();
|
||||||
|
|
||||||
var consulFactory = provider.GetService<IConsulClientFactory>();
|
var consulFactory = provider.GetService<IConsulClientFactory>();
|
||||||
|
|
||||||
var consulRegistryConfiguration = new ConsulRegistryConfiguration(config.Scheme, config.Host, config.Port, reRoute.ServiceName, config.Token);
|
var consulRegistryConfiguration = new ConsulRegistryConfiguration(config.Scheme, config.Host, config.Port, route.ServiceName, config.Token);
|
||||||
|
|
||||||
var consulServiceDiscoveryProvider = new Consul(consulRegistryConfiguration, factory, consulFactory);
|
var consulServiceDiscoveryProvider = new Consul(consulRegistryConfiguration, factory, consulFactory);
|
||||||
|
|
||||||
|
@ -6,13 +6,13 @@
|
|||||||
|
|
||||||
public static class EurekaProviderFactory
|
public static class EurekaProviderFactory
|
||||||
{
|
{
|
||||||
public static ServiceDiscoveryFinderDelegate Get = (provider, config, reRoute) =>
|
public static ServiceDiscoveryFinderDelegate Get = (provider, config, route) =>
|
||||||
{
|
{
|
||||||
var client = provider.GetService<IDiscoveryClient>();
|
var client = provider.GetService<IDiscoveryClient>();
|
||||||
|
|
||||||
if (config.Type?.ToLower() == "eureka" && client != null)
|
if (config.Type?.ToLower() == "eureka" && client != null)
|
||||||
{
|
{
|
||||||
return new Eureka(reRoute.ServiceName, client);
|
return new Eureka(route.ServiceName, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -9,20 +9,20 @@ namespace Ocelot.Provider.Kubernetes
|
|||||||
{
|
{
|
||||||
public static class KubernetesProviderFactory
|
public static class KubernetesProviderFactory
|
||||||
{
|
{
|
||||||
public static ServiceDiscoveryFinderDelegate Get = (provider, config, reRoute) =>
|
public static ServiceDiscoveryFinderDelegate Get = (provider, config, route) =>
|
||||||
{
|
{
|
||||||
var factory = provider.GetService<IOcelotLoggerFactory>();
|
var factory = provider.GetService<IOcelotLoggerFactory>();
|
||||||
return GetKubeProvider(provider, config, reRoute, factory);
|
return GetKubeProvider(provider, config, route, factory);
|
||||||
};
|
};
|
||||||
|
|
||||||
private static ServiceDiscovery.Providers.IServiceDiscoveryProvider GetKubeProvider(IServiceProvider provider, ServiceProviderConfiguration config, DownstreamReRoute reRoute, IOcelotLoggerFactory factory)
|
private static ServiceDiscovery.Providers.IServiceDiscoveryProvider GetKubeProvider(IServiceProvider provider, ServiceProviderConfiguration config, DownstreamRoute route, IOcelotLoggerFactory factory)
|
||||||
{
|
{
|
||||||
var kubeClient = provider.GetService<IKubeApiClient>();
|
var kubeClient = provider.GetService<IKubeApiClient>();
|
||||||
|
|
||||||
var k8sRegistryConfiguration = new KubeRegistryConfiguration()
|
var k8sRegistryConfiguration = new KubeRegistryConfiguration()
|
||||||
{
|
{
|
||||||
KeyOfServiceInK8s = reRoute.ServiceName,
|
KeyOfServiceInK8s = route.ServiceName,
|
||||||
KubeNamespace = string.IsNullOrEmpty(reRoute.ServiceNamespace) ? config.Namespace : reRoute.ServiceNamespace
|
KubeNamespace = string.IsNullOrEmpty(route.ServiceNamespace) ? config.Namespace : route.ServiceNamespace
|
||||||
};
|
};
|
||||||
|
|
||||||
var k8sServiceDiscoveryProvider = new KubernetesServiceDiscoveryProvider(k8sRegistryConfiguration, factory, kubeClient);
|
var k8sServiceDiscoveryProvider = new KubernetesServiceDiscoveryProvider(k8sRegistryConfiguration, factory, kubeClient);
|
||||||
|
@ -26,9 +26,9 @@
|
|||||||
|
|
||||||
builder.Services.AddSingleton(errorMapping);
|
builder.Services.AddSingleton(errorMapping);
|
||||||
|
|
||||||
DelegatingHandler QosDelegatingHandlerDelegate(DownstreamReRoute reRoute, IOcelotLoggerFactory logger)
|
DelegatingHandler QosDelegatingHandlerDelegate(DownstreamRoute route, IOcelotLoggerFactory logger)
|
||||||
{
|
{
|
||||||
return new PollyCircuitBreakingDelegatingHandler(new PollyQoSProvider(reRoute, logger), logger);
|
return new PollyCircuitBreakingDelegatingHandler(new PollyQoSProvider(route, logger), logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.Services.AddSingleton((QosDelegatingHandlerDelegate)QosDelegatingHandlerDelegate);
|
builder.Services.AddSingleton((QosDelegatingHandlerDelegate)QosDelegatingHandlerDelegate);
|
||||||
|
@ -14,23 +14,23 @@ namespace Ocelot.Provider.Polly
|
|||||||
private readonly AsyncTimeoutPolicy _timeoutPolicy;
|
private readonly AsyncTimeoutPolicy _timeoutPolicy;
|
||||||
private readonly IOcelotLogger _logger;
|
private readonly IOcelotLogger _logger;
|
||||||
|
|
||||||
public PollyQoSProvider(DownstreamReRoute reRoute, IOcelotLoggerFactory loggerFactory)
|
public PollyQoSProvider(DownstreamRoute route, IOcelotLoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
_logger = loggerFactory.CreateLogger<PollyQoSProvider>();
|
_logger = loggerFactory.CreateLogger<PollyQoSProvider>();
|
||||||
|
|
||||||
Enum.TryParse(reRoute.QosOptions.TimeoutStrategy, out TimeoutStrategy strategy);
|
Enum.TryParse(route.QosOptions.TimeoutStrategy, out TimeoutStrategy strategy);
|
||||||
|
|
||||||
_timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(reRoute.QosOptions.TimeoutValue), strategy);
|
_timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(route.QosOptions.TimeoutValue), strategy);
|
||||||
|
|
||||||
if (reRoute.QosOptions.ExceptionsAllowedBeforeBreaking > 0)
|
if (route.QosOptions.ExceptionsAllowedBeforeBreaking > 0)
|
||||||
{
|
{
|
||||||
_circuitBreakerPolicy = Policy
|
_circuitBreakerPolicy = Policy
|
||||||
.Handle<HttpRequestException>()
|
.Handle<HttpRequestException>()
|
||||||
.Or<TimeoutRejectedException>()
|
.Or<TimeoutRejectedException>()
|
||||||
.Or<TimeoutException>()
|
.Or<TimeoutException>()
|
||||||
.CircuitBreakerAsync(
|
.CircuitBreakerAsync(
|
||||||
exceptionsAllowedBeforeBreaking: reRoute.QosOptions.ExceptionsAllowedBeforeBreaking,
|
exceptionsAllowedBeforeBreaking: route.QosOptions.ExceptionsAllowedBeforeBreaking,
|
||||||
durationOfBreak: TimeSpan.FromMilliseconds(reRoute.QosOptions.DurationOfBreak),
|
durationOfBreak: TimeSpan.FromMilliseconds(route.QosOptions.DurationOfBreak),
|
||||||
onBreak: (ex, breakDelay) =>
|
onBreak: (ex, breakDelay) =>
|
||||||
{
|
{
|
||||||
_logger.LogError(
|
_logger.LogError(
|
||||||
|
@ -21,13 +21,13 @@
|
|||||||
|
|
||||||
public async Task Invoke(HttpContext httpContext)
|
public async Task Invoke(HttpContext httpContext)
|
||||||
{
|
{
|
||||||
var downstreamReRoute = httpContext.Items.DownstreamReRoute();
|
var downstreamRoute = httpContext.Items.DownstreamRoute();
|
||||||
|
|
||||||
if (httpContext.Request.Method.ToUpper() != "OPTIONS" && IsAuthenticatedRoute(downstreamReRoute))
|
if (httpContext.Request.Method.ToUpper() != "OPTIONS" && IsAuthenticatedRoute(downstreamRoute))
|
||||||
{
|
{
|
||||||
Logger.LogInformation($"{httpContext.Request.Path} is an authenticated route. {MiddlewareName} checking if client is authenticated");
|
Logger.LogInformation($"{httpContext.Request.Path} is an authenticated route. {MiddlewareName} checking if client is authenticated");
|
||||||
|
|
||||||
var result = await httpContext.AuthenticateAsync(downstreamReRoute.AuthenticationOptions.AuthenticationProviderKey);
|
var result = await httpContext.AuthenticateAsync(downstreamRoute.AuthenticationOptions.AuthenticationProviderKey);
|
||||||
|
|
||||||
httpContext.User = result.Principal;
|
httpContext.User = result.Principal;
|
||||||
|
|
||||||
@ -54,9 +54,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsAuthenticatedRoute(DownstreamReRoute reRoute)
|
private static bool IsAuthenticatedRoute(DownstreamRoute route)
|
||||||
{
|
{
|
||||||
return reRoute.IsAuthenticated;
|
return route.IsAuthenticated;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,13 +27,13 @@
|
|||||||
|
|
||||||
public async Task Invoke(HttpContext httpContext)
|
public async Task Invoke(HttpContext httpContext)
|
||||||
{
|
{
|
||||||
var downstreamReRoute = httpContext.Items.DownstreamReRoute();
|
var downstreamRoute = httpContext.Items.DownstreamRoute();
|
||||||
|
|
||||||
if (!IsOptionsHttpMethod(httpContext) && IsAuthenticatedRoute(downstreamReRoute))
|
if (!IsOptionsHttpMethod(httpContext) && IsAuthenticatedRoute(downstreamRoute))
|
||||||
{
|
{
|
||||||
Logger.LogInformation("route is authenticated scopes must be checked");
|
Logger.LogInformation("route is authenticated scopes must be checked");
|
||||||
|
|
||||||
var authorised = _scopesAuthoriser.Authorise(httpContext.User, downstreamReRoute.AuthenticationOptions.AllowedScopes);
|
var authorised = _scopesAuthoriser.Authorise(httpContext.User, downstreamRoute.AuthenticationOptions.AllowedScopes);
|
||||||
|
|
||||||
if (authorised.IsError)
|
if (authorised.IsError)
|
||||||
{
|
{
|
||||||
@ -52,15 +52,15 @@
|
|||||||
Logger.LogWarning("user scopes is not authorised setting pipeline error");
|
Logger.LogWarning("user scopes is not authorised setting pipeline error");
|
||||||
|
|
||||||
httpContext.Items.SetError(new UnauthorisedError(
|
httpContext.Items.SetError(new UnauthorisedError(
|
||||||
$"{httpContext.User.Identity.Name} unable to access {downstreamReRoute.UpstreamPathTemplate.OriginalValue}"));
|
$"{httpContext.User.Identity.Name} unable to access {downstreamRoute.UpstreamPathTemplate.OriginalValue}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsOptionsHttpMethod(httpContext) && IsAuthorisedRoute(downstreamReRoute))
|
if (!IsOptionsHttpMethod(httpContext) && IsAuthorisedRoute(downstreamRoute))
|
||||||
{
|
{
|
||||||
Logger.LogInformation("route is authorised");
|
Logger.LogInformation("route is authorised");
|
||||||
|
|
||||||
var authorised = _claimsAuthoriser.Authorise(httpContext.User, downstreamReRoute.RouteClaimsRequirement, httpContext.Items.TemplatePlaceholderNameAndValues());
|
var authorised = _claimsAuthoriser.Authorise(httpContext.User, downstreamRoute.RouteClaimsRequirement, httpContext.Items.TemplatePlaceholderNameAndValues());
|
||||||
|
|
||||||
if (authorised.IsError)
|
if (authorised.IsError)
|
||||||
{
|
{
|
||||||
@ -72,19 +72,19 @@
|
|||||||
|
|
||||||
if (IsAuthorised(authorised))
|
if (IsAuthorised(authorised))
|
||||||
{
|
{
|
||||||
Logger.LogInformation($"{httpContext.User.Identity.Name} has succesfully been authorised for {downstreamReRoute.UpstreamPathTemplate.OriginalValue}.");
|
Logger.LogInformation($"{httpContext.User.Identity.Name} has succesfully been authorised for {downstreamRoute.UpstreamPathTemplate.OriginalValue}.");
|
||||||
await _next.Invoke(httpContext);
|
await _next.Invoke(httpContext);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.LogWarning($"{httpContext.User.Identity.Name} is not authorised to access {downstreamReRoute.UpstreamPathTemplate.OriginalValue}. Setting pipeline error");
|
Logger.LogWarning($"{httpContext.User.Identity.Name} is not authorised to access {downstreamRoute.UpstreamPathTemplate.OriginalValue}. Setting pipeline error");
|
||||||
|
|
||||||
httpContext.Items.SetError(new UnauthorisedError($"{httpContext.User.Identity.Name} is not authorised to access {downstreamReRoute.UpstreamPathTemplate.OriginalValue}"));
|
httpContext.Items.SetError(new UnauthorisedError($"{httpContext.User.Identity.Name} is not authorised to access {downstreamRoute.UpstreamPathTemplate.OriginalValue}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.LogInformation($"{downstreamReRoute.DownstreamPathTemplate.Value} route does not require user to be authorised");
|
Logger.LogInformation($"{downstreamRoute.DownstreamPathTemplate.Value} route does not require user to be authorised");
|
||||||
await _next.Invoke(httpContext);
|
await _next.Invoke(httpContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,14 +94,14 @@
|
|||||||
return authorised.Data;
|
return authorised.Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsAuthenticatedRoute(DownstreamReRoute reRoute)
|
private static bool IsAuthenticatedRoute(DownstreamRoute route)
|
||||||
{
|
{
|
||||||
return reRoute.IsAuthenticated;
|
return route.IsAuthenticated;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsAuthorisedRoute(DownstreamReRoute reRoute)
|
private static bool IsAuthorisedRoute(DownstreamRoute route)
|
||||||
{
|
{
|
||||||
return reRoute.IsAuthorised;
|
return route.IsAuthorised;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsOptionsHttpMethod(HttpContext httpContext)
|
private static bool IsOptionsHttpMethod(HttpContext httpContext)
|
||||||
|
@ -4,6 +4,6 @@ namespace Ocelot.Cache
|
|||||||
{
|
{
|
||||||
public interface IRegionCreator
|
public interface IRegionCreator
|
||||||
{
|
{
|
||||||
string Create(FileReRoute reRoute);
|
string Create(FileRoute route);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -29,9 +29,9 @@
|
|||||||
|
|
||||||
public async Task Invoke(HttpContext httpContext)
|
public async Task Invoke(HttpContext httpContext)
|
||||||
{
|
{
|
||||||
var downstreamReRoute = httpContext.Items.DownstreamReRoute();
|
var downstreamRoute = httpContext.Items.DownstreamRoute();
|
||||||
|
|
||||||
if (!downstreamReRoute.IsCached)
|
if (!downstreamRoute.IsCached)
|
||||||
{
|
{
|
||||||
await _next.Invoke(httpContext);
|
await _next.Invoke(httpContext);
|
||||||
return;
|
return;
|
||||||
@ -44,7 +44,7 @@
|
|||||||
|
|
||||||
Logger.LogDebug($"Started checking cache for {downstreamUrlKey}");
|
Logger.LogDebug($"Started checking cache for {downstreamUrlKey}");
|
||||||
|
|
||||||
var cached = _outputCache.Get(downStreamRequestCacheKey, downstreamReRoute.CacheOptions.Region);
|
var cached = _outputCache.Get(downStreamRequestCacheKey, downstreamRoute.CacheOptions.Region);
|
||||||
|
|
||||||
if (cached != null)
|
if (cached != null)
|
||||||
{
|
{
|
||||||
@ -73,7 +73,7 @@
|
|||||||
|
|
||||||
cached = await CreateCachedResponse(downstreamResponse);
|
cached = await CreateCachedResponse(downstreamResponse);
|
||||||
|
|
||||||
_outputCache.Add(downStreamRequestCacheKey, cached, TimeSpan.FromSeconds(downstreamReRoute.CacheOptions.TtlSeconds), downstreamReRoute.CacheOptions.Region);
|
_outputCache.Add(downStreamRequestCacheKey, cached, TimeSpan.FromSeconds(downstreamRoute.CacheOptions.TtlSeconds), downstreamRoute.CacheOptions.Region);
|
||||||
|
|
||||||
Logger.LogDebug($"finished response added to cache for {downstreamUrlKey}");
|
Logger.LogDebug($"finished response added to cache for {downstreamUrlKey}");
|
||||||
}
|
}
|
||||||
|
@ -5,16 +5,16 @@ namespace Ocelot.Cache
|
|||||||
{
|
{
|
||||||
public class RegionCreator : IRegionCreator
|
public class RegionCreator : IRegionCreator
|
||||||
{
|
{
|
||||||
public string Create(FileReRoute reRoute)
|
public string Create(FileRoute route)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(reRoute?.FileCacheOptions?.Region))
|
if (!string.IsNullOrEmpty(route?.FileCacheOptions?.Region))
|
||||||
{
|
{
|
||||||
return reRoute?.FileCacheOptions?.Region;
|
return route?.FileCacheOptions?.Region;
|
||||||
}
|
}
|
||||||
|
|
||||||
var methods = string.Join("", reRoute.UpstreamHttpMethod.Select(m => m));
|
var methods = string.Join("", route.UpstreamHttpMethod.Select(m => m));
|
||||||
|
|
||||||
var region = $"{methods}{reRoute.UpstreamPathTemplate.Replace("/", "")}";
|
var region = $"{methods}{route.UpstreamPathTemplate.Replace("/", "")}";
|
||||||
|
|
||||||
return region;
|
return region;
|
||||||
}
|
}
|
||||||
|
@ -23,13 +23,13 @@
|
|||||||
|
|
||||||
public async Task Invoke(HttpContext httpContext)
|
public async Task Invoke(HttpContext httpContext)
|
||||||
{
|
{
|
||||||
var downstreamReRoute = httpContext.Items.DownstreamReRoute();
|
var downstreamRoute = httpContext.Items.DownstreamRoute();
|
||||||
|
|
||||||
if (downstreamReRoute.ClaimsToClaims.Any())
|
if (downstreamRoute.ClaimsToClaims.Any())
|
||||||
{
|
{
|
||||||
Logger.LogDebug("this route has instructions to convert claims to other claims");
|
Logger.LogDebug("this route has instructions to convert claims to other claims");
|
||||||
|
|
||||||
var result = _addClaimsToRequest.SetClaimsOnContext(downstreamReRoute.ClaimsToClaims, httpContext);
|
var result = _addClaimsToRequest.SetClaimsOnContext(downstreamRoute.ClaimsToClaims, httpContext);
|
||||||
|
|
||||||
if (result.IsError)
|
if (result.IsError)
|
||||||
{
|
{
|
||||||
|
@ -7,7 +7,7 @@ using System.Net.Http;
|
|||||||
|
|
||||||
namespace Ocelot.Configuration.Builder
|
namespace Ocelot.Configuration.Builder
|
||||||
{
|
{
|
||||||
public class DownstreamReRouteBuilder
|
public class DownstreamRouteBuilder
|
||||||
{
|
{
|
||||||
private AuthenticationOptions _authenticationOptions;
|
private AuthenticationOptions _authenticationOptions;
|
||||||
private string _loadBalancerKey;
|
private string _loadBalancerKey;
|
||||||
@ -45,7 +45,7 @@ namespace Ocelot.Configuration.Builder
|
|||||||
private string _downstreamHttpMethod;
|
private string _downstreamHttpMethod;
|
||||||
private Version _downstreamHttpVersion;
|
private Version _downstreamHttpVersion;
|
||||||
|
|
||||||
public DownstreamReRouteBuilder()
|
public DownstreamRouteBuilder()
|
||||||
{
|
{
|
||||||
_downstreamAddresses = new List<DownstreamHostAndPort>();
|
_downstreamAddresses = new List<DownstreamHostAndPort>();
|
||||||
_delegatingHandlers = new List<string>();
|
_delegatingHandlers = new List<string>();
|
||||||
@ -53,219 +53,219 @@ namespace Ocelot.Configuration.Builder
|
|||||||
_addHeadersToUpstream = new List<AddHeader>();
|
_addHeadersToUpstream = new List<AddHeader>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithDownstreamAddresses(List<DownstreamHostAndPort> downstreamAddresses)
|
public DownstreamRouteBuilder WithDownstreamAddresses(List<DownstreamHostAndPort> downstreamAddresses)
|
||||||
{
|
{
|
||||||
_downstreamAddresses.AddRange(downstreamAddresses);
|
_downstreamAddresses.AddRange(downstreamAddresses);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithDownStreamHttpMethod(string method)
|
public DownstreamRouteBuilder WithDownStreamHttpMethod(string method)
|
||||||
{
|
{
|
||||||
_downstreamHttpMethod = method;
|
_downstreamHttpMethod = method;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithLoadBalancerOptions(LoadBalancerOptions loadBalancerOptions)
|
public DownstreamRouteBuilder WithLoadBalancerOptions(LoadBalancerOptions loadBalancerOptions)
|
||||||
{
|
{
|
||||||
_loadBalancerOptions = loadBalancerOptions;
|
_loadBalancerOptions = loadBalancerOptions;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithDownstreamScheme(string downstreamScheme)
|
public DownstreamRouteBuilder WithDownstreamScheme(string downstreamScheme)
|
||||||
{
|
{
|
||||||
_downstreamScheme = downstreamScheme;
|
_downstreamScheme = downstreamScheme;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithDownstreamPathTemplate(string input)
|
public DownstreamRouteBuilder WithDownstreamPathTemplate(string input)
|
||||||
{
|
{
|
||||||
_downstreamPathTemplate = input;
|
_downstreamPathTemplate = input;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithUpstreamPathTemplate(UpstreamPathTemplate input)
|
public DownstreamRouteBuilder WithUpstreamPathTemplate(UpstreamPathTemplate input)
|
||||||
{
|
{
|
||||||
_upstreamTemplatePattern = input;
|
_upstreamTemplatePattern = input;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithUpstreamHttpMethod(List<string> input)
|
public DownstreamRouteBuilder WithUpstreamHttpMethod(List<string> input)
|
||||||
{
|
{
|
||||||
_upstreamHttpMethod = (input.Count == 0) ? new List<HttpMethod>() : input.Select(x => new HttpMethod(x.Trim())).ToList();
|
_upstreamHttpMethod = (input.Count == 0) ? new List<HttpMethod>() : input.Select(x => new HttpMethod(x.Trim())).ToList();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithIsAuthenticated(bool input)
|
public DownstreamRouteBuilder WithIsAuthenticated(bool input)
|
||||||
{
|
{
|
||||||
_isAuthenticated = input;
|
_isAuthenticated = input;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithIsAuthorised(bool input)
|
public DownstreamRouteBuilder WithIsAuthorised(bool input)
|
||||||
{
|
{
|
||||||
_isAuthorised = input;
|
_isAuthorised = input;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithRequestIdKey(string input)
|
public DownstreamRouteBuilder WithRequestIdKey(string input)
|
||||||
{
|
{
|
||||||
_requestIdHeaderKey = input;
|
_requestIdHeaderKey = input;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithClaimsToHeaders(List<ClaimToThing> input)
|
public DownstreamRouteBuilder WithClaimsToHeaders(List<ClaimToThing> input)
|
||||||
{
|
{
|
||||||
_claimsToHeaders = input;
|
_claimsToHeaders = input;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithClaimsToClaims(List<ClaimToThing> input)
|
public DownstreamRouteBuilder WithClaimsToClaims(List<ClaimToThing> input)
|
||||||
{
|
{
|
||||||
_claimToClaims = input;
|
_claimToClaims = input;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithRouteClaimsRequirement(Dictionary<string, string> input)
|
public DownstreamRouteBuilder WithRouteClaimsRequirement(Dictionary<string, string> input)
|
||||||
{
|
{
|
||||||
_routeClaimRequirement = input;
|
_routeClaimRequirement = input;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithClaimsToQueries(List<ClaimToThing> input)
|
public DownstreamRouteBuilder WithClaimsToQueries(List<ClaimToThing> input)
|
||||||
{
|
{
|
||||||
_claimToQueries = input;
|
_claimToQueries = input;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithClaimsToDownstreamPath(List<ClaimToThing> input)
|
public DownstreamRouteBuilder WithClaimsToDownstreamPath(List<ClaimToThing> input)
|
||||||
{
|
{
|
||||||
_claimToDownstreamPath = input;
|
_claimToDownstreamPath = input;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithIsCached(bool input)
|
public DownstreamRouteBuilder WithIsCached(bool input)
|
||||||
{
|
{
|
||||||
_isCached = input;
|
_isCached = input;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithCacheOptions(CacheOptions input)
|
public DownstreamRouteBuilder WithCacheOptions(CacheOptions input)
|
||||||
{
|
{
|
||||||
_fileCacheOptions = input;
|
_fileCacheOptions = input;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithQosOptions(QoSOptions input)
|
public DownstreamRouteBuilder WithQosOptions(QoSOptions input)
|
||||||
{
|
{
|
||||||
_qosOptions = input;
|
_qosOptions = input;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithLoadBalancerKey(string loadBalancerKey)
|
public DownstreamRouteBuilder WithLoadBalancerKey(string loadBalancerKey)
|
||||||
{
|
{
|
||||||
_loadBalancerKey = loadBalancerKey;
|
_loadBalancerKey = loadBalancerKey;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithAuthenticationOptions(AuthenticationOptions authenticationOptions)
|
public DownstreamRouteBuilder WithAuthenticationOptions(AuthenticationOptions authenticationOptions)
|
||||||
{
|
{
|
||||||
_authenticationOptions = authenticationOptions;
|
_authenticationOptions = authenticationOptions;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithEnableRateLimiting(bool input)
|
public DownstreamRouteBuilder WithEnableRateLimiting(bool input)
|
||||||
{
|
{
|
||||||
_enableRateLimiting = input;
|
_enableRateLimiting = input;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithRateLimitOptions(RateLimitOptions input)
|
public DownstreamRouteBuilder WithRateLimitOptions(RateLimitOptions input)
|
||||||
{
|
{
|
||||||
_rateLimitOptions = input;
|
_rateLimitOptions = input;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithHttpHandlerOptions(HttpHandlerOptions input)
|
public DownstreamRouteBuilder WithHttpHandlerOptions(HttpHandlerOptions input)
|
||||||
{
|
{
|
||||||
_httpHandlerOptions = input;
|
_httpHandlerOptions = input;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithUseServiceDiscovery(bool useServiceDiscovery)
|
public DownstreamRouteBuilder WithUseServiceDiscovery(bool useServiceDiscovery)
|
||||||
{
|
{
|
||||||
_useServiceDiscovery = useServiceDiscovery;
|
_useServiceDiscovery = useServiceDiscovery;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithServiceName(string serviceName)
|
public DownstreamRouteBuilder WithServiceName(string serviceName)
|
||||||
{
|
{
|
||||||
_serviceName = serviceName;
|
_serviceName = serviceName;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithServiceNamespace(string serviceNamespace)
|
public DownstreamRouteBuilder WithServiceNamespace(string serviceNamespace)
|
||||||
{
|
{
|
||||||
_serviceNamespace = serviceNamespace;
|
_serviceNamespace = serviceNamespace;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithUpstreamHeaderFindAndReplace(List<HeaderFindAndReplace> upstreamHeaderFindAndReplace)
|
public DownstreamRouteBuilder WithUpstreamHeaderFindAndReplace(List<HeaderFindAndReplace> upstreamHeaderFindAndReplace)
|
||||||
{
|
{
|
||||||
_upstreamHeaderFindAndReplace = upstreamHeaderFindAndReplace;
|
_upstreamHeaderFindAndReplace = upstreamHeaderFindAndReplace;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithDownstreamHeaderFindAndReplace(List<HeaderFindAndReplace> downstreamHeaderFindAndReplace)
|
public DownstreamRouteBuilder WithDownstreamHeaderFindAndReplace(List<HeaderFindAndReplace> downstreamHeaderFindAndReplace)
|
||||||
{
|
{
|
||||||
_downstreamHeaderFindAndReplace = downstreamHeaderFindAndReplace;
|
_downstreamHeaderFindAndReplace = downstreamHeaderFindAndReplace;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithKey(string key)
|
public DownstreamRouteBuilder WithKey(string key)
|
||||||
{
|
{
|
||||||
_key = key;
|
_key = key;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithDelegatingHandlers(List<string> delegatingHandlers)
|
public DownstreamRouteBuilder WithDelegatingHandlers(List<string> delegatingHandlers)
|
||||||
{
|
{
|
||||||
_delegatingHandlers = delegatingHandlers;
|
_delegatingHandlers = delegatingHandlers;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithAddHeadersToDownstream(List<AddHeader> addHeadersToDownstream)
|
public DownstreamRouteBuilder WithAddHeadersToDownstream(List<AddHeader> addHeadersToDownstream)
|
||||||
{
|
{
|
||||||
_addHeadersToDownstream = addHeadersToDownstream;
|
_addHeadersToDownstream = addHeadersToDownstream;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithAddHeadersToUpstream(List<AddHeader> addHeadersToUpstream)
|
public DownstreamRouteBuilder WithAddHeadersToUpstream(List<AddHeader> addHeadersToUpstream)
|
||||||
{
|
{
|
||||||
_addHeadersToUpstream = addHeadersToUpstream;
|
_addHeadersToUpstream = addHeadersToUpstream;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithDangerousAcceptAnyServerCertificateValidator(bool dangerousAcceptAnyServerCertificateValidator)
|
public DownstreamRouteBuilder WithDangerousAcceptAnyServerCertificateValidator(bool dangerousAcceptAnyServerCertificateValidator)
|
||||||
{
|
{
|
||||||
_dangerousAcceptAnyServerCertificateValidator = dangerousAcceptAnyServerCertificateValidator;
|
_dangerousAcceptAnyServerCertificateValidator = dangerousAcceptAnyServerCertificateValidator;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithSecurityOptions(SecurityOptions securityOptions)
|
public DownstreamRouteBuilder WithSecurityOptions(SecurityOptions securityOptions)
|
||||||
{
|
{
|
||||||
_securityOptions = securityOptions;
|
_securityOptions = securityOptions;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRouteBuilder WithDownstreamHttpVersion(Version downstreamHttpVersion)
|
public DownstreamRouteBuilder WithDownstreamHttpVersion(Version downstreamHttpVersion)
|
||||||
{
|
{
|
||||||
_downstreamHttpVersion = downstreamHttpVersion;
|
_downstreamHttpVersion = downstreamHttpVersion;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamReRoute Build()
|
public DownstreamRoute Build()
|
||||||
{
|
{
|
||||||
return new DownstreamReRoute(
|
return new DownstreamRoute(
|
||||||
_key,
|
_key,
|
||||||
_upstreamTemplatePattern,
|
_upstreamTemplatePattern,
|
||||||
_upstreamHeaderFindAndReplace,
|
_upstreamHeaderFindAndReplace,
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
namespace Ocelot.Configuration.Builder
|
|
||||||
{
|
|
||||||
using Ocelot.Configuration.File;
|
|
||||||
using Ocelot.Values;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Http;
|
|
||||||
|
|
||||||
public class ReRouteBuilder
|
|
||||||
{
|
|
||||||
private UpstreamPathTemplate _upstreamTemplatePattern;
|
|
||||||
private List<HttpMethod> _upstreamHttpMethod;
|
|
||||||
private string _upstreamHost;
|
|
||||||
private List<DownstreamReRoute> _downstreamReRoutes;
|
|
||||||
private List<AggregateReRouteConfig> _downstreamReRoutesConfig;
|
|
||||||
private string _aggregator;
|
|
||||||
|
|
||||||
public ReRouteBuilder()
|
|
||||||
{
|
|
||||||
_downstreamReRoutes = new List<DownstreamReRoute>();
|
|
||||||
_downstreamReRoutesConfig = new List<AggregateReRouteConfig>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReRouteBuilder WithDownstreamReRoute(DownstreamReRoute value)
|
|
||||||
{
|
|
||||||
_downstreamReRoutes.Add(value);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReRouteBuilder WithDownstreamReRoutes(List<DownstreamReRoute> value)
|
|
||||||
{
|
|
||||||
_downstreamReRoutes = value;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReRouteBuilder WithUpstreamHost(string upstreamAddresses)
|
|
||||||
{
|
|
||||||
_upstreamHost = upstreamAddresses;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReRouteBuilder WithUpstreamPathTemplate(UpstreamPathTemplate input)
|
|
||||||
{
|
|
||||||
_upstreamTemplatePattern = input;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReRouteBuilder WithUpstreamHttpMethod(List<string> input)
|
|
||||||
{
|
|
||||||
_upstreamHttpMethod = (input.Count == 0) ? new List<HttpMethod>() : input.Select(x => new HttpMethod(x.Trim())).ToList();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReRouteBuilder WithAggregateReRouteConfig(List<AggregateReRouteConfig> aggregateReRouteConfigs)
|
|
||||||
{
|
|
||||||
_downstreamReRoutesConfig = aggregateReRouteConfigs;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReRouteBuilder WithAggregator(string aggregator)
|
|
||||||
{
|
|
||||||
_aggregator = aggregator;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReRoute Build()
|
|
||||||
{
|
|
||||||
return new ReRoute(
|
|
||||||
_downstreamReRoutes,
|
|
||||||
_downstreamReRoutesConfig,
|
|
||||||
_upstreamHttpMethod,
|
|
||||||
_upstreamTemplatePattern,
|
|
||||||
_upstreamHost,
|
|
||||||
_aggregator
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
78
src/Ocelot/Configuration/Builder/RouteBuilder.cs
Normal file
78
src/Ocelot/Configuration/Builder/RouteBuilder.cs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
namespace Ocelot.Configuration.Builder
|
||||||
|
{
|
||||||
|
using Ocelot.Configuration.File;
|
||||||
|
using Ocelot.Values;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
|
||||||
|
public class RouteBuilder
|
||||||
|
{
|
||||||
|
private UpstreamPathTemplate _upstreamTemplatePattern;
|
||||||
|
private List<HttpMethod> _upstreamHttpMethod;
|
||||||
|
private string _upstreamHost;
|
||||||
|
private List<DownstreamRoute> _downstreamRoutes;
|
||||||
|
private List<AggregateRouteConfig> _downstreamRoutesConfig;
|
||||||
|
private string _aggregator;
|
||||||
|
|
||||||
|
public RouteBuilder()
|
||||||
|
{
|
||||||
|
_downstreamRoutes = new List<DownstreamRoute>();
|
||||||
|
_downstreamRoutesConfig = new List<AggregateRouteConfig>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteBuilder WithDownstreamRoute(DownstreamRoute value)
|
||||||
|
{
|
||||||
|
_downstreamRoutes.Add(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteBuilder WithDownstreamRoutes(List<DownstreamRoute> value)
|
||||||
|
{
|
||||||
|
_downstreamRoutes = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteBuilder WithUpstreamHost(string upstreamAddresses)
|
||||||
|
{
|
||||||
|
_upstreamHost = upstreamAddresses;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteBuilder WithUpstreamPathTemplate(UpstreamPathTemplate input)
|
||||||
|
{
|
||||||
|
_upstreamTemplatePattern = input;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteBuilder WithUpstreamHttpMethod(List<string> input)
|
||||||
|
{
|
||||||
|
_upstreamHttpMethod = (input.Count == 0) ? new List<HttpMethod>() : input.Select(x => new HttpMethod(x.Trim())).ToList();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteBuilder WithAggregateRouteConfig(List<AggregateRouteConfig> aggregateRouteConfigs)
|
||||||
|
{
|
||||||
|
_downstreamRoutesConfig = aggregateRouteConfigs;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteBuilder WithAggregator(string aggregator)
|
||||||
|
{
|
||||||
|
_aggregator = aggregator;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Route Build()
|
||||||
|
{
|
||||||
|
return new Route(
|
||||||
|
_downstreamRoutes,
|
||||||
|
_downstreamRoutesConfig,
|
||||||
|
_upstreamHttpMethod,
|
||||||
|
_upstreamTemplatePattern,
|
||||||
|
_upstreamHost,
|
||||||
|
_aggregator
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
namespace Ocelot.Configuration.Builder
|
namespace Ocelot.Configuration.Builder
|
||||||
{
|
{
|
||||||
public class ReRouteOptionsBuilder
|
public class RouteOptionsBuilder
|
||||||
{
|
{
|
||||||
private bool _isAuthenticated;
|
private bool _isAuthenticated;
|
||||||
private bool _isAuthorised;
|
private bool _isAuthorised;
|
||||||
@ -8,39 +8,39 @@ namespace Ocelot.Configuration.Builder
|
|||||||
private bool _enableRateLimiting;
|
private bool _enableRateLimiting;
|
||||||
private bool _useServiceDiscovery;
|
private bool _useServiceDiscovery;
|
||||||
|
|
||||||
public ReRouteOptionsBuilder WithIsCached(bool isCached)
|
public RouteOptionsBuilder WithIsCached(bool isCached)
|
||||||
{
|
{
|
||||||
_isCached = isCached;
|
_isCached = isCached;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReRouteOptionsBuilder WithIsAuthenticated(bool isAuthenticated)
|
public RouteOptionsBuilder WithIsAuthenticated(bool isAuthenticated)
|
||||||
{
|
{
|
||||||
_isAuthenticated = isAuthenticated;
|
_isAuthenticated = isAuthenticated;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReRouteOptionsBuilder WithIsAuthorised(bool isAuthorised)
|
public RouteOptionsBuilder WithIsAuthorised(bool isAuthorised)
|
||||||
{
|
{
|
||||||
_isAuthorised = isAuthorised;
|
_isAuthorised = isAuthorised;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReRouteOptionsBuilder WithRateLimiting(bool enableRateLimiting)
|
public RouteOptionsBuilder WithRateLimiting(bool enableRateLimiting)
|
||||||
{
|
{
|
||||||
_enableRateLimiting = enableRateLimiting;
|
_enableRateLimiting = enableRateLimiting;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReRouteOptionsBuilder WithUseServiceDiscovery(bool useServiceDiscovery)
|
public RouteOptionsBuilder WithUseServiceDiscovery(bool useServiceDiscovery)
|
||||||
{
|
{
|
||||||
_useServiceDiscovery = useServiceDiscovery;
|
_useServiceDiscovery = useServiceDiscovery;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReRouteOptions Build()
|
public RouteOptions Build()
|
||||||
{
|
{
|
||||||
return new ReRouteOptions(_isAuthenticated, _isAuthorised, _isCached, _enableRateLimiting, _useServiceDiscovery);
|
return new RouteOptions(_isAuthenticated, _isAuthorised, _isCached, _enableRateLimiting, _useServiceDiscovery);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -14,42 +14,42 @@ namespace Ocelot.Configuration.Creator
|
|||||||
_creator = creator;
|
_creator = creator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ReRoute> Create(FileConfiguration fileConfiguration, List<ReRoute> reRoutes)
|
public List<Route> Create(FileConfiguration fileConfiguration, List<Route> routes)
|
||||||
{
|
{
|
||||||
return fileConfiguration.Aggregates
|
return fileConfiguration.Aggregates
|
||||||
.Select(aggregate => SetUpAggregateReRoute(reRoutes, aggregate, fileConfiguration.GlobalConfiguration))
|
.Select(aggregate => SetUpAggregateRoute(routes, aggregate, fileConfiguration.GlobalConfiguration))
|
||||||
.Where(aggregate => aggregate != null)
|
.Where(aggregate => aggregate != null)
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReRoute SetUpAggregateReRoute(IEnumerable<ReRoute> reRoutes, FileAggregateReRoute aggregateReRoute, FileGlobalConfiguration globalConfiguration)
|
private Route SetUpAggregateRoute(IEnumerable<Route> routes, FileAggregateRoute aggregateRoute, FileGlobalConfiguration globalConfiguration)
|
||||||
{
|
{
|
||||||
var applicableReRoutes = new List<DownstreamReRoute>();
|
var applicableRoutes = new List<DownstreamRoute>();
|
||||||
var allReRoutes = reRoutes.SelectMany(x => x.DownstreamReRoute);
|
var allRoutes = routes.SelectMany(x => x.DownstreamRoute);
|
||||||
|
|
||||||
foreach (var reRouteKey in aggregateReRoute.ReRouteKeys)
|
foreach (var routeKey in aggregateRoute.RouteKeys)
|
||||||
{
|
{
|
||||||
var selec = allReRoutes.FirstOrDefault(q => q.Key == reRouteKey);
|
var selec = allRoutes.FirstOrDefault(q => q.Key == routeKey);
|
||||||
if (selec == null)
|
if (selec == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
applicableReRoutes.Add(selec);
|
applicableRoutes.Add(selec);
|
||||||
}
|
}
|
||||||
|
|
||||||
var upstreamTemplatePattern = _creator.Create(aggregateReRoute);
|
var upstreamTemplatePattern = _creator.Create(aggregateRoute);
|
||||||
|
|
||||||
var reRoute = new ReRouteBuilder()
|
var route = new RouteBuilder()
|
||||||
.WithUpstreamHttpMethod(aggregateReRoute.UpstreamHttpMethod)
|
.WithUpstreamHttpMethod(aggregateRoute.UpstreamHttpMethod)
|
||||||
.WithUpstreamPathTemplate(upstreamTemplatePattern)
|
.WithUpstreamPathTemplate(upstreamTemplatePattern)
|
||||||
.WithDownstreamReRoutes(applicableReRoutes)
|
.WithDownstreamRoutes(applicableRoutes)
|
||||||
.WithAggregateReRouteConfig(aggregateReRoute.ReRouteKeysConfig)
|
.WithAggregateRouteConfig(aggregateRoute.RouteKeysConfig)
|
||||||
.WithUpstreamHost(aggregateReRoute.UpstreamHost)
|
.WithUpstreamHost(aggregateRoute.UpstreamHost)
|
||||||
.WithAggregator(aggregateReRoute.Aggregator)
|
.WithAggregator(aggregateRoute.Aggregator)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
return reRoute;
|
return route;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,9 @@ namespace Ocelot.Configuration.Creator
|
|||||||
{
|
{
|
||||||
public class AuthenticationOptionsCreator : IAuthenticationOptionsCreator
|
public class AuthenticationOptionsCreator : IAuthenticationOptionsCreator
|
||||||
{
|
{
|
||||||
public AuthenticationOptions Create(FileReRoute reRoute)
|
public AuthenticationOptions Create(FileRoute route)
|
||||||
{
|
{
|
||||||
return new AuthenticationOptions(reRoute.AuthenticationOptions.AllowedScopes, reRoute.AuthenticationOptions.AuthenticationProviderKey);
|
return new AuthenticationOptions(route.AuthenticationOptions.AllowedScopes, route.AuthenticationOptions.AuthenticationProviderKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ namespace Ocelot.Configuration.Creator
|
|||||||
_versionCreator = versionCreator;
|
_versionCreator = versionCreator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InternalConfiguration Create(FileConfiguration fileConfiguration, List<ReRoute> reRoutes)
|
public InternalConfiguration Create(FileConfiguration fileConfiguration, List<Route> routes)
|
||||||
{
|
{
|
||||||
var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileConfiguration.GlobalConfiguration);
|
var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileConfiguration.GlobalConfiguration);
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ namespace Ocelot.Configuration.Creator
|
|||||||
|
|
||||||
var version = _versionCreator.Create(fileConfiguration.GlobalConfiguration.DownstreamHttpVersion);
|
var version = _versionCreator.Create(fileConfiguration.GlobalConfiguration.DownstreamHttpVersion);
|
||||||
|
|
||||||
return new InternalConfiguration(reRoutes,
|
return new InternalConfiguration(routes,
|
||||||
adminPath,
|
adminPath,
|
||||||
serviceProviderConfiguration,
|
serviceProviderConfiguration,
|
||||||
fileConfiguration.GlobalConfiguration.RequestIdKey,
|
fileConfiguration.GlobalConfiguration.RequestIdKey,
|
||||||
|
@ -6,9 +6,9 @@ namespace Ocelot.Configuration.Creator
|
|||||||
{
|
{
|
||||||
public class DownstreamAddressesCreator : IDownstreamAddressesCreator
|
public class DownstreamAddressesCreator : IDownstreamAddressesCreator
|
||||||
{
|
{
|
||||||
public List<DownstreamHostAndPort> Create(FileReRoute reRoute)
|
public List<DownstreamHostAndPort> Create(FileRoute route)
|
||||||
{
|
{
|
||||||
return reRoute.DownstreamHostAndPorts.Select(hostAndPort => new DownstreamHostAndPort(hostAndPort.Host, hostAndPort.Port)).ToList();
|
return route.DownstreamHostAndPorts.Select(hostAndPort => new DownstreamHostAndPort(hostAndPort.Host, hostAndPort.Port)).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,32 +16,32 @@ namespace Ocelot.Configuration.Creator
|
|||||||
_versionCreator = versionCreator;
|
_versionCreator = versionCreator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ReRoute> Create(FileConfiguration fileConfiguration)
|
public List<Route> Create(FileConfiguration fileConfiguration)
|
||||||
{
|
{
|
||||||
return fileConfiguration.DynamicReRoutes
|
return fileConfiguration.DynamicRoutes
|
||||||
.Select(dynamic => SetUpDynamicReRoute(dynamic, fileConfiguration.GlobalConfiguration))
|
.Select(dynamic => SetUpDynamicRoute(dynamic, fileConfiguration.GlobalConfiguration))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReRoute SetUpDynamicReRoute(FileDynamicReRoute fileDynamicReRoute, FileGlobalConfiguration globalConfiguration)
|
private Route SetUpDynamicRoute(FileDynamicRoute fileDynamicRoute, FileGlobalConfiguration globalConfiguration)
|
||||||
{
|
{
|
||||||
var rateLimitOption = _rateLimitOptionsCreator
|
var rateLimitOption = _rateLimitOptionsCreator
|
||||||
.Create(fileDynamicReRoute.RateLimitRule, globalConfiguration);
|
.Create(fileDynamicRoute.RateLimitRule, globalConfiguration);
|
||||||
|
|
||||||
var version = _versionCreator.Create(fileDynamicReRoute.DownstreamHttpVersion);
|
var version = _versionCreator.Create(fileDynamicRoute.DownstreamHttpVersion);
|
||||||
|
|
||||||
var downstreamReRoute = new DownstreamReRouteBuilder()
|
var downstreamRoute = new DownstreamRouteBuilder()
|
||||||
.WithEnableRateLimiting(rateLimitOption.EnableRateLimiting)
|
.WithEnableRateLimiting(rateLimitOption.EnableRateLimiting)
|
||||||
.WithRateLimitOptions(rateLimitOption)
|
.WithRateLimitOptions(rateLimitOption)
|
||||||
.WithServiceName(fileDynamicReRoute.ServiceName)
|
.WithServiceName(fileDynamicRoute.ServiceName)
|
||||||
.WithDownstreamHttpVersion(version)
|
.WithDownstreamHttpVersion(version)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var reRoute = new ReRouteBuilder()
|
var route = new RouteBuilder()
|
||||||
.WithDownstreamReRoute(downstreamReRoute)
|
.WithDownstreamRoute(downstreamRoute)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
return reRoute;
|
return route;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,12 @@ namespace Ocelot.Configuration.Creator
|
|||||||
private readonly IConfigurationValidator _configurationValidator;
|
private readonly IConfigurationValidator _configurationValidator;
|
||||||
private readonly IConfigurationCreator _configCreator;
|
private readonly IConfigurationCreator _configCreator;
|
||||||
private readonly IDynamicsCreator _dynamicsCreator;
|
private readonly IDynamicsCreator _dynamicsCreator;
|
||||||
private readonly IReRoutesCreator _reRoutesCreator;
|
private readonly IRoutesCreator _routesCreator;
|
||||||
private readonly IAggregatesCreator _aggregatesCreator;
|
private readonly IAggregatesCreator _aggregatesCreator;
|
||||||
|
|
||||||
public FileInternalConfigurationCreator(
|
public FileInternalConfigurationCreator(
|
||||||
IConfigurationValidator configurationValidator,
|
IConfigurationValidator configurationValidator,
|
||||||
IReRoutesCreator reRoutesCreator,
|
IRoutesCreator routesCreator,
|
||||||
IAggregatesCreator aggregatesCreator,
|
IAggregatesCreator aggregatesCreator,
|
||||||
IDynamicsCreator dynamicsCreator,
|
IDynamicsCreator dynamicsCreator,
|
||||||
IConfigurationCreator configCreator
|
IConfigurationCreator configCreator
|
||||||
@ -25,7 +25,7 @@ namespace Ocelot.Configuration.Creator
|
|||||||
_configCreator = configCreator;
|
_configCreator = configCreator;
|
||||||
_dynamicsCreator = dynamicsCreator;
|
_dynamicsCreator = dynamicsCreator;
|
||||||
_aggregatesCreator = aggregatesCreator;
|
_aggregatesCreator = aggregatesCreator;
|
||||||
_reRoutesCreator = reRoutesCreator;
|
_routesCreator = routesCreator;
|
||||||
_configurationValidator = configurationValidator;
|
_configurationValidator = configurationValidator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,18 +38,18 @@ namespace Ocelot.Configuration.Creator
|
|||||||
return new ErrorResponse<IInternalConfiguration>(response.Data.Errors);
|
return new ErrorResponse<IInternalConfiguration>(response.Data.Errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
var reRoutes = _reRoutesCreator.Create(fileConfiguration);
|
var routes = _routesCreator.Create(fileConfiguration);
|
||||||
|
|
||||||
var aggregates = _aggregatesCreator.Create(fileConfiguration, reRoutes);
|
var aggregates = _aggregatesCreator.Create(fileConfiguration, routes);
|
||||||
|
|
||||||
var dynamicReRoute = _dynamicsCreator.Create(fileConfiguration);
|
var dynamicRoute = _dynamicsCreator.Create(fileConfiguration);
|
||||||
|
|
||||||
var mergedReRoutes = reRoutes
|
var mergedRoutes = routes
|
||||||
.Union(aggregates)
|
.Union(aggregates)
|
||||||
.Union(dynamicReRoute)
|
.Union(dynamicRoute)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var config = _configCreator.Create(fileConfiguration, mergedReRoutes);
|
var config = _configCreator.Create(fileConfiguration, mergedRoutes);
|
||||||
|
|
||||||
return new OkResponse<IInternalConfiguration>(config);
|
return new OkResponse<IInternalConfiguration>(config);
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,12 @@ namespace Ocelot.Configuration.Creator
|
|||||||
_placeholders = placeholders;
|
_placeholders = placeholders;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HeaderTransformations Create(FileReRoute fileReRoute)
|
public HeaderTransformations Create(FileRoute fileRoute)
|
||||||
{
|
{
|
||||||
var upstream = new List<HeaderFindAndReplace>();
|
var upstream = new List<HeaderFindAndReplace>();
|
||||||
var addHeadersToUpstream = new List<AddHeader>();
|
var addHeadersToUpstream = new List<AddHeader>();
|
||||||
|
|
||||||
foreach (var input in fileReRoute.UpstreamHeaderTransform)
|
foreach (var input in fileRoute.UpstreamHeaderTransform)
|
||||||
{
|
{
|
||||||
if (input.Value.Contains(","))
|
if (input.Value.Contains(","))
|
||||||
{
|
{
|
||||||
@ -46,7 +46,7 @@ namespace Ocelot.Configuration.Creator
|
|||||||
var downstream = new List<HeaderFindAndReplace>();
|
var downstream = new List<HeaderFindAndReplace>();
|
||||||
var addHeadersToDownstream = new List<AddHeader>();
|
var addHeadersToDownstream = new List<AddHeader>();
|
||||||
|
|
||||||
foreach (var input in fileReRoute.DownstreamHeaderTransform)
|
foreach (var input in fileRoute.DownstreamHeaderTransform)
|
||||||
{
|
{
|
||||||
if (input.Value.Contains(","))
|
if (input.Value.Contains(","))
|
||||||
{
|
{
|
||||||
|
@ -5,6 +5,6 @@ namespace Ocelot.Configuration.Creator
|
|||||||
{
|
{
|
||||||
public interface IAggregatesCreator
|
public interface IAggregatesCreator
|
||||||
{
|
{
|
||||||
List<ReRoute> Create(FileConfiguration fileConfiguration, List<ReRoute> reRoutes);
|
List<Route> Create(FileConfiguration fileConfiguration, List<Route> routes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,6 @@ namespace Ocelot.Configuration.Creator
|
|||||||
{
|
{
|
||||||
public interface IAuthenticationOptionsCreator
|
public interface IAuthenticationOptionsCreator
|
||||||
{
|
{
|
||||||
AuthenticationOptions Create(FileReRoute reRoute);
|
AuthenticationOptions Create(FileRoute route);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,6 @@ namespace Ocelot.Configuration.Creator
|
|||||||
{
|
{
|
||||||
public interface IConfigurationCreator
|
public interface IConfigurationCreator
|
||||||
{
|
{
|
||||||
InternalConfiguration Create(FileConfiguration fileConfiguration, List<ReRoute> reRoutes);
|
InternalConfiguration Create(FileConfiguration fileConfiguration, List<Route> routes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,6 @@ namespace Ocelot.Configuration.Creator
|
|||||||
{
|
{
|
||||||
public interface IDownstreamAddressesCreator
|
public interface IDownstreamAddressesCreator
|
||||||
{
|
{
|
||||||
List<DownstreamHostAndPort> Create(FileReRoute reRoute);
|
List<DownstreamHostAndPort> Create(FileRoute route);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,6 @@ namespace Ocelot.Configuration.Creator
|
|||||||
{
|
{
|
||||||
public interface IDynamicsCreator
|
public interface IDynamicsCreator
|
||||||
{
|
{
|
||||||
List<ReRoute> Create(FileConfiguration fileConfiguration);
|
List<Route> Create(FileConfiguration fileConfiguration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,6 @@ namespace Ocelot.Configuration.Creator
|
|||||||
{
|
{
|
||||||
public interface IHeaderFindAndReplaceCreator
|
public interface IHeaderFindAndReplaceCreator
|
||||||
{
|
{
|
||||||
HeaderTransformations Create(FileReRoute fileReRoute);
|
HeaderTransformations Create(FileRoute fileRoute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,6 @@ namespace Ocelot.Configuration.Creator
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IHttpHandlerOptionsCreator
|
public interface IHttpHandlerOptionsCreator
|
||||||
{
|
{
|
||||||
HttpHandlerOptions Create(FileHttpHandlerOptions fileReRoute);
|
HttpHandlerOptions Create(FileHttpHandlerOptions fileRoute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
using Ocelot.Configuration.File;
|
|
||||||
|
|
||||||
namespace Ocelot.Configuration.Creator
|
|
||||||
{
|
|
||||||
public interface IReRouteKeyCreator
|
|
||||||
{
|
|
||||||
string Create(FileReRoute fileReRoute);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
using Ocelot.Configuration.File;
|
|
||||||
|
|
||||||
namespace Ocelot.Configuration.Creator
|
|
||||||
{
|
|
||||||
public interface IReRouteOptionsCreator
|
|
||||||
{
|
|
||||||
ReRouteOptions Create(FileReRoute fileReRoute);
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,8 +3,8 @@ using System.Collections.Generic;
|
|||||||
|
|
||||||
namespace Ocelot.Configuration.Creator
|
namespace Ocelot.Configuration.Creator
|
||||||
{
|
{
|
||||||
public interface IReRoutesCreator
|
public interface IRoutesCreator
|
||||||
{
|
{
|
||||||
List<ReRoute> Create(FileConfiguration fileConfiguration);
|
List<Route> Create(FileConfiguration fileConfiguration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,6 @@ namespace Ocelot.Configuration.Creator
|
|||||||
{
|
{
|
||||||
public interface IRequestIdKeyCreator
|
public interface IRequestIdKeyCreator
|
||||||
{
|
{
|
||||||
string Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration);
|
string Create(FileRoute fileRoute, FileGlobalConfiguration globalConfiguration);
|
||||||
}
|
}
|
||||||
}
|
}
|
9
src/Ocelot/Configuration/Creator/IRouteKeyCreator.cs
Normal file
9
src/Ocelot/Configuration/Creator/IRouteKeyCreator.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using Ocelot.Configuration.File;
|
||||||
|
|
||||||
|
namespace Ocelot.Configuration.Creator
|
||||||
|
{
|
||||||
|
public interface IRouteKeyCreator
|
||||||
|
{
|
||||||
|
string Create(FileRoute fileRoute);
|
||||||
|
}
|
||||||
|
}
|
9
src/Ocelot/Configuration/Creator/IRouteOptionsCreator.cs
Normal file
9
src/Ocelot/Configuration/Creator/IRouteOptionsCreator.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using Ocelot.Configuration.File;
|
||||||
|
|
||||||
|
namespace Ocelot.Configuration.Creator
|
||||||
|
{
|
||||||
|
public interface IRouteOptionsCreator
|
||||||
|
{
|
||||||
|
RouteOptions Create(FileRoute fileRoute);
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,6 @@ namespace Ocelot.Configuration.Creator
|
|||||||
{
|
{
|
||||||
public interface IUpstreamTemplatePatternCreator
|
public interface IUpstreamTemplatePatternCreator
|
||||||
{
|
{
|
||||||
UpstreamPathTemplate Create(IReRoute reRoute);
|
UpstreamPathTemplate Create(IRoute route);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
using Ocelot.Configuration.File;
|
|
||||||
using Ocelot.LoadBalancer.LoadBalancers;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Ocelot.Configuration.Creator
|
|
||||||
{
|
|
||||||
public class ReRouteKeyCreator : IReRouteKeyCreator
|
|
||||||
{
|
|
||||||
public string Create(FileReRoute fileReRoute)
|
|
||||||
{
|
|
||||||
if (IsStickySession(fileReRoute))
|
|
||||||
{
|
|
||||||
return $"{nameof(CookieStickySessions)}:{fileReRoute.LoadBalancerOptions.Key}";
|
|
||||||
}
|
|
||||||
|
|
||||||
return $"{fileReRoute.UpstreamPathTemplate}|{string.Join(",", fileReRoute.UpstreamHttpMethod)}|{string.Join(",", fileReRoute.DownstreamHostAndPorts.Select(x => $"{x.Host}:{x.Port}"))}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsStickySession(FileReRoute fileReRoute)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(fileReRoute.LoadBalancerOptions.Type)
|
|
||||||
&& !string.IsNullOrEmpty(fileReRoute.LoadBalancerOptions.Key)
|
|
||||||
&& fileReRoute.LoadBalancerOptions.Type == nameof(CookieStickySessions))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
using Ocelot.Configuration.Builder;
|
|
||||||
using Ocelot.Configuration.File;
|
|
||||||
|
|
||||||
namespace Ocelot.Configuration.Creator
|
|
||||||
{
|
|
||||||
public class ReRouteOptionsCreator : IReRouteOptionsCreator
|
|
||||||
{
|
|
||||||
public ReRouteOptions Create(FileReRoute fileReRoute)
|
|
||||||
{
|
|
||||||
var isAuthenticated = IsAuthenticated(fileReRoute);
|
|
||||||
var isAuthorised = IsAuthorised(fileReRoute);
|
|
||||||
var isCached = IsCached(fileReRoute);
|
|
||||||
var enableRateLimiting = IsEnableRateLimiting(fileReRoute);
|
|
||||||
var useServiceDiscovery = !string.IsNullOrEmpty(fileReRoute.ServiceName);
|
|
||||||
|
|
||||||
var options = new ReRouteOptionsBuilder()
|
|
||||||
.WithIsAuthenticated(isAuthenticated)
|
|
||||||
.WithIsAuthorised(isAuthorised)
|
|
||||||
.WithIsCached(isCached)
|
|
||||||
.WithRateLimiting(enableRateLimiting)
|
|
||||||
.WithUseServiceDiscovery(useServiceDiscovery)
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsEnableRateLimiting(FileReRoute fileReRoute)
|
|
||||||
{
|
|
||||||
return (fileReRoute.RateLimitOptions != null && fileReRoute.RateLimitOptions.EnableRateLimiting) ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsAuthenticated(FileReRoute fileReRoute)
|
|
||||||
{
|
|
||||||
return !string.IsNullOrEmpty(fileReRoute.AuthenticationOptions?.AuthenticationProviderKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsAuthorised(FileReRoute fileReRoute)
|
|
||||||
{
|
|
||||||
return fileReRoute.RouteClaimsRequirement?.Count > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsCached(FileReRoute fileReRoute)
|
|
||||||
{
|
|
||||||
return fileReRoute.FileCacheOptions.TtlSeconds > 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,12 +4,12 @@ namespace Ocelot.Configuration.Creator
|
|||||||
{
|
{
|
||||||
public class RequestIdKeyCreator : IRequestIdKeyCreator
|
public class RequestIdKeyCreator : IRequestIdKeyCreator
|
||||||
{
|
{
|
||||||
public string Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
|
public string Create(FileRoute fileRoute, FileGlobalConfiguration globalConfiguration)
|
||||||
{
|
{
|
||||||
var reRouteId = !string.IsNullOrEmpty(fileReRoute.RequestIdKey);
|
var routeId = !string.IsNullOrEmpty(fileRoute.RequestIdKey);
|
||||||
|
|
||||||
var requestIdKey = reRouteId
|
var requestIdKey = routeId
|
||||||
? fileReRoute.RequestIdKey
|
? fileRoute.RequestIdKey
|
||||||
: globalConfiguration.RequestIdKey;
|
: globalConfiguration.RequestIdKey;
|
||||||
|
|
||||||
return requestIdKey;
|
return requestIdKey;
|
||||||
|
31
src/Ocelot/Configuration/Creator/RouteKeyCreator.cs
Normal file
31
src/Ocelot/Configuration/Creator/RouteKeyCreator.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using Ocelot.Configuration.File;
|
||||||
|
using Ocelot.LoadBalancer.LoadBalancers;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Ocelot.Configuration.Creator
|
||||||
|
{
|
||||||
|
public class RouteKeyCreator : IRouteKeyCreator
|
||||||
|
{
|
||||||
|
public string Create(FileRoute fileRoute)
|
||||||
|
{
|
||||||
|
if (IsStickySession(fileRoute))
|
||||||
|
{
|
||||||
|
return $"{nameof(CookieStickySessions)}:{fileRoute.LoadBalancerOptions.Key}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{fileRoute.UpstreamPathTemplate}|{string.Join(",", fileRoute.UpstreamHttpMethod)}|{string.Join(",", fileRoute.DownstreamHostAndPorts.Select(x => $"{x.Host}:{x.Port}"))}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsStickySession(FileRoute fileRoute)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(fileRoute.LoadBalancerOptions.Type)
|
||||||
|
&& !string.IsNullOrEmpty(fileRoute.LoadBalancerOptions.Key)
|
||||||
|
&& fileRoute.LoadBalancerOptions.Type == nameof(CookieStickySessions))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
src/Ocelot/Configuration/Creator/RouteOptionsCreator.cs
Normal file
47
src/Ocelot/Configuration/Creator/RouteOptionsCreator.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
namespace Ocelot.Configuration.Creator
|
||||||
|
{
|
||||||
|
using Ocelot.Configuration.Builder;
|
||||||
|
using Ocelot.Configuration.File;
|
||||||
|
|
||||||
|
public class RouteOptionsCreator : IRouteOptionsCreator
|
||||||
|
{
|
||||||
|
public RouteOptions Create(FileRoute fileRoute)
|
||||||
|
{
|
||||||
|
var isAuthenticated = IsAuthenticated(fileRoute);
|
||||||
|
var isAuthorised = IsAuthorised(fileRoute);
|
||||||
|
var isCached = IsCached(fileRoute);
|
||||||
|
var enableRateLimiting = IsEnableRateLimiting(fileRoute);
|
||||||
|
var useServiceDiscovery = !string.IsNullOrEmpty(fileRoute.ServiceName);
|
||||||
|
|
||||||
|
var options = new RouteOptionsBuilder()
|
||||||
|
.WithIsAuthenticated(isAuthenticated)
|
||||||
|
.WithIsAuthorised(isAuthorised)
|
||||||
|
.WithIsCached(isCached)
|
||||||
|
.WithRateLimiting(enableRateLimiting)
|
||||||
|
.WithUseServiceDiscovery(useServiceDiscovery)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsEnableRateLimiting(FileRoute fileRoute)
|
||||||
|
{
|
||||||
|
return (fileRoute.RateLimitOptions != null && fileRoute.RateLimitOptions.EnableRateLimiting) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsAuthenticated(FileRoute fileRoute)
|
||||||
|
{
|
||||||
|
return !string.IsNullOrEmpty(fileRoute.AuthenticationOptions?.AuthenticationProviderKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsAuthorised(FileRoute fileRoute)
|
||||||
|
{
|
||||||
|
return fileRoute.RouteClaimsRequirement?.Count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsCached(FileRoute fileRoute)
|
||||||
|
{
|
||||||
|
return fileRoute.FileCacheOptions.TtlSeconds > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,12 @@
|
|||||||
namespace Ocelot.Configuration.Creator
|
namespace Ocelot.Configuration.Creator
|
||||||
{
|
{
|
||||||
using Builder;
|
using Ocelot.Configuration.Builder;
|
||||||
using Cache;
|
using Ocelot.Cache;
|
||||||
using File;
|
using Ocelot.Configuration.File;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
public class ReRoutesCreator : IReRoutesCreator
|
public class RoutesCreator : IRoutesCreator
|
||||||
{
|
{
|
||||||
private readonly ILoadBalancerOptionsCreator _loadBalancerOptionsCreator;
|
private readonly ILoadBalancerOptionsCreator _loadBalancerOptionsCreator;
|
||||||
private readonly IClaimsToThingCreator _claimsToThingCreator;
|
private readonly IClaimsToThingCreator _claimsToThingCreator;
|
||||||
@ -14,35 +14,35 @@ namespace Ocelot.Configuration.Creator
|
|||||||
private readonly IUpstreamTemplatePatternCreator _upstreamTemplatePatternCreator;
|
private readonly IUpstreamTemplatePatternCreator _upstreamTemplatePatternCreator;
|
||||||
private readonly IRequestIdKeyCreator _requestIdKeyCreator;
|
private readonly IRequestIdKeyCreator _requestIdKeyCreator;
|
||||||
private readonly IQoSOptionsCreator _qosOptionsCreator;
|
private readonly IQoSOptionsCreator _qosOptionsCreator;
|
||||||
private readonly IReRouteOptionsCreator _fileReRouteOptionsCreator;
|
private readonly IRouteOptionsCreator _fileRouteOptionsCreator;
|
||||||
private readonly IRateLimitOptionsCreator _rateLimitOptionsCreator;
|
private readonly IRateLimitOptionsCreator _rateLimitOptionsCreator;
|
||||||
private readonly IRegionCreator _regionCreator;
|
private readonly IRegionCreator _regionCreator;
|
||||||
private readonly IHttpHandlerOptionsCreator _httpHandlerOptionsCreator;
|
private readonly IHttpHandlerOptionsCreator _httpHandlerOptionsCreator;
|
||||||
private readonly IHeaderFindAndReplaceCreator _headerFAndRCreator;
|
private readonly IHeaderFindAndReplaceCreator _headerFAndRCreator;
|
||||||
private readonly IDownstreamAddressesCreator _downstreamAddressesCreator;
|
private readonly IDownstreamAddressesCreator _downstreamAddressesCreator;
|
||||||
private readonly IReRouteKeyCreator _reRouteKeyCreator;
|
private readonly IRouteKeyCreator _routeKeyCreator;
|
||||||
private readonly ISecurityOptionsCreator _securityOptionsCreator;
|
private readonly ISecurityOptionsCreator _securityOptionsCreator;
|
||||||
private readonly IVersionCreator _versionCreator;
|
private readonly IVersionCreator _versionCreator;
|
||||||
|
|
||||||
public ReRoutesCreator(
|
public RoutesCreator(
|
||||||
IClaimsToThingCreator claimsToThingCreator,
|
IClaimsToThingCreator claimsToThingCreator,
|
||||||
IAuthenticationOptionsCreator authOptionsCreator,
|
IAuthenticationOptionsCreator authOptionsCreator,
|
||||||
IUpstreamTemplatePatternCreator upstreamTemplatePatternCreator,
|
IUpstreamTemplatePatternCreator upstreamTemplatePatternCreator,
|
||||||
IRequestIdKeyCreator requestIdKeyCreator,
|
IRequestIdKeyCreator requestIdKeyCreator,
|
||||||
IQoSOptionsCreator qosOptionsCreator,
|
IQoSOptionsCreator qosOptionsCreator,
|
||||||
IReRouteOptionsCreator fileReRouteOptionsCreator,
|
IRouteOptionsCreator fileRouteOptionsCreator,
|
||||||
IRateLimitOptionsCreator rateLimitOptionsCreator,
|
IRateLimitOptionsCreator rateLimitOptionsCreator,
|
||||||
IRegionCreator regionCreator,
|
IRegionCreator regionCreator,
|
||||||
IHttpHandlerOptionsCreator httpHandlerOptionsCreator,
|
IHttpHandlerOptionsCreator httpHandlerOptionsCreator,
|
||||||
IHeaderFindAndReplaceCreator headerFAndRCreator,
|
IHeaderFindAndReplaceCreator headerFAndRCreator,
|
||||||
IDownstreamAddressesCreator downstreamAddressesCreator,
|
IDownstreamAddressesCreator downstreamAddressesCreator,
|
||||||
ILoadBalancerOptionsCreator loadBalancerOptionsCreator,
|
ILoadBalancerOptionsCreator loadBalancerOptionsCreator,
|
||||||
IReRouteKeyCreator reRouteKeyCreator,
|
IRouteKeyCreator routeKeyCreator,
|
||||||
ISecurityOptionsCreator securityOptionsCreator,
|
ISecurityOptionsCreator securityOptionsCreator,
|
||||||
IVersionCreator versionCreator
|
IVersionCreator versionCreator
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
_reRouteKeyCreator = reRouteKeyCreator;
|
_routeKeyCreator = routeKeyCreator;
|
||||||
_loadBalancerOptionsCreator = loadBalancerOptionsCreator;
|
_loadBalancerOptionsCreator = loadBalancerOptionsCreator;
|
||||||
_downstreamAddressesCreator = downstreamAddressesCreator;
|
_downstreamAddressesCreator = downstreamAddressesCreator;
|
||||||
_headerFAndRCreator = headerFAndRCreator;
|
_headerFAndRCreator = headerFAndRCreator;
|
||||||
@ -53,115 +53,115 @@ namespace Ocelot.Configuration.Creator
|
|||||||
_authOptionsCreator = authOptionsCreator;
|
_authOptionsCreator = authOptionsCreator;
|
||||||
_claimsToThingCreator = claimsToThingCreator;
|
_claimsToThingCreator = claimsToThingCreator;
|
||||||
_qosOptionsCreator = qosOptionsCreator;
|
_qosOptionsCreator = qosOptionsCreator;
|
||||||
_fileReRouteOptionsCreator = fileReRouteOptionsCreator;
|
_fileRouteOptionsCreator = fileRouteOptionsCreator;
|
||||||
_httpHandlerOptionsCreator = httpHandlerOptionsCreator;
|
_httpHandlerOptionsCreator = httpHandlerOptionsCreator;
|
||||||
_loadBalancerOptionsCreator = loadBalancerOptionsCreator;
|
_loadBalancerOptionsCreator = loadBalancerOptionsCreator;
|
||||||
_securityOptionsCreator = securityOptionsCreator;
|
_securityOptionsCreator = securityOptionsCreator;
|
||||||
_versionCreator = versionCreator;
|
_versionCreator = versionCreator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ReRoute> Create(FileConfiguration fileConfiguration)
|
public List<Route> Create(FileConfiguration fileConfiguration)
|
||||||
{
|
{
|
||||||
return fileConfiguration.ReRoutes
|
return fileConfiguration.Routes
|
||||||
.Select(reRoute =>
|
.Select(route =>
|
||||||
{
|
{
|
||||||
var downstreamReRoute = SetUpDownstreamReRoute(reRoute, fileConfiguration.GlobalConfiguration);
|
var downstreamRoute = SetUpDownstreamRoute(route, fileConfiguration.GlobalConfiguration);
|
||||||
return SetUpReRoute(reRoute, downstreamReRoute);
|
return SetUpRoute(route, downstreamRoute);
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private DownstreamReRoute SetUpDownstreamReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
|
private DownstreamRoute SetUpDownstreamRoute(FileRoute fileRoute, FileGlobalConfiguration globalConfiguration)
|
||||||
{
|
{
|
||||||
var fileReRouteOptions = _fileReRouteOptionsCreator.Create(fileReRoute);
|
var fileRouteOptions = _fileRouteOptionsCreator.Create(fileRoute);
|
||||||
|
|
||||||
var requestIdKey = _requestIdKeyCreator.Create(fileReRoute, globalConfiguration);
|
var requestIdKey = _requestIdKeyCreator.Create(fileRoute, globalConfiguration);
|
||||||
|
|
||||||
var reRouteKey = _reRouteKeyCreator.Create(fileReRoute);
|
var routeKey = _routeKeyCreator.Create(fileRoute);
|
||||||
|
|
||||||
var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileReRoute);
|
var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileRoute);
|
||||||
|
|
||||||
var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute);
|
var authOptionsForRoute = _authOptionsCreator.Create(fileRoute);
|
||||||
|
|
||||||
var claimsToHeaders = _claimsToThingCreator.Create(fileReRoute.AddHeadersToRequest);
|
var claimsToHeaders = _claimsToThingCreator.Create(fileRoute.AddHeadersToRequest);
|
||||||
|
|
||||||
var claimsToClaims = _claimsToThingCreator.Create(fileReRoute.AddClaimsToRequest);
|
var claimsToClaims = _claimsToThingCreator.Create(fileRoute.AddClaimsToRequest);
|
||||||
|
|
||||||
var claimsToQueries = _claimsToThingCreator.Create(fileReRoute.AddQueriesToRequest);
|
var claimsToQueries = _claimsToThingCreator.Create(fileRoute.AddQueriesToRequest);
|
||||||
|
|
||||||
var claimsToDownstreamPath = _claimsToThingCreator.Create(fileReRoute.ChangeDownstreamPathTemplate);
|
var claimsToDownstreamPath = _claimsToThingCreator.Create(fileRoute.ChangeDownstreamPathTemplate);
|
||||||
|
|
||||||
var qosOptions = _qosOptionsCreator.Create(fileReRoute.QoSOptions, fileReRoute.UpstreamPathTemplate, fileReRoute.UpstreamHttpMethod);
|
var qosOptions = _qosOptionsCreator.Create(fileRoute.QoSOptions, fileRoute.UpstreamPathTemplate, fileRoute.UpstreamHttpMethod);
|
||||||
|
|
||||||
var rateLimitOption = _rateLimitOptionsCreator.Create(fileReRoute.RateLimitOptions, globalConfiguration);
|
var rateLimitOption = _rateLimitOptionsCreator.Create(fileRoute.RateLimitOptions, globalConfiguration);
|
||||||
|
|
||||||
var region = _regionCreator.Create(fileReRoute);
|
var region = _regionCreator.Create(fileRoute);
|
||||||
|
|
||||||
var httpHandlerOptions = _httpHandlerOptionsCreator.Create(fileReRoute.HttpHandlerOptions);
|
var httpHandlerOptions = _httpHandlerOptionsCreator.Create(fileRoute.HttpHandlerOptions);
|
||||||
|
|
||||||
var hAndRs = _headerFAndRCreator.Create(fileReRoute);
|
var hAndRs = _headerFAndRCreator.Create(fileRoute);
|
||||||
|
|
||||||
var downstreamAddresses = _downstreamAddressesCreator.Create(fileReRoute);
|
var downstreamAddresses = _downstreamAddressesCreator.Create(fileRoute);
|
||||||
|
|
||||||
var lbOptions = _loadBalancerOptionsCreator.Create(fileReRoute.LoadBalancerOptions);
|
var lbOptions = _loadBalancerOptionsCreator.Create(fileRoute.LoadBalancerOptions);
|
||||||
|
|
||||||
var securityOptions = _securityOptionsCreator.Create(fileReRoute.SecurityOptions);
|
var securityOptions = _securityOptionsCreator.Create(fileRoute.SecurityOptions);
|
||||||
|
|
||||||
var downstreamHttpVersion = _versionCreator.Create(fileReRoute.DownstreamHttpVersion);
|
var downstreamHttpVersion = _versionCreator.Create(fileRoute.DownstreamHttpVersion);
|
||||||
|
|
||||||
var reRoute = new DownstreamReRouteBuilder()
|
var route = new DownstreamRouteBuilder()
|
||||||
.WithKey(fileReRoute.Key)
|
.WithKey(fileRoute.Key)
|
||||||
.WithDownstreamPathTemplate(fileReRoute.DownstreamPathTemplate)
|
.WithDownstreamPathTemplate(fileRoute.DownstreamPathTemplate)
|
||||||
.WithUpstreamHttpMethod(fileReRoute.UpstreamHttpMethod)
|
.WithUpstreamHttpMethod(fileRoute.UpstreamHttpMethod)
|
||||||
.WithUpstreamPathTemplate(upstreamTemplatePattern)
|
.WithUpstreamPathTemplate(upstreamTemplatePattern)
|
||||||
.WithIsAuthenticated(fileReRouteOptions.IsAuthenticated)
|
.WithIsAuthenticated(fileRouteOptions.IsAuthenticated)
|
||||||
.WithAuthenticationOptions(authOptionsForRoute)
|
.WithAuthenticationOptions(authOptionsForRoute)
|
||||||
.WithClaimsToHeaders(claimsToHeaders)
|
.WithClaimsToHeaders(claimsToHeaders)
|
||||||
.WithClaimsToClaims(claimsToClaims)
|
.WithClaimsToClaims(claimsToClaims)
|
||||||
.WithRouteClaimsRequirement(fileReRoute.RouteClaimsRequirement)
|
.WithRouteClaimsRequirement(fileRoute.RouteClaimsRequirement)
|
||||||
.WithIsAuthorised(fileReRouteOptions.IsAuthorised)
|
.WithIsAuthorised(fileRouteOptions.IsAuthorised)
|
||||||
.WithClaimsToQueries(claimsToQueries)
|
.WithClaimsToQueries(claimsToQueries)
|
||||||
.WithClaimsToDownstreamPath(claimsToDownstreamPath)
|
.WithClaimsToDownstreamPath(claimsToDownstreamPath)
|
||||||
.WithRequestIdKey(requestIdKey)
|
.WithRequestIdKey(requestIdKey)
|
||||||
.WithIsCached(fileReRouteOptions.IsCached)
|
.WithIsCached(fileRouteOptions.IsCached)
|
||||||
.WithCacheOptions(new CacheOptions(fileReRoute.FileCacheOptions.TtlSeconds, region))
|
.WithCacheOptions(new CacheOptions(fileRoute.FileCacheOptions.TtlSeconds, region))
|
||||||
.WithDownstreamScheme(fileReRoute.DownstreamScheme)
|
.WithDownstreamScheme(fileRoute.DownstreamScheme)
|
||||||
.WithLoadBalancerOptions(lbOptions)
|
.WithLoadBalancerOptions(lbOptions)
|
||||||
.WithDownstreamAddresses(downstreamAddresses)
|
.WithDownstreamAddresses(downstreamAddresses)
|
||||||
.WithLoadBalancerKey(reRouteKey)
|
.WithLoadBalancerKey(routeKey)
|
||||||
.WithQosOptions(qosOptions)
|
.WithQosOptions(qosOptions)
|
||||||
.WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting)
|
.WithEnableRateLimiting(fileRouteOptions.EnableRateLimiting)
|
||||||
.WithRateLimitOptions(rateLimitOption)
|
.WithRateLimitOptions(rateLimitOption)
|
||||||
.WithHttpHandlerOptions(httpHandlerOptions)
|
.WithHttpHandlerOptions(httpHandlerOptions)
|
||||||
.WithServiceName(fileReRoute.ServiceName)
|
.WithServiceName(fileRoute.ServiceName)
|
||||||
.WithServiceNamespace(fileReRoute.ServiceNamespace)
|
.WithServiceNamespace(fileRoute.ServiceNamespace)
|
||||||
.WithUseServiceDiscovery(fileReRouteOptions.UseServiceDiscovery)
|
.WithUseServiceDiscovery(fileRouteOptions.UseServiceDiscovery)
|
||||||
.WithUpstreamHeaderFindAndReplace(hAndRs.Upstream)
|
.WithUpstreamHeaderFindAndReplace(hAndRs.Upstream)
|
||||||
.WithDownstreamHeaderFindAndReplace(hAndRs.Downstream)
|
.WithDownstreamHeaderFindAndReplace(hAndRs.Downstream)
|
||||||
.WithDelegatingHandlers(fileReRoute.DelegatingHandlers)
|
.WithDelegatingHandlers(fileRoute.DelegatingHandlers)
|
||||||
.WithAddHeadersToDownstream(hAndRs.AddHeadersToDownstream)
|
.WithAddHeadersToDownstream(hAndRs.AddHeadersToDownstream)
|
||||||
.WithAddHeadersToUpstream(hAndRs.AddHeadersToUpstream)
|
.WithAddHeadersToUpstream(hAndRs.AddHeadersToUpstream)
|
||||||
.WithDangerousAcceptAnyServerCertificateValidator(fileReRoute.DangerousAcceptAnyServerCertificateValidator)
|
.WithDangerousAcceptAnyServerCertificateValidator(fileRoute.DangerousAcceptAnyServerCertificateValidator)
|
||||||
.WithSecurityOptions(securityOptions)
|
.WithSecurityOptions(securityOptions)
|
||||||
.WithDownstreamHttpVersion(downstreamHttpVersion)
|
.WithDownstreamHttpVersion(downstreamHttpVersion)
|
||||||
.WithDownStreamHttpMethod(fileReRoute.DownstreamHttpMethod)
|
.WithDownStreamHttpMethod(fileRoute.DownstreamHttpMethod)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
return reRoute;
|
return route;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReRoute SetUpReRoute(FileReRoute fileReRoute, DownstreamReRoute downstreamReRoutes)
|
private Route SetUpRoute(FileRoute fileRoute, DownstreamRoute downstreamRoutes)
|
||||||
{
|
{
|
||||||
var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileReRoute);
|
var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileRoute);
|
||||||
|
|
||||||
var reRoute = new ReRouteBuilder()
|
var route = new RouteBuilder()
|
||||||
.WithUpstreamHttpMethod(fileReRoute.UpstreamHttpMethod)
|
.WithUpstreamHttpMethod(fileRoute.UpstreamHttpMethod)
|
||||||
.WithUpstreamPathTemplate(upstreamTemplatePattern)
|
.WithUpstreamPathTemplate(upstreamTemplatePattern)
|
||||||
.WithDownstreamReRoute(downstreamReRoutes)
|
.WithDownstreamRoute(downstreamRoutes)
|
||||||
.WithUpstreamHost(fileReRoute.UpstreamHost)
|
.WithUpstreamHost(fileRoute.UpstreamHost)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
return reRoute;
|
return route;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,9 +13,9 @@ namespace Ocelot.Configuration.Creator
|
|||||||
private const string RegExForwardSlashOnly = "^/$";
|
private const string RegExForwardSlashOnly = "^/$";
|
||||||
private const string RegExForwardSlashAndOnePlaceHolder = "^/.*";
|
private const string RegExForwardSlashAndOnePlaceHolder = "^/.*";
|
||||||
|
|
||||||
public UpstreamPathTemplate Create(IReRoute reRoute)
|
public UpstreamPathTemplate Create(IRoute route)
|
||||||
{
|
{
|
||||||
var upstreamTemplate = reRoute.UpstreamPathTemplate;
|
var upstreamTemplate = route.UpstreamPathTemplate;
|
||||||
|
|
||||||
var placeholders = new List<string>();
|
var placeholders = new List<string>();
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ namespace Ocelot.Configuration.Creator
|
|||||||
//hack to handle /{url} case
|
//hack to handle /{url} case
|
||||||
if (ForwardSlashAndOnePlaceHolder(upstreamTemplate, placeholders, postitionOfPlaceHolderClosingBracket))
|
if (ForwardSlashAndOnePlaceHolder(upstreamTemplate, placeholders, postitionOfPlaceHolderClosingBracket))
|
||||||
{
|
{
|
||||||
return new UpstreamPathTemplate(RegExForwardSlashAndOnePlaceHolder, 0, false, reRoute.UpstreamPathTemplate);
|
return new UpstreamPathTemplate(RegExForwardSlashAndOnePlaceHolder, 0, false, route.UpstreamPathTemplate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,7 +60,7 @@ namespace Ocelot.Configuration.Creator
|
|||||||
|
|
||||||
if (upstreamTemplate == "/")
|
if (upstreamTemplate == "/")
|
||||||
{
|
{
|
||||||
return new UpstreamPathTemplate(RegExForwardSlashOnly, reRoute.Priority, containsQueryString, reRoute.UpstreamPathTemplate);
|
return new UpstreamPathTemplate(RegExForwardSlashOnly, route.Priority, containsQueryString, route.UpstreamPathTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (upstreamTemplate.EndsWith("/"))
|
if (upstreamTemplate.EndsWith("/"))
|
||||||
@ -68,11 +68,11 @@ namespace Ocelot.Configuration.Creator
|
|||||||
upstreamTemplate = upstreamTemplate.Remove(upstreamTemplate.Length - 1, 1) + "(/|)";
|
upstreamTemplate = upstreamTemplate.Remove(upstreamTemplate.Length - 1, 1) + "(/|)";
|
||||||
}
|
}
|
||||||
|
|
||||||
var route = reRoute.ReRouteIsCaseSensitive
|
var template = route.RouteIsCaseSensitive
|
||||||
? $"^{upstreamTemplate}{RegExMatchEndString}"
|
? $"^{upstreamTemplate}{RegExMatchEndString}"
|
||||||
: $"^{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}";
|
: $"^{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}";
|
||||||
|
|
||||||
return new UpstreamPathTemplate(route, reRoute.Priority, containsQueryString, reRoute.UpstreamPathTemplate);
|
return new UpstreamPathTemplate(template, route.Priority, containsQueryString, route.UpstreamPathTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ForwardSlashAndOnePlaceHolder(string upstreamTemplate, List<string> placeholders, int postitionOfPlaceHolderClosingBracket)
|
private bool ForwardSlashAndOnePlaceHolder(string upstreamTemplate, List<string> placeholders, int postitionOfPlaceHolderClosingBracket)
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
namespace Ocelot.Configuration
|
namespace Ocelot.Configuration
|
||||||
{
|
{
|
||||||
using Creator;
|
using Ocelot.Configuration.Creator;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Values;
|
using Ocelot.Values;
|
||||||
|
|
||||||
public class DownstreamReRoute
|
public class DownstreamRoute
|
||||||
{
|
{
|
||||||
public DownstreamReRoute(
|
public DownstreamRoute(
|
||||||
string key,
|
string key,
|
||||||
UpstreamPathTemplate upstreamPathTemplate,
|
UpstreamPathTemplate upstreamPathTemplate,
|
||||||
List<HeaderFindAndReplace> upstreamHeadersFindAndReplace,
|
List<HeaderFindAndReplace> upstreamHeadersFindAndReplace,
|
@ -1,8 +1,8 @@
|
|||||||
namespace Ocelot.Configuration.File
|
namespace Ocelot.Configuration.File
|
||||||
{
|
{
|
||||||
public class AggregateReRouteConfig
|
public class AggregateRouteConfig
|
||||||
{
|
{
|
||||||
public string ReRouteKey { get; set; }
|
public string RouteKey { get; set; }
|
||||||
public string Parameter { get; set; }
|
public string Parameter { get; set; }
|
||||||
public string JsonPath { get; set; }
|
public string JsonPath { get; set; }
|
||||||
}
|
}
|
@ -1,14 +1,14 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ocelot.Configuration.File
|
namespace Ocelot.Configuration.File
|
||||||
{
|
{
|
||||||
public class FileAggregateReRoute : IReRoute
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
public class FileAggregateRoute : IRoute
|
||||||
{
|
{
|
||||||
public List<string> ReRouteKeys { get; set; }
|
public List<string> RouteKeys { get; set; }
|
||||||
public List<AggregateReRouteConfig> ReRouteKeysConfig { get; set; }
|
public List<AggregateRouteConfig> RouteKeysConfig { get; set; }
|
||||||
public string UpstreamPathTemplate { get; set; }
|
public string UpstreamPathTemplate { get; set; }
|
||||||
public string UpstreamHost { get; set; }
|
public string UpstreamHost { get; set; }
|
||||||
public bool ReRouteIsCaseSensitive { get; set; }
|
public bool RouteIsCaseSensitive { get; set; }
|
||||||
public string Aggregator { get; set; }
|
public string Aggregator { get; set; }
|
||||||
|
|
||||||
// Only supports GET..are you crazy!! POST, PUT WOULD BE CRAZY!! :)
|
// Only supports GET..are you crazy!! POST, PUT WOULD BE CRAZY!! :)
|
@ -6,17 +6,17 @@ namespace Ocelot.Configuration.File
|
|||||||
{
|
{
|
||||||
public FileConfiguration()
|
public FileConfiguration()
|
||||||
{
|
{
|
||||||
ReRoutes = new List<FileReRoute>();
|
Routes = new List<FileRoute>();
|
||||||
GlobalConfiguration = new FileGlobalConfiguration();
|
GlobalConfiguration = new FileGlobalConfiguration();
|
||||||
Aggregates = new List<FileAggregateReRoute>();
|
Aggregates = new List<FileAggregateRoute>();
|
||||||
DynamicReRoutes = new List<FileDynamicReRoute>();
|
DynamicRoutes = new List<FileDynamicRoute>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FileReRoute> ReRoutes { get; set; }
|
public List<FileRoute> Routes { get; set; }
|
||||||
public List<FileDynamicReRoute> DynamicReRoutes { get; set; }
|
public List<FileDynamicRoute> DynamicRoutes { get; set; }
|
||||||
|
|
||||||
// Seperate field for aggregates because this let's you re-use ReRoutes in multiple Aggregates
|
// Seperate field for aggregates because this let's you re-use Routes in multiple Aggregates
|
||||||
public List<FileAggregateReRoute> Aggregates { get; set; }
|
public List<FileAggregateRoute> Aggregates { get; set; }
|
||||||
|
|
||||||
public FileGlobalConfiguration GlobalConfiguration { get; set; }
|
public FileGlobalConfiguration GlobalConfiguration { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Ocelot.Configuration.File
|
namespace Ocelot.Configuration.File
|
||||||
{
|
{
|
||||||
public class FileDynamicReRoute
|
public class FileDynamicRoute
|
||||||
{
|
{
|
||||||
public string ServiceName { get; set; }
|
public string ServiceName { get; set; }
|
||||||
public FileRateLimitRule RateLimitRule { get; set; }
|
public FileRateLimitRule RateLimitRule { get; set; }
|
@ -1,10 +1,10 @@
|
|||||||
using System.Collections.Generic;
|
namespace Ocelot.Configuration.File
|
||||||
|
{
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ocelot.Configuration.File
|
public class FileRoute : IRoute
|
||||||
{
|
{
|
||||||
public class FileReRoute : IReRoute
|
public FileRoute()
|
||||||
{
|
|
||||||
public FileReRoute()
|
|
||||||
{
|
{
|
||||||
UpstreamHttpMethod = new List<string>();
|
UpstreamHttpMethod = new List<string>();
|
||||||
AddHeadersToRequest = new Dictionary<string, string>();
|
AddHeadersToRequest = new Dictionary<string, string>();
|
||||||
@ -39,7 +39,7 @@ namespace Ocelot.Configuration.File
|
|||||||
public Dictionary<string, string> ChangeDownstreamPathTemplate { get; set; }
|
public Dictionary<string, string> ChangeDownstreamPathTemplate { get; set; }
|
||||||
public string RequestIdKey { get; set; }
|
public string RequestIdKey { get; set; }
|
||||||
public FileCacheOptions FileCacheOptions { get; set; }
|
public FileCacheOptions FileCacheOptions { get; set; }
|
||||||
public bool ReRouteIsCaseSensitive { get; set; }
|
public bool RouteIsCaseSensitive { get; set; }
|
||||||
public string ServiceName { get; set; }
|
public string ServiceName { get; set; }
|
||||||
public string ServiceNamespace { get; set; }
|
public string ServiceNamespace { get; set; }
|
||||||
public string DownstreamScheme { get; set; }
|
public string DownstreamScheme { get; set; }
|
@ -1,9 +1,9 @@
|
|||||||
namespace Ocelot.Configuration.File
|
namespace Ocelot.Configuration.File
|
||||||
{
|
{
|
||||||
public interface IReRoute
|
public interface IRoute
|
||||||
{
|
{
|
||||||
string UpstreamPathTemplate { get; set; }
|
string UpstreamPathTemplate { get; set; }
|
||||||
bool ReRouteIsCaseSensitive { get; set; }
|
bool RouteIsCaseSensitive { get; set; }
|
||||||
int Priority { get; set; }
|
int Priority { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ namespace Ocelot.Configuration
|
|||||||
|
|
||||||
public interface IInternalConfiguration
|
public interface IInternalConfiguration
|
||||||
{
|
{
|
||||||
List<ReRoute> ReRoutes { get; }
|
List<Route> Routes { get; }
|
||||||
|
|
||||||
string AdministrationPath { get; }
|
string AdministrationPath { get; }
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ namespace Ocelot.Configuration
|
|||||||
public class InternalConfiguration : IInternalConfiguration
|
public class InternalConfiguration : IInternalConfiguration
|
||||||
{
|
{
|
||||||
public InternalConfiguration(
|
public InternalConfiguration(
|
||||||
List<ReRoute> reRoutes,
|
List<Route> routes,
|
||||||
string administrationPath,
|
string administrationPath,
|
||||||
ServiceProviderConfiguration serviceProviderConfiguration,
|
ServiceProviderConfiguration serviceProviderConfiguration,
|
||||||
string requestId,
|
string requestId,
|
||||||
@ -17,7 +17,7 @@ namespace Ocelot.Configuration
|
|||||||
HttpHandlerOptions httpHandlerOptions,
|
HttpHandlerOptions httpHandlerOptions,
|
||||||
Version downstreamHttpVersion)
|
Version downstreamHttpVersion)
|
||||||
{
|
{
|
||||||
ReRoutes = reRoutes;
|
Routes = routes;
|
||||||
AdministrationPath = administrationPath;
|
AdministrationPath = administrationPath;
|
||||||
ServiceProviderConfiguration = serviceProviderConfiguration;
|
ServiceProviderConfiguration = serviceProviderConfiguration;
|
||||||
RequestId = requestId;
|
RequestId = requestId;
|
||||||
@ -28,7 +28,7 @@ namespace Ocelot.Configuration
|
|||||||
DownstreamHttpVersion = downstreamHttpVersion;
|
DownstreamHttpVersion = downstreamHttpVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ReRoute> ReRoutes { get; }
|
public List<Route> Routes { get; }
|
||||||
public string AdministrationPath { get; }
|
public string AdministrationPath { get; }
|
||||||
public ServiceProviderConfiguration ServiceProviderConfiguration { get; }
|
public ServiceProviderConfiguration ServiceProviderConfiguration { get; }
|
||||||
public string RequestId { get; }
|
public string RequestId { get; }
|
||||||
|
@ -5,18 +5,18 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
|
||||||
public class ReRoute
|
public class Route
|
||||||
{
|
{
|
||||||
public ReRoute(List<DownstreamReRoute> downstreamReRoute,
|
public Route(List<DownstreamRoute> downstreamRoute,
|
||||||
List<AggregateReRouteConfig> downstreamReRouteConfig,
|
List<AggregateRouteConfig> downstreamRouteConfig,
|
||||||
List<HttpMethod> upstreamHttpMethod,
|
List<HttpMethod> upstreamHttpMethod,
|
||||||
UpstreamPathTemplate upstreamTemplatePattern,
|
UpstreamPathTemplate upstreamTemplatePattern,
|
||||||
string upstreamHost,
|
string upstreamHost,
|
||||||
string aggregator)
|
string aggregator)
|
||||||
{
|
{
|
||||||
UpstreamHost = upstreamHost;
|
UpstreamHost = upstreamHost;
|
||||||
DownstreamReRoute = downstreamReRoute;
|
DownstreamRoute = downstreamRoute;
|
||||||
DownstreamReRouteConfig = downstreamReRouteConfig;
|
DownstreamRouteConfig = downstreamRouteConfig;
|
||||||
UpstreamHttpMethod = upstreamHttpMethod;
|
UpstreamHttpMethod = upstreamHttpMethod;
|
||||||
UpstreamTemplatePattern = upstreamTemplatePattern;
|
UpstreamTemplatePattern = upstreamTemplatePattern;
|
||||||
Aggregator = aggregator;
|
Aggregator = aggregator;
|
||||||
@ -25,8 +25,8 @@
|
|||||||
public UpstreamPathTemplate UpstreamTemplatePattern { get; private set; }
|
public UpstreamPathTemplate UpstreamTemplatePattern { get; private set; }
|
||||||
public List<HttpMethod> UpstreamHttpMethod { get; private set; }
|
public List<HttpMethod> UpstreamHttpMethod { get; private set; }
|
||||||
public string UpstreamHost { get; private set; }
|
public string UpstreamHost { get; private set; }
|
||||||
public List<DownstreamReRoute> DownstreamReRoute { get; private set; }
|
public List<DownstreamRoute> DownstreamRoute { get; private set; }
|
||||||
public List<AggregateReRouteConfig> DownstreamReRouteConfig { get; private set; }
|
public List<AggregateRouteConfig> DownstreamRouteConfig { get; private set; }
|
||||||
public string Aggregator { get; private set; }
|
public string Aggregator { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,8 +1,8 @@
|
|||||||
namespace Ocelot.Configuration
|
namespace Ocelot.Configuration
|
||||||
{
|
{
|
||||||
public class ReRouteOptions
|
public class RouteOptions
|
||||||
{
|
{
|
||||||
public ReRouteOptions(bool isAuthenticated, bool isAuthorised, bool isCached, bool isEnableRateLimiting, bool useServiceDiscovery)
|
public RouteOptions(bool isAuthenticated, bool isAuthorised, bool isCached, bool isEnableRateLimiting, bool useServiceDiscovery)
|
||||||
{
|
{
|
||||||
IsAuthenticated = isAuthenticated;
|
IsAuthenticated = isAuthenticated;
|
||||||
IsAuthorised = isAuthorised;
|
IsAuthorised = isAuthorised;
|
@ -16,54 +16,54 @@
|
|||||||
{
|
{
|
||||||
private readonly List<ServiceDiscoveryFinderDelegate> _serviceDiscoveryFinderDelegates;
|
private readonly List<ServiceDiscoveryFinderDelegate> _serviceDiscoveryFinderDelegates;
|
||||||
|
|
||||||
public FileConfigurationFluentValidator(IServiceProvider provider, ReRouteFluentValidator reRouteFluentValidator, FileGlobalConfigurationFluentValidator fileGlobalConfigurationFluentValidator)
|
public FileConfigurationFluentValidator(IServiceProvider provider, RouteFluentValidator routeFluentValidator, FileGlobalConfigurationFluentValidator fileGlobalConfigurationFluentValidator)
|
||||||
{
|
{
|
||||||
_serviceDiscoveryFinderDelegates = provider
|
_serviceDiscoveryFinderDelegates = provider
|
||||||
.GetServices<ServiceDiscoveryFinderDelegate>()
|
.GetServices<ServiceDiscoveryFinderDelegate>()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
RuleForEach(configuration => configuration.ReRoutes)
|
RuleForEach(configuration => configuration.Routes)
|
||||||
.SetValidator(reRouteFluentValidator);
|
.SetValidator(routeFluentValidator);
|
||||||
|
|
||||||
RuleFor(configuration => configuration.GlobalConfiguration)
|
RuleFor(configuration => configuration.GlobalConfiguration)
|
||||||
.SetValidator(fileGlobalConfigurationFluentValidator);
|
.SetValidator(fileGlobalConfigurationFluentValidator);
|
||||||
|
|
||||||
RuleForEach(configuration => configuration.ReRoutes)
|
RuleForEach(configuration => configuration.Routes)
|
||||||
.Must((config, reRoute) => IsNotDuplicateIn(reRoute, config.ReRoutes))
|
.Must((config, route) => IsNotDuplicateIn(route, config.Routes))
|
||||||
.WithMessage((config, reRoute) => $"{nameof(reRoute)} {reRoute.UpstreamPathTemplate} has duplicate");
|
.WithMessage((config, route) => $"{nameof(route)} {route.UpstreamPathTemplate} has duplicate");
|
||||||
|
|
||||||
RuleForEach(configuration => configuration.ReRoutes)
|
RuleForEach(configuration => configuration.Routes)
|
||||||
.Must((config, reRoute) => HaveServiceDiscoveryProviderRegistered(reRoute, config.GlobalConfiguration.ServiceDiscoveryProvider))
|
.Must((config, route) => HaveServiceDiscoveryProviderRegistered(route, config.GlobalConfiguration.ServiceDiscoveryProvider))
|
||||||
.WithMessage((config, reRoute) => $"Unable to start Ocelot, errors are: Unable to start Ocelot because either a ReRoute or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?");
|
.WithMessage((config, route) => $"Unable to start Ocelot, errors are: Unable to start Ocelot because either a Route or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?");
|
||||||
|
|
||||||
RuleForEach(configuration => configuration.ReRoutes)
|
RuleForEach(configuration => configuration.Routes)
|
||||||
.Must((config, reRoute) => IsPlaceholderNotDuplicatedIn(reRoute.UpstreamPathTemplate))
|
.Must((config, route) => IsPlaceholderNotDuplicatedIn(route.UpstreamPathTemplate))
|
||||||
.WithMessage((config, reRoute) => $"{nameof(reRoute)} {reRoute.UpstreamPathTemplate} has duplicated placeholder");
|
.WithMessage((config, route) => $"{nameof(route)} {route.UpstreamPathTemplate} has duplicated placeholder");
|
||||||
|
|
||||||
RuleFor(configuration => configuration.GlobalConfiguration.ServiceDiscoveryProvider)
|
RuleFor(configuration => configuration.GlobalConfiguration.ServiceDiscoveryProvider)
|
||||||
.Must(HaveServiceDiscoveryProviderRegistered)
|
.Must(HaveServiceDiscoveryProviderRegistered)
|
||||||
.WithMessage((config, reRoute) => $"Unable to start Ocelot, errors are: Unable to start Ocelot because either a ReRoute or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?");
|
.WithMessage((config, route) => $"Unable to start Ocelot, errors are: Unable to start Ocelot because either a Route or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?");
|
||||||
|
|
||||||
RuleForEach(configuration => configuration.ReRoutes)
|
RuleForEach(configuration => configuration.Routes)
|
||||||
.Must((config, reRoute) => IsNotDuplicateIn(reRoute, config.Aggregates))
|
.Must((config, route) => IsNotDuplicateIn(route, config.Aggregates))
|
||||||
.WithMessage((config, reRoute) => $"{nameof(reRoute)} {reRoute.UpstreamPathTemplate} has duplicate aggregate");
|
.WithMessage((config, route) => $"{nameof(route)} {route.UpstreamPathTemplate} has duplicate aggregate");
|
||||||
|
|
||||||
RuleForEach(configuration => configuration.Aggregates)
|
RuleForEach(configuration => configuration.Aggregates)
|
||||||
.Must((config, aggregateReRoute) => IsNotDuplicateIn(aggregateReRoute, config.Aggregates))
|
.Must((config, aggregateRoute) => IsNotDuplicateIn(aggregateRoute, config.Aggregates))
|
||||||
.WithMessage((config, aggregate) => $"{nameof(aggregate)} {aggregate.UpstreamPathTemplate} has duplicate aggregate");
|
.WithMessage((config, aggregate) => $"{nameof(aggregate)} {aggregate.UpstreamPathTemplate} has duplicate aggregate");
|
||||||
|
|
||||||
RuleForEach(configuration => configuration.Aggregates)
|
RuleForEach(configuration => configuration.Aggregates)
|
||||||
.Must((config, aggregateReRoute) => AllReRoutesForAggregateExist(aggregateReRoute, config.ReRoutes))
|
.Must((config, aggregateRoute) => AllRoutesForAggregateExist(aggregateRoute, config.Routes))
|
||||||
.WithMessage((config, aggregateReRoute) => $"ReRoutes for {nameof(aggregateReRoute)} {aggregateReRoute.UpstreamPathTemplate} either do not exist or do not have correct ServiceName property");
|
.WithMessage((config, aggregateRoute) => $"Routes for {nameof(aggregateRoute)} {aggregateRoute.UpstreamPathTemplate} either do not exist or do not have correct ServiceName property");
|
||||||
|
|
||||||
RuleForEach(configuration => configuration.Aggregates)
|
RuleForEach(configuration => configuration.Aggregates)
|
||||||
.Must((config, aggregateReRoute) => DoesNotContainReRoutesWithSpecificRequestIdKeys(aggregateReRoute, config.ReRoutes))
|
.Must((config, aggregateRoute) => DoesNotContainRoutesWithSpecificRequestIdKeys(aggregateRoute, config.Routes))
|
||||||
.WithMessage((config, aggregateReRoute) => $"{nameof(aggregateReRoute)} {aggregateReRoute.UpstreamPathTemplate} contains ReRoute with specific RequestIdKey, this is not possible with Aggregates");
|
.WithMessage((config, aggregateRoute) => $"{nameof(aggregateRoute)} {aggregateRoute.UpstreamPathTemplate} contains Route with specific RequestIdKey, this is not possible with Aggregates");
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool HaveServiceDiscoveryProviderRegistered(FileReRoute reRoute, FileServiceDiscoveryProvider serviceDiscoveryProvider)
|
private bool HaveServiceDiscoveryProviderRegistered(FileRoute route, FileServiceDiscoveryProvider serviceDiscoveryProvider)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(reRoute.ServiceName))
|
if (string.IsNullOrEmpty(route.ServiceName))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -107,11 +107,11 @@
|
|||||||
return new OkResponse<ConfigurationValidationResult>(result);
|
return new OkResponse<ConfigurationValidationResult>(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool AllReRoutesForAggregateExist(FileAggregateReRoute fileAggregateReRoute, List<FileReRoute> reRoutes)
|
private bool AllRoutesForAggregateExist(FileAggregateRoute fileAggregateRoute, List<FileRoute> routes)
|
||||||
{
|
{
|
||||||
var reRoutesForAggregate = reRoutes.Where(r => fileAggregateReRoute.ReRouteKeys.Contains(r.Key));
|
var routesForAggregate = routes.Where(r => fileAggregateRoute.RouteKeys.Contains(r.Key));
|
||||||
|
|
||||||
return reRoutesForAggregate.Count() == fileAggregateReRoute.ReRouteKeys.Count;
|
return routesForAggregate.Count() == fileAggregateRoute.RouteKeys.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsPlaceholderNotDuplicatedIn(string upstreamPathTemplate)
|
private bool IsPlaceholderNotDuplicatedIn(string upstreamPathTemplate)
|
||||||
@ -122,34 +122,34 @@
|
|||||||
return upstreamPathPlaceholders.Count() == upstreamPathPlaceholders.Distinct().Count();
|
return upstreamPathPlaceholders.Count() == upstreamPathPlaceholders.Distinct().Count();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool DoesNotContainReRoutesWithSpecificRequestIdKeys(FileAggregateReRoute fileAggregateReRoute,
|
private static bool DoesNotContainRoutesWithSpecificRequestIdKeys(FileAggregateRoute fileAggregateRoute,
|
||||||
List<FileReRoute> reRoutes)
|
List<FileRoute> routes)
|
||||||
{
|
{
|
||||||
var reRoutesForAggregate = reRoutes.Where(r => fileAggregateReRoute.ReRouteKeys.Contains(r.Key));
|
var routesForAggregate = routes.Where(r => fileAggregateRoute.RouteKeys.Contains(r.Key));
|
||||||
|
|
||||||
return reRoutesForAggregate.All(r => string.IsNullOrEmpty(r.RequestIdKey));
|
return routesForAggregate.All(r => string.IsNullOrEmpty(r.RequestIdKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsNotDuplicateIn(FileReRoute reRoute,
|
private static bool IsNotDuplicateIn(FileRoute route,
|
||||||
List<FileReRoute> reRoutes)
|
List<FileRoute> routes)
|
||||||
{
|
{
|
||||||
var matchingReRoutes = reRoutes
|
var matchingRoutes = routes
|
||||||
.Where(r => r.UpstreamPathTemplate == reRoute.UpstreamPathTemplate
|
.Where(r => r.UpstreamPathTemplate == route.UpstreamPathTemplate
|
||||||
&& r.UpstreamHost == reRoute.UpstreamHost)
|
&& r.UpstreamHost == route.UpstreamHost)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (matchingReRoutes.Count == 1)
|
if (matchingRoutes.Count == 1)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var allowAllVerbs = matchingReRoutes.Any(x => x.UpstreamHttpMethod.Count == 0);
|
var allowAllVerbs = matchingRoutes.Any(x => x.UpstreamHttpMethod.Count == 0);
|
||||||
|
|
||||||
var duplicateAllowAllVerbs = matchingReRoutes.Count(x => x.UpstreamHttpMethod.Count == 0) > 1;
|
var duplicateAllowAllVerbs = matchingRoutes.Count(x => x.UpstreamHttpMethod.Count == 0) > 1;
|
||||||
|
|
||||||
var specificVerbs = matchingReRoutes.Any(x => x.UpstreamHttpMethod.Count != 0);
|
var specificVerbs = matchingRoutes.Any(x => x.UpstreamHttpMethod.Count != 0);
|
||||||
|
|
||||||
var duplicateSpecificVerbs = matchingReRoutes.SelectMany(x => x.UpstreamHttpMethod).GroupBy(x => x.ToLower()).SelectMany(x => x.Skip(1)).Any();
|
var duplicateSpecificVerbs = matchingRoutes.SelectMany(x => x.UpstreamHttpMethod).GroupBy(x => x.ToLower()).SelectMany(x => x.Skip(1)).Any();
|
||||||
|
|
||||||
if (duplicateAllowAllVerbs || duplicateSpecificVerbs || (allowAllVerbs && specificVerbs))
|
if (duplicateAllowAllVerbs || duplicateSpecificVerbs || (allowAllVerbs && specificVerbs))
|
||||||
{
|
{
|
||||||
@ -159,26 +159,26 @@
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsNotDuplicateIn(FileReRoute reRoute,
|
private static bool IsNotDuplicateIn(FileRoute route,
|
||||||
List<FileAggregateReRoute> aggregateReRoutes)
|
List<FileAggregateRoute> aggregateRoutes)
|
||||||
{
|
{
|
||||||
var duplicate = aggregateReRoutes
|
var duplicate = aggregateRoutes
|
||||||
.Any(a => a.UpstreamPathTemplate == reRoute.UpstreamPathTemplate
|
.Any(a => a.UpstreamPathTemplate == route.UpstreamPathTemplate
|
||||||
&& a.UpstreamHost == reRoute.UpstreamHost
|
&& a.UpstreamHost == route.UpstreamHost
|
||||||
&& reRoute.UpstreamHttpMethod.Select(x => x.ToLower()).Contains("get"));
|
&& route.UpstreamHttpMethod.Select(x => x.ToLower()).Contains("get"));
|
||||||
|
|
||||||
return !duplicate;
|
return !duplicate;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsNotDuplicateIn(FileAggregateReRoute reRoute,
|
private static bool IsNotDuplicateIn(FileAggregateRoute route,
|
||||||
List<FileAggregateReRoute> aggregateReRoutes)
|
List<FileAggregateRoute> aggregateRoutes)
|
||||||
{
|
{
|
||||||
var matchingReRoutes = aggregateReRoutes
|
var matchingRoutes = aggregateRoutes
|
||||||
.Where(r => r.UpstreamPathTemplate == reRoute.UpstreamPathTemplate
|
.Where(r => r.UpstreamPathTemplate == route.UpstreamPathTemplate
|
||||||
&& r.UpstreamHost == reRoute.UpstreamHost)
|
&& r.UpstreamHost == route.UpstreamHost)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
return matchingReRoutes.Count <= 1;
|
return matchingRoutes.Count <= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ namespace Ocelot.Configuration.Validator
|
|||||||
{
|
{
|
||||||
RuleFor(qosOptions => qosOptions)
|
RuleFor(qosOptions => qosOptions)
|
||||||
.Must(HaveQosHandlerRegistered)
|
.Must(HaveQosHandlerRegistered)
|
||||||
.WithMessage("Unable to start Ocelot because either a ReRoute or GlobalConfiguration are using QoSOptions but no QosDelegatingHandlerDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Polly and services.AddPolly()?");
|
.WithMessage("Unable to start Ocelot because either a Route or GlobalConfiguration are using QoSOptions but no QosDelegatingHandlerDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Polly and services.AddPolly()?");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ namespace Ocelot.Configuration.Validator
|
|||||||
{
|
{
|
||||||
RuleFor(r => r.Host)
|
RuleFor(r => r.Host)
|
||||||
.NotEmpty()
|
.NotEmpty()
|
||||||
.WithMessage("When not using service discovery Host must be set on DownstreamHostAndPorts if you are not using ReRoute.Host or Ocelot cannot find your service!");
|
.WithMessage("When not using service discovery Host must be set on DownstreamHostAndPorts if you are not using Route.Host or Ocelot cannot find your service!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Ocelot.Configuration.Validator
|
namespace Ocelot.Configuration.Validator
|
||||||
{
|
{
|
||||||
using File;
|
using Ocelot.Configuration.File;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -8,83 +8,83 @@
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
public class ReRouteFluentValidator : AbstractValidator<FileReRoute>
|
public class RouteFluentValidator : AbstractValidator<FileRoute>
|
||||||
{
|
{
|
||||||
private readonly IAuthenticationSchemeProvider _authenticationSchemeProvider;
|
private readonly IAuthenticationSchemeProvider _authenticationSchemeProvider;
|
||||||
|
|
||||||
public ReRouteFluentValidator(IAuthenticationSchemeProvider authenticationSchemeProvider, HostAndPortValidator hostAndPortValidator, FileQoSOptionsFluentValidator fileQoSOptionsFluentValidator)
|
public RouteFluentValidator(IAuthenticationSchemeProvider authenticationSchemeProvider, HostAndPortValidator hostAndPortValidator, FileQoSOptionsFluentValidator fileQoSOptionsFluentValidator)
|
||||||
{
|
{
|
||||||
_authenticationSchemeProvider = authenticationSchemeProvider;
|
_authenticationSchemeProvider = authenticationSchemeProvider;
|
||||||
|
|
||||||
RuleFor(reRoute => reRoute.QoSOptions)
|
RuleFor(route => route.QoSOptions)
|
||||||
.SetValidator(fileQoSOptionsFluentValidator);
|
.SetValidator(fileQoSOptionsFluentValidator);
|
||||||
|
|
||||||
RuleFor(reRoute => reRoute.DownstreamPathTemplate)
|
RuleFor(route => route.DownstreamPathTemplate)
|
||||||
.NotEmpty()
|
.NotEmpty()
|
||||||
.WithMessage("{PropertyName} cannot be empty");
|
.WithMessage("{PropertyName} cannot be empty");
|
||||||
|
|
||||||
RuleFor(reRoute => reRoute.UpstreamPathTemplate)
|
RuleFor(route => route.UpstreamPathTemplate)
|
||||||
.NotEmpty()
|
.NotEmpty()
|
||||||
.WithMessage("{PropertyName} cannot be empty");
|
.WithMessage("{PropertyName} cannot be empty");
|
||||||
|
|
||||||
When(reRoute => !string.IsNullOrEmpty(reRoute.DownstreamPathTemplate), () =>
|
When(route => !string.IsNullOrEmpty(route.DownstreamPathTemplate), () =>
|
||||||
{
|
{
|
||||||
RuleFor(reRoute => reRoute.DownstreamPathTemplate)
|
RuleFor(route => route.DownstreamPathTemplate)
|
||||||
.Must(path => path.StartsWith("/"))
|
.Must(path => path.StartsWith("/"))
|
||||||
.WithMessage("{PropertyName} {PropertyValue} doesnt start with forward slash");
|
.WithMessage("{PropertyName} {PropertyValue} doesnt start with forward slash");
|
||||||
|
|
||||||
RuleFor(reRoute => reRoute.DownstreamPathTemplate)
|
RuleFor(route => route.DownstreamPathTemplate)
|
||||||
.Must(path => !path.Contains("//"))
|
.Must(path => !path.Contains("//"))
|
||||||
.WithMessage("{PropertyName} {PropertyValue} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature.");
|
.WithMessage("{PropertyName} {PropertyValue} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature.");
|
||||||
|
|
||||||
RuleFor(reRoute => reRoute.DownstreamPathTemplate)
|
RuleFor(route => route.DownstreamPathTemplate)
|
||||||
.Must(path => !path.Contains("https://") && !path.Contains("http://"))
|
.Must(path => !path.Contains("https://") && !path.Contains("http://"))
|
||||||
.WithMessage("{PropertyName} {PropertyValue} contains scheme");
|
.WithMessage("{PropertyName} {PropertyValue} contains scheme");
|
||||||
});
|
});
|
||||||
|
|
||||||
When(reRoute => !string.IsNullOrEmpty(reRoute.UpstreamPathTemplate), () =>
|
When(route => !string.IsNullOrEmpty(route.UpstreamPathTemplate), () =>
|
||||||
{
|
{
|
||||||
RuleFor(reRoute => reRoute.UpstreamPathTemplate)
|
RuleFor(route => route.UpstreamPathTemplate)
|
||||||
.Must(path => !path.Contains("//"))
|
.Must(path => !path.Contains("//"))
|
||||||
.WithMessage("{PropertyName} {PropertyValue} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature.");
|
.WithMessage("{PropertyName} {PropertyValue} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature.");
|
||||||
|
|
||||||
RuleFor(reRoute => reRoute.UpstreamPathTemplate)
|
RuleFor(route => route.UpstreamPathTemplate)
|
||||||
.Must(path => path.StartsWith("/"))
|
.Must(path => path.StartsWith("/"))
|
||||||
.WithMessage("{PropertyName} {PropertyValue} doesnt start with forward slash");
|
.WithMessage("{PropertyName} {PropertyValue} doesnt start with forward slash");
|
||||||
|
|
||||||
RuleFor(reRoute => reRoute.UpstreamPathTemplate)
|
RuleFor(route => route.UpstreamPathTemplate)
|
||||||
.Must(path => !path.Contains("https://") && !path.Contains("http://"))
|
.Must(path => !path.Contains("https://") && !path.Contains("http://"))
|
||||||
.WithMessage("{PropertyName} {PropertyValue} contains scheme");
|
.WithMessage("{PropertyName} {PropertyValue} contains scheme");
|
||||||
});
|
});
|
||||||
|
|
||||||
When(reRoute => reRoute.RateLimitOptions.EnableRateLimiting, () =>
|
When(route => route.RateLimitOptions.EnableRateLimiting, () =>
|
||||||
{
|
{
|
||||||
RuleFor(reRoute => reRoute.RateLimitOptions.Period)
|
RuleFor(route => route.RateLimitOptions.Period)
|
||||||
.NotEmpty()
|
.NotEmpty()
|
||||||
.WithMessage("RateLimitOptions.Period is empty");
|
.WithMessage("RateLimitOptions.Period is empty");
|
||||||
|
|
||||||
RuleFor(reRoute => reRoute.RateLimitOptions)
|
RuleFor(route => route.RateLimitOptions)
|
||||||
.Must(IsValidPeriod)
|
.Must(IsValidPeriod)
|
||||||
.WithMessage("RateLimitOptions.Period does not contain integer then s (second), m (minute), h (hour), d (day) e.g. 1m for 1 minute period");
|
.WithMessage("RateLimitOptions.Period does not contain integer then s (second), m (minute), h (hour), d (day) e.g. 1m for 1 minute period");
|
||||||
});
|
});
|
||||||
|
|
||||||
RuleFor(reRoute => reRoute.AuthenticationOptions)
|
RuleFor(route => route.AuthenticationOptions)
|
||||||
.MustAsync(IsSupportedAuthenticationProviders)
|
.MustAsync(IsSupportedAuthenticationProviders)
|
||||||
.WithMessage("{PropertyName} {PropertyValue} is unsupported authentication provider");
|
.WithMessage("{PropertyName} {PropertyValue} is unsupported authentication provider");
|
||||||
|
|
||||||
When(reRoute => string.IsNullOrEmpty(reRoute.ServiceName), () =>
|
When(route => string.IsNullOrEmpty(route.ServiceName), () =>
|
||||||
{
|
{
|
||||||
RuleFor(r => r.DownstreamHostAndPorts).NotEmpty()
|
RuleFor(r => r.DownstreamHostAndPorts).NotEmpty()
|
||||||
.WithMessage("When not using service discovery DownstreamHostAndPorts must be set and not empty or Ocelot cannot find your service!");
|
.WithMessage("When not using service discovery DownstreamHostAndPorts must be set and not empty or Ocelot cannot find your service!");
|
||||||
});
|
});
|
||||||
|
|
||||||
When(reRoute => string.IsNullOrEmpty(reRoute.ServiceName), () =>
|
When(route => string.IsNullOrEmpty(route.ServiceName), () =>
|
||||||
{
|
{
|
||||||
RuleForEach(reRoute => reRoute.DownstreamHostAndPorts)
|
RuleForEach(route => route.DownstreamHostAndPorts)
|
||||||
.SetValidator(hostAndPortValidator);
|
.SetValidator(hostAndPortValidator);
|
||||||
});
|
});
|
||||||
|
|
||||||
When(reRoute => !string.IsNullOrEmpty(reRoute.DownstreamHttpVersion), () =>
|
When(route => !string.IsNullOrEmpty(route.DownstreamHttpVersion), () =>
|
||||||
{
|
{
|
||||||
RuleFor(r => r.DownstreamHttpVersion).Matches("^[0-9]([.,][0-9]{1,1})?$");
|
RuleFor(r => r.DownstreamHttpVersion).Matches("^[0-9]([.,][0-9]{1,1})?$");
|
||||||
});
|
});
|
@ -1,6 +1,6 @@
|
|||||||
namespace Ocelot.DependencyInjection
|
namespace Ocelot.DependencyInjection
|
||||||
{
|
{
|
||||||
using Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Configuration.Memory;
|
using Microsoft.Extensions.Configuration.Memory;
|
||||||
@ -70,7 +70,7 @@ namespace Ocelot.DependencyInjection
|
|||||||
}
|
}
|
||||||
|
|
||||||
fileConfiguration.Aggregates.AddRange(config.Aggregates);
|
fileConfiguration.Aggregates.AddRange(config.Aggregates);
|
||||||
fileConfiguration.ReRoutes.AddRange(config.ReRoutes);
|
fileConfiguration.Routes.AddRange(config.Routes);
|
||||||
}
|
}
|
||||||
|
|
||||||
var json = JsonConvert.SerializeObject(fileConfiguration);
|
var json = JsonConvert.SerializeObject(fileConfiguration);
|
||||||
|
@ -38,11 +38,11 @@ namespace Ocelot.DependencyInjection
|
|||||||
where T : ILoadBalancer;
|
where T : ILoadBalancer;
|
||||||
|
|
||||||
IOcelotBuilder AddCustomLoadBalancer<T>(
|
IOcelotBuilder AddCustomLoadBalancer<T>(
|
||||||
Func<DownstreamReRoute, IServiceDiscoveryProvider, T> loadBalancerFactoryFunc)
|
Func<DownstreamRoute, IServiceDiscoveryProvider, T> loadBalancerFactoryFunc)
|
||||||
where T : ILoadBalancer;
|
where T : ILoadBalancer;
|
||||||
|
|
||||||
IOcelotBuilder AddCustomLoadBalancer<T>(
|
IOcelotBuilder AddCustomLoadBalancer<T>(
|
||||||
Func<IServiceProvider, DownstreamReRoute, IServiceDiscoveryProvider, T> loadBalancerFactoryFunc)
|
Func<IServiceProvider, DownstreamRoute, IServiceDiscoveryProvider, T> loadBalancerFactoryFunc)
|
||||||
where T : ILoadBalancer;
|
where T : ILoadBalancer;
|
||||||
|
|
||||||
IOcelotBuilder AddConfigPlaceholders();
|
IOcelotBuilder AddConfigPlaceholders();
|
||||||
|
@ -65,13 +65,13 @@ namespace Ocelot.DependencyInjection
|
|||||||
Services.TryAddSingleton<IInternalConfigurationRepository, InMemoryInternalConfigurationRepository>();
|
Services.TryAddSingleton<IInternalConfigurationRepository, InMemoryInternalConfigurationRepository>();
|
||||||
Services.TryAddSingleton<IConfigurationValidator, FileConfigurationFluentValidator>();
|
Services.TryAddSingleton<IConfigurationValidator, FileConfigurationFluentValidator>();
|
||||||
Services.TryAddSingleton<HostAndPortValidator>();
|
Services.TryAddSingleton<HostAndPortValidator>();
|
||||||
Services.TryAddSingleton<IReRoutesCreator, ReRoutesCreator>();
|
Services.TryAddSingleton<IRoutesCreator, RoutesCreator>();
|
||||||
Services.TryAddSingleton<IAggregatesCreator, AggregatesCreator>();
|
Services.TryAddSingleton<IAggregatesCreator, AggregatesCreator>();
|
||||||
Services.TryAddSingleton<IReRouteKeyCreator, ReRouteKeyCreator>();
|
Services.TryAddSingleton<IRouteKeyCreator, RouteKeyCreator>();
|
||||||
Services.TryAddSingleton<IConfigurationCreator, ConfigurationCreator>();
|
Services.TryAddSingleton<IConfigurationCreator, ConfigurationCreator>();
|
||||||
Services.TryAddSingleton<IDynamicsCreator, DynamicsCreator>();
|
Services.TryAddSingleton<IDynamicsCreator, DynamicsCreator>();
|
||||||
Services.TryAddSingleton<ILoadBalancerOptionsCreator, LoadBalancerOptionsCreator>();
|
Services.TryAddSingleton<ILoadBalancerOptionsCreator, LoadBalancerOptionsCreator>();
|
||||||
Services.TryAddSingleton<ReRouteFluentValidator>();
|
Services.TryAddSingleton<RouteFluentValidator>();
|
||||||
Services.TryAddSingleton<FileGlobalConfigurationFluentValidator>();
|
Services.TryAddSingleton<FileGlobalConfigurationFluentValidator>();
|
||||||
Services.TryAddSingleton<FileQoSOptionsFluentValidator>();
|
Services.TryAddSingleton<FileQoSOptionsFluentValidator>();
|
||||||
Services.TryAddSingleton<IClaimsToThingCreator, ClaimsToThingCreator>();
|
Services.TryAddSingleton<IClaimsToThingCreator, ClaimsToThingCreator>();
|
||||||
@ -80,7 +80,7 @@ namespace Ocelot.DependencyInjection
|
|||||||
Services.TryAddSingleton<IRequestIdKeyCreator, RequestIdKeyCreator>();
|
Services.TryAddSingleton<IRequestIdKeyCreator, RequestIdKeyCreator>();
|
||||||
Services.TryAddSingleton<IServiceProviderConfigurationCreator, ServiceProviderConfigurationCreator>();
|
Services.TryAddSingleton<IServiceProviderConfigurationCreator, ServiceProviderConfigurationCreator>();
|
||||||
Services.TryAddSingleton<IQoSOptionsCreator, QoSOptionsCreator>();
|
Services.TryAddSingleton<IQoSOptionsCreator, QoSOptionsCreator>();
|
||||||
Services.TryAddSingleton<IReRouteOptionsCreator, ReRouteOptionsCreator>();
|
Services.TryAddSingleton<IRouteOptionsCreator, RouteOptionsCreator>();
|
||||||
Services.TryAddSingleton<IRateLimitOptionsCreator, RateLimitOptionsCreator>();
|
Services.TryAddSingleton<IRateLimitOptionsCreator, RateLimitOptionsCreator>();
|
||||||
Services.TryAddSingleton<IBaseUrlFinder, BaseUrlFinder>();
|
Services.TryAddSingleton<IBaseUrlFinder, BaseUrlFinder>();
|
||||||
Services.TryAddSingleton<IRegionCreator, RegionCreator>();
|
Services.TryAddSingleton<IRegionCreator, RegionCreator>();
|
||||||
@ -175,14 +175,14 @@ namespace Ocelot.DependencyInjection
|
|||||||
public IOcelotBuilder AddCustomLoadBalancer<T>()
|
public IOcelotBuilder AddCustomLoadBalancer<T>()
|
||||||
where T : ILoadBalancer, new()
|
where T : ILoadBalancer, new()
|
||||||
{
|
{
|
||||||
AddCustomLoadBalancer((provider, reRoute, serviceDiscoveryProvider) => new T());
|
AddCustomLoadBalancer((provider, route, serviceDiscoveryProvider) => new T());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IOcelotBuilder AddCustomLoadBalancer<T>(Func<T> loadBalancerFactoryFunc)
|
public IOcelotBuilder AddCustomLoadBalancer<T>(Func<T> loadBalancerFactoryFunc)
|
||||||
where T : ILoadBalancer
|
where T : ILoadBalancer
|
||||||
{
|
{
|
||||||
AddCustomLoadBalancer((provider, reRoute, serviceDiscoveryProvider) =>
|
AddCustomLoadBalancer((provider, route, serviceDiscoveryProvider) =>
|
||||||
loadBalancerFactoryFunc());
|
loadBalancerFactoryFunc());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -190,26 +190,26 @@ namespace Ocelot.DependencyInjection
|
|||||||
public IOcelotBuilder AddCustomLoadBalancer<T>(Func<IServiceProvider, T> loadBalancerFactoryFunc)
|
public IOcelotBuilder AddCustomLoadBalancer<T>(Func<IServiceProvider, T> loadBalancerFactoryFunc)
|
||||||
where T : ILoadBalancer
|
where T : ILoadBalancer
|
||||||
{
|
{
|
||||||
AddCustomLoadBalancer((provider, reRoute, serviceDiscoveryProvider) =>
|
AddCustomLoadBalancer((provider, route, serviceDiscoveryProvider) =>
|
||||||
loadBalancerFactoryFunc(provider));
|
loadBalancerFactoryFunc(provider));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IOcelotBuilder AddCustomLoadBalancer<T>(Func<DownstreamReRoute, IServiceDiscoveryProvider, T> loadBalancerFactoryFunc)
|
public IOcelotBuilder AddCustomLoadBalancer<T>(Func<DownstreamRoute, IServiceDiscoveryProvider, T> loadBalancerFactoryFunc)
|
||||||
where T : ILoadBalancer
|
where T : ILoadBalancer
|
||||||
{
|
{
|
||||||
AddCustomLoadBalancer((provider, reRoute, serviceDiscoveryProvider) =>
|
AddCustomLoadBalancer((provider, route, serviceDiscoveryProvider) =>
|
||||||
loadBalancerFactoryFunc(reRoute, serviceDiscoveryProvider));
|
loadBalancerFactoryFunc(route, serviceDiscoveryProvider));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IOcelotBuilder AddCustomLoadBalancer<T>(Func<IServiceProvider, DownstreamReRoute, IServiceDiscoveryProvider, T> loadBalancerFactoryFunc)
|
public IOcelotBuilder AddCustomLoadBalancer<T>(Func<IServiceProvider, DownstreamRoute, IServiceDiscoveryProvider, T> loadBalancerFactoryFunc)
|
||||||
where T : ILoadBalancer
|
where T : ILoadBalancer
|
||||||
{
|
{
|
||||||
Services.AddSingleton<ILoadBalancerCreator>(provider =>
|
Services.AddSingleton<ILoadBalancerCreator>(provider =>
|
||||||
new DelegateInvokingLoadBalancerCreator<T>(
|
new DelegateInvokingLoadBalancerCreator<T>(
|
||||||
(reRoute, serviceDiscoveryProvider) =>
|
(route, serviceDiscoveryProvider) =>
|
||||||
loadBalancerFactoryFunc(provider, reRoute, serviceDiscoveryProvider)));
|
loadBalancerFactoryFunc(provider, route, serviceDiscoveryProvider)));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,16 +24,16 @@
|
|||||||
|
|
||||||
public async Task Invoke(HttpContext httpContext)
|
public async Task Invoke(HttpContext httpContext)
|
||||||
{
|
{
|
||||||
var downstreamReRoute = httpContext.Items.DownstreamReRoute();
|
var downstreamRoute = httpContext.Items.DownstreamRoute();
|
||||||
|
|
||||||
if (downstreamReRoute.ClaimsToPath.Any())
|
if (downstreamRoute.ClaimsToPath.Any())
|
||||||
{
|
{
|
||||||
Logger.LogInformation($"{downstreamReRoute.DownstreamPathTemplate.Value} has instructions to convert claims to path");
|
Logger.LogInformation($"{downstreamRoute.DownstreamPathTemplate.Value} has instructions to convert claims to path");
|
||||||
|
|
||||||
var templatePlaceholderNameAndValues = httpContext.Items.TemplatePlaceholderNameAndValues();
|
var templatePlaceholderNameAndValues = httpContext.Items.TemplatePlaceholderNameAndValues();
|
||||||
|
|
||||||
var response = _changeDownstreamPathTemplate.ChangeDownstreamPath(downstreamReRoute.ClaimsToPath, httpContext.User.Claims,
|
var response = _changeDownstreamPathTemplate.ChangeDownstreamPath(downstreamRoute.ClaimsToPath, httpContext.User.Claims,
|
||||||
downstreamReRoute.DownstreamPathTemplate, templatePlaceholderNameAndValues);
|
downstreamRoute.DownstreamPathTemplate, templatePlaceholderNameAndValues);
|
||||||
|
|
||||||
if (response.IsError)
|
if (response.IsError)
|
||||||
{
|
{
|
||||||
|
@ -4,19 +4,19 @@
|
|||||||
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
public class DownstreamRoute
|
public class DownstreamRouteHolder
|
||||||
{
|
{
|
||||||
public DownstreamRoute()
|
public DownstreamRouteHolder()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamRoute(List<PlaceholderNameAndValue> templatePlaceholderNameAndValues, ReRoute reRoute)
|
public DownstreamRouteHolder(List<PlaceholderNameAndValue> templatePlaceholderNameAndValues, Route route)
|
||||||
{
|
{
|
||||||
TemplatePlaceholderNameAndValues = templatePlaceholderNameAndValues;
|
TemplatePlaceholderNameAndValues = templatePlaceholderNameAndValues;
|
||||||
ReRoute = reRoute;
|
Route = route;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PlaceholderNameAndValue> TemplatePlaceholderNameAndValues { get; private set; }
|
public List<PlaceholderNameAndValue> TemplatePlaceholderNameAndValues { get; private set; }
|
||||||
public ReRoute ReRoute { get; private set; }
|
public Route Route { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,28 +1,27 @@
|
|||||||
namespace Ocelot.DownstreamRouteFinder.Finder
|
namespace Ocelot.DownstreamRouteFinder.Finder
|
||||||
{
|
{
|
||||||
using System;
|
using Ocelot.Configuration;
|
||||||
using Configuration;
|
using Ocelot.Configuration.Builder;
|
||||||
using Configuration.Builder;
|
using Ocelot.Configuration.Creator;
|
||||||
using Configuration.Creator;
|
using Ocelot.LoadBalancer.LoadBalancers;
|
||||||
using LoadBalancer.LoadBalancers;
|
using Ocelot.Responses;
|
||||||
using Responses;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using UrlMatcher;
|
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||||
|
|
||||||
public class DownstreamRouteCreator : IDownstreamRouteProvider
|
public class DownstreamRouteCreator : IDownstreamRouteProvider
|
||||||
{
|
{
|
||||||
private readonly IQoSOptionsCreator _qoSOptionsCreator;
|
private readonly IQoSOptionsCreator _qoSOptionsCreator;
|
||||||
private readonly ConcurrentDictionary<string, OkResponse<DownstreamRoute>> _cache;
|
private readonly ConcurrentDictionary<string, OkResponse<DownstreamRouteHolder>> _cache;
|
||||||
|
|
||||||
public DownstreamRouteCreator(IQoSOptionsCreator qoSOptionsCreator)
|
public DownstreamRouteCreator(IQoSOptionsCreator qoSOptionsCreator)
|
||||||
{
|
{
|
||||||
_qoSOptionsCreator = qoSOptionsCreator;
|
_qoSOptionsCreator = qoSOptionsCreator;
|
||||||
_cache = new ConcurrentDictionary<string, OkResponse<DownstreamRoute>>();
|
_cache = new ConcurrentDictionary<string, OkResponse<DownstreamRouteHolder>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response<DownstreamRoute> Get(string upstreamUrlPath, string upstreamQueryString, string upstreamHttpMethod, IInternalConfiguration configuration, string upstreamHost)
|
public Response<DownstreamRouteHolder> Get(string upstreamUrlPath, string upstreamQueryString, string upstreamHttpMethod, IInternalConfiguration configuration, string upstreamHost)
|
||||||
{
|
{
|
||||||
var serviceName = GetServiceName(upstreamUrlPath);
|
var serviceName = GetServiceName(upstreamUrlPath);
|
||||||
|
|
||||||
@ -37,16 +36,16 @@
|
|||||||
|
|
||||||
var loadBalancerKey = CreateLoadBalancerKey(downstreamPathForKeys, upstreamHttpMethod, configuration.LoadBalancerOptions);
|
var loadBalancerKey = CreateLoadBalancerKey(downstreamPathForKeys, upstreamHttpMethod, configuration.LoadBalancerOptions);
|
||||||
|
|
||||||
if (_cache.TryGetValue(loadBalancerKey, out var downstreamRoute))
|
if (_cache.TryGetValue(loadBalancerKey, out var downstreamRouteHolder))
|
||||||
{
|
{
|
||||||
return downstreamRoute;
|
return downstreamRouteHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
var qosOptions = _qoSOptionsCreator.Create(configuration.QoSOptions, downstreamPathForKeys, new List<string> { upstreamHttpMethod });
|
var qosOptions = _qoSOptionsCreator.Create(configuration.QoSOptions, downstreamPathForKeys, new List<string> { upstreamHttpMethod });
|
||||||
|
|
||||||
var upstreamPathTemplate = new UpstreamPathTemplateBuilder().WithOriginalValue(upstreamUrlPath).Build();
|
var upstreamPathTemplate = new UpstreamPathTemplateBuilder().WithOriginalValue(upstreamUrlPath).Build();
|
||||||
|
|
||||||
var downstreamReRouteBuilder = new DownstreamReRouteBuilder()
|
var downstreamRouteBuilder = new DownstreamRouteBuilder()
|
||||||
.WithServiceName(serviceName)
|
.WithServiceName(serviceName)
|
||||||
.WithLoadBalancerKey(loadBalancerKey)
|
.WithLoadBalancerKey(loadBalancerKey)
|
||||||
.WithDownstreamPathTemplate(downstreamPath)
|
.WithDownstreamPathTemplate(downstreamPath)
|
||||||
@ -58,32 +57,32 @@
|
|||||||
.WithDownstreamHttpVersion(configuration.DownstreamHttpVersion)
|
.WithDownstreamHttpVersion(configuration.DownstreamHttpVersion)
|
||||||
.WithUpstreamPathTemplate(upstreamPathTemplate);
|
.WithUpstreamPathTemplate(upstreamPathTemplate);
|
||||||
|
|
||||||
var rateLimitOptions = configuration.ReRoutes != null
|
var rateLimitOptions = configuration.Routes != null
|
||||||
? configuration.ReRoutes
|
? configuration.Routes
|
||||||
.SelectMany(x => x.DownstreamReRoute)
|
.SelectMany(x => x.DownstreamRoute)
|
||||||
.FirstOrDefault(x => x.ServiceName == serviceName)
|
.FirstOrDefault(x => x.ServiceName == serviceName)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
if (rateLimitOptions != null)
|
if (rateLimitOptions != null)
|
||||||
{
|
{
|
||||||
downstreamReRouteBuilder
|
downstreamRouteBuilder
|
||||||
.WithRateLimitOptions(rateLimitOptions.RateLimitOptions)
|
.WithRateLimitOptions(rateLimitOptions.RateLimitOptions)
|
||||||
.WithEnableRateLimiting(true);
|
.WithEnableRateLimiting(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
var downstreamReRoute = downstreamReRouteBuilder.Build();
|
var downstreamRoute = downstreamRouteBuilder.Build();
|
||||||
|
|
||||||
var reRoute = new ReRouteBuilder()
|
var route = new RouteBuilder()
|
||||||
.WithDownstreamReRoute(downstreamReRoute)
|
.WithDownstreamRoute(downstreamRoute)
|
||||||
.WithUpstreamHttpMethod(new List<string>() { upstreamHttpMethod })
|
.WithUpstreamHttpMethod(new List<string>() { upstreamHttpMethod })
|
||||||
.WithUpstreamPathTemplate(upstreamPathTemplate)
|
.WithUpstreamPathTemplate(upstreamPathTemplate)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
downstreamRoute = new OkResponse<DownstreamRoute>(new DownstreamRoute(new List<PlaceholderNameAndValue>(), reRoute));
|
downstreamRouteHolder = new OkResponse<DownstreamRouteHolder>(new DownstreamRouteHolder(new List<PlaceholderNameAndValue>(), route));
|
||||||
|
|
||||||
_cache.AddOrUpdate(loadBalancerKey, downstreamRoute, (x, y) => downstreamRoute);
|
_cache.AddOrUpdate(loadBalancerKey, downstreamRouteHolder, (x, y) => downstreamRouteHolder);
|
||||||
|
|
||||||
return downstreamRoute;
|
return downstreamRouteHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string RemoveQueryString(string downstreamPath)
|
private static string RemoveQueryString(string downstreamPath)
|
||||||
|
@ -17,46 +17,46 @@ namespace Ocelot.DownstreamRouteFinder.Finder
|
|||||||
_placeholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder;
|
_placeholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response<DownstreamRoute> Get(string upstreamUrlPath, string upstreamQueryString, string httpMethod, IInternalConfiguration configuration, string upstreamHost)
|
public Response<DownstreamRouteHolder> Get(string upstreamUrlPath, string upstreamQueryString, string httpMethod, IInternalConfiguration configuration, string upstreamHost)
|
||||||
{
|
{
|
||||||
var downstreamRoutes = new List<DownstreamRoute>();
|
var downstreamRoutes = new List<DownstreamRouteHolder>();
|
||||||
|
|
||||||
var applicableReRoutes = configuration.ReRoutes
|
var applicableRoutes = configuration.Routes
|
||||||
.Where(r => RouteIsApplicableToThisRequest(r, httpMethod, upstreamHost))
|
.Where(r => RouteIsApplicableToThisRequest(r, httpMethod, upstreamHost))
|
||||||
.OrderByDescending(x => x.UpstreamTemplatePattern.Priority);
|
.OrderByDescending(x => x.UpstreamTemplatePattern.Priority);
|
||||||
|
|
||||||
foreach (var reRoute in applicableReRoutes)
|
foreach (var route in applicableRoutes)
|
||||||
{
|
{
|
||||||
var urlMatch = _urlMatcher.Match(upstreamUrlPath, upstreamQueryString, reRoute.UpstreamTemplatePattern);
|
var urlMatch = _urlMatcher.Match(upstreamUrlPath, upstreamQueryString, route.UpstreamTemplatePattern);
|
||||||
|
|
||||||
if (urlMatch.Data.Match)
|
if (urlMatch.Data.Match)
|
||||||
{
|
{
|
||||||
downstreamRoutes.Add(GetPlaceholderNamesAndValues(upstreamUrlPath, upstreamQueryString, reRoute));
|
downstreamRoutes.Add(GetPlaceholderNamesAndValues(upstreamUrlPath, upstreamQueryString, route));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (downstreamRoutes.Any())
|
if (downstreamRoutes.Any())
|
||||||
{
|
{
|
||||||
var notNullOption = downstreamRoutes.FirstOrDefault(x => !string.IsNullOrEmpty(x.ReRoute.UpstreamHost));
|
var notNullOption = downstreamRoutes.FirstOrDefault(x => !string.IsNullOrEmpty(x.Route.UpstreamHost));
|
||||||
var nullOption = downstreamRoutes.FirstOrDefault(x => string.IsNullOrEmpty(x.ReRoute.UpstreamHost));
|
var nullOption = downstreamRoutes.FirstOrDefault(x => string.IsNullOrEmpty(x.Route.UpstreamHost));
|
||||||
|
|
||||||
return notNullOption != null ? new OkResponse<DownstreamRoute>(notNullOption) : new OkResponse<DownstreamRoute>(nullOption);
|
return notNullOption != null ? new OkResponse<DownstreamRouteHolder>(notNullOption) : new OkResponse<DownstreamRouteHolder>(nullOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ErrorResponse<DownstreamRoute>(new UnableToFindDownstreamRouteError(upstreamUrlPath, httpMethod));
|
return new ErrorResponse<DownstreamRouteHolder>(new UnableToFindDownstreamRouteError(upstreamUrlPath, httpMethod));
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool RouteIsApplicableToThisRequest(ReRoute reRoute, string httpMethod, string upstreamHost)
|
private bool RouteIsApplicableToThisRequest(Route route, string httpMethod, string upstreamHost)
|
||||||
{
|
{
|
||||||
return (reRoute.UpstreamHttpMethod.Count == 0 || reRoute.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(httpMethod.ToLower())) &&
|
return (route.UpstreamHttpMethod.Count == 0 || route.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(httpMethod.ToLower())) &&
|
||||||
(string.IsNullOrEmpty(reRoute.UpstreamHost) || reRoute.UpstreamHost == upstreamHost);
|
(string.IsNullOrEmpty(route.UpstreamHost) || route.UpstreamHost == upstreamHost);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DownstreamRoute GetPlaceholderNamesAndValues(string path, string query, ReRoute reRoute)
|
private DownstreamRouteHolder GetPlaceholderNamesAndValues(string path, string query, Route route)
|
||||||
{
|
{
|
||||||
var templatePlaceholderNameAndValues = _placeholderNameAndValueFinder.Find(path, query, reRoute.UpstreamTemplatePattern.OriginalValue);
|
var templatePlaceholderNameAndValues = _placeholderNameAndValueFinder.Find(path, query, route.UpstreamTemplatePattern.OriginalValue);
|
||||||
|
|
||||||
return new DownstreamRoute(templatePlaceholderNameAndValues.Data, reRoute);
|
return new DownstreamRouteHolder(templatePlaceholderNameAndValues.Data, route);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,9 @@
|
|||||||
|
|
||||||
public IDownstreamRouteProvider Get(IInternalConfiguration config)
|
public IDownstreamRouteProvider Get(IInternalConfiguration config)
|
||||||
{
|
{
|
||||||
//todo - this is a bit hacky we are saying there are no reRoutes or there are reRoutes but none of them have
|
//todo - this is a bit hacky we are saying there are no routes or there are routes but none of them have
|
||||||
//an upstream path template which means they are dyanmic and service discovery is on...
|
//an upstream path template which means they are dyanmic and service discovery is on...
|
||||||
if ((!config.ReRoutes.Any() || config.ReRoutes.All(x => string.IsNullOrEmpty(x.UpstreamTemplatePattern?.OriginalValue))) && IsServiceDiscovery(config.ServiceProviderConfiguration))
|
if ((!config.Routes.Any() || config.Routes.All(x => string.IsNullOrEmpty(x.UpstreamTemplatePattern?.OriginalValue))) && IsServiceDiscovery(config.ServiceProviderConfiguration))
|
||||||
{
|
{
|
||||||
_logger.LogInformation($"Selected {nameof(DownstreamRouteCreator)} as DownstreamRouteProvider for this request");
|
_logger.LogInformation($"Selected {nameof(DownstreamRouteCreator)} as DownstreamRouteProvider for this request");
|
||||||
return _providers[nameof(DownstreamRouteCreator)];
|
return _providers[nameof(DownstreamRouteCreator)];
|
||||||
|
@ -5,6 +5,6 @@ namespace Ocelot.DownstreamRouteFinder.Finder
|
|||||||
{
|
{
|
||||||
public interface IDownstreamRouteProvider
|
public interface IDownstreamRouteProvider
|
||||||
{
|
{
|
||||||
Response<DownstreamRoute> Get(string upstreamUrlPath, string upstreamQueryString, string upstreamHttpMethod, IInternalConfiguration configuration, string upstreamHost);
|
Response<DownstreamRouteHolder> Get(string upstreamUrlPath, string upstreamQueryString, string upstreamHttpMethod, IInternalConfiguration configuration, string upstreamHost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ namespace Ocelot.DownstreamRouteFinder.Finder
|
|||||||
public class UnableToFindDownstreamRouteError : Error
|
public class UnableToFindDownstreamRouteError : Error
|
||||||
{
|
{
|
||||||
public UnableToFindDownstreamRouteError(string path, string httpVerb)
|
public UnableToFindDownstreamRouteError(string path, string httpVerb)
|
||||||
: base($"Failed to match ReRoute configuration for upstream path: {path}, verb: {httpVerb}.", OcelotErrorCode.UnableToFindDownstreamRouteError, 404)
|
: base($"Failed to match Route configuration for upstream path: {path}, verb: {httpVerb}.", OcelotErrorCode.UnableToFindDownstreamRouteError, 404)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ namespace Ocelot.DownstreamRouteFinder.Middleware
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var downstreamPathTemplates = string.Join(", ", response.Data.ReRoute.DownstreamReRoute.Select(r => r.DownstreamPathTemplate.Value));
|
var downstreamPathTemplates = string.Join(", ", response.Data.Route.DownstreamRoute.Select(r => r.DownstreamPathTemplate.Value));
|
||||||
Logger.LogDebug($"downstream templates are {downstreamPathTemplates}");
|
Logger.LogDebug($"downstream templates are {downstreamPathTemplates}");
|
||||||
|
|
||||||
// why set both of these on HttpContext
|
// why set both of these on HttpContext
|
||||||
|
@ -32,12 +32,12 @@ namespace Ocelot.DownstreamUrlCreator.Middleware
|
|||||||
|
|
||||||
public async Task Invoke(HttpContext httpContext)
|
public async Task Invoke(HttpContext httpContext)
|
||||||
{
|
{
|
||||||
var downstreamReRoute = httpContext.Items.DownstreamReRoute();
|
var downstreamRoute = httpContext.Items.DownstreamRoute();
|
||||||
|
|
||||||
var templatePlaceholderNameAndValues = httpContext.Items.TemplatePlaceholderNameAndValues();
|
var templatePlaceholderNameAndValues = httpContext.Items.TemplatePlaceholderNameAndValues();
|
||||||
|
|
||||||
var response = _replacer
|
var response = _replacer
|
||||||
.Replace(downstreamReRoute.DownstreamPathTemplate.Value, templatePlaceholderNameAndValues);
|
.Replace(downstreamRoute.DownstreamPathTemplate.Value, templatePlaceholderNameAndValues);
|
||||||
|
|
||||||
var downstreamRequest = httpContext.Items.DownstreamRequest();
|
var downstreamRequest = httpContext.Items.DownstreamRequest();
|
||||||
|
|
||||||
@ -49,17 +49,17 @@ namespace Ocelot.DownstreamUrlCreator.Middleware
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(downstreamReRoute.DownstreamScheme))
|
if (!string.IsNullOrEmpty(downstreamRoute.DownstreamScheme))
|
||||||
{
|
{
|
||||||
//todo make sure this works, hopefully there is a test ;E
|
//todo make sure this works, hopefully there is a test ;E
|
||||||
httpContext.Items.DownstreamRequest().Scheme = downstreamReRoute.DownstreamScheme;
|
httpContext.Items.DownstreamRequest().Scheme = downstreamRoute.DownstreamScheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
var internalConfiguration = httpContext.Items.IInternalConfiguration();
|
var internalConfiguration = httpContext.Items.IInternalConfiguration();
|
||||||
|
|
||||||
if (ServiceFabricRequest(internalConfiguration, downstreamReRoute))
|
if (ServiceFabricRequest(internalConfiguration, downstreamRoute))
|
||||||
{
|
{
|
||||||
var pathAndQuery = CreateServiceFabricUri(downstreamRequest, downstreamReRoute, templatePlaceholderNameAndValues, response);
|
var pathAndQuery = CreateServiceFabricUri(downstreamRequest, downstreamRoute, templatePlaceholderNameAndValues, response);
|
||||||
|
|
||||||
//todo check this works again hope there is a test..
|
//todo check this works again hope there is a test..
|
||||||
downstreamRequest.AbsolutePath = pathAndQuery.path;
|
downstreamRequest.AbsolutePath = pathAndQuery.path;
|
||||||
@ -133,17 +133,17 @@ namespace Ocelot.DownstreamUrlCreator.Middleware
|
|||||||
return dsPath.Value.Contains("?");
|
return dsPath.Value.Contains("?");
|
||||||
}
|
}
|
||||||
|
|
||||||
private (string path, string query) CreateServiceFabricUri(DownstreamRequest downstreamRequest, DownstreamReRoute downstreamReRoute, List<PlaceholderNameAndValue> templatePlaceholderNameAndValues, Response<DownstreamPath> dsPath)
|
private (string path, string query) CreateServiceFabricUri(DownstreamRequest downstreamRequest, DownstreamRoute downstreamRoute, List<PlaceholderNameAndValue> templatePlaceholderNameAndValues, Response<DownstreamPath> dsPath)
|
||||||
{
|
{
|
||||||
var query = downstreamRequest.Query;
|
var query = downstreamRequest.Query;
|
||||||
var serviceName = _replacer.Replace(downstreamReRoute.ServiceName, templatePlaceholderNameAndValues);
|
var serviceName = _replacer.Replace(downstreamRoute.ServiceName, templatePlaceholderNameAndValues);
|
||||||
var pathTemplate = $"/{serviceName.Data.Value}{dsPath.Data.Value}";
|
var pathTemplate = $"/{serviceName.Data.Value}{dsPath.Data.Value}";
|
||||||
return (pathTemplate, query);
|
return (pathTemplate, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool ServiceFabricRequest(IInternalConfiguration config, DownstreamReRoute downstreamReRoute)
|
private static bool ServiceFabricRequest(IInternalConfiguration config, DownstreamRoute downstreamRoute)
|
||||||
{
|
{
|
||||||
return config.ServiceProviderConfiguration.Type?.ToLower() == "servicefabric" && downstreamReRoute.UseServiceDiscovery;
|
return config.ServiceProviderConfiguration.Type?.ToLower() == "servicefabric" && downstreamRoute.UseServiceDiscovery;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user