I'm running a WebJob locally -- still connecting to the same Storage service on Azure -- but when I publish it on Azure, it's failing.
It was failing locally as well with the same error but I was able to fix it and run it perfectly fine on my local dev machine. Any idea why it may fail on Azure?.
To reiterate the point, even though it's running locally, it still connects to the same queue and storage account on Azure. So the only thing that's running locally is the code.
Here's the error I'm getting on Azure Portal under WebJob logs:
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.ActivatorInstanceFactory
1.Create() at Microsoft.Azure.WebJobs.Host.Executors.FunctionInvoker
1.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. I created the WebJob in VS 2015 Cloud -> Azure WebJob. Also, it targets .NET Framework 4.6.2
One other important point, I have an appsettings.json file that contains some setting info. This is in the bin directory. I do read this file and get some settings that are used in my code. When I FTP'ed into the WebJobs directory, I see the appsettings.json file there. Not sure if the issue could be related to that.
UPDATE: Here's Main:
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)
};
}
}
Here's MyJobActivator:
public class MyJobActivator : IJobActivator
{
private readonly IKernel _container;
public MyJobActivator(IKernel container)
{
_container = container;
}
public T CreateInstance<T>()
{
return _container.Get<T>();
}
}
Here's my Ninject Bindings 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>();
}
}
The Functions class looks like this:
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;
}
}
}