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

Settings for a single-file WinForms app goes into new folders for every publish #31959

Closed
livarcocc opened this issue Sep 30, 2019 · 23 comments
Closed
Assignees
Milestone

Comments

@livarcocc
Copy link
Contributor

From @felizk on Saturday, September 28, 2019 9:41:57 PM

Steps to reproduce

  • Publish a self contained WinForms app.
  • Run it.
  • Change and save some Settings (using the WinForms style .settings)
  • Notice settings are saved in LocalAppData ultimately in a folder with this kind of postfix: "_Url_2z3wslwxp2unr2f2llkyxtrbrq3rb5cd"
  • Repeat, notice the postfix has changed and settings are not reused

Expected behavior

To be able to persist settings between versions of the application.

Actual behavior

Every time you publish, settings are effectively wiped.

Copied from original issue: dotnet/cli#12749

@merriemcgaw
Copy link
Member

@Vino-Wang can you check to see if this happens with only self-contained or both self-contained and framework dependent apps. Chat with @dreddy-work if you need help.

@Vino-Wang
Copy link

@merriemcgaw , sorry for the delay, will check it

@dreddy-work
Copy link
Member

@felizk, can you help elaborate on step "Change and save some Settings (using the WinForms style .settings)" what exactly you changes and how? we are trying to repro on our side. @Vino-Wang

@merriemcgaw
Copy link
Member

I'm concerned there's a designer component and perhaps a build component to this issue. I don't think we are going to have time to get a fix put together for 3.1. More likely 5.0

@felizk
Copy link

felizk commented Nov 2, 2019

Hello all, sorry I missed the request for elaboration.

I used the settings designer to add some settings for my project. Then I have a tickbox and when it is ticked I do "Settings.Default.tickBoxTicked = true;" and save the settings like this "Settings.Default.Save();"

@weltkante
Copy link
Contributor

weltkante commented Nov 4, 2019

I'm concerned there's a designer component and perhaps a build component to this issue.

Isn't the Settings filename/folder just determined by the assembly identity? I never noticed anything in VS design/build time influencing the settings. The fact that it gets an URL suffix looks odd though, almost as if it were treated as a clickonce app or something. It probably picks a wrong codepath because .NET Core neither has a managed .exe nor a .exe.config file. This is destined to confuse the old logic.

I'm not up to date what the state of the .exe.config files is, but if they are gone you need to put the whole settings logic through a major rewrite because it is intertwined deeply with that config file.

I would say there are potentially two issues here:

  • determining the correct filename needs to determine the main application module. This is currently not possibel due to issue In self-contained app Application.ExecutablePath returns dll winforms#1143 - even though its closed its not fixed, in fact I think closing it as dupe is wrong, IMHO the WinForms logic for the Application class needs a fix regardless of .NET Core AppContext.BaseDirectory. I'm not sure if a fix for In self-contained app Application.ExecutablePath returns dll winforms#1143 would automatically also remove the URL suffix for settings, or if this needes fixes in multiple locations and not just in the Application class.
  • the logic based on .exe.config will probably not work anymore since that file is gone? (might be mistaken)

@merriemcgaw
Copy link
Member

@AdamYoblick and @RussKie need to work together to make sure this is working, and that we're able to create/update this in the designer.

@RussKie
Copy link
Member

RussKie commented Feb 4, 2020

I think we need dotnet/winforms#1143 fixed first, then look at whether this is still an issue.

@JeremyKuhne JeremyKuhne self-assigned this Feb 4, 2020
@JeremyKuhne
Copy link
Member

This only happens when you republish. Running a self-contained executable multiple times does keep the same user settings file.

User settings files are, by design, using the location of the entry assembly to generate their hash (see ClientConfigPaths).

The self-extracting logic is using something to generate it's temp folder name that doesn't appear to be the time stamps of the outer exe. It seems like this issue is totally contained to publishing and as such isn't something an end-user would see. Windows Forms has nothing to do with it and the issue should move over to the runtime repo for tracking as a hosting issue. @swaroop-sridhar, I believe this is in your area?

@maryamariyan, this is a System.Configuration related issue. There currently isn't a way to configure the user file location.

@swaroop-sridhar
Copy link
Contributor

@JeremyKuhne By design, the single-file apps are published with a new ID each time they are published. This ensures that files different builds/configurations/versions of the same app do not get their extracted files mixed up.

The SDK's support for incremental compilation on publish is limited, so we may end up generating the single-file with a new ID even on a publish with no actual changes.

There are work-items filed to support generating bundles with fixed IDs for limited testing purposes, but in this case the burden of ensuring correct extraction is on the user.
#3601, #3596.

I think the correct action for files that contain settings that survive across builds is to exclude them from being bundled into the single-file.

CC: @jeffschwMSFT @lpereira

@JeremyKuhne
Copy link
Member

I think the correct action for files that contain settings that survive across builds is to exclude them from being bundled into the single-file.

The app itself has the settings, which is the problem. It would be nice if there was a way to see that we're running under this scenario and be able to take the location of the launching wrapped exe in some way.

@paul1956
Copy link
Contributor

paul1956 commented Feb 8, 2020

Why would an end user ever want to lose their settings when a app is upgraded? Is this ever the correct behavior and if it is there is a very easy solution (don't have/use an Upgrade Setting)? @swaroop-sridhar this is not something a developer or end-user should have to deal with. I don't know of a single app I have worked with that does not have any settings. The biggest complaint people have with the Facebook app on Apple is it loses its sound setting on every upgrade and it continues to get negative reviews because of it (not the fault of WinForms just a data point of getting this correct).

@swaroop-sridhar
Copy link
Contributor

@JeremyKuhne @paul1956

I understand the problem better now -- I suggested that the settings file be excluded because I thought that it was a build time artifact. But I get that the app generates it as part of its execution.

When an app is published as a single-file, there's no guaranteed "location" of the app.dll. The fact that the application.dll is extracted to a temporary directory on disk is a matter of implementation. The extraction location can change with builds of the app, or with releases of .net. In fact, from .net 5, the app will be loaded directly from the app, and not extracted at all.

So, assuming that the Appdomain.BaseDirectory() \ Assembly.GetEntryAssembly().ManifestModule.Name is the path of the app.dll is wrong in a single-file build.

The only file that is guaranteed to have a location is the single-file app itself. So, the settings should be written wrt that location. Looks like this path can be obtained via Application.ExecutablePath
once dotnet/winforms#2801 is checked in.

@JeremyKuhne
Copy link
Member

So, the settings should be written wrt that location. Looks like this path can be obtained via Application.ExecutablePath once dotnet/winforms#2801 is checked in.

Beyond the fact that Windows Forms is above System.Configuration, we can't do that without risking breaking other users of System.Configuration (there are over 50 million downloads of the System.Configuration.ConfigurationManager package, we need to be very careful with changes to heuristics). We need to have a way to programmatically and definitively know that we're in this special state to make this seamless for users.

If we're changing the behavior in .NET 5 that the entry assembly always gives the same path and changes accordingly when it moves around then that will "fix" the issue.

In any case, this issue has nothing to do with WinForms. It's a breaking change in a formerly constant setting (AppDomain.CurrentDomain.BaseDirectory) due to changes in our hosting here that breaks System.Configuration. I don't have the rights to move the issue to the runtime repo, but it should be moved there. @merriemcgaw do you have the rights to do so?

Apologies in advance, but I'm going on vacation and won't be able to reply for a bit. I'll be back on the 18th. :)

@RussKie
Copy link
Member

RussKie commented Feb 8, 2020

If we're changing the behavior in .NET 5 that the entry assembly always gives the same path and changes accordingly when it moves around then that will "fix" the issue.

Are you talking about this - dotnet/winforms#2801?

I don't have the rights to move the issue to the runtime repo, but it should be moved there. @merriemcgaw Merrie McGaw FTE do you have the rights to do so?

@livarcocc can you move the issue to the Runtime?

@paul1956
Copy link
Contributor

paul1956 commented Feb 8, 2020

@swaroop-sridhar This is not something a developer has any control over. Settings are part of the infrastructure at least for VB in Core as of what is publicly available (3.1 and WinForms). I think they are stored in ...App.dll.config. If "the app will be loaded directly from the app, and not extracted at all" how are assets found, does everything have to be a resource and loaded with resource manager?

@merriemcgaw
Copy link
Member

Per request from @JeremyKuhne I'll move to the runtime repo.

@merriemcgaw merriemcgaw transferred this issue from dotnet/winforms Feb 8, 2020
@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added the untriaged New issue has not been triaged by the area owner label Feb 8, 2020
@JeremyKuhne JeremyKuhne added this to the 5.0 milestone Feb 8, 2020
@JeremyKuhne JeremyKuhne added area-System.Configuration bug and removed untriaged New issue has not been triaged by the area owner labels Feb 8, 2020
@swaroop-sridhar swaroop-sridhar self-assigned this Feb 8, 2020
@swaroop-sridhar swaroop-sridhar changed the title Settings for a self-contained WinForms goes into new folders for every publish Settings for a single-file WinForms app goes into new folders for every publish Feb 8, 2020
@swaroop-sridhar
Copy link
Contributor

swaroop-sridhar commented Feb 13, 2020

@paul1956, Yes, in .net 5 single-file apps, it is recommended that assets be stored as resources and loaded through resource handling API. However, this configuration will not work for app-configuration that should service across updates. The settings should be stored elsewhere, separate from the app, which will be replaced in each build.

@swaroop-sridhar
Copy link
Contributor

@JeremyKuhne @paul1956

There are two levels of problem/solutions to this problem:
(1) The specific case of config file, computed as:
Appdomain.CurrentDomain.BaseDirectory()\Assembly.GetEntryAssembly().ManifestModule.Name + .config

In .net 5 single-file apps, the AppContext.BaseDirectory will be set to the location of the single-file app -- since there may not be a location associated with the app.dll at all. This will make the current code work OK. That is, the app.dll.config file will live beside the single-file app.exe, even though there's no corresponding app.dll.

(2) Assemblies loaded from within single-file apps will be treated as if loaded from a memory-stream. So Assembly.Location will return null. Apps that depend on assembly-location semantics will need to be aware of this distinction. However, we can consider providing APIs to abstract this distinction for specific use-cases. If you have any concerns beyond the AppContext.BaseDirectory please let us know at your earliest convenience. Thanks.

CC: @jkotas

@swaroop-sridhar
Copy link
Contributor

This is a variant of #3704

@paul1956
Copy link
Contributor

@swaroop-sridhar OK, for now storing new things in Resources doesn't work in Visual Studio for Core apps (I assume that will be fixed). Settings are the things that need to be preserved across apps and are handled by the run-time so it should just work. Finding files in other places, sounds like should be discouraged, though some examples might be needed dealing with application files in Single-File Apps. If I remember correctly in WPF "assets" are stored in a relative directory not in a resource so that might still be an issue.

FYI Some of the solutions you find on StackOverflow below but it sounds like both are wrong going forward

    Private Function GetAssetPath() As String
        Using processModule As ProcessModule = Process.GetCurrentProcess().MainModule
            Return Path.GetDirectoryName(processModule?.FileName)
        End Using
    End Function

and

        'To get the location the assembly normally resides on disk or the install directory
        Dim CodeBasePath As String = Reflection.Assembly.GetExecutingAssembly().CodeBase
        'once you have the path you get the directory with:
        Dim AssetsPath As String = Path.GetDirectoryName(CodeBasePath)

@AdamYoblick AdamYoblick removed their assignment Feb 19, 2020
@karelz
Copy link
Member

karelz commented Feb 22, 2020

@swaroop-sridhar only 1 area label per issue please - see why.

@JeremyKuhne JeremyKuhne removed their assignment Mar 25, 2020
@agocke agocke modified the milestones: 5.0.0, 6.0.0 Aug 14, 2020
@swaroop-sridhar swaroop-sridhar removed their assignment Sep 8, 2020
@agocke
Copy link
Member

agocke commented Aug 16, 2021

This should be fixed now that apps are not extracted.

@agocke agocke closed this as completed Aug 16, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Sep 15, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests