Asp.NET core backend service application - asp.net

Can I create an Asp.Net core application that can essentially mimic a windows service and just constantly run in the background? I suspect you can but I am unsure which application type to use (ie. console app, web app, etc.).
Scenario: This is a very niche situation as it will be created for a cloud based environment we are using, Siemens MindSphere. We have an application in the cloud already that can read from a PostgreSQL database, but we need a backend service app which every hour on the hour can call MindSphere Api's, receive data from it and populate a field in the above database with this data. Is this possible using .net core?

You can use Background tasks. Example of timed task:
internal class TimedHostedService : IHostedService, IDisposable
{
private readonly ILogger _logger;
private Timer _timer;
public TimedHostedService(ILogger<TimedHostedService> logger)
{
_logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Background Service is starting.");
_timer = new Timer(DoWork, null, TimeSpan.Zero,
TimeSpan.FromSeconds(5));
return Task.CompletedTask;
}
private void DoWork(object state)
{
_logger.LogInformation("Timed Background Service is working.");
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Background Service is stopping.");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
Registration in Startup.cs in ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddHostedService<TimedHostedService>();
...
}

Related

How can I track when a Linux Azure App Service is Stopping and Stopped?

I have a basic ASP.NET application hosted as an Azure linux app service and I want to track when the service is Starting, Started, Stopping and Stopped. This works great for Starting and Started but when it comes to Stopping and Stopped it doesn't appear that the linux app service calls the necessary OnStopping and OnStopped methods.
Code for the Hosted Service
internal class LifetimeEventsHostedService : IHostedService
{
private readonly ILogger _logger;
private readonly IHostApplicationLifetime _appLifetime;
public LifetimeEventsHostedService(
ILogger<LifetimeEventsHostedService> logger,
IHostApplicationLifetime appLifetime)
{
_logger = logger;
_appLifetime = appLifetime;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("***Starting Service Async");
_appLifetime.ApplicationStarted.Register(OnStarted);
_appLifetime.ApplicationStopping.Register(OnStopping);
_appLifetime.ApplicationStopped.Register(OnStopped);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("***Stopping Service Async");
return Task.CompletedTask;
}
private void OnStarted()
{
_logger.LogInformation("***Starting Service. OnStarted has been called.");
}
private void OnStopping()
{
_logger.LogInformation("***Stopping Service. OnStopping has been called.");
}
private void OnStopped()
{
_logger.LogInformation("***Stopped Service. OnStopped has been called.");
}
}
The above code works fine for Starting and Started but not for Stopping and Stopped. It also works fine in a Windows App Service. Is this a bug with Linux App Services? Is there anyway to circumvent this?

How do I inject a DBContext into a service in Startup?

I have a service that I want to use in a .Net core Blazor app.
The service uses a context that I want to pass to it.
public class MyService
{
public AddDbContextContext { get; set; }
public MyService(AddDbContext mycontext)
{
Context = mycontext;
}
}
In Startup, I create the context that I want the service to use:
public void ConfigureServices(IServiceCollection services)
{
//configure the context
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("HIDDEN"));
//how do I pass the context?
services.AddSingleton<MyService>();
}
How do I pass the context to service?
How do I pass the context to service?
You don't pass the context to the service. It is automatically done when the DI container creates your service.
Since your DBContext is named ApplicationDbContext, your service should look like this:
public class MyService
{
private ApplicationDbContext _context;
public MyService(ApplicationDbContext context)
{
_context = context;
}
}
Note: You can only use DBContext in Blazor Server App
Note: I've only answered your question here. But it's very likely you'll have issues with the DBContext, depending on what you do in your service. You should consult the documents how to use the DBContext in Blazor, particularly, why and how you should use AddDbContextFactory

How to correctly use dependency Injection with .Net Core SignalR

I'm learning .Net Core SignalR and investigating how I could use it with my app live charts. I play with some examples on the net and they all work, but I don't know how to use SignalR with database polling. I'm getting below error:
Cannot access a disposed object ...
I'm assuming it is related to my contex is being disposed after request is completed. I'm using dependency injection.
ChatController
public class ChatController : ControllerBase
{
private IChatService _chatService;
private IChatContext<ChatHub> _hub;
public ChatController(IChatContext<ChatHub> hub, IChatService chatService)
{
_hub = hub;
_chatService = chatService;
}
public IActionResult Get()
{
var timerManager = new TimerManager(() => _hub.Clients.All.SendAsync("transferchatdata", _chatService.ChatDataByProds()));
return Ok(new { Message = "Request Completed" });
}
}
ChatService
public interface IChatService
{
IEnumerable<ChatDataByProd> ChatDataByProds();
}
public class ChatService : IChatService
{
private ChatContext _context;
public ChatService(ChatContext context)
{
_context = context;
}
public IEnumerable<ChatDataByProd> ChatDataByProds()
{
return _context.ChatDataByProds;
}
}
ChatHub
public class ChatHub : Hub
{
}
It seems that you are using a EF Core context that is a scoped lifetime service, which means per-request lifetime in ASP.NET Core. Your ChatService must have a longer lifetime than a HTTP request, and a single instance of the database context would be disposed by the container while you are still holding the reference to it.
Thus, you need to obtain an IServiceProvider container in the ctor of ChatService, and GetService the database context each time when you need to access the database.

Asp.Net Core run once function

When start Asp.Net Core I have to call the database through EntityFrameworkCore, I have to run it only once during user "Session"
Any suggests ?
I usually use IHostedService. There is a great article on this by Andrew Lock.
In essence, what you want to do is implement the IHostedService interface and put your DB code in the StartAsync method.
public class MigratorHostedService: IHostedService
{
// We need to inject the IServiceProvider so we can create
// the scoped service, MyDbContext
private readonly IServiceProvider _serviceProvider;
public MigratorStartupFilter(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
// Create a new scope to retrieve scoped services
using(var scope = _seviceProvider.CreateScope())
{
// Get the DbContext instance
var myDbContext = scope.ServiceProvider.GetRequiredService<MyDbContext>();
//Do the migration asynchronously
await myDbContext.Database.MigrateAsync();
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
// noop
return Task.CompletedTask;
}
}
This code was taken directly from the article mentioned and is only placed here to answer the question asked. All credit must go to Andrew Lock

Custom Authorize filter with aspnet core

Hi I am trying to create a custom authorize filter that will allow me to authorize requests coming from localhost automatically (which will be used for my tests).
I found the following one for Asp.net however am having trouble porting it to asp.net core.
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext.Request.Url.IsLoopback)
{
// It was a local request => authorize the guy
return true;
}
return base.AuthorizeCore(httpContext);
}
}
How can I port this to asp.net core?
You can create a middleware in which you can authorize requests coming from localhost automatically.
public class MyAuthorize
{
private readonly RequestDelegate _next;
public MyAuthorize(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
// authorize request source here.
await _next(httpContext);
}
}
Then create an extension method
public static class CustomMiddleware
{
public static IApplicationBuilder UseMyAuthorize(this IApplicationBuilder builder)
{
return builder.UseMiddleware<MyAuthorize>();
}
}
and finally add it in startup Configure method.
app.UseMyAuthorize();
Asp.Net Core did not have IsLoopback property. Here is a work around for this
https://stackoverflow.com/a/41242493/2337983
You can also read more about Middleware here

Resources