You can use C# handlers to respond to received events and execute the corresponding business logic. This topic describes the concepts and features of C# handlers and provides examples.
If you want to use HTTP triggers or custom domain names to access functions, obtain request struct before you define HTTP responses. For more information, see Use an HTTP trigger to invoke a function.
What is a handler?
A handler for a function in Function Compute is the method that is used to process requests in function code. When the function is invoked, Function Compute uses the handler that you configure to process requests.
You can configure a handler for a function when you create or update the function in the Function Compute console. For more information, see Create an event function.
Handlers of C# functions in Function Compute follow the Assembly::Namespace.ClassName::MethodName
format.
Parameter | Description |
Assembly | The name of the created assembly. |
Namespace | The name of the namespace. |
ClassName | The name of the class. |
MethodName | The name of the method. |
For example, if the name of the assembly is HelloFcApp
, the handler is HelloFcApp::Example.HelloFC::StreamHandler
. Sample code:
using System.IO;
namespace Example
{
public class HelloFC
{
public async Task<Stream> StreamHandler(Stream input)
{
//function logic
}
}
}
Configurations of handlers must conform to the configuration specifications of Function Compute. The configuration specifications vary based on the handler type.
Handler interface
When you create a C# function, you must specify a handler method, which is executed when the function is invoked. This handler method can be either a static method or an instance method. If you want to access an IFcContext
object in the handler method, you must specify the second parameter in the method as the IFcContext
object. The following code snippet shows the definition of the handler method that is supported by event functions.
ReturnType HandlerName(InputType input, IFcContext context); //IFcContext contained
ReturnType HandlerName(InputType input); //IFcContext not contained
Async Task<ReturnType> HandlerName(InputType input, IFcContext context);
Async Task<ReturnType> HandlerName(InputType input);
Function Compute supports Async in C# functions. If Async is used, the execution of functions waits for the execution of asynchronous methods to complete. Parameter description
ReturnType: the type of the returned object. The returned object can be a
void
orSystem.IO.Stream
object, or any object that can be serialized and deserialized in JSON. If a Stream object is returned, the content of the Stream object is directly returned in the response body. Otherwise, the object is returned in the response body after being serialized in the JSON format.InputType: the type of the input parameter, which can be a System.IO.Stream object or an object that can be JSON serialized or deserialized.
IFcContext: the context object of the function. For more information, see Context.
Event handlers
Function Compute writes functions in C#. The Aliyun.Serverless.Core
dependency package is required. You can introduce the dependency package to the .csproj file by using the following method:
<ItemGroup>
<PackageReference Include="Aliyun.Serverless.Core" Version="1.0.1" />
</ItemGroup>
The Aliyun.Serverless.Core
package defines two parameter types for an event handler:
Stream Handler
Uses streams to receive the input
event
data and returns the execution results. You must read the input data from the input streams and then write the execution results to output streams.POCO Handler
Allows you to customize the input and output data in plain old class objects (POCO).
Stream Handler
The following example provides the sample code of a simple stream handler:
using System.IO;
using System.Threading.Tasks;
using Aliyun.Serverless.Core;
using Microsoft.Extensions.Logging;
namespace Example
{
public class Hello
{
public async Task<Stream> StreamHandler(Stream input, IFcContext context)
{
IFcLogger logger = context.Logger;
logger.LogInformation("Handle request: {0}", context.RequestId);
MemoryStream copy = new MemoryStream();
await input.CopyToAsync(copy);
copy.Seek(0, SeekOrigin.Begin);
return copy;
}
static void Main(string[] args){}
}
}
Description:
Namespaces and classes
In the preceding sample code, the namespace is
Example
, the class name isHello
, and the method name isStreamHandler
. If the assembly name isHelloFcApp
, the configuration of the handler isHelloFcApp::Example.Hello::StreamHandler
.Stream input parameter
The input of the handler. The input type for this example is Stream.
(Optional) IFcContext context parameter
A context object that contains information about the function and requests.
Task<Stream> response
The return value, which is of the Stream type.
POCO Handler
The following example provides the sample code of a simple POCO handler:
using Aliyun.Serverless.Core;
using Microsoft.Extensions.Logging;
namespace Example
{
public class Hello
{
public class Product
{
public string Id { get; set; }
public string Description { get; set; }
}
// Optional serializer class. If it is not specified, the default serializer (based on JSON.Net) will be used.
// [FcSerializer(typeof(MySerialization))]
public Product PocoHandler(Product product, IFcContext context)
{
string Id = product.Id;
string Description = product.Description;
context.Logger.LogInformation("Id {0}, Description {1}", Id, Description);
return product;
}
static void Main(string[] args){}
}
}
In addition to Stream objects, POCO can also be used as input and output parameters. If the POCO does not specify a specific JSON serialization object, Function Compute uses JSON.Net to perform JSON serialization and deserialization of the object. Description:
Namespaces and classes
In the preceding sample code, the namespace is
Example
, the class name isHello
, and the method name isPocoHandler
. If the assembly name isHelloFcApp
, the configuration of the handler isHelloFcApp::Example.Hello::PocoHandler
.Product product
parameterThe input of the handler. The input type for this example is
Product Class
. If POCO does not specify a specific JSON serialization object, Function Compute uses JSON.Net to perform JSON deserialization of the object.(Optional) IFcContext context parameter
A context object that contains information about the function and requests.
Product
responseThe return value is of the
POCO Product
type. If POCO does not specify a specific JSON serialization object, Function Compute uses JSON.Net to perform JSON serialization of the object.
Custom serializers
By default, Function Compute provides serializers that are based on Json.NET. If the default serializers cannot meet your business requirements, you can implement a custom serializer based on IFcSerializer
in Aliyun.Serverless.Core
.
public interface IFcSerializer
{
T Deserialize<T>(Stream requestStream);
void Serialize<T>(T response, Stream responseStream);
}
Use an HTTP trigger to invoke a function
Sample code
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
using Aliyun.Serverless.Core;
using Microsoft.Extensions.Logging;
namespace Example
{
public class Hello
{
public class HTTPTriggerEvent
{
public string Version { get; set; }
public string RawPath { get; set; }
public string Body { get; set; }
public bool IsBase64Encoded { get; set; }
public RequestContext RequestContext { get; set; }
public Dictionary<string, string> Headers { get; set; }
public Dictionary<string, string> QueryParameters { get; set; }
public override string ToString()
{
return JsonSerializer.Serialize(this);
}
}
public class RequestContext
{
public string AccountId { get; set; }
public string DomainName { get; set; }
public string DomainPrefix { get; set; }
public string RequestId { get; set; }
public string Time { get; set; }
public string TimeEpoch { get; set; }
public Dictionary<string, string> Http { get; set; }
}
public class HTTPTriggerResponse
{
public int StatusCode { get; set; }
public Dictionary<string, string> Headers { get; set; }
public bool IsBase64Encoded { get; set; }
public string Body { get; set; }
}
public HTTPTriggerResponse PocoHandler(HTTPTriggerEvent input, IFcContext context)
{
context.Logger.LogInformation("receive event: {0}", input.ToString());
string requestBody = input.Body;
if (input.IsBase64Encoded)
{
byte[] decodedBytes = Convert.FromBase64String(input.Body);
requestBody = Encoding.UTF8.GetString(decodedBytes);
}
return new HTTPTriggerResponse
{
StatusCode = 200,
IsBase64Encoded = false,
Body = requestBody
};
}
static void Main(string[] args){}
}
}
Before you start
You have used the preceding example to create a function in the C# runtime. For more information, see Create an event function and Configure an HTTP trigger that invokes a function with HTTP requests.
Procedure
Log on to the Function Compute console. In the left-side navigation pane, click Functions.
In the top navigation bar, select a region. On the Functions page, click the function that you want to manage.
On the function details page, click the Triggers tab to obtain the public endpoint of the HTTP trigger.
Run the following command in curl to invoke the function:
curl -i "https://test-python-ipgrwr****.cn-shanghai.fcapp.run" -d 'Hello fc3.0'
In the preceding command,
https://test-python-ipgrwr****.cn-shanghai.fcapp.run
is the obtained public endpoint of the HTTP trigger.ImportantIf the Authentication Method parameter of the HTTP trigger is set to No Authentication, you can use Postman or curl to invoke the function. For more information, see Procedure.
If the Authentication Method parameter of the HTTP trigger is set to Signature Authentication or JWT Authentication, you can use the signature method or JWT authentication method to invoke the function. For more information, see Authentication.
The following result is returned:
HTTP/1.1 200 OK Content-Disposition: attachment Content-Length: 12 Content-Type: application/json X-Fc-Request-Id: 1-64f7449a-127fbe39cd7681596e33ebad Date: Tue, 05 Sep 2023 15:09:14 GMT Hello fc3.0
Possible errors
This sample code can be called by using an HTTP trigger or a custom domain name. If you use an API operation but the configured test parameters do not comply with the request format requirements of HTTP triggers, an error is reported.
For example, the following response is returned if you invoke the function by clicking Test Function in the Function Compute console after you configure the request parameters as "Hello, FC!"
.
{
"errorMessage": "Unexpected character encountered while parsing value: H. Path '', line 0, position 0.",
"errorType": "Newtonsoft.Json.JsonReaderException",
"stackTrace": [
" at Newtonsoft.Json.JsonTextReader.ParseValue()",
" at Newtonsoft.Json.JsonReader.ReadAndMoveToContent()",
" at Newtonsoft.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter)",
" at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)",
" at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)",
" at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)",
" at Newtonsoft.Json.JsonSerializer.Deserialize[T](JsonReader reader)",
" at Aliyun.Serverless.Core.JsonSerializer.Deserialize[T](Stream requestStream) in /dotnetcore/Libraries/src/Aliyun.Serverless.Core.Impl/JsonSerializer.cs:line 95"
]
}
Sample programs
Function Compute official libraries contain sample programs that use various handler types and interfaces. Each sample program contains methods for easy compilation and deployment.
dotnet3-blank-stream-event: uses the event callbacks in the stream format.
dotnet3-blank-poco-event: uses the event callbacks in the POCO format.