Skip to content
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

Npgsql GAC Installation is excluded by default #2170

Closed
cristiscu opened this issue Sep 24, 2018 · 14 comments
Closed

Npgsql GAC Installation is excluded by default #2170

cristiscu opened this issue Sep 24, 2018 · 14 comments

Comments

@cristiscu
Copy link

cristiscu commented Sep 24, 2018

For the new Npgsql v4 ADO.NET installation setup, for PostgreSQL 10, on Windows.

Npgsql GAC Installation" is not selected by default. More, it's not "the recommended way to use Npgsql (use nuget instead)":

npgsql

In fact, the recommended way to use a ADO.NET provider, by Microsoft (as a good coding practice), is NOT to embed it at compile time within a project.

My app (which is for different RDBMSs, not just for PostgreSQL), sends users to your Npgsql install page, when they have to use Postgres, and later discovers your library installed from machine.config. I do not embed Npgsql (and other zillion of drivers) within my app, when I distribute it.

By excluding the option of default registration in machine.config, you actually made it more complex and send the wrong message.

Also, in real life, your driver is not used just by developers! Clients don't know about Nuget and do not have to be worried they do something wrong when they register your drive in machine.config!

Please consider registering your driver in machine.config by default, and changing the message.

@austindrenski
Copy link
Contributor

I'm sympathetic to your concerns of introducing GAC-related topics to non-developers.

At the same time, I'm not sure I'm convinced (yet) that requiring users to opt-in for GAC installation is such a bad thing. In fact, I lean toward wanting to force users to acknowledge that third-party software is about to be installed globally.

Additionally, while the screenshot labels that installer section "Custom Setup", it's actually the only setup path available (e.g. there's no basic/custom installer paths).

Have you received end-user feedback about the current installer?

/cc @roji @YohDeadfall @Brar

@cristiscu
Copy link
Author

Hi Austin. Yes, someone complained he wasn't able to see the new Npqsql driver installed in my app. That's how I discovered (it took me a while :)) that now it's just optional. And I'll have to adapt the public instructions to my users...

Just be aware this driver was already installed by many non-technical clients. I think you guys (not me :)) exposed them now to "GAC" and other technical terms, by making that setting optional :)

I see your point, as writing to machine.config is more restrictive, but the installation requires anyway admin privileges, I think. Just be aware other people may have concerns just like mine, looking for its installation in GAC, as in the past version, and having a hard time discovering what it was.

Cheers,
-Cris

@roji
Copy link
Member

roji commented Sep 24, 2018

In fact, the recommended way to use a ADO.NET provider, by Microsoft (as a good coding practice), is NOT to embed it at compile time within a project.

This seems to be a pretty outdated recommendation (can you point to where you're seeing this?). For one thing, it is simply not possible in .NET Core, which doesn't have a GAC at all. Another issue is which version of Npgsql the user installs, and whether it is compatible with your application or not... If you bundle your dependencies with your application, you can be sure your users are always getting the right version.

At the end of the day, a GAC installation is a pretty serious, and more importantly, global thing - it is done at the machine level. There are many reasons that nuget became such a popular alternative to GAC installations, and that the latter were dropped entirely in the newer world of .NET Core. This is why we want to make sure users understand what it is they're doing, and help them avoid doing it unless they really need to.

I don't know anything about your application, but I'd consider dropping the GAC dependency and bundling Npgsql with your application (via nuget). Other than that, I guess it's a matter of clearer documentation, on your side and possibly also on others. I don't know about a .NET database driver installation being done by "non-technical clients" (I guess that depends on your definition of non-technical), but if you have concrete wording changes to propose we can certainly consider it...

I'm going to close this issue for now, as I don't think GAC installation should become the default, but we can definitely continue this discussion (and I can reopen later if needed).

@roji roji closed this as completed Sep 24, 2018
@ajcvickers
Copy link

Just a note from the Microsoft side--all the current advice around use of .NET is definitely to NOT put anything in the GAC. If there is any advice that is coming from Microsoft that says otherwise, then please let myself and @divega know, since we would like to follow up on it and get that recommendation removed.

@cristiscu
Copy link
Author

cristiscu commented Sep 24, 2018

(no need to reopen it later, I just wanted to make you aware of this issue, guys...)

@roji,

  1. It's not outdated. I don't find now my original source (I think it was in a book), but you can see the concept here, using DbProviderFactories. Both early and late-binding have their pros and cons, and both are largely used.

  2. I see your point guys with the GAC, but so far you're the only ones braking this rule, of registering by default your drivers also in machine.config upon setup. I checked with MySQL, Oracle, Sybase etc and they all put them also in the GAC. (I don't try to change your mind again, I'm just making a point).

  3. I'm aware the driver a client install could in theory break my app. That's why I periodically test and update my app with the latest drives. When drivers are embedded, you force people to use just one single version of that drive. Also, people may have a different driver, from a diff vendor, they may want to use for a database! It is impossible and overkill to bundle so many drivers in ANY app.

  4. Nuget is for developers, while we are talking here about distribution bundles. Late-binding is not perfect, but lets people use a variety of providers, while early-binding has its own big problems. I initially developed my app with all db drivers bundled, and I ran into huge issues (no time to get into all details).

  5. My app is for Windows only, I don't have enough commercial interest for .NET Core (I mean Mac and Linux), so I'm not interested in it.

  6. "Non-technical" meant for me someone who does not necessarily need to know about GAC and machine.config to install a simple db driver for an application. Many generic database clients still require ADO.NET or JDBC drivers installed by users with limited tech knowledge. Look at Connector/NET (for MySQL), for instance, and you'll see no screen with tech mumbo-jumbo. That's an usability issue. If you want to make your drive just for the experts, it's fine :)

Good chat anyway. I'm also interested to see more points and possible solutions for this early vs late binding issues.

@cristiscu
Copy link
Author

@ajkvickers, thanks for jumping in.

If it's not out of topic, what are your current recommendations about using DbProviderFactories.GetFactoryClasses with the .NET providers? If that's outdated, how do you prevent including dozens of drivers in the distribution kit of a multi-client db app?

Much appreciate it,
-Cris

@roji
Copy link
Member

roji commented Sep 24, 2018

I see your point guys with the GAC, but so far you're the only ones braking this rule, of registering by default your drivers also in machine.config upon setup. I checked with MySQL, Oracle, Sybase etc and they all put them also in the GAC. (I don't try to change your mind again, I'm just making a point).

To make sure I'm not missing anything, you're only referring to the checkbox being on or off by default, in the installer, right? It's worth bearing in mind that the Npgsql MSI installer used to be only for GAC installation, so there was no need for a checkbox at all. At some point performance counter setup was added, at which point GAC installation became optional. I have no idea what the other installers are doing.

I'm aware the driver a client install could in theory break my app. That's why I periodically test and update my app with the latest drives. When drivers are embedded, you force people to use just one single version of that drive. Also, people may have a different driver, from a diff vendor, they may want to use for a database! It is impossible and overkill to bundle so many drivers in ANY app.

Forcing people to use just one version of a dependency (database driver or otherwise) seems to be a good thing... All other dependencies of your application (e.g. JSON parser or any other lib) are "forced" onto your users, why should database drivers be any different? Also, you may periodically test and update your app, but you have no way of knowing, at the end of the day, which version of your application is being used with which version of Npgsql. Maybe Npgsql released a new version, and one of your users is trying to install it before you could make your application compatible with it... That doesn't seem like a very viable installation story...

Nuget is for developers, while we are talking here about distribution bundles. Late-binding is not perfect, but lets people use a variety of providers, while early-binding has its own big problems. I initially developed my app with all db drivers bundled, and I ran into huge issues (no time to get into all details).

There are other provider late binding options... You could check a plugins directory somewhere inside your application directory, load that and attempt to find a class implementing DbProviderFactory (in .NET Core you can also register these in DbProviderFactories). This would provide you with the same loose coupling/late binding, without any sort of machine-global GAC installation. Granted, it means more work for you, and users would have to manually drop ADO.NET driver assemblies in your plugins directory, but this seems reasonable, and more or less in line with how this works in other languages/frameworks - people need to manually drop JDBC JARs inside application directories in the Java world.

"Non-technical" meant for me someone who does not necessarily need to know about GAC and machine.config to install a simple db driver for an application. Many generic database clients still require ADO.NET or JDBC drivers installed by users with limited tech knowledge. Look at Connector/NET (for MySQL), for instance, and you'll see no screen with tech mumbo-jumbo. That's an usability issue. If you want to make your drive just for the experts, it's fine :)

That's somewhat valid. But the root issue here is that the .NET world is in transition from one model (GAC, global, requiring administrator rights etc.) to another (or rather, has already transitioned). Since the GAC model is basically deprecated, a (somewhat technical) warning doesn't seem completely unreasonable. But again, if you'd like to suggest a different text I'll be glad to consider it.

To summarize some points already made... I don't think there are a gazillion databases out there that need to be supported. It seems to make sense to me to bundle at least the main ones: 4-5 should cover a big majority of mainstream database use. Aside from making installation completely effortless for (most) users (totally out of the box experience for bundled drivers), this has the significant added advantage of allowing you to be sure that your application works correctly with the only driver version you ship with (you can set up a CI/CD pipeline that verifies this). This tight coupling of the application with its dependencies really is very important IMHO, and can prevent lots of compatibility issues for users.

Besides all that, there's also nothing stopping you from opening up your application to additional drivers (or versions of bundled drivers) via a plugin directory as described above.

@ajcvickers
Copy link

@cristiscu What @roji said. :-)

@cristiscu
Copy link
Author

As you said, the alternatives you suggested are not necessarily easier or better, for both the dev and the client. And people just like myself have to be able to maintain previous apps with no major investment each time third-party change.

DBeaver (in Java) used to have such a plugin directory, and it was hard to use. Now they provide a lot of drivers embedded. But the download is much bigger, whether or not we use most of those databases.

Aqua Studio is another beast of this kind. Scroll down to its Supported Environments here, to see how many clients a multi-client db app may support today...

Bundling just a bunch of them is something I did (nothing to install for SQL Server, SQLite and 2-3 others), but with external drivers like Npqsql constantly updated, I prefer to keep it late bound. And don't worry, as long as I use just the standard ADO.NET interfaces, and you guys don't brake the backward compatibility (and I think you don't), there is no reason a new version should fail. It happened to me just once in several years, when someone (not you) published indeed a bad version.

...I'll not waste your time anymore, thanks for the chat and keep up the good work. It was just this new usability issue that I thought worth discussing a bit, that's all :)

Cheers.

@cristiscu
Copy link
Author

Shay, quick last question please, as I plan to include now Npgsql (through Nuget) in the installation package:

I must be sure it does not break my app if PostgreSQL not installed locally (the db connection should return w/ typical error). I know it should work well just for remote PostgreSQL and Amazon Redshift, but I found nowhere if there are any problems on such cases.

Or on more than one Npgsql drivers or versions installed. Or if the user later installs PostgreSQL locally.

Thanks in advance.

@roji
Copy link
Member

roji commented Sep 25, 2018

Some answers on the continued discussion (which I do find interesting/valuable BTW):

As you said, the alternatives you suggested are not necessarily easier or better, for both the dev and the client. And people just like myself have to be able to maintain previous apps with no major investment each time third-party change.

These alternatives really are easier and better, at least in some ways. Once again, GAC installation requires admin privileges (which not all of your users may want/have), it requires users to install another component in addition to your application (instead of your application working out of the box), and potentially destablizes user systems via global GAC and machines.config modifications (this last part isn't theoretical). In short, GAC installation has some severe shortcomings, which is also why it's deprecated...

Importantly, you really don't have to maintain anything each time 3rd-party change happens: it's fine to run with older versions of database drivers, as long as your applications works well. Try thinking of database drivers just like any other dependency (e.g. nuget) that your application uses - there really isn't that big of a difference. You occasionally release new versions of your application, updating your dependency versions when you do so.

DBeaver (in Java) used to have such a plugin directory, and it was hard to use. Now they provide a lot of drivers embedded. But the download is much bigger, whether or not we use most of those databases.

Npgsql's DLL is around 60KB... if we had hundreds or thousands of providers, your argument would make a lot more sense, but with the small number of mainstream databases - less so... Even the Aqua Data Studio list you link isn't that big, and contains many duplicates since it lists databases rather than drivers (Amazon Redshift, Greenplum and PostgreSQL are all Npgsql).

The several extra MBs we're talking about seem well worth the totally seamless out-of-the-box experience for users, as well as the 100% tested and certified guarantee that the driver will work.

Bundling just a bunch of them is something I did (nothing to install for SQL Server, SQLite and 2-3 others), but with external drivers like Npqsql constantly updated, I prefer to keep it late bound. And don't worry, as long as I use just the standard ADO.NET interfaces, and you guys don't brake the backward compatibility (and I think you don't), there is no reason a new version should fail. It happened to me just once in several years, when someone (not you) published indeed a bad version.

As I wrote above, you shouldn't feel an absolute need to update Npgsql constantly. But more importantly, if you do, then relying on your users to install Npgsql probably makes things a lot worst: users will typically install Npgsql once, at the same time they install your application, and never update it again. On the other hand, if you bundle Npgsql with your application, you at least make sure that whenever they upgrade your app, they receive a (well-tested) upgrade of Npgsql as well.

Finally, once again, updating a dependency should be something the application developer does (i.e. you) and tests carefully, rather than a user randomly installing some version. Over the years that have definitely been several releases breaking backwards compat in various ways - some were international major versions and some were mistakes (including several by me :)). There really isn't that much value in decoupling your application from its dependencies this way, and introducing the risk of issues...

...I'll not waste your time anymore, thanks for the chat and keep up the good work. It was just this new usability issue that I thought worth discussing a bit, that's all :)

No problem and I don't consider this a waste of anyone's time!

@roji
Copy link
Member

roji commented Sep 25, 2018

I must be sure it does not break my app if PostgreSQL not installed locally (the db connection should return w/ typical error). I know it should work well just for remote PostgreSQL and Amazon Redshift, but I found nowhere if there are any problems on such cases.

Or on more than one Npgsql drivers or versions installed. Or if the user later installs PostgreSQL locally.

I'm not sure I understand your question: are you asking whether a GAC-based or nuget-based installation of Npgsql affects how connections are made? Or whether the remote vs. local PostgreSQL makes any difference? The answer is no to both counts... You connect to PostgreSQL (or Redshift) by specifying the host in the connection string, and that host can happen to be localhost. There shouldn't be anything specific to think about.

If I've misunderstood your question please let me know.

@cristiscu
Copy link
Author

I'm not sure I understand your question

Providers like IBM.Data.DB2 require more uncoupled (i.e. late bound) client software installed. I had the bad surprise, in the past, to discover other similar drivers that compile well with the hosting application, but break it at runtime, if other DLLs are not discovered on client's machine.

I don't think your driver may have this problem, but I was just checking, to make sure. I'll test anyway my app on a clean machine, for all the drivers I'll try to embed now: Npgsql, MySql.Data, FirebirdSql.Data.FirebirdClient, System.Data.SQLite.Core, Oracle.ManagedDataAccess, Microsoft.SqlServer.Compact. Your driver looks small, but I'm afraid those coming from Oracle or IBM are much bigger, a few MB at least :) We'll see...

@roji
Copy link
Member

roji commented Sep 25, 2018

OK, good luck and don't hesitate to post back if you have any further questions. Keep in mind that Npgsql does have some minimal dependencies (take a look at its nuspec).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants