WebJob 在 Azure 上失败但在本地 运行 正常

WebJob Failing on Azure but Locally Running Fine

我 运行 在本地创建一个 WebJob -- 仍然连接到 Azure 上的同一个存储服务 -- 但是当我在 Azure 上发布它时,它失败了。

它也在本地失败并出现相同的错误,但我能够修复它并且 运行 它在我的本地开发机器上完全没问题。知道为什么它在 Azure 上可能会失败吗?

重申一下,即使它在本地 运行ning,它仍然连接到 Azure 上的相同队列和存储帐户。因此,唯一 运行 本地化的就是代码。

这是我在 WebJob 日志下的 Azure 门户上遇到的错误:

Microsoft.Azure.WebJobs.Host.FunctionInvocationException: Microsoft.Azure.WebJobs.Host.FunctionInvocationException: Exception while executing function: Functions.ProcessQueueMessage ---> System.MissingMethodException: No parameterless constructor defined for this object. at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) at System.Activator.CreateInstanceT at Microsoft.Azure.WebJobs.Host.Executors.DefaultJobActivator.CreateInstanceT at Microsoft.Azure.WebJobs.Host.Executors.ActivatorInstanceFactory1.Create() at Microsoft.Azure.WebJobs.Host.Executors.FunctionInvoker1.d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.d__31.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.d__2c.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task) at Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.d__13.MoveNext() --- End of inner exception stack trace --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.d__13.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.d__1.MoveNext()

P.S。我在 VS 2015 Cloud -> Azure WebJob 中创建了 WebJob。此外,它还针对 .NET Framework 4.6.2

还有一点很重要,我有一个 appsettings.json 文件,其中包含一些设置信息。这是在 bin 目录中。我确实阅读了这个文件并获得了我的代码中使用的一些设置。当我 FTP 进入 WebJobs 目录时,我在那里看到了 appsettings.json 文件。不确定问题是否与此有关。

更新: 这是主要内容:

class Program
{
   static readonly IKernel Kernel = new StandardKernel();
   static JobHostConfiguration config;

   static void Main()
   {
      BootStrapIoc();

      var host = new JobHost(config);
      host.RunAndBlock();
   }

   private static void BootStrapIoc()
   {
      Kernel.Load(Assembly.GetExecutingAssembly());
      config = new JobHostConfiguration
      {
         JobActivator = new MyJobActivator(Kernel)
      };
   }
}

这是 MyJobActivator:

public class MyJobActivator : IJobActivator
{
   private readonly IKernel _container;

   public MyJobActivator(IKernel container)
   {
      _container = container;
   }

   public T CreateInstance<T>()
   {
      return _container.Get<T>();
   }
}

这是我的 Ninject 绑定 class

public class NinjectBindings : Ninject.Modules.NinjectModule
{
   IConfiguration Configuration;

   public override void Load()
   {

      Bind<IConfiguration>().ToMethod(ctx => {
            var builder = new ConfigurationBuilder();
            builder.SetBasePath(Directory.GetCurrentDirectory());
            builder.AddJsonFile("appsettings.json");
            Configuration = builder.Build();
                return Configuration;
            });

       // Bind clients
       var docDbClient = new Clients.DocumentDb.DocumentDbClient(Configuration);

       // Bind Services
       Bind<ISomeService>().To<SomeService>();

       // Bind Repositories
       Bind<ISomeRepository>().To<SomeRepository>();
    }
}

函数 class 看起来像这样:

public class Functions
{
   private ISomeService _someService;

   public Functions(ISomeService someService)
   {
      _someService = someService;
   }

   public async Task ProcessQueueMessage([QueueTrigger("my-queue")] MyMessageObject message, TextWriter log)
   {
      switch(message.typeId)
      {
         case MyEnum.TypeA:
            _someService.FunctionA(message);
            break;
         case MyEnum.TypeB:
            _someService.FunctionB(message);
            break;
       }
    }
}

您得到的例外是

No parameterless constructor defined for this object

实现队列处理方法的对象必须具有无参数构造函数,以便 JobHost 能够创建它(抱歉,这是我在没有看到代码示例的情况下所能给出的最佳指示)

Microsoft.Azure.WebJobs.Host.FunctionInvocationException: Exception while executing function: Functions.ProcessQueueMessage ---> System.MissingMethodException: No parameterless constructor defined for this object.

根据你的描述,我自己测试了这个问题,根据你的代码,我可能会遇到同样的错误。经过一些试验后,我可以让它在我这边和 Azure 上按预期工作。以下是一些可能的原因,您可以参考:

Program.cs > 主要

IKernel Kernel = new StandardKernel();
Kernel.Load(Assembly.GetExecutingAssembly());
var config = new JobHostConfiguration
{
    JobActivator = new MyJobActivator(Kernel)
};

//Initializes a new instance of the Microsoft.Azure.WebJobs.JobHost class using the configuration provided.
var host = new JobHost(config);
host.RunAndBlock();

要加载 appsettings.json 文件,您可以按如下方式配置映射器:

Bind<IConfiguration>().ToMethod(ctx =>
{
    var builder = new ConfigurationBuilder();

    //set base path to the current working directory of your application
    builder.SetBasePath(Directory.GetCurrentDirectory());
    builder.AddJsonFile("appsettings.json");
    IConfigurationRoot Configuration = builder.Build();
    return Configuration;
});

注意:确保appsettings.json在项目的根目录下,并将"Copy to Output Directory"设置为Copy always

我的测试结果: