C# 在本地运行一次计时器触发的Azure函数的最简单方法是什么?

C# 在本地运行一次计时器触发的Azure函数的最简单方法是什么?,c#,azure,timer,azure-functions,C#,Azure,Timer,Azure Functions,我有一些C#Azure函数,它们按照使用的时间表运行。我这样设置它们,其中%TimerSchedule%指的是应用程序设置中的cron表达式: public static void Run([TimerTrigger("%TimerSchedule%")]TimerInfo myTimer, TraceWriter log) 在开发过程中,我经常希望使用Azure functions Tools for Visual Studio+Azure functions核心工具在本地运行函数。但是当我

我有一些C#Azure函数,它们按照使用的时间表运行。我这样设置它们,其中
%TimerSchedule%
指的是应用程序设置中的cron表达式:

public static void Run([TimerTrigger("%TimerSchedule%")]TimerInfo myTimer, TraceWriter log)
在开发过程中,我经常希望使用Azure functions Tools for Visual Studio+Azure functions核心工具在本地运行函数。但是当我点击F5在本地调试函数时,它(通常)不会立即运行。相反,它会根据计时器计划开始等待下一个事件。例如,如果我的cron表达式要求每天晚上8点运行,那么我必须等到晚上8点,函数才能在我的机器上实际运行

所以我的问题是:让函数在本地运行一次的最简单和最好的方法是什么?

我尝试过或考虑过的事情:

  • 为本地开发使用更频繁的计时器时间表
    • 这是可以的,但并不完美——除非它非常频繁,否则您仍然需要等待一点,如果它非常频繁,那么函数可能会运行多次。这就是我现在正在做的
  • 编写一个控制台应用程序或单元测试,直接调用函数的
    Run()
    方法
    • 这并不是100%直接的,因为您必须为
      Run()
      提供
      TimerInfo
      TraceWriter
      参数,而我发现关于这一点的文档非常少
  • 微软的页面在这个主题上并没有太大帮助——它只提到计时器触发器作为测试其他触发器类型的一种方式


    在一个完美的世界中,我点击F5,该函数将立即运行一次——就像开发一个“普通的.NET应用程序一样。

    您也许可以使用文档中的
    runnstartup
    标志。它不完全符合您关于它只运行一次的简要说明,但它至少应该在应用程序启动后在本地执行它

    使用属性绑定的示例:


    [TimerTrigger(“%TimerSchedule%”,runnstartup=true)]TimerInfo myTimer
    我有同样的问题。我用一个单元测试修复了它。 实际上,您需要删除TraceWriter和TimerInfo

    这里有一些我是如何做到这一点的代码

    TimerInfo:

    public class ScheduleStub : TimerInfo
    {
        public ScheduleStub(TimerSchedule schedule, ScheduleStatus status, bool isPastDue = false) : base(schedule, status, isPastDue)
        {
        }
    }
    
    还有TraceWriter:

     public class TraceWriterStub : TraceWriter
    {
        protected TraceLevel _level;
        protected List<TraceEvent> _traces;
    
        public TraceWriterStub(TraceLevel level) : base(level)
        {
            _level = level;
            _traces = new List<TraceEvent>();
        }
    
        public override void Trace(TraceEvent traceEvent)
        {
            _traces.Add(traceEvent);
        }
    
        public List<TraceEvent> Traces => _traces;
    }
    
    公共类TraceWriterStub:TraceWriter
    {
    受保护的跟踪电平;
    受保护的列表跟踪;
    公共TraceWriterStub(TraceLevel):基本(level)
    {
    _级别=级别;
    _traces=新列表();
    }
    公共覆盖无效跟踪(TraceEvent TraceEvent)
    {
    _traces.Add(traceEvent);
    }
    公共列表跟踪=>\u跟踪;
    }
    
    我也有同样的问题,并使用调试标志仅在调试时运行启动:

            public static void Run(
                [TimerTrigger("* 0 7 * * 1-5"
    #if DEBUG
                , RunOnStartup=true
    #endif
                )]TimerInfo myTimer, TraceWriter log)
            {
    

    只需在同一类中添加另一个HTTP触发器类型的函数,添加代码,或者从该函数调用Run方法并从浏览器中调用它

    请确保在部署到prod时注释/删除该函数,否则您将能够通过prod中的HTTP调用触发该函数。

    非HTTP触发函数 对于HTTP触发器和Webhook以外的所有类型的函数,可以通过调用管理端点在本地测试函数。在本地服务器上使用HTTP POST请求调用此端点将触发该函数。您可以选择将测试数据传递给POST请求主体中的执行。此功能类似于Azure门户中的测试选项卡

    您可以调用以下管理员端点来触发非HTTP函数:

    http://localhost:{port}/admin/functions/{function\u name}

    要将测试数据传递给函数的管理员端点,必须在POST请求消息的正文中提供数据。消息正文必须具有以下JSON格式:

    {
    “输入”:”
    }
    
    如果您使用的是VS代码,请使用:
  • 点击F5进入调试模式,这将启动功能应用程序
  • 转到活动栏中的Azure图标
  • localproject
    下,找到要运行的函数,右键单击,然后选择“立即执行函数”

  • 看看这篇文章。

    使用邮递员应该可以做到这一点。按照以下步骤在本地运行或调试计时器触发器

    一,。运行您的项目

  • 打开邮递员并通过此url
    http://localhost:{port}/admin/functions/{function\u name}

  • 确保使用Json主体为的POST方法 { “输入”:” }

  • 按发送


  • 您应该会收到202的响应。

    我是否正确地认为,无论何时部署该功能,它都会在云中运行一次该功能?似乎表明是的。如果是这样的话,这是朝着正确方向迈出的一大步,但如果我不想改变“生产”行为,那么在部署之前就必须将其还原,这有点遗憾。@ripley_uuu是的,我相信你是正确的。一个选项是将布尔值绑定到配置中的变量中,类似于绑定“TimerSchedule”的方式。从那里,您可以将本地开发设置为true,生产(或其他)环境设置为false,这是您认为合适的。“%%”语法不适用于非字符串值。从中可以看出,它似乎不建议在大多数情况下使用runnstartup参数<代码>如果为true,则在运行时启动时调用该函数。例如,运行时在函数应用程序因不活动而处于空闲状态后唤醒时启动。当功能应用程序因功能更改而重新启动时,以及当功能应用程序向外扩展时**所以Runnstartup应该很少被设置为true,特别是在生产中**@日产这是真的,但是,OP声明这是为了在本地运行,而不是在生产环境中运行…这看起来很可怕,但嘿,这正是我需要的,它可以工作。这
            public static void Run(
                [TimerTrigger("* 0 7 * * 1-5"
    #if DEBUG
                , RunOnStartup=true
    #endif
                )]TimerInfo myTimer, TraceWriter log)
            {
    
    {
        "input": "<trigger_input>"
    }