Skip to content

Commit 1cd3f9e

Browse files
authored
Merge pull request #13 from ddevadat/dotnet-samples
added dotnet function for ords sql queries
2 parents 9bd05fe + 0aa2170 commit 1cd3f9e

File tree

14 files changed

+500
-1
lines changed

14 files changed

+500
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ This repository provides examples demonstrating how to use Oracle Functions.
2626
| Copy object from one OCI Object Storage bucket to another |[sample](./samples/oci-objectstorage-copy-objects-python)||[sample](./samples/oci-objectstorage-copy-objects-dotnet)|
2727
| Display an OCI Cloud Event |[sample](./samples/oci-event-display-python)||[sample](./samples/oci-event-display-dotnet)|
2828
| Invoke another Function using the OCI SDK |[sample](./samples/oci-invoke-function-python)||[sample](./samples/oci-invoke-function-dotnet)|
29-
| Run a SQL statement against Autonomous DB using ORDS | [sample](./samples/oci-adb-ords-runsql-python) |
29+
| Run a SQL statement against Autonomous DB using ORDS | [sample](./samples/oci-adb-ords-runsql-python) ||[sample](./samples/oci-adb-ords-runsql-dotnet)|
3030
| Run a SQL statement against Autonomous DB using DB Client |[sample](./samples/oci-adb-client-runsql-python)||
3131
| Publish a notification using ONS |[sample](./samples/oci-ons-publish-python)|
3232
| Send an email using Email Delivery Service |[sample](./samples/oci-email-send-python)|
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
using System;
3+
using System.Threading.Tasks;
4+
using System.Text;
5+
6+
using Oci.Common.Model;
7+
using Oci.Common;
8+
using Oci.Common.Auth;
9+
using Oci.Common.Http.Signing;
10+
using System.Net.Http;
11+
12+
13+
namespace RunSQL
14+
{
15+
public class HttpClientHelper
16+
{
17+
public static HttpClient GetHttpClient()
18+
{
19+
try
20+
{
21+
// return new KmsCryptoClient(ResourcePrincipalAuthenticationDetailsProvider.GetProvider(), new ClientConfiguration(), crypto_endpoint);
22+
return new HttpClient(OciHttpClientHandler.FromAuthProvider(ResourcePrincipalAuthenticationDetailsProvider.GetProvider()));
23+
}
24+
catch (Exception ex)
25+
{
26+
Console.WriteLine("Unable To Create Resource Principal Provider: {0}", ex.Message);
27+
Console.WriteLine("Defaulting to Instance Provider");
28+
return new HttpClient(OciHttpClientHandler.FromAuthProvider(new InstancePrincipalsAuthenticationDetailsProvider()));
29+
}
30+
}
31+
32+
}
33+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM fnproject/dotnet:3.1-1.0.4-dev as build-stage
2+
WORKDIR /function
3+
COPY . .
4+
RUN dotnet sln add RunSQL.csproj
5+
RUN dotnet build RunSQL.csproj -c Release
6+
RUN dotnet publish RunSQL.csproj -c Release -o out
7+
FROM fnproject/dotnet:3.1-1.0.4
8+
WORKDIR /function
9+
COPY --from=build-stage /function/out/ /function/
10+
ENTRYPOINT ["dotnet", "RunSQL.dll"]
11+
CMD ["RunSQL:Function:function_handler"]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
Microsoft Visual Studio Solution File, Format Version 12.00
2+
# Visual Studio 15
3+
VisualStudioVersion = 15.0.26124.0
4+
MinimumVisualStudioVersion = 15.0.26124.0
5+
Global
6+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
7+
Debug|Any CPU = Debug|Any CPU
8+
Debug|x64 = Debug|x64
9+
Debug|x86 = Debug|x86
10+
Release|Any CPU = Release|Any CPU
11+
Release|x64 = Release|x64
12+
Release|x86 = Release|x86
13+
EndGlobalSection
14+
GlobalSection(SolutionProperties) = preSolution
15+
HideSolutionNode = FALSE
16+
EndGlobalSection
17+
EndGlobal
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
3+
namespace RunSQL
4+
{
5+
6+
class InputMessage
7+
{
8+
public string sql { get; set; }
9+
10+
11+
}
12+
13+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
using System.Collections.Generic;
3+
// using System.Collections;
4+
// using System.Collections.Specialized;
5+
6+
namespace RunSQL
7+
{
8+
9+
class OutputDetails
10+
{
11+
public string sql { get; set; }
12+
13+
public List<Dictionary<string, string>> result { get; set; }
14+
15+
// public string error { get; set; }
16+
public List<string> error { get; set; }
17+
18+
}
19+
20+
}
Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
# Function that executes a SQL statement using ORDS
2+
3+
This function connects to an Autonomous Database using ORDS and executes a SQL statement.
4+
5+
As you make your way through this tutorial, look out for this icon ![user input icon](./images/userinput.png).
6+
Whenever you see it, it's time for you to perform an action.
7+
8+
9+
## Prerequisites
10+
Before you deploy this sample function, make sure you have run step A, B and C of the [Oracle Functions Quick Start Guide for Cloud Shell](https://www.oracle.com/webfolder/technetwork/tutorials/infographics/oci_functions_cloudshell_quickview/functions_quickview_top/functions_quickview/index.html)
11+
* A - Set up your tenancy
12+
* B - Create application
13+
* C - Set up your Cloud Shell dev environment
14+
15+
16+
## List Applications
17+
Assuming your have successfully completed the prerequisites, you should see your
18+
application in the list of applications.
19+
```
20+
fn ls apps
21+
```
22+
23+
24+
## Create or Update your Dynamic Group
25+
In order to use other OCI Services, your function must be part of a dynamic group. For information on how to create a dynamic group, refer to the [documentation](https://docs.cloud.oracle.com/iaas/Content/Identity/Tasks/managingdynamicgroups.htm#To).
26+
27+
When specifying the *Matching Rules*, we suggest matching all functions in a compartment with:
28+
```
29+
ALL {resource.type = 'fnfunc', resource.compartment.id = 'ocid1.compartment.oc1..aaaaaxxxxx'}
30+
```
31+
Please check the [Accessing Other Oracle Cloud Infrastructure Resources from Running Functions](https://docs.cloud.oracle.com/en-us/iaas/Content/Functions/Tasks/functionsaccessingociresources.htm) for other *Matching Rules* options.
32+
33+
34+
35+
## Review and customize the function
36+
Review the following files in the current folder:
37+
* the code of the function, [RunSQL.cs](./RunSQL.cs)
38+
* its dependencies, [RunSQL.csproj](./RunSQL.csproj)
39+
* the function metadata, [func.yaml](./func.yaml)
40+
41+
In the code, we assume the schema and the database username are the same. Feel free to change this.
42+
43+
44+
## Deploy the function
45+
In Cloud Shell, run the *fn deploy* command to build the function and its dependencies as a Docker image,
46+
push the image to OCIR, and deploy the function to Oracle Functions in your application.
47+
48+
![user input icon](./images/userinput.png)
49+
```
50+
fn -v deploy --app <app-name>
51+
```
52+
53+
54+
## Create an Autonomous Database
55+
Use an existing Autonomous Database (either Transaction Processing or Datawarehouse) or create a new one as follows.
56+
57+
On the OCI console, navigate to *Autonomous Transaction Processing* or *Autonomous Data Warehouse* and click *Create Autonomous Database*. In the Create Autonomous Database dialog, enter the following:
58+
- Display Name
59+
- Compartment
60+
- Database Name
61+
- Infrastructure Type: Shared
62+
- Admin password
63+
- License type
64+
65+
![ADB create](./images/ADB-create.png)
66+
For more information, go to https://docs.cloud.oracle.com/iaas/Content/Database/Tasks/adbcreating.htm
67+
68+
On the Autonomous Database detail page, click *Service Console*
69+
![ADB Service Console](./images/ADB-serviceconsole.png)
70+
71+
On the Service Console, navigate to Development and copy the ORDS Base URL, we will need it in the next section.
72+
![ADB ORDS URL](./images/ADB-ORDS-URL.png)
73+
74+
The *admin* schema is enabled for REST access by default, so you can test the function using the *admin* schema. For Production, it is recommended to create a separate schema and enable REST Service. For more information on how to do this, check the documentation at https://docs.oracle.com/en/database/oracle/oracle-rest-data-services/19.1/index.html.
75+
76+
77+
## Set the function configuration values
78+
The function requires the config value *ords-base-url*, *db-schema* and *db-pwd-cypher* to be set.
79+
![user input icon](../images/userinput.png)
80+
81+
Use the *fn CLI* to set the config value:
82+
```
83+
fn config function <app-name> <function-name> ords_base_url <ORDS-Base-URL>
84+
fn config function <app-name> <function-name> db_schema <DB-schema>
85+
fn config function <app-name> <function-name> db_pwd_cypher <DB-encrypted-password>
86+
```
87+
e.g.
88+
```
89+
fn config function myapp oci-adb-ords-runsql-dotnet ords_base_urll "https://xxxxxx-db123456.adb.us-region.oraclecloudapps.com/ords/"
90+
fn config function myapp oci-adb-ords-runsql-dotnet db_schema "admin"
91+
fn config function myapp oci-adb-ords-runsql-dotnet db_pwd_cypher "xxxxxxxxx"
92+
```
93+
94+
95+
## Invoke the function
96+
![user input icon](./images/userinput.png)
97+
```
98+
99+
echo '{"sql":"<sql statement>"}' | fn invoke <app-name> oci-adb-ords-runsql-dotnet
100+
```
101+
e.g.:
102+
```
103+
echo '{"sql":"select sysdate from dual"}' | fn invoke myapp oci-adb-ords-runsql-dotnet
104+
```
105+
106+
Upon success, the function returns a JSON object similar to this:
107+
```json
108+
{"output":[{"sql":"select sysdate from dual","result":[{"sysdate":"10/20/2022 00:29:35"}],"error":[]}]}
109+
```
110+
Here is another example with the table EMP created in the ADMIN schema. Ref. https://docs.oracle.com/en/database/oracle/oracle-rest-data-services/19.4/qsord/get-started-with-oracle-rest-data-services.html#GUID-14BE2F08-842E-4D2F-86B9-EA245B8487F9.
111+
112+
```bash
113+
echo '{"sql":"select * from emp"}' | fn invoke myapp oci-adb-ords-runsql-dotnet | jq .
114+
```
115+
```
116+
{
117+
"output": [
118+
{
119+
"sql": "select * from emp",
120+
"result": [
121+
{
122+
"empno": "7369",
123+
"ename": "SMITH",
124+
"job": "CLERK",
125+
"mgr": "7902",
126+
"hiredate": "12/17/1980 00:00:00",
127+
"sal": "800",
128+
"comm": null,
129+
"deptno": "20"
130+
},
131+
{
132+
"empno": "7499",
133+
"ename": "ALLEN",
134+
"job": "SALESMAN",
135+
"mgr": "7698",
136+
"hiredate": "02/20/1981 00:00:00",
137+
"sal": "1600",
138+
"comm": "300",
139+
"deptno": "30"
140+
},
141+
{
142+
"empno": "7521",
143+
"ename": "WARD",
144+
"job": "SALESMAN",
145+
"mgr": "7698",
146+
"hiredate": "02/22/1981 00:00:00",
147+
"sal": "1250",
148+
"comm": "500",
149+
"deptno": "30"
150+
},
151+
{
152+
"empno": "7566",
153+
"ename": "JONES",
154+
"job": "MANAGER",
155+
"mgr": "7839",
156+
"hiredate": "04/02/1981 00:00:00",
157+
"sal": "2975",
158+
"comm": null,
159+
"deptno": "20"
160+
},
161+
{
162+
"empno": "7654",
163+
"ename": "MARTIN",
164+
"job": "SALESMAN",
165+
"mgr": "7698",
166+
"hiredate": "09/28/1981 00:00:00",
167+
"sal": "1250",
168+
"comm": "1400",
169+
"deptno": "30"
170+
},
171+
{
172+
"empno": "7698",
173+
"ename": "BLAKE",
174+
"job": "MANAGER",
175+
"mgr": "7839",
176+
"hiredate": "05/01/1981 00:00:00",
177+
"sal": "2850",
178+
"comm": null,
179+
"deptno": "30"
180+
},
181+
{
182+
"empno": "7782",
183+
"ename": "CLARK",
184+
"job": "MANAGER",
185+
"mgr": "7839",
186+
"hiredate": "06/09/1981 00:00:00",
187+
"sal": "2450",
188+
"comm": null,
189+
"deptno": "10"
190+
},
191+
{
192+
"empno": "7788",
193+
"ename": "SCOTT",
194+
"job": "ANALYST",
195+
"mgr": "7566",
196+
"hiredate": "04/19/1987 00:00:00",
197+
"sal": "3000",
198+
"comm": null,
199+
"deptno": "20"
200+
},
201+
{
202+
"empno": "7839",
203+
"ename": "KING",
204+
"job": "PRESIDENT",
205+
"mgr": null,
206+
"hiredate": "11/17/1981 00:00:00",
207+
"sal": "5000",
208+
"comm": null,
209+
"deptno": "10"
210+
},
211+
{
212+
"empno": "7844",
213+
"ename": "TURNER",
214+
"job": "SALESMAN",
215+
"mgr": "7698",
216+
"hiredate": "09/08/1981 00:00:00",
217+
"sal": "1500",
218+
"comm": "0",
219+
"deptno": "30"
220+
},
221+
{
222+
"empno": "7876",
223+
"ename": "ADAMS",
224+
"job": "CLERK",
225+
"mgr": "7788",
226+
"hiredate": "05/23/1987 00:00:00",
227+
"sal": "1100",
228+
"comm": null,
229+
"deptno": "20"
230+
},
231+
{
232+
"empno": "7900",
233+
"ename": "JAMES",
234+
"job": "CLERK",
235+
"mgr": "7698",
236+
"hiredate": "12/03/1981 00:00:00",
237+
"sal": "950",
238+
"comm": null,
239+
"deptno": "30"
240+
},
241+
{
242+
"empno": "7902",
243+
"ename": "FORD",
244+
"job": "ANALYST",
245+
"mgr": "7566",
246+
"hiredate": "12/03/1981 00:00:00",
247+
"sal": "3000",
248+
"comm": null,
249+
"deptno": "20"
250+
},
251+
{
252+
"empno": "7934",
253+
"ename": "MILLER",
254+
"job": "CLERK",
255+
"mgr": "7782",
256+
"hiredate": "01/23/1982 00:00:00",
257+
"sal": "1300",
258+
"comm": null,
259+
"deptno": "10"
260+
}
261+
],
262+
"error": []
263+
}
264+
]
265+
}
266+
```
267+
268+
269+
## Monitoring Functions
270+
271+
Learn how to configure basic observability for your function using metrics, alarms and email alerts:
272+
* [Basic Guidance for Monitoring your Functions](../basic-observability/functions.md)
273+

0 commit comments

Comments
 (0)