I'm trying to build simple azure functions v2 application that will contain two functions, one is triggered based on TimerTrigger and another that will be triggered by EventHubTrigger. Also I have IoC container configuration using Startup.cs class. TimerTrigger - works fine, but I have some troubles with EventHubTrigger.
Here is my setup. EventHubFunction:
namespace BgService
{
public class MyFunctions
{
[FunctionName("MyFunction")]
public async Task RunAsync([EventHubTrigger("myHubName", Connection = "hub")] string events, ILogger log)
{
}
}
}
local.settings.json:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "*****",
"hub": "Endpoint=sb://***.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=***"
}
}
My Startup.cs:
[assembly: FunctionsStartup(typeof(BgService.Startup))]
namespace BgService
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
// SomeConfiguration
}
}
When I run my azure function project I get a next error:
[19.07.2019 12:26:23] Microsoft.Azure.WebJobs.Host: Error indexing method 'MyFunction'. Microsoft.Azure.WebJobs.EventHubs: Value cannot be null.
[19.07.2019 12:26:23] Parameter name: receiverConnectionString.
Used version of Microsoft.NET.Sdk.Functions -> 1.0.29
And now the tricky part:
When I downgrade the version of Microsoft.NET.Sdk.Functions to 1.0.25 without any modification in code -> it magically starts to work, BUT Startup.Configure() method is not called any more(in version 1.0.29 it is working).
Thanks for any assistance, spent a hours on troubleshooting this problem.
Maybe this could help https://github.com/Azure/Azure-Functions/issues/1299
You should as a workaround downgrade package Microsoft.Azure.EventHubs to 3.0.0
Related
I'm trying to run/debug a new Azure function (V4, dotnet 6.0) from Visual Studio 2022. The function uses TimerTrigger and to debug it I tried using RunOnStartup = true in the TimerTriggerAttribute. I also tried a POST call to http://localhost:7071/admin/functions/<functionName> with an empty request body {} from the postman. But no luck. The debugger won't hit the function.
I've another function decorated with HttpTrigger, which runs successfully. But the one with TimerTrigger is not getting called.
Below is the code for the function and the related settings.
Function
namespace ImageAnalysisFunction
{
public class ImageAnalysis
{
[FunctionName("ImageAnalysis")]
public void Run([TimerTrigger("*/5 * * * * *", RunOnStartup = true)] TimerInfo myTimer)
{
Debug.WriteLine($"Timer triggered at: {DateTime.UtcNow}");
}
}
}
local.sttings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet"
}
}
Startup.cs
[assembly: FunctionsStartup(typeof(ImageAnalysisFunction.Startup))]
namespace ImageAnalysisFunction
{
/// <summary>
/// Startup class to configure dependency injection, swagger and other stuff
/// </summary>
public class Startup : FunctionsStartup
{
/// <inherit />
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddLogging();
}
/// <inherit />
public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
base.ConfigureAppConfiguration(builder);
#if DEBUG
FunctionsHostBuilderContext context = builder.GetContext();
builder
.ConfigurationBuilder
.AddJsonFile(Path.Combine(context.ApplicationRootPath, $"appsettings.{context.EnvironmentName}.json"), optional: true, reloadOnChange: false);
#endif
}
}
}
Runtime output
Azure Functions is built on top of the App Service Infrastructure.
Debug.WriteLine method writes the information to the trace listeners in the Listeners collection about the debug.
As given in this SO Thread, System.Diagnostics.Trace class instead of Debug is the better approach given for adding the log messages to application logs.
Azure Function .NET 6 Timer Trigger - VS 2022
I've been developing a .NET Core 6 console application (not ASP.NET) the last weeks and now I've tried to implement Entity Framework 6 migrations to it.
However, even though I reused some code from a working database model that used migrations, now I can't manage to make it work and I've also been struggling due to the lack of output from dotnet-ef.
For reasons I can't remember, the database project I reused code from used Design-Time DbContext creation. I don't know if that's my optimal way to make migrations but at least it managed to work on the previous project. I implemented the required IDesignTimeDbContextFactory<DbContext> interface the same way it was done previously:
public class MySqlContextFactory : IDesignTimeDbContextFactory<MySqlContext>
{
public MySqlContext CreateDbContext(string[] args)
{
DbContextOptionsBuilder optionsBuilder = new();
ServerVersion mariaDbVersion = new MariaDbServerVersion(new Version(10, 6, 5));
optionsBuilder.UseMySql(DatabaseCredentials.GetConnectionString(), mariaDbVersion);
return new MySqlContext();
}
}
public class MySqlContext : DbContext
{
public DbSet<Endpoint> EndpointsSet { get; set; }
private readonly string _connectionString;
public MySqlContext() : base()
=> _connectionString = DatabaseCredentials.GetConnectionString();
public MySqlContext(string connectionString) : base()
=> _connectionString = connectionString;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> Configurator.Configure(optionsBuilder, _connectionString);
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> Configurator.Create(modelBuilder);
}
public static void Configure(DbContextOptionsBuilder optionsBuilder, string connectionString)
{
ServerVersion mariaDbVersion = new MariaDbServerVersion(new Version(10, 6, 5));
optionsBuilder.UseMySql(connectionString, mariaDbVersion);
}
public static void Create(ModelBuilder modelBuilder)
{
IEnumerable<Type> types = ReflectionUtils.GetImplementedTypes(typeof(IEntityTypeConfiguration<>));
if (types.Any())
{
foreach (Type entityConfigurationType in types)
{
modelBuilder.ApplyConfigurationsFromAssembly(entityConfigurationType.Assembly);
}
}
else
{
Environment.Exit((int) EExitCodes.EF_MODEL_NOT_FOUND);
}
}
However, when I tried to create the first migration, I've been prompted with this absolutely non-descriptive output from the dotnet-ef tool:
PS> dotnet ef migrations add Init
Build started...
Build succeeded.
PS>
But no migrations were made nor anything changed in my project. So I decide to force dotnet ef to tell me more things by appending the --verbose flag on the PS command:
[...]
Build succeeded.
dotnet exec --depsfile F:\pablo\Documents\source\MyBot\bin\Debug\net6.0\MyBot.deps.json --additionalprobingpath C:\Users\pablo\.nuget\packages --runtimeconfig F:\pablo\Documents\source\MyBot\bin\Debug\net6.0\MyBot.runtimeconfig.json C:\Users\pablo\.dotnet\tools\.store\dotnet-ef\6.0.1\dotnet-ef\6.0.1\tools\netcoreapp3.1\any\tools\netcoreapp2.0\any\ef.dll migrations add Init -o Migrations\Init --assembly F:\pablo\Documents\source\MyBot\bin\Debug\net6.0\MyBot.dll --project F:\pablo\Documents\source\MyBot\MyBot.csproj --startup-assembly F:\pablo\Documents\source\MyBot\bin\Debug\net6.0\MyBot.dll --startup-project F:\pablo\Documents\source\MyBot\MyBot.csproj --project-dir F:\pablo\Documents\source\MyBot\ --root-namespace MyBot--language C# --framework net6.0 --nullable --working-dir F:\pablo\Documents\source\MyBot--verbose
Using assembly 'MyBot'.
Using startup assembly 'MyBot'.
Using application base 'F:\pablo\Documents\source\MyBot\bin\Debug\net6.0'.
Using working directory 'F:\pablo\Documents\source\MyBot'.
Using root namespace 'MyBot'.
Using project directory 'F:\pablo\Documents\source\MyBot\'.
Remaining arguments: .
Finding DbContext classes...
Finding IDesignTimeDbContextFactory implementations...
Found IDesignTimeDbContextFactory implementation 'MySqlContextFactory'.
Found DbContext 'MySqlContext'.
Finding application service provider in assembly 'MyBot'...
Finding Microsoft.Extensions.Hosting service provider...
No static method 'CreateHostBuilder(string[])' was found on class 'Program'.
No application service provider was found.
Finding DbContext classes in the project...
Using DbContext factory 'MySqlContextFactory'.
PS>
The first thing I thought I could search for was that CreateHostBuilder function the tool is searching but not retrieving. However, once again, all the documentation I could find was refer to ASP.NET applications, and programming patterns I'm not implementing in my bot application. My app does retrieve the services via Dependency Injection, custom made (maybe that's the reason of the line No application service provider was found. ?), but I didn't find a way to implement that CreateHostBuilder function without changing everything.
Just for adding the information, this is how I managed to create and configure the EF model with the non-migrations approach:
public static IServiceProvider GetServices(DiscordSocketClient client, CommandService commands)
{
ServiceCollection services = new();
services.AddSingleton(client);
services.AddSingleton(commands);
services.AddSingleton<HttpClient>();
services.AddDbContext<MySqlContext>(ServiceLifetime.Scoped);
return AddServices(services) // builds service provider;
}
private static async Task InitDatabaseModel(IServiceProvider provider)
{
MySqlContext? dbCtxt = provider.GetService<MySqlContext>();
if (dbCtxt == null)
{
Environment.Exit((int) EExitCodes.DB_SERVICE_UNAVAILABLE);
}
await dbContext.Database.EnsureDeletedAsync();
await dbContext.Database.EnsureCreatedAsync();
}
But unfortunately, my application is planned to interact with a database dynamically, so the Code-First configuring approach is not valid for me.
How can I solve this? Is an approach problem, or am I messing around with the custom non ASP.NET Dependency Injection provider? Thank you all
There is an issue with your IDesignTimeDbContextFactory. EF Core is trying to your this factory to create a MySqlContext.
public class MySqlContextFactory : IDesignTimeDbContextFactory<MySqlContext>
{
public MySqlContext CreateDbContext(string[] args)
{
// set up options
DbContextOptionsBuilder optionsBuilder = new();
ServerVersion mariaDbVersion = new MariaDbServerVersion(new Version(10, 6, 5));
optionsBuilder.UseMySql(DatabaseCredentials.GetConnectionString(), mariaDbVersion);
// *** this is the issue ***
// return default constructor W/O options (ie, UseMySql is never called)
return new MySqlContext();
}
}
You can add this constructor to your DbContext class:
public MySqlContext(DbContextOptions<MySqlContext> options)
: base(options)
{
}
and then return new MySqlContext(optionsBuilder.Options) from your factory.
I created a standard durable function based from visual studio "Add new function" to project. This works fine out of the box.
Then I followed the steps here: https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection to add dependency injection. Adding Microsoft.Extensions.http.
This breaks the function and I get error:
[03-Mar-20 14:58:18] The 'test' function is in error: The binding type(s) 'orchestrationTrigger' are not registered. Please ensure the type is correct and the binding extension is installed.
[03-Mar-20 14:58:18] The 'test_Hello' function is in error: The binding type(s) 'activityTrigger' are not registered. Please ensure the type is correct and the binding extension is installed.
[03-Mar-20 14:58:18] The 'test_HttpStart' function is in error: Microsoft.Azure.WebJobs.Host: Error indexing method 'test_HttpStart'. Microsoft.Azure.WebJobs.Host: Cannot bind parameter 'starter' to type IDurableOrchestrationClient. Make sure the parameter Type is supported by the binding. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).
In this state startup.cs does not run, which has never happened before in previous functions I have created, but I can fix this by adding extensions.json with the following content:
{
"extensions": [
{
"name": "Startup",
"typeName": "FunctionApp1.Startup, FunctionApp1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
}
]
}
This makes Configure method in startup.cs run, but I still get the same errors.
startup.cs
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddHttpClient();
}
Function2.cs
public class Function2
{
[FunctionName("test")]
public async Task> RunOrchestrator(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
var outputs = new List();
// Replace "hello" with the name of your Durable Activity Function.
outputs.Add(await context.CallActivityAsync<string>("test_Hello", "Tokyo"));
outputs.Add(await context.CallActivityAsync<string>("test_Hello", "Seattle"));
outputs.Add(await context.CallActivityAsync<string>("test_Hello", "London"));
// returns ["Hello Tokyo!", "Hello Seattle!", "Hello London!"]
return outputs;
}
[FunctionName("test_Hello")]
public string SayHello([ActivityTrigger] string name, ILogger log)
{
log.LogInformation($"Saying hello to {name}.");
return $"Hello {name}!";
}
[FunctionName("test_HttpStart")]
public async Task<HttpResponseMessage> HttpStart(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")]HttpRequestMessage req,
[DurableClient]IDurableOrchestrationClient starter,
ILogger log)
{
// Function input comes from the request content.
string instanceId = await starter.StartNewAsync("test", null);
log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
return starter.CreateCheckStatusResponse(req, instanceId);
}
}
I am using .net core 3.1
Microsoft.Azure.Functions.Extensions 1.0.0
Microsoft.Azure.WebJobs.Extensions.DurableTask 2.1.1
Microsoft.Extensions.Http 3.1.2
Microsoft.NET.sdk.Functions 3.0.4
Just for now, try downgrading the Microsoft.NET.sdk.Functions 3.0.4 to a previuos version. The team made some performance improvements, but I've seen people raising the same issue (DI problems)
I am having an issue registering a singleton using Microsoft.Extensions.DependencyInjection. I have created a Startup class (which is definitely working) and created an ITestService with implementation.
The singleton is injected into the function's constructor. Initially I had no issues with this implementation, however, a couple days later the function fails because it can't resolve ITestService. I have no clue why.
here is the Startup class
using Microsoft.Azure.WebJobs.Hosting;
[assembly: WebJobsStartup(typeof(Startup))]
namespace Test.Functions
{
using System;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
public class Startup : IWebJobsStartup
{
public void Configure(IWebJobsBuilder builder)
{
var configuration = new ConfigurationBuilder()
.SetBasePath(Environment.CurrentDirectory)
.AddJsonFile("local.settings.json", true, true)
.AddEnvironmentVariables()
.Build();
builder.Services.AddSingleton<ITestService>(new TestService("test string"));
}
}
}
And here is the function
public class TestFunction
{
private readonly ITestService testService
public TestFunction(ITestService testService)
{
this.testService = testService ?? throw new ArgumentNullException(nameof(testService));
}
[FunctionName(nameof(TestFunction))]
public void Run([ServiceBusTrigger("test", Connection = "ServiceBusConnection")]Message message, ILogger log)
{
////use test service here
}
}
When I debug startup and look at Services I see that the implementation type is null for ITestService, which I assume is why it won't resolve. Like I mentioned this totally worked for a couple days. The version of functions etc have not changed. Any ideas how to get this working again would be greatly appreciated.
update
I tried to simplify this even further and created another dummy interface with an implementation that has a parameter-less constructor. I added it using:
builder.AddSingleton<ITestService2, TestService2>()
It obviously assigned the type to the implementation type, but when it came time to inject it into the constructor it failed with the same can't activate exception.
There's a regression in the latest version of the function host that has broken Dependency Injection.
In order to work around this in an Azure environment, you can lock down the specific version of the functions host by setting the FUNCTIONS_EXTENSION_VERSION application setting to 2.0.12342.0.
If you're running the function host locally using the azure-functions-core-tools NPM package, be sure to use 2.4.419 as the latest version (2.4.498) results in the same issue. You can install that explicitly with the following:
npm i -g azure-functions-core-tools#2.4.419
See this GitHub issue for more background.
Try this in your code:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ITestService, TestService>();
}
Have a go with this
builder.Services.AddSingleton<ITestService>(s => new TestService("test string"));
This uses the IServiceProvider in order to provide the string parameter to the constructor.
EDIT :
Try Changing your code to the below and installing Willezone.Azure.WebJobs.Extensions.DependencyInjection
This adds the extension method AddDependencyInjection and allows you to do the traditional ConfigureServices method call in a net core app startup.
using Microsoft.Azure.WebJobs.Hosting;
[assembly: WebJobsStartup(typeof(Startup))]
namespace Test.Functions
{
using System;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
public class Startup : IWebJobsStartup
{
public void Configure(IWebJobsBuilder builder)
{
var configuration = new ConfigurationBuilder()
.SetBasePath(Environment.CurrentDirectory)
.AddJsonFile("local.settings.json", true, true)
.AddEnvironmentVariables()
.AddDependencyInjection(ConfigureServices)
.Build();
}
private void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ITestService>(s => new TestService("test string"));
}
}
}
I have a simple trigger that is bound to a Service bus topic. I am trying to inject another service into the trigger but i am receiving an error:
Microsoft.Extensions.DependencyInjection.Abstractions: Unable to
resolve service for type 'AzureSearchSBTrigger.SimpleClass' while
attempting to activate 'AzureSearchSBTrigger.AzureServiceTrigger'.
If it remove the constructor the trigger works correctly and i can receive messages, etc.
This is an Azure function 2 (.net core) with Function Runtime Version: 2.0.12332.0
This is how it is setup (and not working)
The main function :
public AzureServiceTrigger(SimpleClass apiClient)
{
}
[FunctionName("AzureServiceTrigger")]
public async Task Run([ServiceBusTrigger("","",Connection = "SBConnectionString")]Message myQueueItem, ILogger log)
{
}
StartUp
[assembly: WebJobsStartup(typeof(StartUp))]
namespace AzureSearchSBTrigger
{
internal class StartUp : IWebJobsStartup
{
public void Configure(IWebJobsBuilder builder)
{
builder.Services.AddSingleton<SimpleClass>();
}
}
}
Simple Class
public class SimpleClass
{
public void Somethingsimple()
{
}
}
Fixed by updating the nuget package Microsoft.NET.Sdk.Functions from 1.0.24 -> 1.0.26
Use anything below Microsoft.NET.Sdk.Functions 3.0.1. I had 3.0.2 and I got this error, I had to downgrade but than again am using ASP.NetCore 2.2, so not sure if that has much to do with it