Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Dalam artikel ini, Anda mengintegrasikan antrean Azure Storage dengan fungsi dan akun penyimpanan yang Anda buat di artikel mulai cepat sebelumnya. Anda mencapai integrasi ini dengan menggunakan pengikatan output yang menulis data dari permintaan HTTP ke pesan dalam antrean. Menyelesaikan artikel ini tidak dikenakan biaya tambahan di luar beberapa sen USD dari mulai cepat sebelumnya. Untuk mempelajari lebih lanjut, lihat konsep pemicu dan pengikatan Azure Functions.
Mengonfigurasi lingkungan lokal Anda
Sebelum memulai, Anda harus menyelesaikan artikel, Mulai Cepat: Membuat proyek Azure Functions dari baris perintah. Jika Anda sudah membersihkan sumber daya di akhir artikel tersebut, lakukan lagi langkah-langkahnya untuk membuat ulang aplikasi fungsi dan sumber daya terkait di Azure.
Sebelum memulai, Anda harus menyelesaikan artikel, Mulai Cepat: Membuat proyek Azure Functions dari baris perintah. Jika Anda sudah membersihkan sumber daya di akhir artikel tersebut, lakukan lagi langkah-langkahnya untuk membuat ulang aplikasi fungsi dan sumber daya terkait di Azure.
Sebelum memulai, Anda harus menyelesaikan artikel, Mulai Cepat: Membuat proyek Azure Functions dari baris perintah. Jika Anda sudah membersihkan sumber daya di akhir artikel tersebut, lakukan lagi langkah-langkahnya untuk membuat ulang aplikasi fungsi dan sumber daya terkait di Azure.
Sebelum memulai, Anda harus menyelesaikan artikel, Mulai Cepat: Membuat proyek Azure Functions dari baris perintah. Jika Anda sudah membersihkan sumber daya di akhir artikel tersebut, lakukan lagi langkah-langkahnya untuk membuat ulang aplikasi fungsi dan sumber daya terkait di Azure.
Sebelum memulai, Anda harus menyelesaikan artikel, Mulai Cepat: Membuat proyek Azure Functions dari baris perintah. Jika Anda sudah membersihkan sumber daya di akhir artikel tersebut, lakukan lagi langkah-langkahnya untuk membuat ulang aplikasi fungsi dan sumber daya terkait di Azure.
Sebelum memulai, Anda harus menyelesaikan artikel, Mulai Cepat: Membuat proyek Azure Functions dari baris perintah. Jika Anda sudah membersihkan sumber daya di akhir artikel tersebut, lakukan lagi langkah-langkahnya untuk membuat ulang aplikasi fungsi dan sumber daya terkait di Azure.
Mengambil string koneksi Azure Storage
Penting
Artikel ini saat ini memperlihatkan cara menyambungkan ke akun Azure Storage Anda dengan menggunakan string koneksi, yang berisi kunci rahasia bersama. Menggunakan string koneksi memudahkan Anda memverifikasi pembaruan data di akun penyimpanan. Untuk keamanan terbaik, Anda harus menggunakan identitas terkelola saat menyambungkan ke akun penyimpanan Anda. Untuk informasi selengkapnya, lihat Koneksi di Panduan Pengembang.
Sebelumnya, Anda telah membuat akun Azure Storage untuk digunakan oleh aplikasi fungsi. String koneksi untuk akun ini disimpan dengan aman di pengaturan aplikasi di Azure. Dengan mengunduh pengaturan ke dalam file local.settings.json, Anda bisa menggunakan menulis koneksi tersebut ke Antrean penyimpanan di akun yang sama saat menjalankan fungsi secara lokal.
Dari akar proyek, jalankan perintah berikut, ganti
<APP_NAME>dengan nama aplikasi fungsi Anda dari langkah sebelumnya. Perintah ini akan menimpa setiap nilai yang ada pada file.func azure functionapp fetch-app-settings <APP_NAME>Buka local.settings.json lalu temukan nilai bernama
AzureWebJobsStorage, yang merupakan string koneksi akun Azure Storage. Anda menggunakan namaAzureWebJobsStoragedan string koneksi di bagian lain artikel ini.
Penting
Karena local.settings.json berisi rahasia yang diunduh dari Azure, harap selalu kecualikan file ini dari kontrol sumber. File .gitignore yang dibuat dengan proyek fungsi lokal mengecualikan file secara default.
Mendaftarkan ekstensi pengikatan
Kecuali untuk pemicu HTTP dan timer, pengikatan diimplementasikan sebagai paket ekstensi. Jalankan perintah dotnet add package berikut di jendela Terminal untuk menambahkan paket ekstensi Storage ke proyek Anda.
dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Storage.Queues --prerelease
Sekarang, Anda dapat menambahkan pengikatan output penyimpanan ke proyek Anda.
Menambahkan definisi pengikatan output ke fungsi
Meskipun fungsi hanya bisa memiliki satu pemicu, fungsi ini dapat memiliki beberapa pengikatan input dan output, yang memungkinkan Anda terhubung ke layanan dan sumber daya Azure lainnya tanpa menulis kode integrasi kustom.
Saat menggunakan model pemrograman Node.js v4, atribut pengikatan didefinisikan langsung dalam file ./src/functions/HttpExample.js . Dari mulai cepat sebelumnya, file Anda sudah berisi pengikatan HTTP yang ditentukan oleh app.http metode .
const { app } = require('@azure/functions');
app.http('httpTrigger', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
handler: async (request, context) => {
try {
context.log(`Http function processed request for url "${request.url}"`);
const name = request.query.get('name') || (await request.text());
context.log(`Name: ${name}`);
if (!name) {
return { status: 404, body: 'Not Found' };
}
return { body: `Hello, ${name}!` };
} catch (error) {
context.log(`Error: ${error}`);
return { status: 500, body: 'Internal Server Error' };
}
},
});
Saat menggunakan model pemrograman Node.js v4, atribut pengikatan didefinisikan langsung dalam file ./src/functions/HttpExample.js . Dari mulai cepat sebelumnya, file Anda sudah berisi pengikatan HTTP yang ditentukan oleh app.http metode .
import {
app,
HttpRequest,
HttpResponseInit,
InvocationContext,
} from '@azure/functions';
export async function httpTrigger1(
request: HttpRequest,
context: InvocationContext,
): Promise<HttpResponseInit> {
context.log(`Http function processed request for url "${request.url}"`);
const name = request.query.get('name') || (await request.text()) || 'world';
return { body: `Hello, ${name}!` };
}
app.http('httpTrigger1', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
handler: httpTrigger1,
});
Anda mendeklarasikan pengikatan ini di file function.json di folder fungsi Anda. Dari mulai cepat sebelumnya, file function.json di folder HttpExample berisi dua pengikatan dalam koleksi bindings:
Saat menggunakan model pemrograman Python v2, atribut pengikatan didefinisikan langsung dalam file function_app.py sebagai dekorator. Dari mulai cepat sebelumnya, file function_app.py Anda sudah berisi satu pengikatan berbasis dekorator:
import azure.functions as func
import logging
app = func.FunctionApp()
@app.function_name(name="HttpTrigger1")
@app.route(route="hello", auth_level=func.AuthLevel.ANONYMOUS)
Dekorator route menambahkan pengikatan HttpTrigger dan HttpOutput ke fungsi, yang memungkinkan fungsi Anda dipicu ketika permintaan http mencapai rute yang ditentukan.
Untuk menulis ke antrean Azure Storage dari fungsi ini, tambahkan queue_output dekorator ke kode fungsi Anda:
@app.queue_output(arg_name="msg", queue_name="outqueue", connection="AzureWebJobsStorage")
Di dekorator, arg_name mengidentifikasi parameter pengikatan yang direferensikan dalam kode Anda, queue_name adalah nama antrean yang ditulis pengikatan, dan connection merupakan nama pengaturan aplikasi yang berisi string koneksi untuk akun Penyimpanan. Di mulai cepat, Anda menggunakan akun penyimpanan yang sama dengan aplikasi fungsi, yang ada di AzureWebJobsStorage pengaturan (dari file local.settings.json ).
queue_name Ketika tidak ada, pengikatan membuatnya pada penggunaan pertama.
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "Request",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "Response"
}
]
Untuk menulis ke antrean Azure Storage:
extraOutputsMenambahkan properti ke konfigurasi pengikatan{ methods: ['GET', 'POST'], extraOutputs: [sendToQueue], // add output binding to HTTP trigger authLevel: 'anonymous', handler: () => {} }output.storageQueueMenambahkan fungsi diapp.httpatas panggilanconst sendToQueue: StorageQueueOutput = output.storageQueue({ queueName: 'outqueue', connection: 'AzureWebJobsStorage', });
Pengikatan kedua dalam koleksi diberi nama res. Pengikatan http ini adalah pengikatan output (out) yang digunakan untuk menulis respons HTTP.
Untuk menulis ke antrean Azure Storage dari fungsi ini, tambahkan pengikatan out jenis queue dengan nama msg, seperti yang ditunjukkan pada kode di bawah ini:
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "Request",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "Response"
},
{
"type": "queue",
"direction": "out",
"name": "msg",
"queueName": "outqueue",
"connection": "AzureWebJobsStorage"
}
]
}
queue Untuk jenis, Anda harus menentukan nama antrean di queueName dan memberikan nama koneksi Azure Storage (dari file local.settings.json) di connection.
Dalam proyek C#, pengikatan didefinisikan sebagai atribut pengikatan pada metode fungsi. Definisi tertentu bergantung pada apakah aplikasi Anda berjalan dalam proses (pustaka kelas C#) atau dalam proses pekerja yang terisolasi.
Buka file proyek HttpExample.cs dan tambahkan kelas MultiResponse berikut:
public class MultiResponse
{
[QueueOutput("outqueue",Connection = "AzureWebJobsStorage")]
public string[] Messages { get; set; }
public HttpResponseData HttpResponse { get; set; }
}
Kelas MultiResponse memungkinkan Anda untuk menulis ke antrean penyimpanan bernama outqueue dan pesan sukses HTTP. Beberapa pesan dapat dikirim ke antrean tersebut karena atribut QueueOutput diterapkan ke array string.
Properti Connection mengatur string koneksi pada akun penyimpanan. Dalam hal ini, Anda dapat mengabaikan Connection karena Anda sudah menggunakan akun penyimpanan default.
Dalam proyek Java, pengikatan didefinisikan sebagai anotasi pengikatan pada metode fungsi. Daftar file function.json kemudian dibuat secara otomatis berdasarkan anotasi ini.
Telusuri ke lokasi kode fungsi Anda di src/main/java, buka file proyek Function.java, dan tambahkan parameter berikut ke definisi metode run:
@QueueOutput(name = "msg", queueName = "outqueue", connection = "AzureWebJobsStorage") OutputBinding<String> msg
Parameter msg adalah tipe OutputBinding<T>, yang mewakili kumpulan string. String ini ditulis sebagai pesan ke output yang mengikat saat fungsi selesai. Dalam hal ini, output adalah antrean penyimpanan `bernama outqueue. String koneksi untuk akun Storage diatur sesuai metode connection. Anda melewati pengaturan aplikasi yang berisi string koneksi akun Penyimpanan, daripada meneruskan string koneksi itu sendiri.
Definisi metode run sekarang harus terlihat seperti contoh berikut:
@FunctionName("HttpTrigger-Java")
public HttpResponseMessage run(
@HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION)
HttpRequestMessage<Optional<String>> request,
@QueueOutput(name = "msg", queueName = "outqueue", connection = "AzureWebJobsStorage")
OutputBinding<String> msg, final ExecutionContext context) {
...
}
Untuk informasi selengkapnya tentang detail pengikatan, lihat konsep pemicu dan pengikatan Azure Functions dan konfigurasi output antrean.
Tambahkan kode untuk menggunakan pengikatan output
Dengan pengikatan antrean yang ditentukan, Anda sekarang dapat memperbarui fungsi Anda untuk menerima parameter output msg dan menulis pesan ke antrean.
Perbarui HttpExample\function_app.py agar sesuai dengan kode berikut, tambahkan msg parameter ke definisi fungsi dan msg.set(name) di bawah if name: pernyataan:
import azure.functions as func
import logging
app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)
@app.route(route="HttpExample")
@app.queue_output(arg_name="msg", queue_name="outqueue", connection="AzureWebJobsStorage")
def HttpExample(req: func.HttpRequest, msg: func.Out [func.QueueMessage]) -> func.HttpResponse:
logging.info('Python HTTP trigger function processed a request.')
name = req.params.get('name')
if not name:
try:
req_body = req.get_json()
except ValueError:
pass
else:
name = req_body.get('name')
if name:
msg.set(name)
return func.HttpResponse(f"Hello, {name}. This HTTP triggered function executed successfully.")
else:
return func.HttpResponse(
"This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.",
status_code=200
)
Parameter msg adalah instans dari azure.functions.Out class. Metode set menuliskan pesan string pada antrean. Dalam hal ini, ini adalah fungsi yang name diteruskan ke fungsi dalam string kueri URL.
Tambahkan kode yang menggunakan objek pengikatan output untuk context.extraOutputs membuat pesan antrean. Tambahkan kode ini sebelum pernyataan pengembalian.
context.extraOutputs.set(sendToQueue, [msg]);
Pada titik ini, fungsi Anda dapat terlihat sebagai berikut:
const { app, output } = require('@azure/functions');
const sendToQueue = output.storageQueue({
queueName: 'outqueue',
connection: 'AzureWebJobsStorage',
});
app.http('HttpExample', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
extraOutputs: [sendToQueue],
handler: async (request, context) => {
try {
context.log(`Http function processed request for url "${request.url}"`);
const name = request.query.get('name') || (await request.text());
context.log(`Name: ${name}`);
if (name) {
const msg = `Name passed to the function ${name}`;
context.extraOutputs.set(sendToQueue, [msg]);
return { body: msg };
} else {
context.log('Missing required data');
return { status: 404, body: 'Missing required data' };
}
} catch (error) {
context.log(`Error: ${error}`);
return { status: 500, body: 'Internal Server Error' };
}
},
});
Tambahkan kode yang menggunakan objek pengikatan output untuk context.extraOutputs membuat pesan antrean. Tambahkan kode ini sebelum pernyataan pengembalian.
context.extraOutputs.set(sendToQueue, [msg]);
Pada titik ini, fungsi Anda dapat terlihat sebagai berikut:
import {
app,
output,
HttpRequest,
HttpResponseInit,
InvocationContext,
StorageQueueOutput,
} from '@azure/functions';
const sendToQueue: StorageQueueOutput = output.storageQueue({
queueName: 'outqueue',
connection: 'AzureWebJobsStorage',
});
export async function HttpExample(
request: HttpRequest,
context: InvocationContext,
): Promise<HttpResponseInit> {
try {
context.log(`Http function processed request for url "${request.url}"`);
const name = request.query.get('name') || (await request.text());
context.log(`Name: ${name}`);
if (name) {
const msg = `Name passed to the function ${name}`;
context.extraOutputs.set(sendToQueue, [msg]);
return { body: msg };
} else {
context.log('Missing required data');
return { status: 404, body: 'Missing required data' };
}
} catch (error) {
context.log(`Error: ${error}`);
return { status: 500, body: 'Internal Server Error' };
}
}
app.http('HttpExample', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
handler: HttpExample,
});
Tambahkan kode yang menggunakan Push-OutputBinding cmdlet untuk menulis teks ke antrean menggunakan pengikatan output msg. Tambahkan kode ini sebelum Anda mengatur status OK dalam pernyataan if.
$outputMsg = $name
Push-OutputBinding -name msg -Value $outputMsg
Pada titik ini, fungsi Anda akan ditampilkan sebagai berikut:
using namespace System.Net
# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)
# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."
# Interact with query parameters or the body of the request.
$name = $Request.Query.Name
if (-not $name) {
$name = $Request.Body.Name
}
if ($name) {
# Write the $name value to the queue,
# which is the name passed to the function.
$outputMsg = $name
Push-OutputBinding -name msg -Value $outputMsg
$status = [HttpStatusCode]::OK
$body = "Hello $name"
}
else {
$status = [HttpStatusCode]::BadRequest
$body = "Please pass a name on the query string or in the request body."
}
# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = $status
Body = $body
})
Ganti kelas HttpExample yang sudah ada dengan kode berikut:
[Function("HttpExample")]
public static MultiResponse Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req,
FunctionContext executionContext)
{
var logger = executionContext.GetLogger("HttpExample");
logger.LogInformation("C# HTTP trigger function processed a request.");
var message = "Welcome to Azure Functions!";
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
response.WriteString(message);
// Return a response to both HTTP trigger and storage output binding.
return new MultiResponse()
{
// Write a single message.
Messages = new string[] { message },
HttpResponse = response
};
}
}
Sekarang, Anda dapat menggunakan parameter msg baru untuk menulis ke pengikatan output dari kode fungsi Anda. Tambahkan garis kode berikut sebelum respons keberhasilan untuk menambahkan nilai name ke pengikatan output msg.
msg.setValue(name);
Saat menggunakan pengikatan output, Anda tidak perlu menggunakan kode SDK Azure Storage untuk mengautentikasi, mendapatkan referensi antrean, atau menulis data. Runtime Functions dan pengikatan output antrean akan melakukan tugas-tugas tersebut untuk Anda.
Metode run Anda sekarang harus terlihat seperti contoh berikut:
public HttpResponseMessage run(
@HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<Optional<String>> request,
@QueueOutput(name = "msg", queueName = "outqueue",
connection = "AzureWebJobsStorage") OutputBinding<String> msg,
final ExecutionContext context) {
context.getLogger().info("Java HTTP trigger processed a request.");
// Parse query parameter
String query = request.getQueryParameters().get("name");
String name = request.getBody().orElse(query);
if (name == null) {
return request.createResponseBuilder(HttpStatus.BAD_REQUEST)
.body("Please pass a name on the query string or in the request body").build();
} else {
// Write the name to the message queue.
msg.setValue(name);
return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
}
}
Perbarui tes
Karena arketipe juga membuat kumpulan pengujian, Anda perlu memperbarui pengujian ini untuk menangani parameter msg baru di tanda tangan metode run.
Telusuri lokasi kode pengujian Anda di bawah src/test/java, buka file proyek Function.java, dan ganti baris kode di bawah //Invoke dengan kode berikut:
@SuppressWarnings("unchecked")
final OutputBinding<String> msg = (OutputBinding<String>)mock(OutputBinding.class);
final HttpResponseMessage ret = new Function().run(req, msg, context);
Amati bahwa Anda tidak perlu menulis kode apa pun untuk autentikasi, mendapatkan referensi antrean, atau menulis data. Semua tugas integrasi ini ditangani dengan mudah dalam runtime Azure Functions dan pengikatan output antrean.
Jalankan fungsi secara lokal
Jalankan fungsi Anda dengan memulai host runtime Azure Functions lokal dari folder LocalFunctionProj.
func startMenjelang akhir output, baris berikut harus muncul:
Catatan
Jika HttpExample tidak muncul seperti yang ditunjukkan di atas, Anda mungkin memulai hosting dari luar folder akar proyek. Dalam kasus tersebut, gunakan Ctrl+C untuk menghentikan hosting, buka folder akar proyek, dan jalankan kembali perintah sebelumnya.
Salin URL fungsi HTTP Anda dari output ini ke browser dan tambahkan string
?name=<YOUR_NAME>kueri , membuat URL lengkap sepertihttp://localhost:7071/api/HttpExample?name=Functions. Browser akan menampilkan pesan tanggapan yang mengulang nilai string kueri Anda. Terminal tempat Anda memulai proyek juga menunjukkan output log saat Anda membuat permintaan.Jika sudah selesai, tekan Ctrl + C dan ketik
yuntuk menghentikan hosting fungsi.
Menampilkan pesan dalam antrean Azure Storage
Anda dapat melihat antrean di portal Azure atau di Microsoft Azure Storage Explorer. Anda juga bisa melihat antrean di Azure CLI, seperti yang dijelaskan dalam langkah-langkah berikut:
Buka file local.setting.json proyek fungsi dan salin nilai string koneksi. Di terminal atau jendela perintah, jalankan perintah berikut guna membuat variabel lingkungan bernama
AZURE_STORAGE_CONNECTION_STRING, menempelkan string koneksi spesifik Anda untuk menggantikan<MY_CONNECTION_STRING>. (Variabel lingkungan ini berarti Anda tidak perlu menyediakan string koneksi ke setiap perintah berikutnya menggunakan argumen--connection-string.)export AZURE_STORAGE_CONNECTION_STRING="<MY_CONNECTION_STRING>"(Opsional) Gunakan perintah
az storage queue listuntuk melihat antrean Storage di akun Anda. Output dari perintah ini harus mencakup antrian bernamaoutqueue, yang dibuat ketika fungsi menulis pesan pertamanya pada antrean tersebut.az storage queue list --output tsvGunakan perintah
az storage message getuntuk membaca pesan dari antrean ini, yang seharusnya menjadi nilai yang Anda sediakan saat menguji fungsi sebelumnya. Perintah membaca dan menghapus pesan pertama dari antrean.echo `echo $(az storage message get --queue-name outqueue -o tsv --query '[].{Message:content}') | base64 --decode`Karena isi pesan disimpan dikodekan base64, pesan harus dibaca sandi sebelum ditampilkan. Setelah Anda menjalankan
az storage message get, pesan dihapus dari antrean. Jika hanya ada satu pesan dalamoutqueue, Anda tidak akan mengambil pesan saat menjalankan perintah ini untuk kedua kalinya dan sebaliknya mendapatkan kesalahan.
Menyebarkan ulang proyek ke Azure
Setelah Anda memverifikasi secara lokal bahwa fungsi menulis pesan ke antrean Azure Storage, Anda dapat menyebarkan ulang proyek Anda untuk memperbarui titik akhir yang berjalan di Azure.
Di folder LocalFunctionsProj, gunakan perintah func azure functionapp publish untuk menyebarkan ulang proyek, ganti<APP_NAME> dengan nama aplikasi Anda.
func azure functionapp publish <APP_NAME>
Di folder proyek lokal, gunakan perintah Maven berikut ini untuk menerbitkan ulang proyek Anda:
mvn azure-functions:deploy
Memverifikasi di Azure
Seperti pada mulai cepat sebelumnya, gunakan browser atau CURL untuk menguji fungsi yang telah disebarkan ulang.
Periksa lagi antrean Storage, seperti yang dijelaskan di bagian sebelumnya, untuk memverifikasi bahwa itu berisi pesan baru yang ditulis ke antrean.
Membersihkan sumber daya
Setelah selesai, gunakan perintah berikut untuk menghapus grup sumber daya dan semua sumber daya yang terkandung untuk menghindari timbulnya biaya lebih lanjut.
az group delete --name AzureFunctionsQuickstart-rg
Langkah berikutnya
Anda telah memperbarui fungsi pemicu HTTP Anda untuk menulis data ke antrean Storage. Sekarang Anda dapat mempelajari selengkapnya tentang mengembangkan Functions dari baris perintah menggunakan Core Tools dan Azure CLI: