Asp.Net Core StateLess Serivce Calling StateLess Serice in Azue Service Fabric - service-fabric-stateless

I am trying to call a stateless service from Asp.Net Core Stateless API. I am not able to reach the methods in Stateless Service.
This is the Controller action method which will call the stateless service method.
// GET api/values
[HttpGet]
public async Task<string> GetAsync()
{
var repository = ServiceProxy.Create<IRepository>(
new Uri("fabric:/Application1/Stateless1"));
return await repository.GetSomething();
//return new string[] { "value1", "value2" };
}
This is the method in Stateless service.
internal sealed class Stateless1 : StatelessService, IRepository
{
public Stateless1(StatelessServiceContext context)
: base(context)
{ }
public async Task<string> GetSomething()
{
return await Task.FromResult("HELLO FROM SERVICE!");
}
}
And the listener code is
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return this.CreateServiceInstanceListeners();
}
I am able to hit the controller Get method but it is struck at repository.GetSomething() method and not able to reach that method. I don't know what I am missing here.
Any pointers will be very helpful. Thanks in advance
Update:
Manifest file:

You need to change your CreateServiceInstanceListeners...
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return this.CreateServiceRemotingInstanceListeners();
}
It needs the remoting listener as using the ServiceProxy is a remoting call.

Related

ASP.NET Core/5/6 - When exactly does a "Scoped Service" get disposed?

In ASP.NET Core/5/6 you can register a "Scoped Service" with the ServiceCollectionServiceExtensions.AddScoped() method.
In the Microsoft .NET Article Dependency injection in .NET, it states:
In apps that process requests, scoped services are disposed at the end of the request. https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection#scoped
Is their definition of "end of the request" before or after the response (including headers) has been sent?
Answer: after
After running a test, it looks like scoped services are disposed after the response has finished sending. This is unfortunate, because if the response is a large file, it may take a few seconds to finish sending to the client, and the service will be unnecessarily kept alive (undisposed) that whole time. It would be better if scoped services were disposed before the response begins sending.
Anyway, here's the test I made.
First I created a test IDisposable class that writes to the console whenever it is instantiated and disposed:
public sealed class DisposableTest : IDisposable
{
public DisposableTest()
{
Console.WriteLine("//////////////////// Created");
}
private bool Disposed = false;
public void Dispose()
{
if (!Disposed)
{
Disposed = true;
Console.WriteLine("//////////////////// Disposed");
}
}
}
Then I added the scoped service in Program.cs (for ASP.NET 6):
services.AddScoped<DisposableTest>();
Next I added some middleware to write to the console whenever the Response.OnStarting() and Response.OnCompleted() events were run:
app.Use(async delegate (HttpContext Context, Func<Task> Next)
{
Context.Response.OnStarting(delegate ()
{
Console.WriteLine("//////////////////// Response Started");
return Task.CompletedTask;
});
Context.Response.OnCompleted(delegate ()
{
Console.WriteLine("//////////////////// Response Completed");
return Task.CompletedTask;
});
await Next();
});
Lastly I added the service to the constructor of HomeController so it gets accessed:
public class HomeController : Controller
{
public HomeController(DisposableTest TheTest) { }
public IActionResult Index() { return View(); }
}
After visiting the path /home/index, the IIS Express console showed the following:
It looks like the service is disposed after the response finishes sending.

Asp.Net Core Cannot access a disposed context instance

I'm trying to implement SignalR in order to consume data from a angular frontend application.
I've checked all the results on google that I can find, but I still can't solve my issue.
The error I'm getting is:
Cannot access a disposed context instance. A common cause of this
error is disposing a context instance that was resolved from
dependency injection and then later trying to use the same context
instance elsewhere in your application. This may occur if you are
calling 'Dispose' on the context instance, or wrapping it in a using
statement. If you are using dependency injection, you should let the
dependency injection container take care of disposing context
instances. Object name: 'AdminContext'
Controller
[Route("api/[controller]")]
[ApiController]
public class ChartController : ControllerBase
{
private IHubContext<ChartHub> _hub;
private readonly ILiveMonitoringService _service;
public ChartController(IHubContext<ChartHub> hub, ILiveMonitoringService service)
{
_hub = hub;
_service = service;
}
public IActionResult Get()
{
var timerManager = new TimerManager(async () => await _hub.Clients.All.SendAsync("transferchartdata", await _service.GetAllAsync()));
return Ok(new { Message = "Request Completed" });
}
}
Service
public Task<List<LiveMonitoring>> GetAllAsync()
{
return _repository.GetAll().Take(100).ToListAsync();
}
Repository
public IQueryable<TEntity> GetAll()
{
try
{
return _adminContext.Set<TEntity>();
}
catch (Exception ex)
{
throw new Exception("Couldn't retrieve entities");
}
}
What could be the problem?
I'm pretty sure that TimerManager is your issue. You did not show its declaration but looks like its constructor accepts a callback to be called at some later point of time. And that's the issue. Your scoped service _service is captured in the callback and used at some later point of time when the request has already ended. So after the request ended, the DbContext is disposed and your _service will consume a disposed context.
The fix is to simply get the data first before passing it into your callback so that the _service will not be captured into that callback, like this:
public async Task<IActionResult> Get()
{
var liveMonitorings = await _service.GetAllAsync();
var timerManager = new TimerManager(async () => await _hub.Clients.All.SendAsync("transferchartdata", liveMonitorings));
return Ok(new { Message = "Request Completed" });
}
We need to change the returned type of Get to Task<IActionResult> to support async call.
If you actually want to call _service.GetAllAsync() at some time later (not at the time of requesting Get) inside the callback, you need to inject an IServiceScopeFactory to create a scope for your service inside that callback, like this:
public IActionResult Get([FromServices] IServiceScopeFactory serviceScopeFactory)
{
var timerManager = new TimerManager(async () =>
{
using(var scope = serviceScopeFactory.CreateScope()){
var service = scope.ServiceProvider.GetRequiredService<ILiveMonitoringService>(); ​
​var liveMonitorings = await service.GetAllAsync();
​return await _hub.Clients.All.SendAsync("transferchartdata", liveMonitorings);
​ }
​});
​return Ok(new { Message = "Request Completed" });
}
This way you don't need to inject your _service into the controller's constructor (because it's not used at all).
​

How to start an ASP.NET Core BackgroundService on demand?

I want to be able to start fire-and-forget jobs in ASP.NET Core 2.2. I have tried the following:
services.AddHostedService<TestHostedService>();
public class TestHostedService : BackgroundService
{
private readonly ILogger _logger;
public TestHostedService(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<TestHostedService>();
}
public IBackgroundTaskQueue TaskQueue { get; }
protected async override Task ExecuteAsync(
CancellationToken cancellationToken)
{
_logger.LogInformation("TestHostedService is starting.");
_logger.LogInformation("TestHostedService is stopping.");
}
}
However, this automatically starts and I want to be able to start it on demand, similarly to how Hangfire allows:
BackgroundJob.Enqueue<TestJob>(x => x.DoWork());
This also allows the job to naturally use ASP.NET CORE DI.
Question: How to start an ASP.NET Core BackgroundService on demand?
###Background information
I am dealing with an application that needs to fire-and-forget various methods. The already written code looks like this:
Task.Run(() => RunSomething(_serviceScopeFactory));
This means that each method must explicitly deal with getting a scope and retrieving the dependencies which is quite ugly.
If you want to run the BackgroundService in the MVC controller or other service. You could try to inject the IServiceProvider to that class and then loop all the hosted service and find the background service, at last you could call the startasync method.
More details, you could refer to below codes:
Register the service in Startup.cs
services.AddHostedService<TestHostedService>();
Execute the background service in the controller:
public class HomeController : Controller
{
private readonly IServiceProvider _serviceProdiver;
public HomeController(IServiceProvider serviceProdiver) {
_serviceProdiver = serviceProdiver;
}
public async Task<IActionResult> Index()
{
var allBackgroundServices = _serviceProdiver.GetServices<IHostedService>();
foreach (var hostedService in allBackgroundServices)
{
if (hostedService.GetType() == typeof(TestHostedService))
{
await hostedService.StartAsync(CancellationToken.None);
}
}
return View();
}
}
Result:

Unable to get Scoped Service in aspnetcore 1 - RC1 to work

My scoped service for some reason seems to be generating different instances of the same class when I try to access it in 2 middlewares within the same request.
Scenario: I am adding a scoped service as such:
public interface ISimplyRecorder
{
void AddInfo(string key, string value);
Dictionary<string, string> GetAllInfo();
}
public class SimplyCoreRecorderService : ISimplyRecorder
{
private Dictionary<string,string> data;
public SimplyCoreRecorderService()
{
data = new Dictionary<string, string>();
}
public void AddInfo(string key,string value)
{
data.Add("",value);
}
public Dictionary<string,string> GetAllInfo()
{
return data;
}
}
and then the following in startup.cs
services.AddScoped<ISimplyRecorder,SimplyRecorderService>();
now I am calling this service in the constructor of a sample Middleware. I am able to access the service with a new instance and add data into it and then I call await _next(context). However, when I am calling the service in my HomeController, MVC which follows the middleware above, I seem to be getting a new instance of the service even though it's the same request.
HomeController:
ISimplyRecorder _simply;
private IHostingEnvironment _env;
public HomeController(IHostingEnvironment env,ISimplyRecorder simply)
{
_simply = simply;
_env = env;
}
public IActionResult Index()
{
_simply.AddInfo("Home:Action","resulted in index action");
return View();
}
complete code available at: https://github.com/muqeet-khan/SimplyCore if someone wants to give it a go.
Middlewares are instantiated only once when it's first involved, then all the following requests are handled by that middleware instance. NOT a new middleware instance for each request.
You get your ISimplyRecorder in the constructor of the middleware and "cache" it as a private readonly variable. This means the middleware will get the ISimplyRecorder instance of the first request, then keep adding data to that instance for all the following requests rather than the new ISimplyRecorder instance for the following requests which you get in HomeController.
To solve it, you need to get ISimplyRecorder instance from the Invoke method of the middleware.
// using Microsoft.Extensions.DependencyInjection;
public async Task Invoke(HttpContext httpContext)
{
ISimplyRecorder recoder = httpContext.RequestServices.GetRequiredService<ISimplyRecorder>();
}
EDIT:
The comment of Juergen is correct, I tried it out. You may also just write like this:
public async Task Invoke(HttpContext httpContext, ISimplyRecorder recorder)
{
// recorder is from DI
}

Testing ASP.NET 5 with Entity Framework 7 using in memory database

I am wanting to get ahold of the Context that I am injecting into the controllers during testing and modify the data in the "in memory" version of the database context.
So the controller looks like this
[Route("api/[controller]")]
public class TestController : Controller
{
private readonly TestContext _testContext;
public TestController(TestContext testContext)
{
_testContext = testContext;
}
[HttpGet]
public IActionResult Get()
{
return Ok(new { _testContext.Users });
}
}
The test looks like this
public class SiteTests
{
[Fact]
public async Task GetIt()
{
var server = TestServer.Create(app => { app.UseMvc(); }, services =>
{
services.AddMvc();
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<TestContext>(options => options.UseInMemoryDatabase());
services.AddScoped<TestContext, TestContext>();
});
var client = server.CreateClient();
var response = await client.GetAsync("http://localhost/api/test");
var content = await response.Content.ReadAsStringAsync();
Assert.True(response.IsSuccessStatusCode);
}
}
I would love to somehow get ahold of the context before the client gets the request and modify what data will be coming back from the database context.
I have the test project in GitHub
If you're targeting .NET Core, you won't be able to make use of any automatic mocking frameworks.
The best you can do is make all your methods in TestContext virtual, then extend it in your unit tests.
public class IntegrationTestContext : TestContext
{
// override methods here
}
You can then use
var context = new IntegrationTestContext();
services.AddInstance<TestContext>(context);
You can also capture any extra information you want in IntegrationTestContext and access it from within your test.