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
Related
I am doing simple telegram echo bot on azure, which write telegramid of user to sql database.
I think i don't need to show code, but i can share with code to you if you require me to do this. I will explain by text.
I have function telegrambot which get response from telegram servers and send it to my UpdateService written by me where messages analyze and if message type is text i will write senders Id to my database.
Firstly i decide to just implement simple echo bot without database.
In startup file i write the next code
[assembly: FunctionsStartup(typeof(MyTelegramBot.Startup))]
namespace MyTelegramBot
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddScoped<UpdateService>();
builder.Services.AddLogging();
}
}
}
And i deploy it to Azure. Everything works fine, every message correctly come back to me.
Next i decide to Add database related files: entities, dbcontext
I have one table user and thats all.
Write operations was hold by IDbSaver
namespace MyTelegramBot.Interfaces
{
public interface IDbSaver<T> where T : class
{
Task<AlertMessage> RegisterUser(T entity);
}
}
Implementation of IDbSaver
namespace MyTelegramBot.Services
{
public class DbSaver<T> : IDbSaver<T> where T : class
{
protected DbSet<T> Dbset;
private readonly MyContext _context;
public DbSaver(MyContext context)
{
Dbset = context.Set<T>();
_context = context;
}
public async Task<AlertMessage> RegisterUser(T entity)
{
await Dbset.AddAsync(entity);
try
{
await _context.SaveChangesAsync();
return new AlertMessage()
{
Message = "Success."
};
}
catch(DbUpdateException ex) when(ex.InnerException is SqlException e)
{
if(e.Number == 2601)
{
return new AlertMessage()
{
Message = "Someone(maybe you?) registered same nickname."
};
}
return new AlertMessage()
{
Message = "some text"
};
}
}
}
}
Registered IDbSaver and Dbsaver in startup like
[assembly: FunctionsStartup(typeof(MyTelegramBot.Startup))]
namespace MyTelegramBot
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddScoped<UpdateService>();
builder.Services.AddLogging();
var connectionString = "connectionstring";
builder.Services.AddDbContext<MyContext>(s => s.UseSqlServer(connectionString));
builder.Services.AddScoped(typeof(IDbSaver<>), typeof(DbSaver<>));
}
}
}
And when i deploy it to Azure, deployment process goes well, no errors during publishing it to azure, but in Azure page of my function Alerting message is
MyTelegramBot: Could not load file or assembly 'Microsoft.Extensions.Logging, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. The system cannot find the file specified.
In the nuget package menu i found that microsoft.extensions.logging with version 7 and installed it, deploy again but error message still alive.
Guys, can you please help me.
I have next installed packages:
Microsoft.Azure.Functions.Extensions(1.1.0)
Microsoft.EntityFrameworkCore(7.0.0)
Microsoft.EntityFrameworkCOre.SqlServer(7.0.0)
Microsoft.Extensions.Logging(7.0.0)
Microsoft.Net.Sdk.Function(4.1.1)
Telegram.Bot(18.0.0)
Using:
.net 6.0
functions version v4
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'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
We use dependency injection in our Azure Function (v2 on netstandard20) using parameter binding with IExtensionConfigProvider. After upgrading Microsoft.NET.Sdk.Functions from 1.0.13 to 1.0.19 (which forced an upgrade of Microsoft.Azure.Webjobs.Host to v3) this doesn't work anymore. I can't hit a breakpoint in my IExtensionConfigProvider.Initialize function any more. The same version of the Functions SDK works fine for a sample project with target framework net462, for which it uses Microsoft.Azure.WebJobs v2.
Here's the error it gives at runtime:
Error indexing method 'Function1.Run'. Microsoft.Azure.WebJobs.Host:
Cannot bind parameter 'customThing' to type CustomType. Make sure the
parameter Type is supported by the binding.
And here's the code for the sample app:
public static class Function1
{
[FunctionName("ThisFunction")]
public static async Task Run(
[TimerTrigger("0 */1 * * * *")]TimerInfo timer,
[Inject(typeof(CustomType))] CustomType customThing,
ExecutionContext context)
{
Console.WriteLine(customThing.GetMessage());
}
}
public class CustomType
{
public string GetMessage() => "Hi";
}
[Binding]
[AttributeUsage(AttributeTargets.Parameter)]
public class InjectAttribute : Attribute
{
public Type Type { get; }
public InjectAttribute(Type type) => Type = type;
}
public class InjectConfiguration : IExtensionConfigProvider
{
private IServiceProvider _serviceProvider;
public void Initialize(ExtensionConfigContext context)
{
var services = new ServiceCollection();
services.AddSingleton<CustomType>();
_serviceProvider = services.BuildServiceProvider(true);
context
.AddBindingRule<InjectAttribute>()
.BindToInput<dynamic>(i => _serviceProvider.GetRequiredService(i.Type));
}
}
With the changes made in v3 to DI and the extension model to create a extension (an IExtensionConfigProvider implementation is an extension) now you first need to create a startup class, using [assembly:WebJobsStartup] assembly attribute and implementing IWebJobsStartup interface. In there you can add your own services to the builder via builder.Services and register your extension's config provider class:
[assembly: WebJobsStartup(typeof(WebJobsExtensionStartup ), "A Web Jobs Extension Sample")]
namespace ExtensionSample
{
public class WebJobsExtensionStartup : IWebJobsStartup
{
public void Configure(IWebJobsBuilder builder)
{
//Don't need to create a new service collection just use the built-in one
builder.Services.AddSingleton<CustomType>();
//Registering an extension
builder.AddExtension<InjectConfiguration>();
}
}
}
Then in your IExtensionConfigProvider you can inject any dependencies via constructor injections, for example, binding, bindingproviders, or any other custom dependency. In your case you can just get a reference to the built-in IServiceProvider:
public class InjectConfiguration : IExtensionConfigProvider
{
private IServiceProvider _serviceProvider;
public InjectConfiguration(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void Initialize(ExtensionConfigContext context)
{
context
.AddBindingRule<InjectAttribute>()
.BindToInput<dynamic>(i => _serviceProvider.GetRequiredService(i.Type));
}
}
To get the host to load the extension, it must be registered inside bin/extensions.json file, in JavaScript or Java functions via the func extensions install command. In C# the SDK 1.0.19 looks at build time for classes attributed with WebJobsStartup assembly attribute in the current function project or any dependency (ProjectReference or PackageReference) of the current project, and generates the corresponding extensions.json file.
I recently upgraded from NServiceBus 5x to 6.0.0-beta0004 to be able to host a ASP.NET Core application (whose main function is to listen to NServiceBus messages). I'm having problems with the startup of the host as the endpoint doesn't seem to subscribe to the publisher.
I am using the pubsub example to fix the problem. Apart from the projects that are in there by default, I added one extra project, a fresh ASP.NET Core project (based on the full .NET framework). I tried to use the exact same NServiceBus configuration, but instead of using the app/web.config, I am using the following configuration:
public class ConfigurationSource : IConfigurationSource
{
public T GetConfiguration<T>() where T : class, new()
{
UnicastBusConfig config = new UnicastBusConfig()
{
MessageEndpointMappings = new MessageEndpointMappingCollection()
};
var endpointMapping = new MessageEndpointMapping
{
AssemblyName = "Shared",
Endpoint = "Samples.PubSub.MyPublisher"
};
config.MessageEndpointMappings.Add(endpointMapping);
return config as T;
}
}
The Startup class was extended with the following code:
public IConfigurationRoot Configuration
{
get;
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddMvc();
services.AddSingleton(this.GetBus());
}
private IEndpointInstance GetBus()
{
LogManager.Use<DefaultFactory> ().Level(NServiceBus.Logging.LogLevel.Info);
var endpointConfiguration = new EndpointConfiguration("Samples.PubSub.Subscriber3");
endpointConfiguration.UseSerialization<JsonSerializer>();
endpointConfiguration.DisableFeature<AutoSubscribe>();
endpointConfiguration.UsePersistence<InMemoryPersistence>();
endpointConfiguration.SendFailedMessagesTo("error");
endpointConfiguration.EnableInstallers();
// Skip web.config settings and use programmatic approach
endpointConfiguration.CustomConfigurationSource(new ConfigurationSource());
var endpointInstance = Endpoint.Start(endpointConfiguration).Result;
endpointInstance.Subscribe<IMyEvent>().Wait();
return endpointInstance;
}
The Message Handler is identical to the other Subscriber projects in the solution:
public class EventMessageHandler : IHandleMessages<IMyEvent>
{
static ILog log = LogManager.GetLogger<EventMessageHandler>();
public Task Handle(IMyEvent message, IMessageHandlerContext context)
{
log.Info($"Subscriber 2 received IEvent with Id {message.EventId}.");
log.Info($"Message time: {message.Time}.");
log.Info($"Message duration: {message.Duration}.");
return Task.FromResult(0);
}
}
If I run the sample, I notice Subscriber1 and Subscriber2 are subscribed perfectly and they receive messages if I execute some of the commands in the Publisher console application. However Subscriber3 doesn't appear to be doing anything. No exceptions are thrown and in this sample I don't seem to find any relevant log information that could lead to misconfiguration.
Has anyone tried a similar setup with ASP.NET Core & NServiceBus 6 and if so, what should I do next?
Update 04/04/2017
There are some updates that provide some interesting insights:
https://groups.google.com/forum/#!topic/particularsoftware/AVrA1E-VHtk
https://particular.net/blog/nservicebus-on-net-core-why-not