When you use C# for programming in Function Compute, you must define a C# function as a handler. This topic describes the structure and features of C# event functions.

Definition

When you create a C# function, you must specify a handler method, which is executed along with the function. The handler method can be a static method or an instance method. To access the IFcContext object in the handler method, you need to 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 JSON-deserialized object. When void is returned, Async Task changes to async Task. If a Stream object is returned, the Stream content is included in the response body. Otherwise, the returned object is serialized in JSON format and then included in the response body.
  • InputType indicates the input parameter, which can be System.IO.Stream or any JSON-serialized or JSON-deserialized object.
  • IFcContext indicates the context object of the function.
    The context object includes the following information.
    Parameter Type Description
    RequestId String The unique ID of the request for invoking the function. You can record the ID for troubleshooting if an error occurs.
    FunctionParam Class The basic information of the current function, such as the name, handler, memory, and timeout period of the function.
    Credentials Class The temporary AccessKey pair obtained by Function Compute by assuming your service role. The temporary AccessKey pair is updated every 15 minutes. You can also use temporary security credentials to access other Alibaba Cloud services, such as Object Storage Service (OSS). This prevents you from hard coding the AccessKey credentials in the code. For more information, see Permissions.
    ServiceMeta Class The information about the service to which the function belongs, including the service name, the project and Logstore information of Log Service (SLS) to which the service is connected, qualifier, and version_id. The qualifier parameter indicates the service version or alias that is specified when the function is called. The version_id parameter indicates the version of the service that is called.
    Region String The region to which the function applies, such as cn-shanghai. For more information, see Endpoints.
    AccountId String The ID of the Alibaba Cloud account that calls the function. For more information, see Get an account ID.

For more information, see fc-dotnet-libs.

Handler method examples

When you define functions in C# in Function Compute, you need to add the Aliyun.Serverless.Core package by using Nuget.

  • Stream handler
    The following method returns the input in your request as it is:
    using System.IO;
    using System.Threading.Tasks;
    using Aliyun.Serverless.Core;
    using Microsoft.Extensions.Logging;
    
    namespace FC.Examples
    {
        public class TestHandler
        {
            public async Task<Stream> Echo(Stream input, IFcContext context)
            {
                ILogger 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;
            }
        }
    }
  • POCP handler
    In addition to Stream objects, plain old CLR objects (POCOs) can be used as input and output parameters. If a POCO does not specify a JSON serializer object, Function Compute uses JSON.NET to serialize and deserialize objects in the JSON format by default.
    using Microsoft.Extensions.Logging;
    
    namespace FC.Examples
    {
        public class TestHandler
        {
            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 Echo(Product product, IFcContext context)
            {
                string Id = product.Id;
                string Description = product.Description;
                context.Logger.LogInformation("Id {0}, Description {1}", Id, Description);
                return product;
            }
        }
    }       

Handler specification

When you create a function, you must specify a handler method in the string format to tell Function Compute how to find the target method. The string format is AssemblyFileName::FullClassName::METHOD. The following table describes the parameters.

Parameter Description
AssemblyFileName The name of the file where the function is located.
FullClassName The full name of the class to which the function belongs.
Method The name of the method.

In the preceding handler example, if the Assembly file name is test_assembly, the handler string is test_assembly::FC.Examples.TestHandler::Echo.

Limits

  • The handler parameter format must conform to the preceding definition. The AssemblyFileName parameter is required. The FullClassName parameter is optional and must be the IFcContext object.
  • The handler function does not support generic methods.
  • The input and output parameters must be Stream objects or of a class that can be serialized in the JSON format.
  • The Async function returns Task, in which T must be a Stream object or of a class that can be serialized in the JSON format.

Custom serializers

For POCO handlers, Function Compute provides the default JSON.NET serializer. If the default serializer does not meet your requirements, you can implement a custom serializer by calling the IFcSerializer interface in Aliyun.Serverless.Core.

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

Complete example of event functions

The following C# code shows how to use temporary keys to retrieve a specified object from an OSS bucket.

  1. Create a .NET Core console project.
        [songluo@~/tmp]# mkdir fcdotnetsample
        [songluo@~/tmp]# cd fcdotnetsample
        [songluo@~/tmp/fcdotnetsample]# dotnet new console          
  2. Add the following packages to fcdotnetsample.csproj.
    <ItemGroup>
            <PackageReference Include="Aliyun.Serverless.Core" Version="1.0.1" />
            <PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.9.1" />
    </ItemGroup>    
  3. Edit Program.cs.
        using System;
        using System.IO;
        using Aliyun.OSS;
        using Aliyun.Serverless.Core;
    
        namespace fcdotnetsample
        {
             class Program
            {
                static void Main(string[] args)
                {
                    Console.WriteLine("Hello World!") ;
                }
            }
    
            public class OssFileHandlerRequest
            {
                public string Bucket;
                public string Key;
                public string Endpoint;
            }
    
            public class OSSFileHandler
            {
                public Stream GetOssFile(OssFileHandlerRequest req, IFcContext context)
                {
                    if (req == null)
                    {
                        throw new ArgumentNullException(nameof(req));
                    }
                    if (context == null || context.Credentials == null)
                    {
                        throw new ArgumentNullException(nameof(context));
                    }
                    OssClient ossClient = new OssClient(req.Endpoint, context.Credentials.AccessKeyId, context.Credentials.AccessKeySecret, context.Credentials.SecurityToken);
                    OssObject obj = ossClient.GetObject(req.Bucket, req.Key);
                    return obj.Content;
                }
            }
        }        
  4. Upload the project and compress the target files into a .zip package.
        [songluo@~/tmp/fcdotnetsample]# dotnet publish -c Release
        Microsoft (R) Build Engine version 15.9.20+g88f5fadfbe for .NET Core
        Copyright (C) Microsoft Corporation. All rights reserved.
    
     Restore completed in 47.9 ms for /Users/songluo/tmp/fcdotnetsample/fcdotnetsample.csproj.
     fcdotnetsample -> /Users/songluo/tmp/fcdotnetsample/bin/Release/netcoreapp2.1/fcdotnetsample.dll
     fcdotnetsample -> /Users/songluo/tmp/fcdotnetsample/bin/Release/netcoreapp2.1/publish/
        [songluo@~/tmp/fcdotnetsample]# cd /Users/songluo/tmp/fcdotnetsample/bin/Release/netcoreapp2.1/publish/
        [songluo@~/tmp/fcdotnetsample/bin/Release/netcoreapp2.1/publish]# zip -r fcdotnetsample.zip *
     adding: Aliyun.OSS.Core.dll (deflated 60%)
     adding: Aliyun.Serverless.Core.dll (deflated 59%)
     adding: Microsoft.Extensions.Logging.Abstractions.dll (deflated 53%)
     adding: fcdotnetsample.deps.json (deflated 73%)
     adding: fcdotnetsample.dll (deflated 57%)
     adding: fcdotnetsample.pdb (deflated 27%)
     adding: fcdotnetsample.runtimeconfig.json (deflated 23%)
        [songluo@~/tmp/fcdotnetsample/bin/Release/netcoreapp2.1/publish]# ls -ll fcdotnetsample.zip
        -rw-r--r--  1 songluo  staff  130276 Mar 14 17:48 fcdotnetsample.zip
  5. Use fcdotnetsample.zip to create a function with the .NET Core 2.1 runtime and the fcdotnetsample::fcdotnetsample.OSSFileHandler::GetOssFile handler.