diff --git a/Ocelot.sln b/Ocelot.sln
index 6aa429fe..e966a5ae 100644
--- a/Ocelot.sln
+++ b/Ocelot.sln
@@ -39,6 +39,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ocelot.Benchmarks", "test\O
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ocelot.IntegrationTests", "test\Ocelot.IntegrationTests\Ocelot.IntegrationTests.csproj", "{D4575572-99CA-4530-8737-C296EDA326F8}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{E78EF991-3401-459A-94FE-EC4F4E5BD702}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OcelotApplicationApiGateway", "samples\OcelotServiceFabric\src\OcelotApplicationApiGateway\OcelotApplicationApiGateway.csproj", "{1A3A3D97-33AB-48FB-8A9F-92905A15DF74}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OcelotApplicationService", "samples\OcelotServiceFabric\src\OcelotApplicationService\OcelotApplicationService.csproj", "{272DD79B-7D04-4DFB-BB64-B1C098CE8050}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OcelotServiceFabric", "OcelotServiceFabric", "{98424512-BCF5-4F42-ACB2-6D7040D92487}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -69,6 +77,14 @@ Global
{D4575572-99CA-4530-8737-C296EDA326F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D4575572-99CA-4530-8737-C296EDA326F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4575572-99CA-4530-8737-C296EDA326F8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1A3A3D97-33AB-48FB-8A9F-92905A15DF74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1A3A3D97-33AB-48FB-8A9F-92905A15DF74}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1A3A3D97-33AB-48FB-8A9F-92905A15DF74}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1A3A3D97-33AB-48FB-8A9F-92905A15DF74}.Release|Any CPU.Build.0 = Release|Any CPU
+ {272DD79B-7D04-4DFB-BB64-B1C098CE8050}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {272DD79B-7D04-4DFB-BB64-B1C098CE8050}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {272DD79B-7D04-4DFB-BB64-B1C098CE8050}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {272DD79B-7D04-4DFB-BB64-B1C098CE8050}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -80,6 +96,9 @@ Global
{02BBF4C5-517E-4157-8D21-4B8B9E118B7A} = {5B401523-36DA-4491-B73A-7590A26E420B}
{106B49E6-95F6-4A7B-B81C-96BFA74AF035} = {5B401523-36DA-4491-B73A-7590A26E420B}
{D4575572-99CA-4530-8737-C296EDA326F8} = {5B401523-36DA-4491-B73A-7590A26E420B}
+ {1A3A3D97-33AB-48FB-8A9F-92905A15DF74} = {98424512-BCF5-4F42-ACB2-6D7040D92487}
+ {272DD79B-7D04-4DFB-BB64-B1C098CE8050} = {98424512-BCF5-4F42-ACB2-6D7040D92487}
+ {98424512-BCF5-4F42-ACB2-6D7040D92487} = {E78EF991-3401-459A-94FE-EC4F4E5BD702}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {21476EFF-778A-4F97-8A56-D1AF1CEC0C48}
diff --git a/docs/features/servicediscovery.rst b/docs/features/servicediscovery.rst
index 28728db3..f8cadd2e 100644
--- a/docs/features/servicediscovery.rst
+++ b/docs/features/servicediscovery.rst
@@ -6,16 +6,18 @@ for the downstream service Ocelot is forwarding a request to. At the moment this
GlobalConfiguration section which means the same service discovery provider will be used for all ReRoutes
you specify a ServiceName for at ReRoute level.
-At the moment the only supported service discovery provider is Consul. The following is required in the
-GlobalConfiguration. The Provider is required and if you do not specify a host and port the Consul default
+Consul
+^^^^^^
+
+The following is required in the GlobalConfiguration. The Provider is required and if you do not specify a host and port the Consul default
will be used.
.. code-block:: json
"ServiceDiscoveryProvider": {
- "Host": "localhost",
- "Port": 9500
- }
+ "Host": "localhost",
+ "Port": 9500
+ }
In the future we can add a feature that allows ReRoute specfic configuration.
@@ -35,4 +37,4 @@ and LeastConnection algorithm you can use. If no load balancer is specified Ocel
"UseServiceDiscovery": true
}
-When this is set up Ocelot will lookup the downstream host and port from the service discover provider and load balance requests across any available services.
\ No newline at end of file
+When this is set up Ocelot will lookup the downstream host and port from the service discover provider and load balance requests across any available services.
diff --git a/docs/features/servicefabric.rst b/docs/features/servicefabric.rst
new file mode 100644
index 00000000..e6f69983
--- /dev/null
+++ b/docs/features/servicefabric.rst
@@ -0,0 +1,35 @@
+Service Fabric
+==============
+
+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 UseServiceDiscovery as true and 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!
+
+.. code-block:: json
+
+ {
+ "ReRoutes": [
+ {
+ "DownstreamPathTemplate": "/api/values",
+ "UpstreamPathTemplate": "/EquipmentInterfaces",
+ "UpstreamHttpMethod": [
+ "Get"
+ ],
+ "DownstreamScheme": "http",
+ "ServiceName": "OcelotServiceApplication/OcelotApplicationService",
+ "UseServiceDiscovery" : true
+ }
+ ],
+ "GlobalConfiguration": {
+ "RequestIdKey": "OcRequestId",
+ "ServiceDiscoveryProvider": {
+ "Host": "localhost",
+ "Port": 19081,
+ "Type": "ServiceFabric"
+ }
+ }
+ }
diff --git a/docs/index.rst b/docs/index.rst
index 258085ef..43a6c436 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -22,6 +22,7 @@ Thanks for taking a look at the Ocelot documentation. Please use the left hand n
features/routing
features/requestaggregation
features/servicediscovery
+ features/servicefabric
features/authentication
features/authorisation
features/administration
diff --git a/ocelot.postman_collection.json b/postman/ocelot.postman_collection.json
similarity index 96%
rename from ocelot.postman_collection.json
rename to postman/ocelot.postman_collection.json
index 2dc33d33..28bbeb0c 100644
--- a/ocelot.postman_collection.json
+++ b/postman/ocelot.postman_collection.json
@@ -1,314 +1,314 @@
-{
- "id": "4dbde9fe-89f5-be35-bb9f-d3b438e16375",
- "name": "Ocelot",
- "description": "",
- "order": [
- "a1c95935-ed18-d5dc-bcb8-a3db8ba1934f",
- "ea0ed57a-2cb9-8acc-47dd-006b8db2f1b2",
- "c4494401-3985-a5bf-71fb-6e4171384ac6",
- "09af8dda-a9cb-20d2-5ee3-0a3023773a1a",
- "e8825dc3-4137-99a7-0000-ef5786610dc3",
- "fddfc4fa-5114-69e3-4744-203ed71a526b",
- "c45d30d7-d9c4-fa05-8110-d6e769bb6ff9",
- "4684c2fa-f38c-c193-5f55-bf563a1978c6",
- "5f308240-79e3-cf74-7a6b-fe462f0d54f1",
- "178f16da-c61b-c881-1c33-9d64a56851a4",
- "26a08569-85f6-7f9a-726f-61be419c7a34"
- ],
- "folders": [],
- "timestamp": 0,
- "owner": "212120",
- "public": false,
- "requests": [
- {
- "folder": null,
- "id": "09af8dda-a9cb-20d2-5ee3-0a3023773a1a",
- "name": "GET http://localhost:5000/comments?postId=1",
- "dataMode": "params",
- "data": null,
- "rawModeData": null,
- "descriptionFormat": "html",
- "description": "",
- "headers": "",
- "method": "GET",
- "pathVariables": {},
- "url": "http://localhost:5000/comments?postId=1",
- "preRequestScript": null,
- "tests": null,
- "currentHelper": "normal",
- "helperAttributes": {},
- "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375"
- },
- {
- "id": "178f16da-c61b-c881-1c33-9d64a56851a4",
- "headers": "Authorization: Bearer {{AccessToken}}\n",
- "url": "http://localhost:5000/administration/configuration",
- "preRequestScript": null,
- "pathVariables": {},
- "method": "GET",
- "data": null,
- "dataMode": "params",
- "tests": null,
- "currentHelper": "normal",
- "helperAttributes": {},
- "time": 1508914722969,
- "name": "GET http://localhost:5000/admin/configuration",
- "description": "",
- "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375"
- },
- {
- "id": "26a08569-85f6-7f9a-726f-61be419c7a34",
- "headers": "",
- "url": "http://localhost:5000/administration/connect/token",
- "preRequestScript": null,
- "pathVariables": {},
- "method": "POST",
- "data": [
- {
- "key": "client_id",
- "value": "raft",
- "type": "text",
- "enabled": true
- },
- {
- "key": "client_secret",
- "value": "REALLYHARDPASSWORD",
- "type": "text",
- "enabled": true
- },
- {
- "key": "scope",
- "value": "admin raft ",
- "type": "text",
- "enabled": true
- },
- {
- "key": "username",
- "value": "admin",
- "type": "text",
- "enabled": false
- },
- {
- "key": "password",
- "value": "secret",
- "type": "text",
- "enabled": false
- },
- {
- "key": "grant_type",
- "value": "client_credentials",
- "type": "text",
- "enabled": true
- }
- ],
- "dataMode": "params",
- "tests": "var jsonData = JSON.parse(responseBody);\npostman.setGlobalVariable(\"AccessToken\", jsonData.access_token);\npostman.setGlobalVariable(\"RefreshToken\", jsonData.refresh_token);",
- "currentHelper": "normal",
- "helperAttributes": {},
- "time": 1513240031907,
- "name": "POST http://localhost:5000/admin/connect/token copy copy",
- "description": "",
- "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375"
- },
- {
- "folder": null,
- "id": "4684c2fa-f38c-c193-5f55-bf563a1978c6",
- "name": "DELETE http://localhost:5000/posts/1",
- "dataMode": "params",
- "data": null,
- "rawModeData": null,
- "descriptionFormat": "html",
- "description": "",
- "headers": "",
- "method": "DELETE",
- "pathVariables": {},
- "url": "http://localhost:5000/posts/1",
- "preRequestScript": null,
- "tests": null,
- "currentHelper": "normal",
- "helperAttributes": {},
- "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375"
- },
- {
- "id": "5f308240-79e3-cf74-7a6b-fe462f0d54f1",
- "headers": "Authorization: Bearer {{AccessToken}}\n",
- "url": "http://localhost:5000/administration/.well-known/openid-configuration",
- "preRequestScript": null,
- "pathVariables": {},
- "method": "GET",
- "data": null,
- "dataMode": "params",
- "tests": null,
- "currentHelper": "normal",
- "helperAttributes": "{}",
- "time": 1488038888813,
- "name": "GET http://localhost:5000/admin/.well-known/openid-configuration",
- "description": "",
- "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375",
- "folder": null,
- "rawModeData": null,
- "descriptionFormat": null,
- "queryParams": [],
- "headerData": [
- {
- "key": "Authorization",
- "value": "Bearer {{AccessToken}}",
- "description": "",
- "enabled": true
- }
- ],
- "pathVariableData": []
- },
- {
- "id": "a1c95935-ed18-d5dc-bcb8-a3db8ba1934f",
- "folder": null,
- "name": "GET http://localhost:5000/posts",
- "dataMode": "params",
- "data": [
- {
- "key": "client_id",
- "value": "admin",
- "type": "text",
- "enabled": true
- },
- {
- "key": "client_secret",
- "value": "secret",
- "type": "text",
- "enabled": true
- },
- {
- "key": "scope",
- "value": "admin",
- "type": "text",
- "enabled": true
- },
- {
- "key": "username",
- "value": "admin",
- "type": "text",
- "enabled": true
- },
- {
- "key": "password",
- "value": "admin",
- "type": "text",
- "enabled": true
- },
- {
- "key": "grant_type",
- "value": "password",
- "type": "text",
- "enabled": true
- }
- ],
- "rawModeData": null,
- "descriptionFormat": "html",
- "description": "",
- "headers": "",
- "method": "POST",
- "pathVariables": {},
- "url": "http://localhost:5000/admin/configuration",
- "preRequestScript": null,
- "tests": null,
- "currentHelper": "normal",
- "helperAttributes": "{}",
- "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375"
- },
- {
- "folder": null,
- "id": "c4494401-3985-a5bf-71fb-6e4171384ac6",
- "name": "GET http://localhost:5000/posts/1/comments",
- "dataMode": "params",
- "data": null,
- "rawModeData": null,
- "descriptionFormat": "html",
- "description": "",
- "headers": "",
- "method": "GET",
- "pathVariables": {},
- "url": "http://localhost:5000/posts/1/comments",
- "preRequestScript": null,
- "tests": null,
- "currentHelper": "normal",
- "helperAttributes": {},
- "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375"
- },
- {
- "folder": null,
- "id": "c45d30d7-d9c4-fa05-8110-d6e769bb6ff9",
- "name": "PATCH http://localhost:5000/posts/1",
- "dataMode": "raw",
- "data": [],
- "descriptionFormat": "html",
- "description": "",
- "headers": "",
- "method": "PATCH",
- "pathVariables": {},
- "url": "http://localhost:5000/posts/1",
- "preRequestScript": null,
- "tests": null,
- "currentHelper": "normal",
- "helperAttributes": {},
- "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375",
- "rawModeData": "{\n \"title\": \"gfdgsgsdgsdfgsdfgdfg\",\n}"
- },
- {
- "folder": null,
- "id": "e8825dc3-4137-99a7-0000-ef5786610dc3",
- "name": "POST http://localhost:5000/posts/1",
- "dataMode": "raw",
- "data": [],
- "descriptionFormat": "html",
- "description": "",
- "headers": "",
- "method": "POST",
- "pathVariables": {},
- "url": "http://localhost:5000/posts",
- "preRequestScript": null,
- "tests": null,
- "currentHelper": "normal",
- "helperAttributes": {},
- "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375",
- "rawModeData": "{\n \"userId\": 1,\n \"title\": \"test\",\n \"body\": \"test\"\n}"
- },
- {
- "folder": null,
- "id": "ea0ed57a-2cb9-8acc-47dd-006b8db2f1b2",
- "name": "GET http://localhost:5000/posts/1",
- "dataMode": "params",
- "data": null,
- "rawModeData": null,
- "descriptionFormat": "html",
- "description": "",
- "headers": "",
- "method": "GET",
- "pathVariables": {},
- "url": "http://localhost:5000/posts/1",
- "preRequestScript": null,
- "tests": null,
- "currentHelper": "normal",
- "helperAttributes": {},
- "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375"
- },
- {
- "folder": null,
- "id": "fddfc4fa-5114-69e3-4744-203ed71a526b",
- "name": "PUT http://localhost:5000/posts/1",
- "dataMode": "raw",
- "data": [],
- "descriptionFormat": "html",
- "description": "",
- "headers": "",
- "method": "PUT",
- "pathVariables": {},
- "url": "http://localhost:5000/posts/1",
- "preRequestScript": null,
- "tests": null,
- "currentHelper": "normal",
- "helperAttributes": {},
- "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375",
- "rawModeData": "{\n \"userId\": 1,\n \"title\": \"test\",\n \"body\": \"test\"\n}"
- }
- ]
+{
+ "id": "4dbde9fe-89f5-be35-bb9f-d3b438e16375",
+ "name": "Ocelot",
+ "description": "",
+ "order": [
+ "a1c95935-ed18-d5dc-bcb8-a3db8ba1934f",
+ "ea0ed57a-2cb9-8acc-47dd-006b8db2f1b2",
+ "c4494401-3985-a5bf-71fb-6e4171384ac6",
+ "09af8dda-a9cb-20d2-5ee3-0a3023773a1a",
+ "e8825dc3-4137-99a7-0000-ef5786610dc3",
+ "fddfc4fa-5114-69e3-4744-203ed71a526b",
+ "c45d30d7-d9c4-fa05-8110-d6e769bb6ff9",
+ "4684c2fa-f38c-c193-5f55-bf563a1978c6",
+ "5f308240-79e3-cf74-7a6b-fe462f0d54f1",
+ "178f16da-c61b-c881-1c33-9d64a56851a4",
+ "26a08569-85f6-7f9a-726f-61be419c7a34"
+ ],
+ "folders": [],
+ "timestamp": 0,
+ "owner": "212120",
+ "public": false,
+ "requests": [
+ {
+ "folder": null,
+ "id": "09af8dda-a9cb-20d2-5ee3-0a3023773a1a",
+ "name": "GET http://localhost:5000/comments?postId=1",
+ "dataMode": "params",
+ "data": null,
+ "rawModeData": null,
+ "descriptionFormat": "html",
+ "description": "",
+ "headers": "",
+ "method": "GET",
+ "pathVariables": {},
+ "url": "http://localhost:5000/comments?postId=1",
+ "preRequestScript": null,
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375"
+ },
+ {
+ "id": "178f16da-c61b-c881-1c33-9d64a56851a4",
+ "headers": "Authorization: Bearer {{AccessToken}}\n",
+ "url": "http://localhost:5000/administration/configuration",
+ "preRequestScript": null,
+ "pathVariables": {},
+ "method": "GET",
+ "data": null,
+ "dataMode": "params",
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1508914722969,
+ "name": "GET http://localhost:5000/admin/configuration",
+ "description": "",
+ "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375"
+ },
+ {
+ "id": "26a08569-85f6-7f9a-726f-61be419c7a34",
+ "headers": "",
+ "url": "http://localhost:5000/administration/connect/token",
+ "preRequestScript": null,
+ "pathVariables": {},
+ "method": "POST",
+ "data": [
+ {
+ "key": "client_id",
+ "value": "raft",
+ "type": "text",
+ "enabled": true
+ },
+ {
+ "key": "client_secret",
+ "value": "REALLYHARDPASSWORD",
+ "type": "text",
+ "enabled": true
+ },
+ {
+ "key": "scope",
+ "value": "admin raft ",
+ "type": "text",
+ "enabled": true
+ },
+ {
+ "key": "username",
+ "value": "admin",
+ "type": "text",
+ "enabled": false
+ },
+ {
+ "key": "password",
+ "value": "secret",
+ "type": "text",
+ "enabled": false
+ },
+ {
+ "key": "grant_type",
+ "value": "client_credentials",
+ "type": "text",
+ "enabled": true
+ }
+ ],
+ "dataMode": "params",
+ "tests": "var jsonData = JSON.parse(responseBody);\npostman.setGlobalVariable(\"AccessToken\", jsonData.access_token);\npostman.setGlobalVariable(\"RefreshToken\", jsonData.refresh_token);",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1513240031907,
+ "name": "POST http://localhost:5000/admin/connect/token copy copy",
+ "description": "",
+ "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375"
+ },
+ {
+ "folder": null,
+ "id": "4684c2fa-f38c-c193-5f55-bf563a1978c6",
+ "name": "DELETE http://localhost:5000/posts/1",
+ "dataMode": "params",
+ "data": null,
+ "rawModeData": null,
+ "descriptionFormat": "html",
+ "description": "",
+ "headers": "",
+ "method": "DELETE",
+ "pathVariables": {},
+ "url": "http://localhost:5000/posts/1",
+ "preRequestScript": null,
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375"
+ },
+ {
+ "id": "5f308240-79e3-cf74-7a6b-fe462f0d54f1",
+ "headers": "Authorization: Bearer {{AccessToken}}\n",
+ "url": "http://localhost:5000/administration/.well-known/openid-configuration",
+ "preRequestScript": null,
+ "pathVariables": {},
+ "method": "GET",
+ "data": null,
+ "dataMode": "params",
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": "{}",
+ "time": 1488038888813,
+ "name": "GET http://localhost:5000/admin/.well-known/openid-configuration",
+ "description": "",
+ "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375",
+ "folder": null,
+ "rawModeData": null,
+ "descriptionFormat": null,
+ "queryParams": [],
+ "headerData": [
+ {
+ "key": "Authorization",
+ "value": "Bearer {{AccessToken}}",
+ "description": "",
+ "enabled": true
+ }
+ ],
+ "pathVariableData": []
+ },
+ {
+ "id": "a1c95935-ed18-d5dc-bcb8-a3db8ba1934f",
+ "folder": null,
+ "name": "GET http://localhost:5000/posts",
+ "dataMode": "params",
+ "data": [
+ {
+ "key": "client_id",
+ "value": "admin",
+ "type": "text",
+ "enabled": true
+ },
+ {
+ "key": "client_secret",
+ "value": "secret",
+ "type": "text",
+ "enabled": true
+ },
+ {
+ "key": "scope",
+ "value": "admin",
+ "type": "text",
+ "enabled": true
+ },
+ {
+ "key": "username",
+ "value": "admin",
+ "type": "text",
+ "enabled": true
+ },
+ {
+ "key": "password",
+ "value": "admin",
+ "type": "text",
+ "enabled": true
+ },
+ {
+ "key": "grant_type",
+ "value": "password",
+ "type": "text",
+ "enabled": true
+ }
+ ],
+ "rawModeData": null,
+ "descriptionFormat": "html",
+ "description": "",
+ "headers": "",
+ "method": "POST",
+ "pathVariables": {},
+ "url": "http://localhost:5000/admin/configuration",
+ "preRequestScript": null,
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": "{}",
+ "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375"
+ },
+ {
+ "folder": null,
+ "id": "c4494401-3985-a5bf-71fb-6e4171384ac6",
+ "name": "GET http://localhost:5000/posts/1/comments",
+ "dataMode": "params",
+ "data": null,
+ "rawModeData": null,
+ "descriptionFormat": "html",
+ "description": "",
+ "headers": "",
+ "method": "GET",
+ "pathVariables": {},
+ "url": "http://localhost:5000/posts/1/comments",
+ "preRequestScript": null,
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375"
+ },
+ {
+ "folder": null,
+ "id": "c45d30d7-d9c4-fa05-8110-d6e769bb6ff9",
+ "name": "PATCH http://localhost:5000/posts/1",
+ "dataMode": "raw",
+ "data": [],
+ "descriptionFormat": "html",
+ "description": "",
+ "headers": "",
+ "method": "PATCH",
+ "pathVariables": {},
+ "url": "http://localhost:5000/posts/1",
+ "preRequestScript": null,
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375",
+ "rawModeData": "{\n \"title\": \"gfdgsgsdgsdfgsdfgdfg\",\n}"
+ },
+ {
+ "folder": null,
+ "id": "e8825dc3-4137-99a7-0000-ef5786610dc3",
+ "name": "POST http://localhost:5000/posts/1",
+ "dataMode": "raw",
+ "data": [],
+ "descriptionFormat": "html",
+ "description": "",
+ "headers": "",
+ "method": "POST",
+ "pathVariables": {},
+ "url": "http://localhost:5000/posts",
+ "preRequestScript": null,
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375",
+ "rawModeData": "{\n \"userId\": 1,\n \"title\": \"test\",\n \"body\": \"test\"\n}"
+ },
+ {
+ "folder": null,
+ "id": "ea0ed57a-2cb9-8acc-47dd-006b8db2f1b2",
+ "name": "GET http://localhost:5000/posts/1",
+ "dataMode": "params",
+ "data": null,
+ "rawModeData": null,
+ "descriptionFormat": "html",
+ "description": "",
+ "headers": "",
+ "method": "GET",
+ "pathVariables": {},
+ "url": "http://localhost:5000/posts/1",
+ "preRequestScript": null,
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375"
+ },
+ {
+ "folder": null,
+ "id": "fddfc4fa-5114-69e3-4744-203ed71a526b",
+ "name": "PUT http://localhost:5000/posts/1",
+ "dataMode": "raw",
+ "data": [],
+ "descriptionFormat": "html",
+ "description": "",
+ "headers": "",
+ "method": "PUT",
+ "pathVariables": {},
+ "url": "http://localhost:5000/posts/1",
+ "preRequestScript": null,
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "collectionId": "4dbde9fe-89f5-be35-bb9f-d3b438e16375",
+ "rawModeData": "{\n \"userId\": 1,\n \"title\": \"test\",\n \"body\": \"test\"\n}"
+ }
+ ]
}
\ No newline at end of file
diff --git a/samples/OcelotServiceFabric/.gitignore b/samples/OcelotServiceFabric/.gitignore
new file mode 100644
index 00000000..733dbb07
--- /dev/null
+++ b/samples/OcelotServiceFabric/.gitignore
@@ -0,0 +1,269 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Service fabric
+OcelotApplicationApiGatewayPkg/Code
+OcelotApplication/OcelotApplicationApiGatewayPkg/Code/appsettings.json
+OcelotApplication/OcelotApplicationApiGatewayPkg/Code/configuration.json
+OcelotApplication/OcelotApplicationApiGatewayPkg/Code/runtimes/
+OcelotApplicationServicePkg/Code
+OcelotApplication/OcelotApplicationApiGatewayPkg/Code/web.config
+OcelotApplication/OcelotApplicationServicePkg/Code/runtimes/
+!entryPoint.cmd
+!entryPoint.sh
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# DNX
+project.lock.json
+artifacts/
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# except build/, which is used as an MSBuild target.
+!**/packages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/packages/repositories.config
+# NuGet v3's project.json files produces more ignoreable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.pfx
+*.publishsettings
+node_modules/
+orleans.codegen.cs
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# Dotnet generated files
+*.dll
+*.pdb
+*.deps.json
+*.runtimeconfig.json
diff --git a/samples/OcelotServiceFabric/CONTRIBUTING.md b/samples/OcelotServiceFabric/CONTRIBUTING.md
new file mode 100644
index 00000000..5577d2d7
--- /dev/null
+++ b/samples/OcelotServiceFabric/CONTRIBUTING.md
@@ -0,0 +1,11 @@
+# Contributing to Azure samples
+
+Thank you for your interest in contributing to Azure samples!
+
+## Ways to contribute
+
+You can contribute to [Azure samples](https://azure.microsoft.com/documentation/samples/) in a few different ways:
+
+- Submit feedback on [this sample page](https://azure.microsoft.com/documentation/samples/service-fabric-dotnet-web-reference-app/) whether it was helpful or not.
+- Submit issues through [issue tracker](https://github.com/Azure-Samples/service-fabric-dotnet-web-reference-app/issues) on GitHub. We are actively monitoring the issues and improving our samples.
+- If you wish to make code changes to samples, or contribute something new, please follow the [GitHub Forks / Pull requests model](https://help.github.com/articles/fork-a-repo/): Fork the sample repo, make the change and propose it back by submitting a pull request.
diff --git a/samples/OcelotServiceFabric/LICENSE.md b/samples/OcelotServiceFabric/LICENSE.md
new file mode 100644
index 00000000..70aed34a
--- /dev/null
+++ b/samples/OcelotServiceFabric/LICENSE.md
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2016 Azure Samples
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/samples/OcelotServiceFabric/OcelotApplication/ApplicationManifest.xml b/samples/OcelotServiceFabric/OcelotApplication/ApplicationManifest.xml
new file mode 100644
index 00000000..d002e811
--- /dev/null
+++ b/samples/OcelotServiceFabric/OcelotApplication/ApplicationManifest.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/Code/entryPoint.cmd b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/Code/entryPoint.cmd
new file mode 100644
index 00000000..c93389bd
--- /dev/null
+++ b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/Code/entryPoint.cmd
@@ -0,0 +1,2 @@
+dotnet %~dp0\OcelotApplicationApiGateway.dll
+exit /b %errorlevel%
\ No newline at end of file
diff --git a/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/Code/entryPoint.sh b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/Code/entryPoint.sh
new file mode 100644
index 00000000..9cc67287
--- /dev/null
+++ b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/Code/entryPoint.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+check_errs()
+{
+ # Function. Parameter 1 is the return code
+ if [ "${1}" -ne "0" ]; then
+ # make our script exit with the right error code.
+ exit ${1}
+ fi
+}
+
+DIR=`dirname $0`
+
+echo 0x3f > /proc/self/coredump_filter
+
+source $DIR/dotnet-include.sh
+dotnet $DIR/OcelotApplicationApiGateway.dll $@
+check_errs $?
diff --git a/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/Config/Settings.xml b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/Config/Settings.xml
new file mode 100644
index 00000000..902c747a
--- /dev/null
+++ b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/Config/Settings.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/Config/_readme.txt b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/Config/_readme.txt
new file mode 100644
index 00000000..f5e5e287
--- /dev/null
+++ b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/Config/_readme.txt
@@ -0,0 +1,12 @@
+contains a Settings.xml file, that can specify parameters for the service
+
+Configuration packages describe user-defined, application-overridable configuration settings (sections of key-value pairs)
+required for running service replicas/instances of service types specified in the ser-vice manifest. The configuration settings
+must be stored in Settings.xml in the config package folder.
+
+The service developer uses Service Fabric APIs to locate the package folders and read applica-tion-overridable configuration settings.
+The service developer can also register callbacks that are in-voked when any of the configuration packages specified in the
+service manifest are upgraded and re-reads new configuration settings inside that callback.
+
+This means that Service Fabric will not recycle EXEs and DLLHOSTs specified in the host and support packages when
+configuration packages are up-graded.
\ No newline at end of file
diff --git a/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/Data/_readme.txt b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/Data/_readme.txt
new file mode 100644
index 00000000..de32b7d3
--- /dev/null
+++ b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/Data/_readme.txt
@@ -0,0 +1,5 @@
+Data packages contain data files like custom dictionaries,
+non-overridable configuration files, custom initialized data files, etc.
+
+Service Fabric will recycle all EXEs and DLLHOSTs specified in the host and support packages when any of the data packages
+specified inside service manifest are upgraded.
\ No newline at end of file
diff --git a/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/ServiceManifest-Linux.xml b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/ServiceManifest-Linux.xml
new file mode 100644
index 00000000..c1990112
--- /dev/null
+++ b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/ServiceManifest-Linux.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+ entryPoint.sh
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/ServiceManifest-Windows.xml b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/ServiceManifest-Windows.xml
new file mode 100644
index 00000000..a96730d3
--- /dev/null
+++ b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/ServiceManifest-Windows.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+ entryPoint.cmd
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/ServiceManifest.xml b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/ServiceManifest.xml
new file mode 100644
index 00000000..a96730d3
--- /dev/null
+++ b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationApiGatewayPkg/ServiceManifest.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+ entryPoint.cmd
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/Code/entryPoint.cmd b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/Code/entryPoint.cmd
new file mode 100644
index 00000000..9b71795b
--- /dev/null
+++ b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/Code/entryPoint.cmd
@@ -0,0 +1,2 @@
+dotnet %~dp0\OcelotApplicationService.dll
+exit /b %errorlevel%
\ No newline at end of file
diff --git a/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/Code/entryPoint.sh b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/Code/entryPoint.sh
new file mode 100644
index 00000000..9e187faa
--- /dev/null
+++ b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/Code/entryPoint.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+check_errs()
+{
+ # Function. Parameter 1 is the return code
+ if [ "${1}" -ne "0" ]; then
+ # make our script exit with the right error code.
+ exit ${1}
+ fi
+}
+
+DIR=`dirname $0`
+source $DIR/dotnet-include.sh
+
+dotnet $DIR/OcelotApplicationService.dll $@
+check_errs $?
diff --git a/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/Config/Settings.xml b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/Config/Settings.xml
new file mode 100644
index 00000000..902c747a
--- /dev/null
+++ b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/Config/Settings.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/Config/_readme.txt b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/Config/_readme.txt
new file mode 100644
index 00000000..f5e5e287
--- /dev/null
+++ b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/Config/_readme.txt
@@ -0,0 +1,12 @@
+contains a Settings.xml file, that can specify parameters for the service
+
+Configuration packages describe user-defined, application-overridable configuration settings (sections of key-value pairs)
+required for running service replicas/instances of service types specified in the ser-vice manifest. The configuration settings
+must be stored in Settings.xml in the config package folder.
+
+The service developer uses Service Fabric APIs to locate the package folders and read applica-tion-overridable configuration settings.
+The service developer can also register callbacks that are in-voked when any of the configuration packages specified in the
+service manifest are upgraded and re-reads new configuration settings inside that callback.
+
+This means that Service Fabric will not recycle EXEs and DLLHOSTs specified in the host and support packages when
+configuration packages are up-graded.
\ No newline at end of file
diff --git a/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/Data/_readme.txt b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/Data/_readme.txt
new file mode 100644
index 00000000..e51dae93
--- /dev/null
+++ b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/Data/_readme.txt
@@ -0,0 +1,5 @@
+Data packages contain data files like custom dictionaries,
+non-overridable configuration files, custom initialized data files, etc.
+
+Service Fabric will recycle all EXEs and DLLHOSTs specified in the host and support packages when any of the data packages
+specified inside service manifest are upgraded.
\ No newline at end of file
diff --git a/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/ServiceManifest-Linux.xml b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/ServiceManifest-Linux.xml
new file mode 100644
index 00000000..e94651cb
--- /dev/null
+++ b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/ServiceManifest-Linux.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+ entryPoint.sh
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/ServiceManifest-Windows.xml b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/ServiceManifest-Windows.xml
new file mode 100644
index 00000000..61c7ac80
--- /dev/null
+++ b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/ServiceManifest-Windows.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+ entryPoint.cmd
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/ServiceManifest.xml b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/ServiceManifest.xml
new file mode 100644
index 00000000..61c7ac80
--- /dev/null
+++ b/samples/OcelotServiceFabric/OcelotApplication/OcelotApplicationServicePkg/ServiceManifest.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+ entryPoint.cmd
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/OcelotServiceFabric/README.md b/samples/OcelotServiceFabric/README.md
new file mode 100644
index 00000000..099348c6
--- /dev/null
+++ b/samples/OcelotServiceFabric/README.md
@@ -0,0 +1,51 @@
+---
+services: service-fabric
+platforms: dotnet
+author: raunakpandya edited by Tom Pallister for Ocelot
+---
+
+# Ocelot Service Fabric example
+
+This shows a service fabric cluster with Ocelot exposed over HTTP accessing services in the cluster via the naming service. If you want to try and use Ocelot with
+Service Fabric I reccomend using this as a starting point.
+
+Ocelot does not support partitioned services (stateful & actors) at the moment.
+
+I have not tested this sample on Service Fabric hosted on Linux just a Windows dev cluster. This sample assumes a good understanding of Service Fabric.
+
+The rest of this document is from the Microsoft asp.net core service fabric getting started guide.
+
+# Getting started with Service Fabric with .NET Core
+
+This repository contains a set of simple sample projects to help you getting started with Service Fabric on Linux with .NET Core as the framework. As a pre requisite ensure you have the Service Fabric C# SDK installed on ubuntu box. Follow these instruction to [prepare your development environment on Linux][service-fabric-Linux-getting-started]
+
+### Folder Hierarchy
+* src/ - Source of the application divided by different modules by sub-folders.
+* <application package folder>/ - Service Fabric Application folder heirarchy. After compilation the executables are placed in code subfolders.
+* build.sh - Script to build source on Linux shell.
+* build.ps1 - PowerShell script to build source on Windows.
+* install.sh - Script to install Application from Linux shell.
+* install.ps1 - PowerShell script to install application from Windows. Before calling this script run Connect-ServiceFabricCluster localhost:19000 or however you prefer to connect.
+* uninstall.sh - Script to uninstall application from Linux shell.
+* uninstall.ps1 - PowerShell script to unintall application from Windows.
+* dotnet-include.sh - Script to conditionally handle RHEL dotnet cli through scl(software collections)
+
+# Testing
+
+Once everything is up and running on your dev cluster visit http://localhost:31002/EquipmentInterfaces and you should see the following returned.
+
+```json
+["value1","value2"]
+```
+
+If you get any errors please check the service fabric logs and let me know if you need help.
+
+## More information
+
+The [Service Fabric documentation][service-fabric-docs] includes a rich set of tutorials and conceptual articles, which serve as a good complement to the samples.
+
+
+
+[service-fabric-programming-models]: https://azure.microsoft.com/en-us/documentation/articles/service-fabric-choose-framework/
+[service-fabric-docs]: http://aka.ms/servicefabricdocs
+[service-fabric-Linux-getting-started]: https://azure.microsoft.com/en-us/documentation/articles/service-fabric-get-started-linux/
diff --git a/samples/OcelotServiceFabric/build.bat b/samples/OcelotServiceFabric/build.bat
new file mode 100644
index 00000000..9905715a
--- /dev/null
+++ b/samples/OcelotServiceFabric/build.bat
@@ -0,0 +1,12 @@
+cd ./src/OcelotApplicationService/
+dotnet restore -s https://api.nuget.org/v3/index.json
+dotnet build
+dotnet publish -o ../../OcelotApplication/OcelotApplicationServicePkg/Code
+cd ../../
+
+cd ./src/OcelotApplicationApiGateway/
+dotnet restore -s https://api.nuget.org/v3/index.json
+dotnet build
+dotnet publish -o ../../OcelotApplication/OcelotApplicationApiGatewayPkg/Code
+cd ../../
+
diff --git a/samples/OcelotServiceFabric/build.sh b/samples/OcelotServiceFabric/build.sh
new file mode 100644
index 00000000..a18f2a4a
--- /dev/null
+++ b/samples/OcelotServiceFabric/build.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+DIR=`dirname $0`
+source $DIR/dotnet-include.sh
+
+cd $DIR/src/OcelotApplicationService/
+dotnet restore -s https://api.nuget.org/v3/index.json
+dotnet build
+dotnet publish -o ../../OcelotApplication/OcelotApplicationServicePkg/Code
+cd -
+
+cd $DIR/src/OcelotApplicationApiGateway/
+dotnet restore -s https://api.nuget.org/v3/index.json
+dotnet build
+dotnet publish -o ../../OcelotApplication/OcelotApplicationApiGatewayPkg/Code
+cd -
diff --git a/samples/OcelotServiceFabric/dotnet-include.sh b/samples/OcelotServiceFabric/dotnet-include.sh
new file mode 100644
index 00000000..a716f3d8
--- /dev/null
+++ b/samples/OcelotServiceFabric/dotnet-include.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+. /etc/os-release
+linuxDistrib=$ID
+if [ $linuxDistrib = "rhel" ]; then
+ source scl_source enable rh-dotnet20
+ exitCode=$?
+ if [ $exitCode != 0 ]; then
+ echo "Failed: source scl_source enable rh-dotnet20 : ExitCode: $exitCode"
+ exit $exitCode
+ fi
+fi
diff --git a/samples/OcelotServiceFabric/install.ps1 b/samples/OcelotServiceFabric/install.ps1
new file mode 100644
index 00000000..662c59e3
--- /dev/null
+++ b/samples/OcelotServiceFabric/install.ps1
@@ -0,0 +1,20 @@
+$AppPath = "$PSScriptRoot\OcelotApplication"
+$sdkInstallPath = (Get-ItemProperty 'HKLM:\Software\Microsoft\Service Fabric SDK').FabricSDKInstallPath
+$sfSdkPsModulePath = $sdkInstallPath + "Tools\PSModule\ServiceFabricSDK"
+Import-Module $sfSdkPsModulePath\ServiceFabricSDK.psm1
+
+$StatefulServiceManifestlocation = $AppPath + "\OcelotApplicationServicePkg\"
+$StatefulServiceManifestlocationLinux = $StatefulServiceManifestlocation + "\ServiceManifest-Linux.xml"
+$StatefulServiceManifestlocationWindows = $StatefulServiceManifestlocation + "\ServiceManifest-Windows.xml"
+$StatefulServiceManifestlocationFinal= $StatefulServiceManifestlocation + "ServiceManifest.xml"
+Copy-Item -Path $StatefulServiceManifestlocationWindows -Destination $StatefulServiceManifestlocationFinal -Force
+
+$WebServiceManifestlocation = $AppPath + "\OcelotApplicationApiGatewayPkg\"
+$WebServiceManifestlocationLinux = $WebServiceManifestlocation + "\ServiceManifest-Linux.xml"
+$WebServiceManifestlocationWindows = $WebServiceManifestlocation + "\ServiceManifest-Windows.xml"
+$WebServiceManifestlocationFinal= $WebServiceManifestlocation + "ServiceManifest.xml"
+Copy-Item -Path $WebServiceManifestlocationWindows -Destination $WebServiceManifestlocationFinal -Force
+
+Copy-ServiceFabricApplicationPackage -ApplicationPackagePath $AppPath -ApplicationPackagePathInImageStore OcelotServiceApplicationType -ImageStoreConnectionString (Get-ImageStoreConnectionStringFromClusterManifest(Get-ServiceFabricClusterManifest)) -TimeoutSec 1800
+Register-ServiceFabricApplicationType OcelotServiceApplicationType
+New-ServiceFabricApplication fabric:/OcelotServiceApplication OcelotServiceApplicationType 1.0.0
\ No newline at end of file
diff --git a/samples/OcelotServiceFabric/install.sh b/samples/OcelotServiceFabric/install.sh
new file mode 100644
index 00000000..e8245579
--- /dev/null
+++ b/samples/OcelotServiceFabric/install.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+appPkg="$DIR/OcelotServiceApplication"
+
+WebServiceManifestlocation="$appPkg/OcelotApplicationApiGatewayPkg"
+WebServiceManifestlocationLinux="$WebServiceManifestlocation/ServiceManifest-Linux.xml"
+WebServiceManifestlocationWindows="$WebServiceManifestlocation/ServiceManifest-Windows.xml"
+WebServiceManifestlocation="$WebServiceManifestlocation/ServiceManifest.xml"
+cp $WebServiceManifestlocationLinux $WebServiceManifestlocation
+
+
+StatefulServiceManifestlocation="$appPkg/OcelotApplicationServicePkg"
+StatefulServiceManifestlocationLinux="$StatefulServiceManifestlocation/ServiceManifest-Linux.xml"
+StatefulServiceManifestlocationWindows="$StatefulServiceManifestlocation/ServiceManifest-Windows.xml"
+StatefulServiceManifestlocation="$StatefulServiceManifestlocation/ServiceManifest.xml"
+cp $StatefulServiceManifestlocationLinux $StatefulServiceManifestlocation
+cp dotnet-include.sh ./OcelotServiceApplication/OcelotApplicationServicePkg/Code
+cp dotnet-include.sh ./OcelotServiceApplication/OcelotApplicationApiGatewayPkg/Code
+sfctl application upload --path OcelotServiceApplication --show-progress
+sfctl application provision --application-type-build-path OcelotServiceApplication
+sfctl application create --app-name fabric:/OcelotServiceApplication --app-type OcelotServiceApplicationType --app-version 1.0.0
diff --git a/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/OcelotApplicationApiGateway.cs b/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/OcelotApplicationApiGateway.cs
new file mode 100644
index 00000000..28ea7abb
--- /dev/null
+++ b/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/OcelotApplicationApiGateway.cs
@@ -0,0 +1,31 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
+// ------------------------------------------------------------
+
+namespace OcelotApplicationApiGateway
+{
+ using System.Fabric;
+ using Microsoft.ServiceFabric.Services.Communication.Runtime;
+ using Microsoft.ServiceFabric.Services.Runtime;
+ using System.Collections.Generic;
+
+ /// Service that handles front-end web requests and acts as a proxy to the back-end data for the UI web page.
+ /// It is a stateless service that hosts a Web API application on OWIN.
+ internal sealed class OcelotServiceWebService : StatelessService
+ {
+ public OcelotServiceWebService(StatelessServiceContext context)
+ : base(context)
+ { }
+
+ protected override IEnumerable CreateServiceInstanceListeners()
+ {
+ return new[]
+ {
+ new ServiceInstanceListener(
+ initparams => new WebCommunicationListener(string.Empty, initparams),
+ "OcelotServiceWebListener")
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/OcelotApplicationApiGateway.csproj b/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/OcelotApplicationApiGateway.csproj
new file mode 100644
index 00000000..1ff69c09
--- /dev/null
+++ b/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/OcelotApplicationApiGateway.csproj
@@ -0,0 +1,22 @@
+
+
+ Stateless Web Service for Stateful OcelotApplicationApiGateway App
+
+ netcoreapp2.0
+ OcelotApplicationApiGateway
+ Exe
+ OcelotApplicationApiGateway
+
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/Program.cs b/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/Program.cs
new file mode 100644
index 00000000..7da30a50
--- /dev/null
+++ b/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/Program.cs
@@ -0,0 +1,51 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
+// ------------------------------------------------------------
+
+namespace OcelotApplicationApiGateway
+
+{
+ using System;
+ using System.Fabric;
+ using System.Threading;
+ using Microsoft.ServiceFabric.Services.Runtime;
+ using System.Diagnostics.Tracing;
+
+
+ ///
+ /// The service host is the executable that hosts the Service instances.
+ ///
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ // Create Service Fabric runtime and register the service type.
+ try
+ {
+
+ //Creating a new event listener to redirect the traces to a file
+ ServiceEventListener listener = new ServiceEventListener("OcelotApplicationApiGateway");
+ listener.EnableEvents(ServiceEventSource.Current, EventLevel.LogAlways, EventKeywords.All);
+
+ // The ServiceManifest.XML file defines one or more service type names.
+ // Registering a service maps a service type name to a .NET type.
+ // When Service Fabric creates an instance of this service type,
+ // an instance of the class is created in this host process.
+ ServiceRuntime
+ .RegisterServiceAsync("OcelotApplicationApiGatewayType", context => new OcelotServiceWebService (context))
+ .GetAwaiter()
+ .GetResult();
+
+
+ // Prevents this host process from terminating so services keep running.
+ Thread.Sleep(Timeout.Infinite);
+ }
+ catch (Exception ex)
+ {
+ ServiceEventSource.Current.ServiceHostInitializationFailed(ex);
+ throw ex;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/Properties/launchSettings.json b/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/Properties/launchSettings.json
new file mode 100644
index 00000000..e28c3315
--- /dev/null
+++ b/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/Properties/launchSettings.json
@@ -0,0 +1,27 @@
+{
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:36034/",
+ "sslPort": 0
+ }
+ },
+ "profiles": {
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "OcelotApplicationApiGateway": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "applicationUrl": "http://localhost:36035/"
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/ServiceEventListener.cs b/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/ServiceEventListener.cs
new file mode 100644
index 00000000..555f9fde
--- /dev/null
+++ b/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/ServiceEventListener.cs
@@ -0,0 +1,94 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
+// ------------------------------------------------------------
+
+namespace OcelotApplicationApiGateway
+{
+ using System;
+ using System.IO;
+ using System.Linq;
+ using System.Diagnostics.Tracing;
+ using System.Fabric;
+ using System.Fabric.Common;
+ using System.Fabric.Common.Tracing;
+ using Microsoft.ServiceFabric.Services.Runtime;
+ using System.Globalization;
+ using System.Text;
+
+ ///
+ /// ServiceEventListener is a class which listens to the eventsources registered and redirects the traces to a file
+ /// Note that this class serves as a template to EventListener class and redirects the logs to /tmp/{appnameyyyyMMddHHmmssffff}.
+ /// You can extend the functionality by writing your code to implement rolling logs for the logs written through this class.
+ /// You can also write your custom listener class and handle the registered evestsources accordingly.
+ ///
+ internal class ServiceEventListener : EventListener
+ {
+ private string fileName;
+ private string filepath = Path.GetTempPath();
+
+ public ServiceEventListener(string appName)
+ {
+ this.fileName = appName + DateTime.Now.ToString("yyyyMMddHHmmssffff");
+ }
+
+ ///
+ /// We override this method to get a callback on every event we subscribed to with EnableEvents
+ ///
+ /// The event arguments that describe the event.
+ protected override void OnEventWritten(EventWrittenEventArgs eventData)
+ {
+ using (StreamWriter writer = new StreamWriter( new FileStream(filepath + fileName, FileMode.Append)))
+ {
+ // report all event information
+ writer.Write(" {0} ", Write(eventData.Task.ToString(),
+ eventData.EventName,
+ eventData.EventId.ToString(),
+ eventData.Level));
+
+ if (eventData.Message != null)
+ {
+ writer.WriteLine(string.Format(CultureInfo.InvariantCulture, eventData.Message, eventData.Payload.ToArray()));
+ }
+ }
+ }
+
+ private static String Write(string taskName, string eventName, string id, EventLevel level)
+ {
+ StringBuilder output = new StringBuilder();
+
+ DateTime now = DateTime.UtcNow;
+ output.Append(now.ToString("yyyy/MM/dd-HH:mm:ss.fff", CultureInfo.InvariantCulture));
+ output.Append(',');
+ output.Append(ConvertLevelToString(level));
+ output.Append(',');
+ output.Append(taskName);
+
+ if (!string.IsNullOrEmpty(eventName))
+ {
+ output.Append('.');
+ output.Append(eventName);
+ }
+
+ if (!string.IsNullOrEmpty(id))
+ {
+ output.Append('@');
+ output.Append(id);
+ }
+
+ output.Append(',');
+ return output.ToString();
+ }
+
+ private static string ConvertLevelToString(EventLevel level)
+ {
+ switch (level)
+ {
+ case EventLevel.Informational:
+ return "Info";
+ default:
+ return level.ToString();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/ServiceEventSource.cs b/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/ServiceEventSource.cs
new file mode 100644
index 00000000..c0579955
--- /dev/null
+++ b/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/ServiceEventSource.cs
@@ -0,0 +1,86 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
+// ------------------------------------------------------------
+
+namespace OcelotApplicationApiGateway
+{
+ using System;
+ using System.Diagnostics.Tracing;
+ using System.Fabric;
+ using Microsoft.ServiceFabric.Services.Runtime;
+
+ ///
+ /// Implements methods for logging service related events.
+ ///
+ public class ServiceEventSource : EventSource
+ {
+ public static ServiceEventSource Current = new ServiceEventSource();
+
+ // Define an instance method for each event you want to record and apply an [Event] attribute to it.
+ // The method name is the name of the event.
+ // Pass any parameters you want to record with the event (only primitive integer types, DateTime, Guid & string are allowed).
+ // Each event method implementation should check whether the event source is enabled, and if it is, call WriteEvent() method to raise the event.
+ // The number and types of arguments passed to every event method must exactly match what is passed to WriteEvent().
+ // Put [NonEvent] attribute on all methods that do not define an event.
+ // For more information see https://msdn.microsoft.com/en-us/library/system.diagnostics.tracing.eventsource.aspx
+
+ [NonEvent]
+ public void Message(string message, params object[] args)
+ {
+ if (this.IsEnabled())
+ {
+ var finalMessage = string.Format(message, args);
+ this.Message(finalMessage);
+ }
+ }
+
+ private const int MessageEventId = 1;
+
+ [Event(MessageEventId, Level = EventLevel.Informational, Message = "{0}")]
+ public void Message(string message)
+ {
+ if (this.IsEnabled())
+ {
+ this.WriteEvent(MessageEventId, message);
+ }
+ }
+
+ private const int ServiceTypeRegisteredEventId = 3;
+
+ [Event(ServiceTypeRegisteredEventId, Level = EventLevel.Informational, Message = "Service host process {0} registered service type {1}")]
+ public void ServiceTypeRegistered(int hostProcessId, string serviceType)
+ {
+ this.WriteEvent(ServiceTypeRegisteredEventId, hostProcessId, serviceType);
+ }
+
+ [NonEvent]
+ public void ServiceHostInitializationFailed(Exception e)
+ {
+ this.ServiceHostInitializationFailed(e.ToString());
+ }
+
+ private const int ServiceHostInitializationFailedEventId = 4;
+
+ [Event(ServiceHostInitializationFailedEventId, Level = EventLevel.Error, Message = "Service host initialization failed: {0}")]
+ private void ServiceHostInitializationFailed(string exception)
+ {
+ this.WriteEvent(ServiceHostInitializationFailedEventId, exception);
+ }
+
+ [NonEvent]
+ public void ServiceWebHostBuilderFailed(Exception e)
+ {
+ this.ServiceWebHostBuilderFailed(e.ToString());
+ }
+
+ private const int ServiceWebHostBuilderFailedEventId = 5;
+
+ [Event(ServiceWebHostBuilderFailedEventId, Level = EventLevel.Error, Message = "Service Owin Web Host Builder Failed: {0}")]
+ private void ServiceWebHostBuilderFailed(string exception)
+ {
+ this.WriteEvent(ServiceWebHostBuilderFailedEventId, exception);
+ }
+
+ }
+}
diff --git a/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/WebCommunicationListener.cs b/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/WebCommunicationListener.cs
new file mode 100644
index 00000000..6685e11f
--- /dev/null
+++ b/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/WebCommunicationListener.cs
@@ -0,0 +1,125 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
+// ------------------------------------------------------------
+
+namespace OcelotApplicationApiGateway
+{
+ using System;
+ using System.Fabric;
+ using System.Fabric.Description;
+ using System.Globalization;
+ using System.Threading;
+ using System.Threading.Tasks;
+ using Microsoft.AspNetCore.Hosting;
+ using Microsoft.ServiceFabric.Services.Communication.Runtime;
+ using Microsoft.Extensions.Logging;
+ using Microsoft.Extensions.Configuration;
+ using Microsoft.AspNetCore.Builder;
+ using Microsoft.Extensions.DependencyInjection;
+ using Ocelot.DependencyInjection;
+ using Ocelot.Middleware;
+
+ public class WebCommunicationListener : ICommunicationListener
+ {
+ private readonly string appRoot;
+ private readonly ServiceContext serviceInitializationParameters;
+ private string listeningAddress;
+ private string publishAddress;
+
+ // OWIN server handle.
+ private IWebHost webHost;
+
+ public WebCommunicationListener(string appRoot, ServiceContext serviceInitializationParameters)
+ {
+ this.appRoot = appRoot;
+ this.serviceInitializationParameters = serviceInitializationParameters;
+ }
+
+ public Task OpenAsync(CancellationToken cancellationToken)
+ {
+ ServiceEventSource.Current.Message("Initialize");
+
+ EndpointResourceDescription serviceEndpoint = this.serviceInitializationParameters.CodePackageActivationContext.GetEndpoint("WebEndpoint");
+ int port = serviceEndpoint.Port;
+
+ this.listeningAddress = string.Format(
+ CultureInfo.InvariantCulture,
+ "http://+:{0}/{1}",
+ port,
+ string.IsNullOrWhiteSpace(this.appRoot)
+ ? string.Empty
+ : this.appRoot.TrimEnd('/') + '/');
+
+ this.publishAddress = this.listeningAddress.Replace("+", FabricRuntime.GetNodeContext().IPAddressOrFQDN);
+
+ ServiceEventSource.Current.Message("Starting web server on {0}", this.listeningAddress);
+
+ try
+ {
+ this.webHost = new WebHostBuilder()
+ .UseKestrel()
+ //.UseStartup()
+ .UseUrls(this.listeningAddress)
+ .ConfigureAppConfiguration((hostingContext, config) =>
+ {
+ config
+ .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
+ .AddJsonFile("appsettings.json", true, true)
+ .AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true)
+ .AddJsonFile("configuration.json")
+ .AddEnvironmentVariables();
+ })
+ .ConfigureLogging((hostingContext, logging) =>
+ {
+ logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
+ logging.AddConsole();
+ })
+ .ConfigureServices(s => {
+ s.AddOcelot();
+ })
+ .Configure(a => {
+ a.UseOcelot().Wait();
+ })
+ .Build();
+
+ this.webHost.Start();
+ }
+ catch (Exception ex)
+ {
+ ServiceEventSource.Current.ServiceWebHostBuilderFailed(ex);
+ }
+
+ return Task.FromResult(this.publishAddress);
+ }
+
+ public Task CloseAsync(CancellationToken cancellationToken)
+ {
+ this.StopAll();
+ return Task.FromResult(true);
+ }
+
+ public void Abort()
+ {
+ this.StopAll();
+ }
+
+ ///
+ /// Stops, cancels, and disposes everything.
+ ///
+ private void StopAll()
+ {
+ try
+ {
+ if (this.webHost != null)
+ {
+ ServiceEventSource.Current.Message("Stopping web server.");
+ this.webHost.Dispose();
+ }
+ }
+ catch (ObjectDisposedException)
+ {
+ }
+ }
+ }
+}
diff --git a/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/appsettings.json b/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/appsettings.json
new file mode 100644
index 00000000..51d92491
--- /dev/null
+++ b/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/appsettings.json
@@ -0,0 +1,10 @@
+{
+ "Logging": {
+ "IncludeScopes": false,
+ "LogLevel": {
+ "Default": "Trace",
+ "System": "Information",
+ "Microsoft": "Information"
+ }
+ }
+}
diff --git a/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/configuration.json b/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/configuration.json
new file mode 100644
index 00000000..dce3d55e
--- /dev/null
+++ b/samples/OcelotServiceFabric/src/OcelotApplicationApiGateway/configuration.json
@@ -0,0 +1,22 @@
+{
+ "ReRoutes": [
+ {
+ "DownstreamPathTemplate": "/api/values",
+ "UpstreamPathTemplate": "/EquipmentInterfaces",
+ "UpstreamHttpMethod": [
+ "Get"
+ ],
+ "DownstreamScheme": "http",
+ "ServiceName": "OcelotServiceApplication/OcelotApplicationService",
+ "UseServiceDiscovery" : true
+ }
+ ],
+ "GlobalConfiguration": {
+ "RequestIdKey": "OcRequestId",
+ "ServiceDiscoveryProvider": {
+ "Host": "localhost",
+ "Port": 19081,
+ "Type": "ServiceFabric"
+ }
+ }
+}
diff --git a/samples/OcelotServiceFabric/src/OcelotApplicationService/ApiGateway.cs b/samples/OcelotServiceFabric/src/OcelotApplicationService/ApiGateway.cs
new file mode 100644
index 00000000..8c090885
--- /dev/null
+++ b/samples/OcelotServiceFabric/src/OcelotApplicationService/ApiGateway.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.Fabric;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.ServiceFabric.Services.Communication.AspNetCore;
+using Microsoft.ServiceFabric.Services.Communication.Runtime;
+using Microsoft.ServiceFabric.Services.Runtime;
+using Microsoft.Extensions.Logging;
+
+namespace OcelotApplicationService
+{
+ ///
+ /// The FabricRuntime creates an instance of this class for each service type instance.
+ ///
+ internal sealed class ApiGateway : StatelessService
+ {
+ public ApiGateway(StatelessServiceContext context)
+ : base(context)
+ { }
+
+ ///
+ /// Optional override to create listeners (like tcp, http) for this service instance.
+ ///
+ /// The collection of listeners.
+ protected override IEnumerable CreateServiceInstanceListeners()
+ {
+ return new ServiceInstanceListener[]
+ {
+ new ServiceInstanceListener(serviceContext =>
+ new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
+ {
+ Console.WriteLine($"Starting Kestrel on {url}");
+ ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting Kestrel on {url}");
+
+ return new WebHostBuilder()
+ .UseKestrel()
+ .ConfigureServices(
+ services => services
+ .AddSingleton(serviceContext))
+ .UseContentRoot(Directory.GetCurrentDirectory())
+ .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.UseUniqueServiceUrl)
+ .UseStartup()
+ .UseUrls(url)
+ .ConfigureLogging((hostingContext, logging) =>
+ {
+ logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
+ logging.AddConsole();
+ })
+ .Build();
+ }))
+ };
+ }
+ }
+}
diff --git a/samples/OcelotServiceFabric/src/OcelotApplicationService/Controllers/ValuesController.cs b/samples/OcelotServiceFabric/src/OcelotApplicationService/Controllers/ValuesController.cs
new file mode 100644
index 00000000..13e56999
--- /dev/null
+++ b/samples/OcelotServiceFabric/src/OcelotApplicationService/Controllers/ValuesController.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+
+namespace OcelotApplicationService.Controllers
+{
+ [Route("api/[controller]")]
+ public class ValuesController : Controller
+ {
+ // GET api/values
+ [HttpGet]
+ public IEnumerable Get()
+ {
+ return new string[] { "value1", "value2" };
+ }
+
+ // GET api/values/5
+ [HttpGet("{id}")]
+ public string Get(int id)
+ {
+ return "value";
+ }
+
+ // POST api/values
+ [HttpPost]
+ public void Post([FromBody]string value)
+ {
+ }
+
+ // PUT api/values/5
+ [HttpPut("{id}")]
+ public void Put(int id, [FromBody]string value)
+ {
+ }
+
+ // DELETE api/values/5
+ [HttpDelete("{id}")]
+ public void Delete(int id)
+ {
+ }
+ }
+}
diff --git a/samples/OcelotServiceFabric/src/OcelotApplicationService/OcelotApplicationService.csproj b/samples/OcelotServiceFabric/src/OcelotApplicationService/OcelotApplicationService.csproj
new file mode 100644
index 00000000..34991440
--- /dev/null
+++ b/samples/OcelotServiceFabric/src/OcelotApplicationService/OcelotApplicationService.csproj
@@ -0,0 +1,21 @@
+
+
+ Stateless Service Application
+
+ Exe
+ netcoreapp2.0
+ OcelotApplicationService
+ OcelotApplicationService
+ $(PackageTargetFallback)
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/OcelotServiceFabric/src/OcelotApplicationService/Program.cs b/samples/OcelotServiceFabric/src/OcelotApplicationService/Program.cs
new file mode 100644
index 00000000..b9d7d72e
--- /dev/null
+++ b/samples/OcelotServiceFabric/src/OcelotApplicationService/Program.cs
@@ -0,0 +1,38 @@
+using Microsoft.ServiceFabric.Services.Runtime;
+using System;
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace OcelotApplicationService
+{
+ internal static class Program
+ {
+ ///
+ /// This is the entry point of the service host process.
+ ///
+ private static void Main()
+ {
+ try
+ {
+ // The ServiceManifest.XML file defines one or more service type names.
+ // Registering a service maps a service type name to a .NET type.
+ // When Service Fabric creates an instance of this service type,
+ // an instance of the class is created in this host process.
+
+ ServiceRuntime.RegisterServiceAsync("OcelotApplicationServiceType",
+ context => new ApiGateway(context)).GetAwaiter().GetResult();
+
+ ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(ApiGateway).Name);
+
+ // Prevents this host process from terminating so services keeps running.
+ Thread.Sleep(Timeout.Infinite);
+ }
+ catch (Exception e)
+ {
+ ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString());
+ throw;
+ }
+ }
+ }
+}
diff --git a/samples/OcelotServiceFabric/src/OcelotApplicationService/ServiceEventSource.cs b/samples/OcelotServiceFabric/src/OcelotApplicationService/ServiceEventSource.cs
new file mode 100644
index 00000000..13e2df12
--- /dev/null
+++ b/samples/OcelotServiceFabric/src/OcelotApplicationService/ServiceEventSource.cs
@@ -0,0 +1,189 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.Tracing;
+using System.Fabric;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace OcelotApplicationService
+{
+ [EventSource(Name = "MyCompany-ServiceOcelotApplication-OcelotService")]
+ internal sealed class ServiceEventSource : EventSource
+ {
+ public static readonly ServiceEventSource Current = new ServiceEventSource();
+
+ static ServiceEventSource()
+ {
+ // A workaround for the problem where ETW activities do not get tracked until Tasks infrastructure is initialized.
+ // This problem will be fixed in .NET Framework 4.6.2.
+ Task.Run(() => { });
+ }
+
+ // Instance constructor is private to enforce singleton semantics
+ private ServiceEventSource() : base() { }
+
+ #region Keywords
+ // Event keywords can be used to categorize events.
+ // Each keyword is a bit flag. A single event can be associated with multiple keywords (via EventAttribute.Keywords property).
+ // Keywords must be defined as a public class named 'Keywords' inside EventSource that uses them.
+ public static class Keywords
+ {
+ public const EventKeywords Requests = (EventKeywords)0x1L;
+ public const EventKeywords ServiceInitialization = (EventKeywords)0x2L;
+ }
+ #endregion
+
+ #region Events
+ // Define an instance method for each event you want to record and apply an [Event] attribute to it.
+ // The method name is the name of the event.
+ // Pass any parameters you want to record with the event (only primitive integer types, DateTime, Guid & string are allowed).
+ // Each event method implementation should check whether the event source is enabled, and if it is, call WriteEvent() method to raise the event.
+ // The number and types of arguments passed to every event method must exactly match what is passed to WriteEvent().
+ // Put [NonEvent] attribute on all methods that do not define an event.
+ // For more information see https://msdn.microsoft.com/en-us/library/system.diagnostics.tracing.eventsource.aspx
+
+ [NonEvent]
+ public void Message(string message, params object[] args)
+ {
+ if (this.IsEnabled())
+ {
+ string finalMessage = string.Format(message, args);
+ Message(finalMessage);
+ }
+ }
+
+ private const int MessageEventId = 1;
+ [Event(MessageEventId, Level = EventLevel.Informational, Message = "{0}")]
+ public void Message(string message)
+ {
+ if (this.IsEnabled())
+ {
+ WriteEvent(MessageEventId, message);
+ }
+ }
+
+ [NonEvent]
+ public void ServiceMessage(ServiceContext serviceContext, string message, params object[] args)
+ {
+ if (this.IsEnabled())
+ {
+
+ string finalMessage = string.Format(message, args);
+ ServiceMessage(
+ serviceContext.ServiceName.ToString(),
+ serviceContext.ServiceTypeName,
+ GetReplicaOrInstanceId(serviceContext),
+ serviceContext.PartitionId,
+ serviceContext.CodePackageActivationContext.ApplicationName,
+ serviceContext.CodePackageActivationContext.ApplicationTypeName,
+ serviceContext.NodeContext.NodeName,
+ finalMessage);
+ }
+ }
+
+ // For very high-frequency events it might be advantageous to raise events using WriteEventCore API.
+ // This results in more efficient parameter handling, but requires explicit allocation of EventData structure and unsafe code.
+ // To enable this code path, define UNSAFE conditional compilation symbol and turn on unsafe code support in project properties.
+ private const int ServiceMessageEventId = 2;
+ [Event(ServiceMessageEventId, Level = EventLevel.Informational, Message = "{7}")]
+ private
+#if UNSAFE
+ unsafe
+#endif
+ void ServiceMessage(
+ string serviceName,
+ string serviceTypeName,
+ long replicaOrInstanceId,
+ Guid partitionId,
+ string applicationName,
+ string applicationTypeName,
+ string nodeName,
+ string message)
+ {
+#if !UNSAFE
+ WriteEvent(ServiceMessageEventId, serviceName, serviceTypeName, replicaOrInstanceId, partitionId, applicationName, applicationTypeName, nodeName, message);
+#else
+ const int numArgs = 8;
+ fixed (char* pServiceName = serviceName, pServiceTypeName = serviceTypeName, pApplicationName = applicationName, pApplicationTypeName = applicationTypeName, pNodeName = nodeName, pMessage = message)
+ {
+ EventData* eventData = stackalloc EventData[numArgs];
+ eventData[0] = new EventData { DataPointer = (IntPtr) pServiceName, Size = SizeInBytes(serviceName) };
+ eventData[1] = new EventData { DataPointer = (IntPtr) pServiceTypeName, Size = SizeInBytes(serviceTypeName) };
+ eventData[2] = new EventData { DataPointer = (IntPtr) (&replicaOrInstanceId), Size = sizeof(long) };
+ eventData[3] = new EventData { DataPointer = (IntPtr) (&partitionId), Size = sizeof(Guid) };
+ eventData[4] = new EventData { DataPointer = (IntPtr) pApplicationName, Size = SizeInBytes(applicationName) };
+ eventData[5] = new EventData { DataPointer = (IntPtr) pApplicationTypeName, Size = SizeInBytes(applicationTypeName) };
+ eventData[6] = new EventData { DataPointer = (IntPtr) pNodeName, Size = SizeInBytes(nodeName) };
+ eventData[7] = new EventData { DataPointer = (IntPtr) pMessage, Size = SizeInBytes(message) };
+
+ WriteEventCore(ServiceMessageEventId, numArgs, eventData);
+ }
+#endif
+ }
+
+ private const int ServiceTypeRegisteredEventId = 3;
+ [Event(ServiceTypeRegisteredEventId, Level = EventLevel.Informational, Message = "Service host process {0} registered service type {1}", Keywords = Keywords.ServiceInitialization)]
+ public void ServiceTypeRegistered(int hostProcessId, string serviceType)
+ {
+ WriteEvent(ServiceTypeRegisteredEventId, hostProcessId, serviceType);
+ }
+
+ private const int ServiceHostInitializationFailedEventId = 4;
+ [Event(ServiceHostInitializationFailedEventId, Level = EventLevel.Error, Message = "Service host initialization failed", Keywords = Keywords.ServiceInitialization)]
+ public void ServiceHostInitializationFailed(string exception)
+ {
+ WriteEvent(ServiceHostInitializationFailedEventId, exception);
+ }
+
+ // A pair of events sharing the same name prefix with a "Start"/"Stop" suffix implicitly marks boundaries of an event tracing activity.
+ // These activities can be automatically picked up by debugging and profiling tools, which can compute their execution time, child activities,
+ // and other statistics.
+ private const int ServiceRequestStartEventId = 5;
+ [Event(ServiceRequestStartEventId, Level = EventLevel.Informational, Message = "Service request '{0}' started", Keywords = Keywords.Requests)]
+ public void ServiceRequestStart(string requestTypeName)
+ {
+ WriteEvent(ServiceRequestStartEventId, requestTypeName);
+ }
+
+ private const int ServiceRequestStopEventId = 6;
+ [Event(ServiceRequestStopEventId, Level = EventLevel.Informational, Message = "Service request '{0}' finished", Keywords = Keywords.Requests)]
+ public void ServiceRequestStop(string requestTypeName, string exception = "")
+ {
+ WriteEvent(ServiceRequestStopEventId, requestTypeName, exception);
+ }
+ #endregion
+
+ #region Private methods
+ private static long GetReplicaOrInstanceId(ServiceContext context)
+ {
+ StatelessServiceContext stateless = context as StatelessServiceContext;
+ if (stateless != null)
+ {
+ return stateless.InstanceId;
+ }
+
+ StatefulServiceContext stateful = context as StatefulServiceContext;
+ if (stateful != null)
+ {
+ return stateful.ReplicaId;
+ }
+
+ throw new NotSupportedException("Context type not supported.");
+ }
+#if UNSAFE
+ private int SizeInBytes(string s)
+ {
+ if (s == null)
+ {
+ return 0;
+ }
+ else
+ {
+ return (s.Length + 1) * sizeof(char);
+ }
+ }
+#endif
+ #endregion
+ }
+}
diff --git a/samples/OcelotServiceFabric/src/OcelotApplicationService/Startup.cs b/samples/OcelotServiceFabric/src/OcelotApplicationService/Startup.cs
new file mode 100644
index 00000000..022fcb0e
--- /dev/null
+++ b/samples/OcelotServiceFabric/src/OcelotApplicationService/Startup.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+
+namespace OcelotApplicationService
+{
+ public class Startup
+ {
+ public Startup(IConfiguration configuration)
+ {
+ Configuration = configuration;
+ }
+
+ public IConfiguration Configuration { get; }
+
+ // This method gets called by the runtime. Use this method to add services to the container.
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddMvc();
+ }
+
+ // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
+ {
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+ }
+
+ app.UseMvc();
+ }
+ }
+}
diff --git a/samples/OcelotServiceFabric/src/global.json b/samples/OcelotServiceFabric/src/global.json
new file mode 100644
index 00000000..8288598a
--- /dev/null
+++ b/samples/OcelotServiceFabric/src/global.json
@@ -0,0 +1,6 @@
+{
+ "projects": [ "../"],
+ "sdk": {
+ "version": "2.1.4"
+ }
+}
\ No newline at end of file
diff --git a/samples/OcelotServiceFabric/uninstall.ps1 b/samples/OcelotServiceFabric/uninstall.ps1
new file mode 100644
index 00000000..032ee0e8
--- /dev/null
+++ b/samples/OcelotServiceFabric/uninstall.ps1
@@ -0,0 +1,2 @@
+Remove-ServiceFabricApplication fabric:/OcelotServiceApplication
+Unregister-ServiceFabricApplicationType OcelotServiceApplicationType 1.0.0
\ No newline at end of file
diff --git a/samples/OcelotServiceFabric/uninstall.sh b/samples/OcelotServiceFabric/uninstall.sh
new file mode 100644
index 00000000..45fc561c
--- /dev/null
+++ b/samples/OcelotServiceFabric/uninstall.sh
@@ -0,0 +1,5 @@
+#!/bin/bash -x
+
+sfctl application delete --application-id OcelotServiceApplication
+sfctl application unprovision --application-type-name OcelotServiceApplicationType --application-type-version 1.0.0
+sfctl store delete --content-path OcelotServiceApplication
\ No newline at end of file
diff --git a/src/Ocelot/Configuration/Builder/DownstreamReRouteBuilder.cs b/src/Ocelot/Configuration/Builder/DownstreamReRouteBuilder.cs
index bc860424..0e7509b9 100644
--- a/src/Ocelot/Configuration/Builder/DownstreamReRouteBuilder.cs
+++ b/src/Ocelot/Configuration/Builder/DownstreamReRouteBuilder.cs
@@ -36,7 +36,6 @@ namespace Ocelot.Configuration.Builder
private readonly List _downstreamAddresses;
private string _upstreamHost;
private string _key;
-
public DownstreamReRouteBuilder()
{
_downstreamAddresses = new List();
diff --git a/src/Ocelot/Configuration/Builder/ServiceProviderConfigurationBuilder.cs b/src/Ocelot/Configuration/Builder/ServiceProviderConfigurationBuilder.cs
index 0999a47c..b1f4e832 100644
--- a/src/Ocelot/Configuration/Builder/ServiceProviderConfigurationBuilder.cs
+++ b/src/Ocelot/Configuration/Builder/ServiceProviderConfigurationBuilder.cs
@@ -4,6 +4,7 @@ namespace Ocelot.Configuration.Builder
{
private string _serviceDiscoveryProviderHost;
private int _serviceDiscoveryProviderPort;
+ private string _type;
public ServiceProviderConfigurationBuilder WithServiceDiscoveryProviderHost(string serviceDiscoveryProviderHost)
{
@@ -17,9 +18,15 @@ namespace Ocelot.Configuration.Builder
return this;
}
+ public ServiceProviderConfigurationBuilder WithServiceDiscoveryProviderType(string type)
+ {
+ _type = type;
+ return this;
+ }
+
public ServiceProviderConfiguration Build()
{
- return new ServiceProviderConfiguration(_serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort);
+ return new ServiceProviderConfiguration(_type, _serviceDiscoveryProviderHost, _serviceDiscoveryProviderPort);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs
index cfc3e7c7..c104385a 100644
--- a/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs
+++ b/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs
@@ -7,12 +7,14 @@ namespace Ocelot.Configuration.Creator
{
public ServiceProviderConfiguration Create(FileGlobalConfiguration globalConfiguration)
{
+ //todo log or return error here dont just default to something that wont work..
var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
return new ServiceProviderConfigurationBuilder()
- .WithServiceDiscoveryProviderHost(globalConfiguration?.ServiceDiscoveryProvider?.Host)
- .WithServiceDiscoveryProviderPort(serviceProviderPort)
- .Build();
+ .WithServiceDiscoveryProviderHost(globalConfiguration?.ServiceDiscoveryProvider?.Host)
+ .WithServiceDiscoveryProviderPort(serviceProviderPort)
+ .WithServiceDiscoveryProviderType(globalConfiguration?.ServiceDiscoveryProvider?.Type)
+ .Build();
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Ocelot/Configuration/File/FileServiceDiscoveryProvider.cs b/src/Ocelot/Configuration/File/FileServiceDiscoveryProvider.cs
index f9c370b1..203cc675 100644
--- a/src/Ocelot/Configuration/File/FileServiceDiscoveryProvider.cs
+++ b/src/Ocelot/Configuration/File/FileServiceDiscoveryProvider.cs
@@ -4,5 +4,6 @@ namespace Ocelot.Configuration.File
{
public string Host {get;set;}
public int Port { get; set; }
+ public string Type { get; set; }
}
-}
\ No newline at end of file
+}
diff --git a/src/Ocelot/Configuration/Repository/ConsulFileConfigurationRepository.cs b/src/Ocelot/Configuration/Repository/ConsulFileConfigurationRepository.cs
index 91b4bd9d..13c128b9 100644
--- a/src/Ocelot/Configuration/Repository/ConsulFileConfigurationRepository.cs
+++ b/src/Ocelot/Configuration/Repository/ConsulFileConfigurationRepository.cs
@@ -18,8 +18,8 @@ namespace Ocelot.Configuration.Repository
public ConsulFileConfigurationRepository(Cache.IOcelotCache cache, ServiceProviderConfiguration serviceProviderConfig)
{
- var consulHost = string.IsNullOrEmpty(serviceProviderConfig?.ServiceProviderHost) ? "localhost" : serviceProviderConfig?.ServiceProviderHost;
- var consulPort = serviceProviderConfig?.ServiceProviderPort ?? 8500;
+ var consulHost = string.IsNullOrEmpty(serviceProviderConfig?.Host) ? "localhost" : serviceProviderConfig?.Host;
+ var consulPort = serviceProviderConfig?.Port ?? 8500;
var configuration = new ConsulRegistryConfiguration(consulHost, consulPort, _ocelotConfiguration);
_cache = cache;
_consul = new ConsulClient(c =>
@@ -76,4 +76,4 @@ namespace Ocelot.Configuration.Repository
return new ErrorResponse(new UnableToSetConfigInConsulError($"Unable to set FileConfiguration in consul, response status code from consul was {result.StatusCode}"));
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Ocelot/Configuration/ServiceProviderConfiguraion.cs b/src/Ocelot/Configuration/ServiceProviderConfiguraion.cs
index 272d2205..9df16ea2 100644
--- a/src/Ocelot/Configuration/ServiceProviderConfiguraion.cs
+++ b/src/Ocelot/Configuration/ServiceProviderConfiguraion.cs
@@ -2,13 +2,15 @@
{
public class ServiceProviderConfiguration
{
- public ServiceProviderConfiguration(string serviceProviderHost, int serviceProviderPort)
+ public ServiceProviderConfiguration(string type, string host, int port)
{
- ServiceProviderHost = serviceProviderHost;
- ServiceProviderPort = serviceProviderPort;
+ Host = host;
+ Port = port;
+ Type = type;
}
- public string ServiceProviderHost { get; private set; }
- public int ServiceProviderPort { get; private set; }
+ public string Host { get; private set; }
+ public int Port { get; private set; }
+ public string Type { get; private set; }
}
-}
\ No newline at end of file
+}
diff --git a/src/Ocelot/Configuration/Validator/FileConfigurationFluentValidator.cs b/src/Ocelot/Configuration/Validator/FileConfigurationFluentValidator.cs
index 58da7c4f..d0c6de0e 100644
--- a/src/Ocelot/Configuration/Validator/FileConfigurationFluentValidator.cs
+++ b/src/Ocelot/Configuration/Validator/FileConfigurationFluentValidator.cs
@@ -30,7 +30,7 @@ namespace Ocelot.Configuration.Validator
RuleForEach(configuration => configuration.Aggregates)
.Must((config, aggregateReRoute) => AllReRoutesForAggregateExist(aggregateReRoute, config.ReRoutes))
- .WithMessage((config, aggregateReRoute) => $"ReRoutes for {nameof(aggregateReRoute)} {aggregateReRoute.UpstreamPathTemplate} either do not exist or do not have correct Key property");
+ .WithMessage((config, aggregateReRoute) => $"ReRoutes for {nameof(aggregateReRoute)} {aggregateReRoute.UpstreamPathTemplate} either do not exist or do not have correct ServiceName property");
RuleForEach(configuration => configuration.Aggregates)
.Must((config, aggregateReRoute) => DoesNotContainReRoutesWithSpecificRequestIdKeys(aggregateReRoute, config.ReRoutes))
diff --git a/src/Ocelot/DependencyInjection/OcelotBuilder.cs b/src/Ocelot/DependencyInjection/OcelotBuilder.cs
index f4192713..ccd2a9be 100644
--- a/src/Ocelot/DependencyInjection/OcelotBuilder.cs
+++ b/src/Ocelot/DependencyInjection/OcelotBuilder.cs
@@ -99,7 +99,6 @@ namespace Ocelot.DependencyInjection
_services.TryAddSingleton();
_services.TryAddSingleton();
_services.TryAddSingleton();
- _services.TryAddSingleton();
_services.TryAddSingleton();
_services.TryAddSingleton();
_services.TryAddSingleton();
diff --git a/src/Ocelot/DownstreamUrlCreator/IUrlBuilder.cs b/src/Ocelot/DownstreamUrlCreator/IUrlBuilder.cs
index 19fa55a1..9975cec2 100644
--- a/src/Ocelot/DownstreamUrlCreator/IUrlBuilder.cs
+++ b/src/Ocelot/DownstreamUrlCreator/IUrlBuilder.cs
@@ -1,4 +1,5 @@
-using Ocelot.Responses;
+/*
+using Ocelot.Responses;
using Ocelot.Values;
namespace Ocelot.DownstreamUrlCreator
@@ -8,3 +9,4 @@ namespace Ocelot.DownstreamUrlCreator
Response Build(string downstreamPath, string downstreamScheme, ServiceHostAndPort downstreamHostAndPort);
}
}
+*/
diff --git a/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs
index 5b5e8346..dc02a20e 100644
--- a/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs
+++ b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs
@@ -5,6 +5,7 @@ using Ocelot.Infrastructure.RequestData;
using Ocelot.Logging;
using Ocelot.Middleware;
using System;
+using System.Linq;
using Ocelot.DownstreamRouteFinder.Middleware;
namespace Ocelot.DownstreamUrlCreator.Middleware
@@ -14,16 +15,13 @@ namespace Ocelot.DownstreamUrlCreator.Middleware
private readonly OcelotRequestDelegate _next;
private readonly IDownstreamPathPlaceholderReplacer _replacer;
private readonly IOcelotLogger _logger;
- private readonly IUrlBuilder _urlBuilder;
public DownstreamUrlCreatorMiddleware(OcelotRequestDelegate next,
IOcelotLoggerFactory loggerFactory,
- IDownstreamPathPlaceholderReplacer replacer,
- IUrlBuilder urlBuilder)
+ IDownstreamPathPlaceholderReplacer replacer)
{
_next = next;
_replacer = replacer;
- _urlBuilder = urlBuilder;
_logger = loggerFactory.CreateLogger();
}
@@ -40,11 +38,32 @@ namespace Ocelot.DownstreamUrlCreator.Middleware
return;
}
- var uriBuilder = new UriBuilder(context.DownstreamRequest.RequestUri)
+ UriBuilder uriBuilder;
+
+ //todo - feel this is a bit crap the way we build the url dont see why we need this builder thing..maybe i blew my own brains out
+ // when i originally wrote it..
+ if (context.ServiceProviderConfiguration.Type == "ServiceFabric" && context.DownstreamReRoute.UseServiceDiscovery)
{
- Path = dsPath.Data.Value,
- Scheme = context.DownstreamReRoute.DownstreamScheme
- };
+ _logger.LogInformation("DownstreamUrlCreatorMiddleware - going to try set service fabric path");
+
+ var scheme = context.DownstreamReRoute.DownstreamScheme;
+ var host = context.DownstreamRequest.RequestUri.Host;
+ var port = context.DownstreamRequest.RequestUri.Port;
+ var serviceFabricPath = $"/{context.DownstreamReRoute.ServiceName + dsPath.Data.Value}";
+
+ _logger.LogInformation("DownstreamUrlCreatorMiddleware - service fabric path is {proxyUrl}", serviceFabricPath);
+
+ var uri = new Uri($"{scheme}://{host}:{port}{serviceFabricPath}?cmd=instance");
+ uriBuilder = new UriBuilder(uri);
+ }
+ else
+ {
+ uriBuilder = new UriBuilder(context.DownstreamRequest.RequestUri)
+ {
+ Path = dsPath.Data.Value,
+ Scheme = context.DownstreamReRoute.DownstreamScheme
+ };
+ }
context.DownstreamRequest.RequestUri = uriBuilder.Uri;
diff --git a/src/Ocelot/DownstreamUrlCreator/UrlBuilder.cs b/src/Ocelot/DownstreamUrlCreator/UrlBuilder.cs
index 80f2507d..1c5f284c 100644
--- a/src/Ocelot/DownstreamUrlCreator/UrlBuilder.cs
+++ b/src/Ocelot/DownstreamUrlCreator/UrlBuilder.cs
@@ -1,4 +1,5 @@
-using System;
+/*
+using System;
using System.Collections.Generic;
using Ocelot.Errors;
using Ocelot.Responses;
@@ -25,12 +26,11 @@ namespace Ocelot.DownstreamUrlCreator
return new ErrorResponse(new List { new DownstreamHostNullOrEmptyError() });
}
-
var builder = new UriBuilder
{
Host = downstreamHostAndPort.DownstreamHost,
Path = downstreamPath,
- Scheme = downstreamScheme
+ Scheme = downstreamScheme,
};
if (downstreamHostAndPort.DownstreamPort > 0)
@@ -44,3 +44,4 @@ namespace Ocelot.DownstreamUrlCreator
}
}
}
+*/
diff --git a/src/Ocelot/LoadBalancer/LoadBalancers/NoLoadBalancer.cs b/src/Ocelot/LoadBalancer/LoadBalancers/NoLoadBalancer.cs
index 172909d7..203d1b9d 100644
--- a/src/Ocelot/LoadBalancer/LoadBalancers/NoLoadBalancer.cs
+++ b/src/Ocelot/LoadBalancer/LoadBalancers/NoLoadBalancer.cs
@@ -17,6 +17,7 @@ namespace Ocelot.LoadBalancer.LoadBalancers
public async Task> Lease()
{
+ //todo no point spinning a task up here, also first or default could be null..
var service = await Task.FromResult(_services.FirstOrDefault());
return new OkResponse(service.HostAndPort);
}
diff --git a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs
index 0e75cb1a..de93a19d 100644
--- a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs
+++ b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs
@@ -18,7 +18,7 @@ namespace Ocelot.ServiceDiscovery
{
if (reRoute.UseServiceDiscovery)
{
- return GetServiceDiscoveryProvider(reRoute.ServiceName, serviceConfig.ServiceProviderHost, serviceConfig.ServiceProviderPort);
+ return GetServiceDiscoveryProvider(serviceConfig, reRoute.ServiceName);
}
var services = new List();
@@ -33,9 +33,15 @@ namespace Ocelot.ServiceDiscovery
return new ConfigurationServiceProvider(services);
}
- private IServiceDiscoveryProvider GetServiceDiscoveryProvider(string keyOfServiceInConsul, string providerHostName, int providerPort)
+ private IServiceDiscoveryProvider GetServiceDiscoveryProvider(ServiceProviderConfiguration serviceConfig, string serviceName)
{
- var consulRegistryConfiguration = new ConsulRegistryConfiguration(providerHostName, providerPort, keyOfServiceInConsul);
+ if (serviceConfig.Type == "ServiceFabric")
+ {
+ var config = new ServiceFabricConfiguration(serviceConfig.Host, serviceConfig.Port, serviceName);
+ return new ServiceFabricServiceDiscoveryProvider(config);
+ }
+
+ var consulRegistryConfiguration = new ConsulRegistryConfiguration(serviceConfig.Host, serviceConfig.Port, serviceName);
return new ConsulServiceDiscoveryProvider(consulRegistryConfiguration, _factory);
}
}
diff --git a/src/Ocelot/ServiceDiscovery/ServiceFabricConfiguration.cs b/src/Ocelot/ServiceDiscovery/ServiceFabricConfiguration.cs
new file mode 100644
index 00000000..7522a1e0
--- /dev/null
+++ b/src/Ocelot/ServiceDiscovery/ServiceFabricConfiguration.cs
@@ -0,0 +1,16 @@
+namespace Ocelot.ServiceDiscovery
+{
+ public class ServiceFabricConfiguration
+ {
+ public ServiceFabricConfiguration(string hostName, int port, string serviceName)
+ {
+ HostName = hostName;
+ Port = port;
+ ServiceName = serviceName;
+ }
+
+ public string ServiceName { get; private set; }
+ public string HostName { get; private set; }
+ public int Port { get; private set; }
+ }
+}
diff --git a/src/Ocelot/ServiceDiscovery/ServiceFabricServiceDiscoveryProvider.cs b/src/Ocelot/ServiceDiscovery/ServiceFabricServiceDiscoveryProvider.cs
new file mode 100644
index 00000000..28f9bb65
--- /dev/null
+++ b/src/Ocelot/ServiceDiscovery/ServiceFabricServiceDiscoveryProvider.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Ocelot.Values;
+
+namespace Ocelot.ServiceDiscovery
+{
+ public class ServiceFabricServiceDiscoveryProvider : IServiceDiscoveryProvider
+ {
+ private readonly ServiceFabricConfiguration _configuration;
+
+ public ServiceFabricServiceDiscoveryProvider(ServiceFabricConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+ public async Task> Get()
+ {
+ return new List
+ {
+ new Service(_configuration.ServiceName,
+ new ServiceHostAndPort(_configuration.HostName, _configuration.Port),
+ "doesnt matter with service fabric",
+ "doesnt matter with service fabric",
+ new List())
+ };
+ }
+ }
+}
diff --git a/test/Ocelot.AcceptanceTests/ServiceFabricTests.cs b/test/Ocelot.AcceptanceTests/ServiceFabricTests.cs
new file mode 100644
index 00000000..bfe14103
--- /dev/null
+++ b/test/Ocelot.AcceptanceTests/ServiceFabricTests.cs
@@ -0,0 +1,112 @@
+using System.Linq;
+using Microsoft.Extensions.Primitives;
+
+namespace Ocelot.AcceptanceTests
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Net;
+ using Microsoft.AspNetCore.Builder;
+ using Microsoft.AspNetCore.Hosting;
+ using Microsoft.AspNetCore.Http;
+ using Ocelot.Configuration.File;
+ using Shouldly;
+ using TestStack.BDDfy;
+ using Xunit;
+
+ public class ServiceFabricTests : IDisposable
+ {
+ private IWebHost _builder;
+ private readonly Steps _steps;
+ private string _downstreamPath;
+
+ public ServiceFabricTests()
+ {
+ _steps = new Steps();
+ }
+
+ [Fact]
+ public void should_support_service_fabric_naming_and_dns_service()
+ {
+ var configuration = new FileConfiguration
+ {
+ ReRoutes = new List
+ {
+ new FileReRoute
+ {
+ DownstreamPathTemplate = "/api/values",
+ DownstreamScheme = "http",
+ UpstreamPathTemplate = "/EquipmentInterfaces",
+ UpstreamHttpMethod = new List { "Get" },
+ UseServiceDiscovery = true,
+ ServiceName = "OcelotServiceApplication/OcelotApplicationService"
+ }
+ },
+ GlobalConfiguration = new FileGlobalConfiguration
+ {
+ ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
+ {
+ Host = "localhost",
+ Port = 19081,
+ Type = "ServiceFabric"
+ }
+ }
+ };
+
+ this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:19081", "/OcelotServiceApplication/OcelotApplicationService/api/values", 200, "Hello from Laura"))
+ .And(x => _steps.GivenThereIsAConfiguration(configuration))
+ .And(x => _steps.GivenOcelotIsRunning())
+ .When(x => _steps.WhenIGetUrlOnTheApiGateway("/EquipmentInterfaces"))
+ .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
+ .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
+ .BDDfy();
+ }
+
+ private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody)
+ {
+ _builder = new WebHostBuilder()
+ .UseUrls(baseUrl)
+ .UseKestrel()
+ .UseContentRoot(Directory.GetCurrentDirectory())
+ .UseIISIntegration()
+ .Configure(app =>
+ {
+ app.UsePathBase(basePath);
+ app.Run(async context =>
+ {
+ _downstreamPath = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
+
+ if(_downstreamPath != basePath)
+ {
+ context.Response.StatusCode = statusCode;
+ await context.Response.WriteAsync("downstream path didnt match base path");
+ }
+ else
+ {
+ if (context.Request.Query.TryGetValue("cmd", out var values))
+ {
+ values.First().ShouldBe("instance");
+ context.Response.StatusCode = statusCode;
+ await context.Response.WriteAsync(responseBody);
+ }
+ else
+ {
+ context.Response.StatusCode = statusCode;
+ await context.Response.WriteAsync("downstream path didnt match base path");
+ }
+ }
+ });
+ })
+ .Build();
+
+ _builder.Start();
+ }
+
+ public void Dispose()
+ {
+ _builder?.Dispose();
+ _steps.Dispose();
+ }
+ }
+}
diff --git a/test/Ocelot.UnitTests/Configuration/ConfigurationFluentValidationTests.cs b/test/Ocelot.UnitTests/Configuration/ConfigurationFluentValidationTests.cs
index e7e56178..ba7bfd01 100644
--- a/test/Ocelot.UnitTests/Configuration/ConfigurationFluentValidationTests.cs
+++ b/test/Ocelot.UnitTests/Configuration/ConfigurationFluentValidationTests.cs
@@ -328,7 +328,7 @@ namespace Ocelot.UnitTests.Configuration
this.Given(x => x.GivenAConfiguration(configuration))
.When(x => x.WhenIValidateTheConfiguration())
.Then(x => x.ThenTheResultIsNotValid())
- .And(x => x.ThenTheErrorMessageAtPositionIs(0, "ReRoutes for aggregateReRoute / either do not exist or do not have correct Key property"))
+ .And(x => x.ThenTheErrorMessageAtPositionIs(0, "ReRoutes for aggregateReRoute / either do not exist or do not have correct ServiceName property"))
.BDDfy();
}
diff --git a/test/Ocelot.UnitTests/Configuration/ServiceProviderCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/ServiceProviderCreatorTests.cs
index c0a35696..8b0cc078 100644
--- a/test/Ocelot.UnitTests/Configuration/ServiceProviderCreatorTests.cs
+++ b/test/Ocelot.UnitTests/Configuration/ServiceProviderCreatorTests.cs
@@ -30,13 +30,15 @@ namespace Ocelot.UnitTests.Configuration
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Host = "127.0.0.1",
- Port = 1234
+ Port = 1234,
+ Type = "ServiceFabric"
}
};
var expected = new ServiceProviderConfigurationBuilder()
.WithServiceDiscoveryProviderHost("127.0.0.1")
.WithServiceDiscoveryProviderPort(1234)
+ .WithServiceDiscoveryProviderType("ServiceFabric")
.Build();
this.Given(x => x.GivenTheFollowingReRoute(reRoute))
@@ -63,8 +65,8 @@ namespace Ocelot.UnitTests.Configuration
private void ThenTheConfigIs(ServiceProviderConfiguration expected)
{
- _result.ServiceProviderHost.ShouldBe(expected.ServiceProviderHost);
- _result.ServiceProviderPort.ShouldBe(expected.ServiceProviderPort);
+ _result.Host.ShouldBe(expected.Host);
+ _result.Port.ShouldBe(expected.Port);
}
}
-}
\ No newline at end of file
+}
diff --git a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs
index ec4829a7..d0926fc9 100644
--- a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs
+++ b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs
@@ -1,4 +1,5 @@
-using Ocelot.Middleware;
+using Ocelot.Configuration;
+using Ocelot.Middleware;
namespace Ocelot.UnitTests.DownstreamUrlCreator
{
@@ -27,7 +28,6 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
public class DownstreamUrlCreatorMiddlewareTests
{
private readonly Mock _downstreamUrlTemplateVariableReplacer;
- private readonly Mock _urlBuilder;
private OkResponse _downstreamPath;
private Mock _loggerFactory;
private Mock _logger;
@@ -42,7 +42,6 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
_logger = new Mock();
_loggerFactory.Setup(x => x.CreateLogger()).Returns(_logger.Object);
_downstreamUrlTemplateVariableReplacer = new Mock();
- _urlBuilder = new Mock();
_downstreamContext.DownstreamRequest = new HttpRequestMessage(HttpMethod.Get, "https://my.url/abc/?q=123");
_next = async context => {
//do nothing
@@ -58,6 +57,9 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
.WithDownstreamScheme("https")
.Build();
+ var config = new ServiceProviderConfigurationBuilder()
+ .Build();
+
this.Given(x => x.GivenTheDownStreamRouteIs(
new DownstreamRoute(
new List(),
@@ -66,15 +68,81 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
.WithUpstreamHttpMethod(new List { "Get" })
.Build())))
.And(x => x.GivenTheDownstreamRequestUriIs("http://my.url/abc?q=123"))
+ .And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheUrlReplacerWillReturn("/api/products/1"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("https://my.url:80/api/products/1?q=123"))
.BDDfy();
}
+ [Fact]
+ public void should_not_create_service_fabric_url()
+ {
+ var downstreamReRoute = new DownstreamReRouteBuilder()
+ .WithDownstreamPathTemplate("any old string")
+ .WithUpstreamHttpMethod(new List { "Get" })
+ .WithDownstreamScheme("https")
+ .Build();
+
+ var config = new ServiceProviderConfigurationBuilder()
+ .WithServiceDiscoveryProviderType("ServiceFabric")
+ .WithServiceDiscoveryProviderHost("localhost")
+ .WithServiceDiscoveryProviderPort(19081)
+ .Build();
+
+ this.Given(x => x.GivenTheDownStreamRouteIs(
+ new DownstreamRoute(
+ new List(),
+ new ReRouteBuilder()
+ .WithDownstreamReRoute(downstreamReRoute)
+ .WithUpstreamHttpMethod(new List { "Get" })
+ .Build())))
+ .And(x => x.GivenTheDownstreamRequestUriIs("http://my.url/abc?q=123"))
+ .And(x => GivenTheServiceProviderConfigIs(config))
+ .And(x => x.GivenTheUrlReplacerWillReturn("/api/products/1"))
+ .When(x => x.WhenICallTheMiddleware())
+ .Then(x => x.ThenTheDownstreamRequestUriIs("https://my.url:80/api/products/1?q=123"))
+ .BDDfy();
+ }
+
+ [Fact]
+ public void should_create_service_fabric_url()
+ {
+ var downstreamReRoute = new DownstreamReRouteBuilder()
+ .WithDownstreamScheme("http")
+ .WithServiceName("Ocelot/OcelotApp")
+ .WithUseServiceDiscovery(true)
+ .Build();
+
+ var downstreamRoute = new DownstreamRoute(
+ new List(),
+ new ReRouteBuilder()
+ .WithDownstreamReRoute(downstreamReRoute)
+ .Build());
+
+ var config = new ServiceProviderConfigurationBuilder()
+ .WithServiceDiscoveryProviderType("ServiceFabric")
+ .WithServiceDiscoveryProviderHost("localhost")
+ .WithServiceDiscoveryProviderPort(19081)
+ .Build();
+
+ this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
+ .And(x => GivenTheServiceProviderConfigIs(config))
+ .And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:19081"))
+ .And(x => x.GivenTheUrlReplacerWillReturn("/api/products/1"))
+ .When(x => x.WhenICallTheMiddleware())
+ .Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:19081/Ocelot/OcelotApp/api/products/1?cmd=instance"))
+ .BDDfy();
+ }
+
+ private void GivenTheServiceProviderConfigIs(ServiceProviderConfiguration config)
+ {
+ _downstreamContext.ServiceProviderConfiguration = config;
+ }
+
private void WhenICallTheMiddleware()
{
- _middleware = new DownstreamUrlCreatorMiddleware(_next, _loggerFactory.Object, _downstreamUrlTemplateVariableReplacer.Object, _urlBuilder.Object);
+ _middleware = new DownstreamUrlCreatorMiddleware(_next, _loggerFactory.Object, _downstreamUrlTemplateVariableReplacer.Object);
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
}
diff --git a/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlBuilderTests.cs b/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlBuilderTests.cs
deleted file mode 100644
index 20dfa1a1..00000000
--- a/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlBuilderTests.cs
+++ /dev/null
@@ -1,122 +0,0 @@
-using System;
-using Ocelot.DownstreamUrlCreator;
-using Ocelot.Responses;
-using Ocelot.Values;
-using Shouldly;
-using TestStack.BDDfy;
-using Xunit;
-
-namespace Ocelot.UnitTests.DownstreamUrlCreator
-{
- public class UrlBuilderTests
- {
- private readonly IUrlBuilder _urlBuilder;
- private string _dsPath;
- private string _dsScheme;
- private string _dsHost;
- private int _dsPort;
-
- private Response _result;
-
- public UrlBuilderTests()
- {
- _urlBuilder = new UrlBuilder();
- }
-
- [Fact]
- public void should_return_error_when_downstream_path_is_null()
- {
- this.Given(x => x.GivenADownstreamPath(null))
- .When(x => x.WhenIBuildTheUrl())
- .Then(x => x.ThenThereIsAnErrorOfType())
- .BDDfy();
- }
-
- [Fact]
- public void should_return_error_when_downstream_scheme_is_null()
- {
- this.Given(x => x.GivenADownstreamScheme(null))
- .And(x => x.GivenADownstreamPath("test"))
- .When(x => x.WhenIBuildTheUrl())
- .Then(x => x.ThenThereIsAnErrorOfType())
- .BDDfy();
- }
-
- [Fact]
- public void should_return_error_when_downstream_host_is_null()
- {
- this.Given(x => x.GivenADownstreamScheme(null))
- .And(x => x.GivenADownstreamPath("test"))
- .And(x => x.GivenADownstreamScheme("test"))
- .When(x => x.WhenIBuildTheUrl())
- .Then(x => x.ThenThereIsAnErrorOfType())
- .BDDfy();
- }
-
- [Fact]
- public void should_not_use_port_if_zero()
- {
- this.Given(x => x.GivenADownstreamPath("/api/products/1"))
- .And(x => x.GivenADownstreamScheme("http"))
- .And(x => x.GivenADownstreamHost("127.0.0.1"))
- .And(x => x.GivenADownstreamPort(0))
- .When(x => x.WhenIBuildTheUrl())
- .Then(x => x.ThenTheUrlIsReturned("http://127.0.0.1/api/products/1"))
- .And(x => x.ThenTheUrlIsWellFormed())
- .BDDfy();
- }
-
- [Fact]
- public void should_build_well_formed_uri()
- {
- this.Given(x => x.GivenADownstreamPath("/api/products/1"))
- .And(x => x.GivenADownstreamScheme("http"))
- .And(x => x.GivenADownstreamHost("127.0.0.1"))
- .And(x => x.GivenADownstreamPort(5000))
- .When(x => x.WhenIBuildTheUrl())
- .Then(x => x.ThenTheUrlIsReturned("http://127.0.0.1:5000/api/products/1"))
- .And(x => x.ThenTheUrlIsWellFormed())
- .BDDfy();
- }
-
- private void ThenThereIsAnErrorOfType()
- {
- _result.Errors[0].ShouldBeOfType();
- }
-
- private void GivenADownstreamPath(string dsPath)
- {
- _dsPath = dsPath;
- }
-
- private void GivenADownstreamScheme(string dsScheme)
- {
- _dsScheme = dsScheme;
- }
-
- private void GivenADownstreamHost(string dsHost)
- {
- _dsHost = dsHost;
- }
-
- private void GivenADownstreamPort(int dsPort)
- {
- _dsPort = dsPort;
- }
-
- private void WhenIBuildTheUrl()
- {
- _result = _urlBuilder.Build(_dsPath, _dsScheme, new ServiceHostAndPort(_dsHost, _dsPort));
- }
-
- private void ThenTheUrlIsReturned(string expected)
- {
- _result.Data.Value.ShouldBe(expected);
- }
-
- private void ThenTheUrlIsWellFormed()
- {
- Uri.IsWellFormedUriString(_result.Data.Value, UriKind.Absolute).ShouldBeTrue();
- }
- }
-}
diff --git a/test/Ocelot.UnitTests/ServiceDiscovery/ServiceFabricServiceDiscoveryProviderTests.cs b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceFabricServiceDiscoveryProviderTests.cs
new file mode 100644
index 00000000..39deb681
--- /dev/null
+++ b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceFabricServiceDiscoveryProviderTests.cs
@@ -0,0 +1,58 @@
+namespace Ocelot.UnitTests.ServiceDiscovery
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Text;
+ using Consul;
+ using Microsoft.AspNetCore.Builder;
+ using Microsoft.AspNetCore.Hosting;
+ using Microsoft.AspNetCore.Http;
+ using Moq;
+ using Ocelot.Logging;
+ using Ocelot.ServiceDiscovery;
+ using Ocelot.Values;
+ using Xunit;
+ using TestStack.BDDfy;
+ using Shouldly;
+
+ public class ServiceFabricServiceDiscoveryProviderTests
+ {
+ private ServiceFabricServiceDiscoveryProvider _provider;
+ private ServiceFabricConfiguration _config;
+ private string _host;
+ private string _serviceName;
+ private int _port;
+ private List _services;
+
+ [Fact]
+ public void should_return_service_fabric_naming_service()
+ {
+ this.Given(x => GivenTheFollowing())
+ .When(x => WhenIGet())
+ .Then(x => ThenTheServiceFabricNamingServiceIsRetured())
+ .BDDfy();
+ }
+
+ private void GivenTheFollowing()
+ {
+ _host = "localhost";
+ _serviceName = "OcelotServiceApplication/OcelotApplicationService";
+ _port = 19081;
+ }
+
+ private void WhenIGet()
+ {
+ _config = new ServiceFabricConfiguration(_host, _port, _serviceName);
+ _provider = new ServiceFabricServiceDiscoveryProvider(_config);
+ _services = _provider.Get().GetAwaiter().GetResult();
+ }
+
+ private void ThenTheServiceFabricNamingServiceIsRetured()
+ {
+ _services.Count.ShouldBe(1);
+ _services[0].HostAndPort.DownstreamHost.ShouldBe(_host);
+ _services[0].HostAndPort.DownstreamPort.ShouldBe(_port);
+ }
+ }
+}
diff --git a/test/Ocelot.UnitTests/ServiceDiscovery/ServiceProviderFactoryTests.cs b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceProviderFactoryTests.cs
index f8c60bb7..021b9efb 100644
--- a/test/Ocelot.UnitTests/ServiceDiscovery/ServiceProviderFactoryTests.cs
+++ b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceProviderFactoryTests.cs
@@ -77,6 +77,24 @@ namespace Ocelot.UnitTests.ServiceDiscovery
.BDDfy();
}
+ [Fact]
+ public void should_return_service_fabric_provider()
+ {
+ var reRoute = new DownstreamReRouteBuilder()
+ .WithServiceName("product")
+ .WithUseServiceDiscovery(true)
+ .Build();
+
+ var serviceConfig = new ServiceProviderConfigurationBuilder()
+ .WithServiceDiscoveryProviderType("ServiceFabric")
+ .Build();
+
+ this.Given(x => x.GivenTheReRoute(serviceConfig, reRoute))
+ .When(x => x.WhenIGetTheServiceProvider())
+ .Then(x => x.ThenTheServiceProviderIs())
+ .BDDfy();
+ }
+
private void ThenTheFollowingServicesAreReturned(List downstreamAddresses)
{
var result = (ConfigurationServiceProvider)_result;