This topic describes the structure and characteristics of event handlers in C#.

Handler interface

When you create a C# function, you must specify a handler method, which is executed along with the function. This Handler method can be either a static method or an instance method. To access the IFcContext object in the handler method, you must set the second parameter in this method to IFcContext. The following examples show handler methods supported by Function Compute.

ReturnType HandlerName(InputType input, IFcContext context);  //IFcContext included 
ReturnType HandlerName(InputType input); //IFcContext not included 
Async Task<ReturnType> HandlerName(InputType input, IFcContext context);
Async Task<ReturnType> HandlerName(InputType input);
Function Compute supports the use of Async in functions defined in C#, where the function is executed after the asynchronous method is executed. In the preceding definition:
  • ReturnType is the returned object, which can be void, a System.IO.Stream, or any JSON-serialized or deserialized object. 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 JSON format.
  • InputType indicates the input parameter, which can be System.IO.Stream or any JSON-serialized or deserialized object.
  • IFcContext indicates the context object of the function. For more information, see Context.

Event handlers

Function Compute use C# to write functions. The Aliyun.Serverless.Core dependency package must be introduced. You can introduce this package in 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 event handlers.

  • Stream Handler

    Uses streams to receive the input event data and returns the execution result. You must read the input data from input streams and then write the execution result to output streams.

  • POCO Handler

    Allows you to customize the inputs and outputs in plain old class object (POCO) types.

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){}
    }
}
In the preceding sample code:
  • Namespaces and classes

    The namespace is Example, the class name is Hello, and the method name is StreamHandler. If the assembly name is HelloFcApp, the configuration of the handler is HelloFcApp::Example.Hello::StreamHandler.

  • Stream input parameter

    The input to the handler. The input type for this example is Stream.

  • (Optional) IFcContext context parameter

    A context object that contains information about the function and the request.

  • 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, POCOs can also be used as input and output parameters. If the POCO does not specify a specific JSON-serialized object, Function Compute uses JSON.Net to perform JSON serialization and deserialization on the object. In the preceding sample code:
  • Namespaces and classes

    The namespace is Example, the class name is Hello, and the method name is PocoHandler. If the assembly name is HelloFcApp, the configuration of the handler is HelloFcApp::Example.Hello::PocoHandler.

  • Product product parameter

    The input to the handler. The input type for this example is Product Class. If the POCO does not specify a specific JSON-serialized object, Function Compute uses JSON.Net to deserialize the object.

  • (Optional) IFcContext context parameter

    A context object that contains information about the function and the request.

  • Product response

    The return value is of the POCO Product type. If the POCO does not specify a specific JSON serialization object, Function Compute uses JSON.Net to serialize the object.

Custom serializer

By default, Function Compute provides serialization interfaces that are based on JSON .NET. If the default serialization interface cannot meet your business requirements, you can implement custom serialization interfaces based on the interface IFcSerializer in Aliyun.Serverless.Core.

public interface IFcSerializer
{
    T Deserialize<T>(Stream requestStream);
    void Serialize<T>(T response, Stream responseStream);
}      

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.