-
Notifications
You must be signed in to change notification settings - Fork 132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
System.InvalidCastException when querying for postgis Point if Hangfire is being setup before the application context #322
Comments
This looks like the same issue we had a while ago, at least similar. Hangfire.PostgreSql does not change any type mappings so I'm exactly sure what to make of it. Please see the steps in this comment. Hopefully @dmitry-vychikov is able to help as I personally don't have time in the near future for debugging this. First step is changing the order and it seems to work, so it's interesting to see if the type mappings are registered correctly which you can see while debugging. |
Hi @Cherepoc I'm on vacation now and not able to look at the zip file yet.
It feels like This doesn't seem like a hangfire issue on its own, but it creates confusion. Workaround If you need a workaround, then you can:
Improvements in hangfire
Anyway, I will get back from vacation in 1-2 weeks, double check the repro to confirm my thoughts, and reply here. |
Thanks for taking the time replying during the vacation!
We probably can add a wrapper factory which either uses the data source or connection string directly, but it feels cumbersome and still just a band-aid. Another option is to move to a different versioning scheme and have multiple "active" package versions. |
@dmitry-vychikov Thanks! Unfortunately it does not specify what exactly it tries to convert, but after some experimentation I managed to repeat the error in the example app under some specific conditions:
Here's the exception: Here's an updated example app |
I do not believe this is related to the original problem. This error is caused by usage of NodaTime which seems to be not natively supported by Dapper. You can check this thread DapperLib/Dapper#198. Maybe some workaround proposed there can help. Or disable NodaTime completely. Explanation
** NpgsqlDataSource** mentioned above should fix the problem. I think, we don't really want to run NodaTime with Hangfire. But as @azygis mentioned, it is not straightforward because of strange Microsoft's versioning schemes :( |
@Cherepoc Here's a fix that allows to keep NodaTime.
class MyHangfireConnectionFactory : IConnectionFactory
{
private readonly NpgsqlDataSource _dataSource;
public MyHangfireConnectionFactory(NpgsqlDataSource dataSource)
{
_dataSource = dataSource;
}
public NpgsqlConnection GetOrCreateConnection()
{
return _dataSource.CreateConnection();
}
}
public static IServiceCollection AddOmHangfire(this IServiceCollection services, string connectionString)
{
//NOTE: create factory outside of AddHangfire lambda.
// The datasource MUST be created before `NpgsqlConnection.GlobalTypeMapper` static object is polluted by `o.UseNodaTime` and similar calls
// because datasource inherits global mappings at creation time.
var factory = new MyHangfireConnectionFactory(NpgsqlDataSource.Create(connectionString));
services.AddHangfire(
config =>
{
var options = new PostgreSqlStorageOptions(...);
config.UsePostgreSqlStorage(factory, options);
...
}
); I briefly tested this with your example, and it does not give me any errors after applying the fix. Thanks to @azygis for mentioning the wrapper factory and giving me a large hint :) **To @azygis **
Well, Hangfire is dependent on 3rd party libs, so we have to account for their design flaws. It is a band aid, but only until we can reference |
First of all, you're a legend @dmitry-vychikov!
I meant having multiple versions, v1 and v2 and maintaining them both, backporting changes from v2 into v1 for those unfortunate not being able to use data source, at least the changes that are possible. Edit to say that I actually forgot about conditional compilation. But unfortunately that still requires hard Npgsql 7.0 dependency, which as you mentioned as well is a breaking change. Unless we go reflection all the way with lowest 6, but we might still end up with wrong assumptions between 6 and 7, throwing random stuff at runtime. |
@dmitry-vychikov Thanks! Your solution works. |
Took the advice of using the |
I have a feeling that we actually can do it. If we add multiple target frameworks to the package, and then use condition in csproj file to include either Npgsql 6 or 7 depending on target framework used. I'm not 100% sure, but I can try it later today and submit a PR. Another maybe simpler option is to create a brand new package
|
We can't force people to upgrade to Npgsql7 if they're on .NET 7 and still use Npgsql6. Npgsql works with virtually any .net version and we shouldn't put such a hard lock either. Now the second suggestion I like - a separate library which drags a later dependency. Really less confusing than the previous approach. Will probably go that route. Edit to add: we could probably still do that with current version. Obsolete members will still be there for the next version(s), but we can already support the data source. |
@dmitry-vychikov thanks for your workaround from above, it works. By the way, I found another workaround that is working as well and may also be starting point of a proper fix/patch. #162 (comment). |
Hi!
I have a console application "worker" that performs background tasks using Hangfire with postgresql storage. I have postgis extension installed and some of my entities have properties with the type Point. I configure both the database context and hangfire through DI services. Some time ago I found this error that was frequently happening in worker:
System.InvalidCastException: Can't cast database type . to Point
It turned out that if a hangfire service like IRecurringJobManager is requested before the DbContext then anytime you want to load an entity with a Point property, it fails, but if the DbContext is requested before the IRecurringJobManager, then everything works fine.
Here's an example project. You'll get the same error if you run it (you should have a postgres database of course and a correct connection string). In Startup method of the Program class if you move getting IRecurringJobManager to the bottom, then you won't get any error, even if request a new ApplicationDbContext again after it.
NpgSqlBugDemo.zip
The text was updated successfully, but these errors were encountered: