函数计算新功能-----支持C#函数

本文涉及的产品
对象存储 OSS,OSS 加速器 50 GB 1个月
简介: 前言函数计算作为新兴的事件驱动serverless平台正受到越来越多开发者的欢迎,之前已支持Java, Python, Nodejs, Php四种语言。现在函数计算正式支持C#。由于其和Java类似的功能以及和Windows的紧密集成,.Net在中小企业中非常普及,许多中小企业的内部应用都是基于.Net开发。

前言

函数计算作为新兴的事件驱动serverless平台正受到越来越多开发者的欢迎,之前已支持Java, Python, Nodejs, Php四种语言。现在函数计算正式支持C#。由于其和Java类似的功能以及和Windows的紧密集成,.Net在中小企业中非常普及,许多中小企业的内部应用都是基于.Net开发。是时候让这些传统应用拥抱新兴的serverless平台了。.Net平台中目前得到最多关注的便是.Net Core,它是目前微软主推的真正的跨平台语言。自.Net core 2.1之后,现有的.Net程序可以非常方便的移植。目前函数计算支持的.Net版本便是.Net Core 2.1。

功能介绍

在函数计算中运行.net程序分为两种模式,一种是以Library形式运行用户提供的函数--我们称之为Normal Invoke,主要面向计算场景,可以对接除http trigger以外的其他trigger;另一种是以Web App形式运行用户提供的Asp.Net Core Web App(包括Web Api或者MVC Web App/Razer Web App),主要面向Web服务场景,需要对接Http trigger,我们称之为Http Invoke。下面分别介绍如何开发这两种场景的函数计算代码。

Normal Invoke开发

在函数计算中开发Normal Invoke非常简单,它包括一个Handler函数和一个可选的Init函数,我们支持static函数或者instance函数,以下只显示instance函数的签名。

Handler API 签名

OutputType func(InputType input) // 此处InputType和OutputType可以为Stream或者任何可序列化的对象。
OutputType func(InputType, IFcContext context) // 增加了IFcContext参数,可以获得函数计算相关信息(比如用来访问阿里云的临时AK等)
async Task<OutputType> func(InputType input)   // 当然,目前流行的Async style函数我们也一样支持,此处返回值也可以是async Task,下面也一样,省去不表。
async Task<OutputType> func(InputType input, IFcContext context)

从上面的签名可以看出,我们对于用户代码的限制是非常少的。如果不需要用到context的话完全不需要依赖任何函数计算的SDK,几乎就是free style编程。当然我们还是推荐用户采用带IFcContext的函数签名,除了能方便安全的访问阿里云资源之外,它自带的RequestId以及Logger对象等都是开发者诊断调试的好伙伴,下面是IFcContext定义,起内容和其他语言类似。

 public interface IFcContext
 {
        string RequestId { get; }

        IFunctionParameter FunctionParam {get;}

        IFcLogger Logger { get; }

        ICredentials Credentials {get;}

        string AccountId { get; }

        string Region { get; }

        IServiceMeta ServiceMeta { get; }
 }

在工程中添加Aliyun.Serverless.Core包即可使用该接口。

初始化 API

初始化API用来完成一些全局的初始化工作---也就是说该API只在容器服务的第一个请求时才被调用。

void Init(IFcContext context) //初始化函数不能有返回值,因为无法返回给用户。如果有返回值,那它也会被忽略

注意事项

  • 我们期望用户编写的函数是stateless的,基于这个前提和效率方面的考虑,Handler以及Init函数所在的对象在不同的请求之间是有可能被重用的。所以说如果Handler或者Init有改变对象成员变量的行为,则该函数运行时的结果可能受到上一次调用的影响。
  • 关于InputType以及OutputType,我们支持任何能被NewtonSoft.Json序列化的对象。如果该对象无法被NewtonSoft.Json序列化,则用户需要在类的定义上指定FcASerializes属性,以指定自定义的序列化方法,该自定义序列化实现需要随用户代码一起上传。
  • 初始化API和Handler API必须是public.

Http Invoke 开发

是的,用户可以在函数计算运行Asp.Net Core程序。将原有的Asp.Net Core程序改造成能被函数计算执行的代码也是非常简单的,在Nuget添加Aliyun.Serverless.Core.Http之后,只需要少量代码便可以移植到函数计算。

最简单的例子

假如下面是原来的Main函数---通过向导产生的代码

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

只需要在所在工程加入如下代码即可:

using System;
using Aliyun.Serverless.Core.Http;
using Microsoft.AspNetCore.Hosting;
namespace YourNameSpace
{
    public class FcRemoteEntrypoint : FcHttpEntrypoint
    {
        protected override void Init(IWebHostBuilder builder)
        {
            builder.UseStartup<Startup>();
        }
    }
}

移植一个简单的WebApp就这么简单。
稍微复杂点的例子,假如我们需要在Main函数里做一些初始化工作,如下代码所示:

public class Program
{
    public static void Main(string[] args)
    {
        Init1();
        IWebHost host = CreateWebHostBuilder(args).Build();
        Init2(host);
        host.Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

此时FcRemoteEntryPoint则应该和Main一样,有Init1()以及Init2()的调用,如下:

using System;
using Aliyun.Serverless.Core.Http;
using Microsoft.AspNetCore.Hosting;
namespace YourNameSpace
{
    public class FcRemoteEntrypoint : FcHttpEntrypoint
    {
        protected override void Init(IWebHostBuilder builder)
        {
            Init1()
            builder.UseStartup<Startup>();
        }

        protected override void PostInit(IWebHost host)
        {
            Init2(host);
        }
    }
}

FcHttpEntrypoint剖析

这里FcHttpEntrypoint是FC提供在Aliyun.Serverless.Core.Http包里的基类,它起到两个作用:1) 调用用户的Asp.Net core初始化代码,作用类似于本地运行的Main函数。2)包含运行用户代码的入口函数,用来从函数计算执行引擎获得请求并传递给用户代码,代码执行完成后将用户响应返回给函数计算执行引擎。最简单的情形下用户只需要实现Init函数即可。下面详细介绍如何重载FcHttpEntrypoint中提供的方法来实现更为复杂的功能。

PostInit

如果需要对这个IWebHost对象在Init()之后、Start()之前做一些初始化操作(比如用DependencyInjection获得一些内部的Service做初始化),那应该重载PostInit函数。

protected virtual void PostInit(IWebHost host) { }

PostMarshallRequestFeature

如果需要对请求做一些额外的处理,可以在PostMarshallRequestFeature中进行

protected virtual void PostMarshallRequestFeature(IHttpRequestFeature aspNetCoreRequestFeature, HttpRequest request, IFcContext fcContext)

PostMarshallResponseFeature

如果需要对响应做一些额外的处理,可以在PostMarshallResponseFeature中进行

protected virtual void PostMarshallResponseFeature(IHttpResponseFeature aspNetCoreResponseFeature, HttpResponse response, IFcContext fcContext)

HandleRequest

HandleRequest是函数计算请求的入口函数,它将请求Mashall成Asp.net core的请求之后传给用户代码进行处理,再将用户代码返回的响应Marshall成函数计算响应返回给用户。在大部分情况下用户不需要重载这一函数。目前唯一需要重载的情况是如果用户设置自定义域名时还包括一个虚拟目录前缀(比如 http://abc.com/a/),由于函数计算的代码无法区分一个URL中哪个部分是虚拟目录,需要用户将request中的Path分成PathBase以及Path两部分,下面是示例代码

public override async Task<HttpResponse> HandleRequest(HttpRequest request, HttpResponse response, IFcContext fcContext)
{
    AdjustRequestPath(request); // set request.Path and request.PathBase correctly. User needs to implement it according to the virtual directory.
    return base.HandleRequest(request, response, fcContext);
}

注意事项

  • 在函数计算中,任何文件的写操作均应该指向NAS盘,本地文件由于各个container之间无法共享,因此无法保存程序的状态。
  • 如果Web工程依赖操作系统相关的native组件,用dotnet publish命令生成的publish文件夹下会产生runtimes目录。而FC默认的bin目录是代码所在目录或者代码所在目录的lib目录,因此需要手工将目录linux-x64/native下的.so文件复制到publish目录(或者publish/lib目录),然后再打包。
  • 目前函数计算要求Web App有自己的自定义域名,否则返回的内容将以附件形式返回,不方便调试。一个绕过的办法是用Chrome一个叫Undisposition的插件自动删除Content-Disposition:Attachment。

开发体验

下面以Normal Invoke为例开发一个简单OSS Event Handler。

创建空白工程

mkdir FcExample
cd FcExample
dotnet new console
或者
dotnet new classlib

添加FC类库引用

编辑FcExample.csproj,添加如下代码

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <AssemblyName>FcExample</AssemblyName>
  </PropertyGroup>
<ItemGroup>
    <PackageReference Include="Aliyun.Serverless.Core" Version="1.0.1" />
    <PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.9.1" />
    <PackageReference Include="Aliyun.Serverless.Core.Mock" Version="1.0.1" />
</ItemGroup>
</Project>

编写函数

编辑Program.cs,添加如下代码

using System;
using System.IO;
using Aliyun.OSS;
using Aliyun.Serverless.Core;
using Aliyun.Serverless.Core.Mock;
using Microsoft.Extensions.Logging;
namespace FcExample 
{
    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("req");
            }
            if (context == null || context.Credentials == null)
            {
                throw new ArgumentNullException("context");
            }

            context.Logger.LogInformation("GetOssFile started. {0}", context.Credentials.AccessKeyId);
            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;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string bucket = "<bucket name>";
            string key = "<key>";
            string id = "<id>";
            string secret = "<key>";
            string endpoint = "<oss endpoint>"; // http://oss-cn-hangzhou.aliyuncs.com
            string accountId = "FakeAccountId";
            string reqId = "RequestId123#" + DateTime.UtcNow;

            OSSFileHandler handler = new OSSFileHandler();
            FcContext context = new FcContext(accountId, reqId);
            Credentials credentials = new Credentials();
            credentials.AccessKeyId = id;
            credentials.AccessKeySecret = secret;
            context.Credentials = credentials;
            Stream stream = handler.GetOssFile(new OssFileHandlerRequest() { Bucket = bucket, Key=key, Endpoint= endpoint}, context);
            // verify stream
            stream.Close();
        }
    }

}

注意事项

  • 入口函数不能被overload--也就是说不允许在类中包含其他同名的函数。
  • 一般推荐本地测试函数在另一个工程中,在产品代码中不需要引用Aliyun.Serverless.Core.Mock,以减小代码包体积。
  • Http Invoke的函数是不能当做Normal Invoke来调用的,反之也亦然。

测试函数

在Main()中输入测试账号以及bucket、key信息,加入适当的检查stream的逻辑后,运行 dotnet run 即可测试

打包

运行dotnet publish -c Release,然后cd bin/Release/netcoreapp2.1/publish,最后zip code.zip *

注意事项

打包时确保所有依赖的dll文件在zip文件的根目录或者名为lib的子目录中,否则该依赖文件可能无法被加载

发布函数

去函数计算控制台创建一个dotnetcore2.1函数,上传code.zip,并指定函数Handler为FcExample::FcExample.OSSFileHandler::GetOssFile

小结

本文简单介绍了如何编写能运行在函数计算中的C#函数,包括normal invoke和Http invoke。如果有任何疑问和建议,欢迎留言。

相关实践学习
函数计算部署PuLID for FLUX人像写真实现智能换颜效果
只需一张图片,生成程序员专属写真!本次实验在函数计算中内置PuLID for FLUX,您可以通过函数计算+Serverless应用中心一键部署Flux模型,快速体验超写实图像生成的魅力。
从 0 入门函数计算
在函数计算的架构中,开发者只需要编写业务代码,并监控业务运行情况就可以了。这将开发者从繁重的运维工作中解放出来,将精力投入到更有意义的开发任务上。
目录
相关文章
|
Shell
Ubuntu20.04安装anaconda并默认激活conda base环境(步骤详细/操作简单实用)
Ubuntu20.04安装anaconda并默认激活conda base环境方法
21554 0
|
安全 Cloud Native Java
【云原生】五年博主教你用阿里云Serverless免费额度搞事情。
传统模式如果个人up主想要搞事情, 就要有一台服务器, 为了省钱可能你还会自己搭建一个数据库。其次你的流量还是需要付费的,如果个人用用还好,但是如果要被人攻击了。那流量蹭蹭的涨, 个人是完全受不了的。这点我是比较有发言权的。因为小编我目前就有一台阿里云实例。目前部署了mysql使用宝塔来维护。每次发布自己上传jar包。下面这个截图就是我的服务, 至于地址嘛,我就不给你们看了。(我怕你们偷我的流量),毕竟前有b站主播鱼皮,网站被攻击的先例,所以咱就低调点,自己用。
2047 0
【云原生】五年博主教你用阿里云Serverless免费额度搞事情。
|
12月前
|
数据采集 算法 数据挖掘
CLIMB自举框架:基于语义聚类的迭代数据混合优化及其在LLM预训练中的应用
英伟达提出的CLIMB框架,是一种自动化优化大型语言模型(LLM)预训练数据混合的创新方法。通过语义嵌入与聚类技术,CLIMB能系统地发现、评估并优化数据混合策略,无需人工干预。该框架包含数据预处理、迭代自举及最优权重确定三大阶段,结合小型代理模型与性能预测器,高效搜索最佳数据比例。实验表明,基于CLIMB优化的数据混合训练的模型,在多项推理任务中显著超越现有方法,展现出卓越性能。此外,研究还构建了高质量的ClimbMix数据集,进一步验证了框架的有效性。
571 0
CLIMB自举框架:基于语义聚类的迭代数据混合优化及其在LLM预训练中的应用
|
12月前
|
存储 人工智能 数据库
Cloudflare推出托管式RAG服务!AutoRAG:从数据上传到索引更新全程托管,文档变动自动同步
AutoRAG是Cloudflare推出的全托管检索增强生成服务,基于自动索引和向量化技术,帮助开发者快速构建上下文感知的AI应用,无需管理底层基础设施。
396 0
Cloudflare推出托管式RAG服务!AutoRAG:从数据上传到索引更新全程托管,文档变动自动同步
|
人工智能 自然语言处理 API
Proxy Lite:仅3B参数的开源视觉模型!快速实现网页自动化,支持在消费级GPU上运行
Proxy Lite 是一款开源的轻量级视觉语言模型,支持自动化网页任务,能够像人类一样操作浏览器,完成网页交互、数据抓取、表单填写等重复性工作,显著降低自动化成本。
944 11
Proxy Lite:仅3B参数的开源视觉模型!快速实现网页自动化,支持在消费级GPU上运行
|
存储 人工智能 边缘计算
AI时代下, 边缘云上的技术演进与场景创新
本文介绍了AI时代下边缘云的技术演进与场景创新。主要内容分为三部分:一是边缘云算力形态的多元化演进,强调阿里云边缘节点服务(ENS)在全球600多个节点的部署,提供低时延、本地化和小型化的价值;二是边缘AI推理的创新发展与实践,涵盖低时延、资源广分布、本地化及弹性需求等优势;三是云游戏在边缘承载的技术演进,探讨云游戏对边缘计算的依赖及其技术方案,如多开技术、云存储和网络架构优化,以提升用户体验并降低成本。文章展示了边缘云在未来智能化、实时化解决方案中的重要性。
672 3
|
机器学习/深度学习 算法 vr&ar
《探索图像处理的无限可能:从技术突破到未来应用》
在数字化时代,图像处理技术已成为关键领域,深刻影响着各行各业。从深度学习的融合到图像增强与修复,再到移动设备的实时处理及医疗应用,图像处理不仅提升了图像质量和安全性,还推动了AR、VR等技术的发展。面对挑战,未来图像处理将在智能安防、交通等领域展现更大潜力,继续引领科技创新与变革。
289 3
|
机器学习/深度学习 人工智能 算法
【AI系统】AI系统概述与设计目标
本文介绍了AI系统的全栈架构,涵盖设计目标、组成和生态。AI系统旨在连接硬件与应用,提供高效的模型服务和开发支持。文中探讨了高效编程语言、开发框架、工具链的重要性,以及AI任务系统级支持、自动编译优化和云原生自动分布式化等关键设计目标。此外,还详细讨论了AI训练与推理框架、AI编译与计算架构、AI硬件与体系结构等组成部分,以及AI算法和框架、更广泛的生态系统等。
837 1
|
存储 缓存 Java
java应用提速(速度与激情)
本文将阐述通过基础设施与工具的改进,实现从构建到启动全方面大幅提速的实践和理论。
50331 13
java应用提速(速度与激情)
|
移动开发 小程序 安全
DingTalk「开发者说」— 钉钉数据授权开发实战
随着《中华人民共和国网络安全法》的实施,对个人信息的保护越来越严格,钉钉遵守安全法要求,对钉钉上个人信息的收集、使用、共享有严格的把关。本次分享主要介绍钉钉如何做个人数据把关,以及在个人选择同意原则下,如何对个人数据做授权流转,以及实践演练。 DingTalk「开发者说」是钉钉开发者最新上线的开发者栏目,联合阿里云ACE团队,分享钉应用开发解决方案、技术更新、实战技巧,致力于成为钉钉与开发者的桥梁与纽带,让更多的钉钉开发者传播技术、提升技能、分享观点。在数字化变革的时代,“云钉一体”“钉钉全面开放”战略之后,希望钉钉技术可以持续激发开发者的创造力,为组织数字化赋能。
2798 4
DingTalk「开发者说」— 钉钉数据授权开发实战