I'm programming a wiki with razor pages in the blazor framework.
Everything was going fine, then I got this error message:
fail: Microsoft.EntityFrameworkCore.Database.Connection[20004]
An error occurred using the connection to database 'aspnet-InternesWiki-8BAA8CA5-BC83-4528-BE5F-4E702A44D17F' on server '(localdb)\MSSQLLocalDB'.
fail: Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher[8]
Failed to invoke hub method 'ConnectCircuit'.
System.ObjectDisposedException: Cannot access a disposed object.
at Microsoft.AspNetCore.Components.Server.Circuits.CircuitHost.SetCircuitUser(ClaimsPrincipal user)
at Microsoft.AspNetCore.Components.Server.ComponentHub.ConnectCircuit(String circuitIdSecret)
at lambda_method11(Closure , Object )
at Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher1.ExecuteMethod(ObjectMethodExecutor methodExecutor, Hub hub, Object[] arguments) at Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher1.g__ExecuteInvocation|16_0(DefaultHubDispatcher1 dispatcher, ObjectMethodExecutor methodExecutor, THub hub, Object[] arguments, AsyncServiceScope scope, IHubActivator1 hubActivator, HubConnectionContext connection, HubMethodInvocationMessage hubMethodInvocationMessage, Boolean isStreamCall)
This is where the error occurs:
public async Task<bool> Insertiket(Eintrage eintag)
{
_context.Eintrage.Add(eintag);
_context.SaveChangesAsync();
return true;
}
SaveChangesAsync() It is no longer executed.
Hopefully you can help me, I don't know what to do.
Many thanks in advance
all project files:
https://anonfiles.com/j1c4Fet1y1/InternesWiki_7z
Reading the exception carefully, we see this:
Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher[8] Failed to invoke hub method 'ConnectCircuit'. System.ObjectDisposedException: Cannot access a disposed object.
It's not a database issue, it's a SignalR one. By reading the SignalR Hubs API Guide at the Hub Object Lifetime section we learn this:
Because instances of the Hub class are transient, you can't use them to maintain state from one method call to the next. Each time the server receives a method call from a client, a new instance of your Hub class processes the message
Now, I don't have the full picture of your architecture, my guess is that you have multiple method calls with that db write operation at the end, when the original Hub class generated at the first method call had already been disposed.
Related
I am trying to use EF Core and NPGSQL to perform CRUD operations on our backend database.
While executing POST method - I am seeing 500 internal server error for every alternative requests.
And below is the error I am seeing on the server logs.
System.InvalidOperationException: Can't close, connection is in state Connecting
at Npgsql.NpgsqlConnection.Close(Boolean async)
at Npgsql.NpgsqlConnection.CloseAsync()
at Npgsql.NpgsqlConnection.<DisposeAsync>g__DisposeAsyncCore|92_0()
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.DisposeAsync()
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.<DisposeAsync>g__Await|15_0(Int32 i, ValueTask vt, List`1 toDispose)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.<DisposeAsync>g__Await|15_0(Int32 i, ValueTask vt, List`1 toDispose)
at Microsoft.AspNetCore.Http.Features.RequestServicesFeature.<DisposeAsync>g__Awaited|9_0(RequestServicesFeature servicesFeature, ValueTask vt)
at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContext.FireOnCompleted()
Also, I am seeing 200 OK response now and then and could see the records being written into postgres DB.
Here is the code snippet I am using to save data into database.
POST Operation:
public async Task postData(ModelInfo modelInfo)
{
_context.modelAddition.Add(modelInfo);
await _context.SaveChangesAsync().ConfigureAwait(false);
}
I tried to make Add() as async and tried using disposeAsync() method as well and I am seeing similar behavior for all those scenarios.
Any help on this ?
I created a custom Health Check that calls an injected service, and that service uses a DbContext to query the DB to get some info. When I launched my application I get the following error:
An attempt was made to use the context while it is being configured. A
DbContext instance cannot be used inside OnConfiguring since it is
still being configured at this point. This can happen if a second
operation is started on this context before a previous operation
completed. Any instance members are not guaranteed to be thread safe.
Is there a way to delay the health check until the DbContext is registered somewhere in the startup?
Below is my health check implementation.
public class HealthCheck : IHealthCheck
{
public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default(CancellationToken))
{
int userCount = dbService.GetUserCount(); // fails in the dbService here
if (userCount > 0)
return Task.FromResult(HealthCheckResult.Healthy("A healthy result."));
return Task.FromResult(new HealthCheckResult(context.Registration.FailureStatus, "An unhealthy result."));
}
}
This is how it is registered in the startup after my dbcontext is registered via AddDbContext
services.AddHealthChecks().AddCheck<HealthCheck>("user_health_check");
You may be able to get around this by adding a DbContextCheck with a custom query? (docs)
My understanding is that you can do something like this:
services.AddHealthChecks()
.AddDbContextCheck<YourDbContext>(customTestQuery:
(db, cancel) => Task.FromResult(db.Users.Any()));
With that said, you may have a concurrency problem here with how your DbContext is being used. Perhaps there's an async call being made that isn't awaited, or maybe there's something wrong with how your context lifetime is configured.
Without knowing the details of how you're registering and configuring your dbcontext or how it's being injected (or not) into what looks like a repository (DbService.GetUserCount()) I can point you toward some additional documentation about avoiding DbContext threading issues and hope it is useful.
I am using Asp.net Core 2. Consider the following classes:
public class BlogDbContext: DbContext
{
.....
}
public interface IBlogData { ... }
public class BlogData : IBlogData
{
private BlogDbContext _context;
public BlogData(BlogDbContext context) { ... }
.......
}
When I used the default value contextLifetime: ServiceLifetime.Scoped as follows,
public void ConfigureServices(IServiceCollection services)
{
.....
services.AddDbContext<BlogDbContext>(...);
.....
services.AddSingleton<IBlogData, BlogData>();
}
Compilation, first migration and first database update were performed without any error. But I got the following error when visiting the page for the first time.
InvalidOperationException: Cannot consume scoped service 'MyProject.Data.BlogDbContext' from singleton 'MyProject.Services.IBlogData'.
Question
Is it correct if I fix the error by changing contextLifetime as follows ?
public void ConfigureServices(IServiceCollection services)
{
.....
services.AddDbContext<BlogDbContext>(...,contextLifetime: ServiceLifetime.Singleton);
.....
services.AddSingleton<IBlogData, BlogData>();
}
Note: this problem is specific to Asp.Net Core 2.0.
It's because you are trying to use a scoped service from a singleton service.
This is new to asp.net core 2.0. Only singleton services can be consumed by a
signleton service.
You need to add BlogData as Scoped.
No, you should generally always used scoped for DbContext in asp.net core that way it gets created once per request and is automatically disposed for you at the end of the request.
You are not really showing the code where the error is happening, but my guess is it is happening because you are running some code in startup to run the migrations. If you confirm that or show the code where the error is actually happening I could offer more help
Old question without a great answer.
The reason you get this error is because a scoped service has to be recreated every time a new page request is made (Atleast within ASP.net). How it does that is everytime a service is "requested" by way of injection (For example within a constructor), it caches the first time it's requested, then for subsequent requests, it simply returns that same instance. At the end of the page load, it trashes this instance.
Now a singleton is instead cached that first time it's requested, but it's never disposed. Every request ever made for the service will return the exact same instance.
The problem is if you have a parent service that is singleton that then references a child service that is scoped. That first request, the parent and child are created. The second request, well the parent is a singleton so it isn't recreated. Now we have a problem, because the child service is scoped, how can it be created for each request if the thing that is requesting it (And thus kicking off the DI), is a singleton? It can't. So an exception is thrown.
Interestingly, it is more about saving yourself from hanging yourself more than anything. For example, if you replace the scoped instance with a transient one, you will still have the same "problem", but it won't throw an exception.
More info here if you need further examples : https://dotnetcoretutorials.com/2018/03/20/cannot-consume-scoped-service-from-singleton-a-lesson-in-asp-net-core-di-scopes/
I am using Signalr 1.1.4 because im still using .net4 so cant upgrade to signalr 2.
Basically i want to post a message from the server to just the caller to avoid messages being sent to any client that did not start the process off.
My hub class looks like this
public class UpdateHub : Hub
{
/// <summary>
/// Sends the message.
/// </summary>
/// <param name="progressMessage">The progress message.</param>
public void SendMessage(string progressMessage)
{
Clients.Client(Context.ConnectionId).sendMessage(string.Format(progressMessage));
}
}
my javascript looks like this
// get handle to subscriptionUpload hub generated by SignalR
var updateHub = $.connection.UpdateHub;
// establish the connection to the server and start server-side operation
$.connection.hub.start();
updateHub.client.sendMessage = function (message)
{
$("container").empty();
$("container").append(message);
}
Now in my controller action method i would like to do something like this
UpdateHub hub = new UpdateHub();
hub.SendMessage("process has started");
//continue on with long process
hub.SendMessage("process has ended");
Is this even possible?
What we can find in documentation documentation:
You don't instantiate the Hub class or call its methods from your own
code on the server; all that is done for you by the SignalR Hubs
pipeline. SignalR creates a new instance of your Hub class each time
it needs to handle a Hub operation such as when a client connects,
disconnects, or makes a method call to the server.
Because instances of the Hub class are transient, you can't use them
to maintain state from one method call to the next. Each time the
server receives a method call from a client, a new instance of your
Hub class processes the message. To maintain state through multiple
connections and method calls, use some other method such as a
database, or a static variable on the Hub class, or a different class
that does not derive from Hub. If you persist data in memory, using a
method such as a static variable on the Hub class, the data will be
lost when the app domain recycles.
And then:
If you want to send messages to clients from your own code that runs
outside the Hub class, you can't do it by instantiating a Hub class
instance, but you can do it by getting a reference to the SignalR
context object for your Hub class.
You can get the context of your hub: GlobalHost.ConnectionManager.GetHubContext<YourHub>()
and then you can use it to call methods on the client side like this:
context.Clients.All.YourMethod(params);
or
context.Clients.Client(someConnectionID).YourMethod(params);
But in this case you won't be able to use Context.ConnectionId in this methods, because you don't have a direct connection to your hub. In this case you will need to store your connections somewhere (static variables, cache, db etc) and then use it to determine which client should be called.
Hope it will help.
I'm trying to share the elements in cache between ServiceStack OOB ICacheClient and a SignalR Hub, but I'm getting the following error when I try to get the user session in the OnDisconnected event
Only ASP.NET Requests accessible via Singletons are supported
I have no issues accessing the session in the OnConnected event, so far this is what I've done:
public class HubService:Hub
{
private readonly IUserRepository _userRepository;
private readonly ICacheClient _cacheClient;
public HubService(IUserRepository userRepository,ICacheClient cacheClient)
{
_userRepository = userRepository;
_cacheClient = cacheClient;
}
public override System.Threading.Tasks.Task OnConnected()
{
var session = _cacheClient.SessionAs<AuthUserSession>();
//Some Code, but No error here
return base.OnConnected();
}
public override System.Threading.Tasks.Task OnDisconnected()
{
var session = _cacheClient.SessionAs<AuthUserSession>();
return base.OnDisconnected();
}
}
I'm using simple injector and my ICacheClient is registered as singleton:
Container.RegisterSingle<ICacheClient>(()=>new MemoryCacheClient());
the question is how do I register requests as singletons in SS? what am I missing on SignalR event?
Edit:
what I tried to expain for register requests in SS is because if there's a possibility to register SS IHttpRequest using a container and set the lifestyle as singleton due to the exception message, it seems like httpContext and IHttprequest are null by the OnDisconnected event
the SS code is the following:
public static string GetSessionId(IHttpRequest httpReq = null)
{
if (httpReq == null && HttpContext.Current == null)
throw new NotImplementedException(OnlyAspNet); //message
httpReq = httpReq ?? HttpContext.Current.Request.ToRequest();
return httpReq.GetSessionId();
}
what I'm trying to do is to store a list of connected users using ICacheClient and I just want to remove the connectionID from the list when a user get disconnected.
Edit:
it seems like according to danludwig post
"There is an interesting thing about SignalR... when a client disconnects from a
hub (for example by closing their browser window), it will create a
new instance of the Hub class in order to invoke OnDisconnected().
When this happens, HttpContext.Current is null. So if this Hub has any dependencies that are >registered per-web-request, something will probably go wrong."
the description above perfectly match my situation
I am no SingalR expert, but based on my experience with it and simple injector, I don't think you can get at Session (or Request, or HttpContext for that matter) during OnDisconnected. It kind of makes sense if you think about it though -- when a client disconnects from a hub, SignalR no longer has access to a session ID, there is no request, there is no more communication with the client. OnDisconnected is basically telling you "here, do something with this ConnectionId because the client it belonged to has gone away." Granted the user may come back, and then you can get access to the web goodies (session, request, etc, as long as you are IIS hosted) during OnReconnected.
I was having similar problems getting some simpleinjector dependencies to have correct lifetime scope during these 3 Hub connection events. There was 1 dependency that I wanted to register per http request, and it worked for everything except OnDisconnected. So I had to fenagle the SI container to use http requests when it could, but use a new lifetime scope when the dependency was needed during an OnDisconnected event. If you care to read it, I have a post here that describes my experiences. Good luck.