When you create a regular .NET 5 or 6 API project, you get some basic classes such as Program.cs and Startup.cs. I want to replicate that in a class project, because I want to be able to configure my services for dependency injection, but I don't want any controllers or HTTP in my project. As an example, let's assume I want to create a .NET 6 project using minimal API/hosting, and I want to check for file changes in a directory:
Program.cs
static async Task Main(string[] args)
{
await CreateHostBuilder(args).Build().RunAsync();
}
static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((_, services) => ConfigureServices(services));
static void ConfigureServices(IServiceCollection services)
{
services.AddTranscient<IFileListener, FileListener>();
}
This is probably a good starting point, which is quite similar to Startup.cs in an API project.
Inside my FileListener class, I want to call a method, that listens for file changes in a folder. Let's call it StartListening(). Where would I call that method? At some point I guess I need to do something like:
var fileListenerService = ((IServiceCollection)services).BuildServiceProvider().GetService<IListener>();
await fileListenerService.StartListening();
But where? Inside the Main method? Inside ConfigureServices? Somewhere else?
Maybe I'm looking at this the wrong way, but essentially I just need to call a method and make it run that method until the application is closed.
Microsoft's hosting has a concept of hosted services to handle background tasks, so you can turn your FileListener into hosted service and register it in DI with AddHostedService and the hosting will start it automatically with DI and cancelation signaling support.
Note that consuming scoped services (like EF context with default registration) from the hosted service requires a little bit extra work.
Related
As the title says,
How can I set up a middleware in a .NET Core 3.1 Azure Functions project? trying to dependency inject an external service that requires middleware.
First off, there are some problems here.
The Function app you create in Visual Studio 19, doesn't contain a Startup.cs class.
So we have to create this manually. Then there's a problem that it's not behaving like a real Startup class. It needs to inherit FunctionsStartup.
This is achieved by adding this line of code before the namespace first for some reason.
[assembly: FunctionsStartup(typeof(test_project.Startup))]
Then we need to inherit FunctionsStartup and then implement it.
public override void Configure(IFunctionsHostBuilder builder)
{
}
So after this, we are able to Add stuff like Singleton or external service like so,
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddSomeExternalService();
builder.Services.AddSingleton<SomeOtherStuff>(
new SomeOtherStuff(config, env_SomeOtherStuff));
}
But now my real problem starts. We need to add middleware for some functionality to work in the external service.
Usually, you can do this in a web applications (not function app) like so,
public void Configure(IApplicationBuilder app)
{
app.UseSomeExternalServiceMiddleware();
}
The problem is, I can't figure out how to do this in a function app with core 3.1
maybe it's not implemented the same way, I don't know why.
Is there a workaround for this sort of problem?
There is no direct way to do this but there is a proposed feature that you can refer to.
More References :
Dependency Injection in Azure Functions with C# (twilio.com)
c# - Azure Functions Runtime v3 Middleware - Stack Overflow
Be able to overwrite http response in IFunctionsWorkerMiddleware · Issue #530 · Azure/azure-functions-dotnet-worker · GitHub
Good time, Stack Overflow community.
I have some questions about software architecture i'm working on and i will appreciate for help with them.
The components of the app are following:
Model project (net core class library). Here i define model classes & database context.
Business project (net core class library). It has reference on the Model assembly and implements business logic. Also here, placed a HostedService with code for working with microservices through EasyNetQ using Send/Receive & Request/Response patterns.
Web API project (net core web api app). It uses Business assembly and provides web api features. This app hosted on iis 10.
Web frontend project (net core razor web app). It also uses Business assembly and provides web UI features. This app hosted on iis 10.
Some microservice apps, that may communicate with Business assembly through EasyNetQ by receiving and sending messages. Every microservice runs in the one instance.
Web api app and web frontend app both working simultaneously. So we have two instances of business logic assembly working at the same time and both of them works with the same rabbitmq queues.
So, i'm afraid that one instance of Business assembly may send message to microservice (IBus.Send), but second instance of Business assembly may receive the message from microservice (IBus.Receive). In this case, as i understand, may be collision because the first instance of Business waits answer and does not receive it, at the same time second instance of Business receives not waitable answer.
A bit of code.
Web api app startup:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddBusiness(Configuration);
...
}
Web frontend app startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddBusiness(Configuration);
...
}
Business logic assembly startup:
public static IServiceCollection AddBusiness(this IServiceCollection services, IConfiguration configuration)
{
...
services.AddSingleton(sp =>
{
var rabbitMqSettings = sp.GetRequiredService<IOptions<RabbitMqSettings>>();
return RabbitHutch.CreateBus(rabbitMqSettings.Value.Connection);
});
services.AddHostedService<RabbitMessagesReceiverService>();
return services;
}
Business logic assembly EasyNetQ code examples:
public class RabbitMessagesReceiverService : BackgroundService
{
readonly IBus _bus;
public RabbitMessagesReceiverService(IBus bus)
{
_bus = bus;
}
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
// receives messages from microservice
_bus.Receive<OutgoingResult>(RabbitHelper.OUTGOING_RESPONSE, async response =>
{
...
}
}
}
or
// sends message to microservice
await _bus.SendAsync<OutgoingRequest>(RabbitHelper.OUTGOING_REQUEST, new OutgoingRequest
{
...
});
I have a .Net core (v2.2) API. That API uses some external service calls. We want to make them as fire and forget calls. We used .net core Background service to implement that. We have multiple background services. Now if I register all those IHostedService in Dependency Injection, The last registered background service works, and others come as null in constructor injection of project. Registering dependencies like:
services.AddHostedService<BackgroundServiceA>();
services.AddHostedService<BackgroundServiceB>();
And also, I tried adding them as:
services.AddSingleton<IHostedService, BackgroundServiceA>();
services.AddSingleton<IHostedService, BackgroundServiceB>();
In both the cases, only BackgroundServiceB works, BackgroundServiceA comes as null in constructor injection.
To handle this, I was using ServiceProvider to get the object.
var services = serviceProvider.GetServices<IHostedService>();
_backgroundServiceA = services.First(o => o.GetType() == typeof(BackgroundServiceA)) as BackgroundServiceA;
Is it a good way to handle such an issue or I am missing something while registering dependencies.
Also, can we trigger both the background calls parallel?
(edit, I initially answered the wrong question....)
Dependency injection doesn't work with multiple implementations of the same interface. Since each hosted service is registered as an implementation of IHostedService, only one service can be easily injected into other types.
However you can register each service again, with a factory method to locate the background singleton instance;
services.AddHostedService<BackgroundServiceA>();
services.AddHostedService<BackgroundServiceB>();
services.AddSingleton<BackgroundServiceA>(p => p.GetServices<IHostedService>().OfType<BackgroundServiceA>().Single());
services.AddSingleton<BackgroundServiceB>(p => p.GetServices<IHostedService>().OfType<BackgroundServiceB>().Single());
Edit: It's probably better to implement this the other way around;
services.AddSingleton<BackgroundServiceA>();
services.AddSingleton<IHostedService>(p => p.GetService<BackgroundServiceA>());
Try to register them via AddHostedService call in separate ConfigureServices call outside startup, as stated in docs:
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.ConfigureServices(services =>
{
services.AddHostedService<BackgroundServiceA>();
services.AddHostedService<BackgroundServiceB>();
});
avoid direct access to hosted service as discussed here
use intermediate service instead as describe in 'Queued background tasks' example
I was trying to migrate the my application from asp.net core 2.1 to 3.0 and there come a first suggested change in program.cs for creation of host.
asp.net core 2.1 program.cs
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
asp.net core 3.0 program.cs
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
I can see that in asp.net core 3.0 it is creating Host instead of WebHost and injecting WebHostBuilder while crating Host.
But I don't have an clear idea here what is difference between Host and WebHost and why asp.net core 3.0 application does not allow to create WebHost?
The difference one could see in .NET Core 3.0 vs .NET core 2.2 code is that .NET core 3.0 uses the Generic Host while .NET Core 2.2 use the Web Host for web application.
The Generic host got included with ASP.NET CORE 2.1 and became the de-facto standard for the future version of .NET Core. Though the Generic host got included in .NET core 2.1 it was only used for non HTTP workloads. In.NET Core 3.0 it became a universal standard (HTTP + non HTTP workloads).
The reason for shifting from WebHost builder to more generic Host builder is because the WebHost builder was tied more to HTTP request and works well for Web application but with the advent of Microservices and Docker it felt the need of a more generic Web host so .NET Core team revamped it, making it usable with console application also. With Generic Host it is possible to utilize the logging, configuration, and DI libraries within a console application.
To create a Host we can use the new HostBuilder, which has a similar set of methods and extensions as the existing WebHostBuilder.There is one main difference to be aware of and that is HostBuilder doesn’t provide an extension method that allows you to use a startup class as we can with the WebHostBuilder. This decision was made primarily to avoid the need to create two separate DI containers behind the scenes. With the generic host, a single service collection is configured and then used to build the final service provider.
Reason to use ConfigureWebHostDefaults is that the new host builder is a Generic Host Builder so it is important to tell that we intend to configure the default settings for a Web Host.
Please refer to the Microsoft reference which recommends using Generic Host here
The host is responsible for application startup and lifetime management. The server is responsible for accepting HTTP requests. Part of the host’s responsibility includes ensuring the application’s services and the server are available and properly configured. You can think of the host as being a wrapper around the server. The host is configured to use a particular server; the server is unaware of its host.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
namespace WebApplication1
{
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
}
}
You create a host using an instance of WebHostBuilder. This is typically done in your app’s entry point: public static void Main. A typical Program.cs, shown below, demonstrates how to use a WebHostBuilder to build a host.
We have an application running different services (c#, .NET Core) LOCAL on a Windows PC.
I now need some kind of mechanism to inform all interested services if data changed in one service (some kind of observer pattern for microservices, or some kind of MQTT (pub/sub) mechanism of c# and .NET Core microservices locally running on a windows pc).
First I want to use Sockets but the Windows documentation says use Signalr instead.
So here is what I have so far:
public class Startup
{
public Startup()
{
// empty
}
public void ConfigureServices(IServiceCollection services)
{
// Add services.
//Test bidirectional communication (pub / sub Pattern over SignalR groups)
services.AddSignalR();
// Add the localization services to the services container.
services.AddLocalization(options => options.ResourcesPath = "Properties");
services.AddMvc()
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseStaticFiles();
// Use sessions
// The order of middleware is important.
// An InvalidOperationException exception will occur when UseSession is invoked after UseMvc.
app.UseSession();
//Test bidirectional communication (pub / sub Pattern over SignalR groups)
//The SignalR Hubs API enables you to call methods on connected clients from the server.
//In the server code, you define methods that are called by client. In the client code, you define methods that are called from the server.
app.UseSignalR(routes =>
{
routes.MapHub<SignalRHub>("/SignalRHub");
});
app.UseMvc(
routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
For the .NET CORE Service
But I now need a client for the c# System.Web.Http.ApiController and can not find an example.
Seems some are confused by our "beautiful" architecture ;-)
I hope the following picture makes it clearer:
So, if Application 1 changes data in Microservice 2, than Application 2 has to be informed.
And again, this is all running local on a Windows PC, no clouds are involved.
Probably missing something from your description.
SignalR is fine if there are clients to report relevant information to.
In your scenario, however, it would seem that the clients are the APIs themselves and this makes little sense to me.
Maybe there's a piece missing in the middle that does the work you're saying.
In any case, you may find relevant technical information about SignalR starting from the official website.
https://learn.microsoft.com/en-us/aspnet/core/signalr/dotnet-client?view=aspnetcore-3.1&tabs=visual-studio