Referencia de punto de conexión RESTful de C# del proveedor de recursos personalizado
Este artículo consiste en una referencia básica de un punto de conexión ReSTful de C# del proveedor de recursos personalizado. Si no está familiarizado con los proveedores de recursos personalizados de Azure, consulte la introducción a los proveedores de recursos personalizados.
Punto de conexión RESTful de Azure Functions
El código siguiente funciona con una aplicación de funciones de Azure. Para obtener información sobre cómo configurar una aplicación de funciones para que funcione con proveedores de recursos personalizados de Azure, consulte el tutorial sobre la configuración de Azure Functions para los proveedores de recursos personalizados de Azure.
#r "Newtonsoft.Json"
#r "Microsoft.WindowsAzure.Storage"
#r "../bin/Microsoft.Azure.Management.ResourceManager.Fluent"
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Configuration;
using System.Text;
using System.Threading;
using System.Globalization;
using System.Collections.Generic;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.WindowsAzure.Storage.Table;
using Microsoft.Azure.Management.ResourceManager.Fluent.Core;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
// Custom Resource Table Entity
public class CustomResource : TableEntity
{
public string Data { get; set; }
}
/// <summary>
/// Entry point for the Azure Function webhook that acts as the service behind a custom resource provider.
/// </summary>
/// <param name="requestMessage">The HTTP request message.</param>
/// <param name="log">The logger.</param>
/// <param name="tableStorage">The Azure Table storage account.</param>
/// <returns>The HTTP response for the custom Azure API.</returns>
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, ILogger log, CloudTable tableStorage)
{
// Get the unique Azure request path from request headers.
var requestPath = req.Headers.GetValues("x-ms-customproviders-requestpath").FirstOrDefault();
if (requestPath == null)
{
var missingHeaderResponse = req.CreateResponse(HttpStatusCode.BadRequest);
missingHeaderResponse.Content = new StringContent(
new JObject(new JProperty("error", "missing 'x-ms-customproviders-requestpath' header")).ToString(),
System.Text.Encoding.UTF8,
"application/json");
}
log.LogInformation($"The Custom Resource Provider Function received a request '{req.Method}' for resource '{requestPath}'.");
// Determines if it is a collection level call or action.
var isResourceRequest = requestPath.Split('/').Length % 2 == 1;
var azureResourceId = isResourceRequest ?
ResourceId.FromString(requestPath) :
ResourceId.FromString($"{requestPath}/");
// Create the Partition Key and Row Key
var partitionKey = $"{azureResourceId.SubscriptionId}:{azureResourceId.ResourceGroupName}:{azureResourceId.Parent.Name}";
var rowKey = $"{azureResourceId.FullResourceType.Replace('/', ':')}:{azureResourceId.Name}";
switch (req.Method)
{
// Action request for a custom action.
case HttpMethod m when m == HttpMethod.Post && !isResourceRequest:
return await TriggerCustomAction(
requestMessage: req);
// Enumerate request for all custom resources.
case HttpMethod m when m == HttpMethod.Get && !isResourceRequest:
return await EnumerateAllCustomResources(
requestMessage: req,
tableStorage: tableStorage,
partitionKey: partitionKey,
resourceType: rowKey);
// Retrieve request for a custom resource.
case HttpMethod m when m == HttpMethod.Get && isResourceRequest:
return await RetrieveCustomResource(
requestMessage: req,
tableStorage: tableStorage,
partitionKey: partitionKey,
rowKey: rowKey);
// Create request for a custom resource.
case HttpMethod m when m == HttpMethod.Put && isResourceRequest:
return await CreateCustomResource(
requestMessage: req,
tableStorage: tableStorage,
azureResourceId: azureResourceId,
partitionKey: partitionKey,
rowKey: rowKey);
// Remove request for a custom resource.
case HttpMethod m when m == HttpMethod.Delete && isResourceRequest:
return await RemoveCustomResource(
requestMessage: req,
tableStorage: tableStorage,
partitionKey: partitionKey,
rowKey: rowKey);
// Invalid request received.
default:
return req.CreateResponse(HttpStatusCode.BadRequest);
}
}
/// <summary>
/// Triggers a custom action with some side effects.
/// </summary>
/// <param name="requestMessage">The HTTP request message.</param>
/// <returns>The HTTP response result of the custom action.</returns>
public static async Task<HttpResponseMessage> TriggerCustomAction(HttpRequestMessage requestMessage)
{
var myCustomActionRequest = await requestMessage.Content.ReadAsStringAsync();
var actionResponse = requestMessage.CreateResponse(HttpStatusCode.OK);
actionResponse.Content = myCustomActionRequest != string.Empty ?
new StringContent(JObject.Parse(myCustomActionRequest).ToString(), System.Text.Encoding.UTF8, "application/json") :
null;
return actionResponse;
}
/// <summary>
/// Enumerates all the stored custom resources for a given type.
/// </summary>
/// <param name="requestMessage">The HTTP request message.</param>
/// <param name="tableStorage">The Azure Table storage account.</param>
/// <param name="partitionKey">The partition key for storage. This is the custom resource provider ID.</param>
/// <param name="resourceType">The resource type of the enumeration.</param>
/// <returns>The HTTP response containing a list of resources stored under 'value'.</returns>
public static async Task<HttpResponseMessage> EnumerateAllCustomResources(HttpRequestMessage requestMessage, CloudTable tableStorage, string partitionKey, string resourceType)
{
// Generate upper bound of the query.
var rowKeyUpperBound = new StringBuilder(resourceType);
rowKeyUpperBound[rowKeyUpperBound.Length - 1]++;
// Create the enumeration query.
var enumerationQuery = new TableQuery<CustomResource>().Where(
TableQuery.CombineFilters(
TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey),
TableOperators.And,
TableQuery.CombineFilters(
TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.GreaterThan, resourceType),
TableOperators.And,
TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThan, rowKeyUpperBound.ToString()))));
var customResources = (await tableStorage.ExecuteQuerySegmentedAsync(enumerationQuery, null))
.ToList().Select(customResource => JToken.Parse(customResource.Data));
var enumerationResponse = requestMessage.CreateResponse(HttpStatusCode.OK);
enumerationResponse.Content = new StringContent(new JObject(new JProperty("value", customResources)).ToString(), System.Text.Encoding.UTF8, "application/json");
return enumerationResponse;
}
/// <summary>
/// Retrieves a custom resource.
/// </summary>
/// <param name="requestMessage">The HTTP request message.</param>
/// <param name="tableStorage">The Azure Table storage account.</param>
/// <param name="partitionKey">The partition key for storage. This is the custom resource provider ID.</param>
/// <param name="rowKey">The row key for storage. This is '{resourceType}:{customResourceName}'.</param>
/// <returns>The HTTP response containing the existing custom resource.</returns>
public static async Task<HttpResponseMessage> RetrieveCustomResource(HttpRequestMessage requestMessage, CloudTable tableStorage, string partitionKey, string rowKey)
{
// Attempt to retrieve the Existing Stored Value
var tableQuery = TableOperation.Retrieve<CustomResource>(partitionKey, rowKey);
var existingCustomResource = (CustomResource)(await tableStorage.ExecuteAsync(tableQuery)).Result;
var retrieveResponse = requestMessage.CreateResponse(
existingCustomResource != null ? HttpStatusCode.OK : HttpStatusCode.NotFound);
retrieveResponse.Content = existingCustomResource != null ?
new StringContent(existingCustomResource.Data, System.Text.Encoding.UTF8, "application/json"):
null;
return retrieveResponse;
}
/// <summary>
/// Creates a custom resource and saves it to Table storage.
/// </summary>
/// <param name="requestMessage">The HTTP request message.</param>
/// <param name="tableStorage">The Azure Table storage account.</param>
/// <param name="azureResourceId">The parsed Azure resource ID.</param>
/// <param name="partitionKey">The partition key for storage. This is the custom resource provider ID.</param>
/// <param name="rowKey">The row key for storage. This is '{resourceType}:{customResourceName}'.</param>
/// <returns>The HTTP response containing the created custom resource.</returns>
public static async Task<HttpResponseMessage> CreateCustomResource(HttpRequestMessage requestMessage, CloudTable tableStorage, ResourceId azureResourceId, string partitionKey, string rowKey)
{
// Constructs the new resource from the request body and adds the Azure Resource Manager fields.
var myCustomResource = JObject.Parse(await requestMessage.Content.ReadAsStringAsync());
myCustomResource["name"] = azureResourceId.Name;
myCustomResource["type"] = azureResourceId.FullResourceType;
myCustomResource["id"] = azureResourceId.Id;
// Save the resource into storage.
var insertOperation = TableOperation.InsertOrReplace(
new CustomResource
{
PartitionKey = partitionKey,
RowKey = rowKey,
Data = myCustomResource.ToString(),
});
await tableStorage.ExecuteAsync(insertOperation);
var createResponse = requestMessage.CreateResponse(HttpStatusCode.OK);
createResponse.Content = new StringContent(myCustomResource.ToString(), System.Text.Encoding.UTF8, "application/json");
return createResponse;
}
/// <summary>
/// Removes an existing custom resource.
/// </summary>
/// <param name="requestMessage">The HTTP request message.</param>
/// <param name="tableStorage">The Azure Table storage account.</param>
/// <param name="partitionKey">The partition key for storage. This is the custom resource provider ID.</param>
/// <param name="rowKey">The row key for storage. This is '{resourceType}:{customResourceName}'.</param>
/// <returns>The HTTP response containing the result of the deletion.</returns>
public static async Task<HttpResponseMessage> RemoveCustomResource(HttpRequestMessage requestMessage, CloudTable tableStorage, string partitionKey, string rowKey)
{
// Attempt to retrieve the existing stored value
var tableQuery = TableOperation.Retrieve<CustomResource>(partitionKey, rowKey);
var existingCustomResource = (CustomResource)(await tableStorage.ExecuteAsync(tableQuery)).Result;
if (existingCustomResource != null) {
var deleteOperation = TableOperation.Delete(existingCustomResource);
await tableStorage.ExecuteAsync(deleteOperation);
}
return requestMessage.CreateResponse(
existingCustomResource != null ? HttpStatusCode.OK : HttpStatusCode.NoContent);
}
Pasos siguientes
- Introducción a los proveedores de recursos personalizados de Azure
- Inicio rápido: Creación de un proveedor de recursos personalizados de Azure e implementación de recursos personalizados
- Cómo: Adición de acciones personalizadas a la API REST de Azure
- Referencia: Referencia de caché de recursos personalizados