dotnet / winforms

Windows Forms is a .NET UI framework for building Windows desktop applications.
MIT License
4.41k stars 982 forks source link

DesignToolsServer and assemblies copied in temp folder #8900

Open maiosoft opened 1 year ago

maiosoft commented 1 year ago

Hi, is there a way to get DesignToolsServer (VS 17.5.3) to copy all assemblies found in the output directory, as in previous versions of Visual Studio (i.e. 17.0.x), or (even better) tell it which additional assemblies to copy? Could I attach a piece of code at some point in this startup process?

My problem is that we use a sort of dependency injection in GUI (also at design time), so not all needed assemblies are referenced by WinForm apps...

Shyam-Gupta commented 1 year ago

We received customer feedback around performance issues while launching the designer when we were copying all assemblies from the output directory. Now we copy only the required ones.

One of the ways to pass design time dlls to DesignToolsServer process is to create a NuGet package for your control assemblies, which will go in lib directory, and place design time dlls under following folder structure: lib\<TargetFramework: e.g., net6.0>\Design\WinForms\<Optional: Minimum VS version: e.g.: 17.5>\Server.

The design time dlls will not participate in NuGet package closure and will not be referenced by the project.

An example path: lib\net6.0\Design\WinForms\17.5\Server The control assemblies will go in lib directory. Design time dlls to be loaded in VS will go in lib\net6.0\Design\WinForms\17.2 directory. Design time dlls to be loaded in DesignToolsServer will go in lib\net6.0\Design\WinForms\17.2\Server directory.

This will ensure that all dlls present under Server directory will be loaded by DesignToolsServer process.

maiosoft commented 1 year ago

Hi Shyam, thanks for the feedback! I know, copying only assemblies that are needed is obviously a good choice, and we have also considered the NuGet way... Unfortunately, at least in this "development phase", the way of packaging and deploying our "dependency injecting library" is a bit tricky, due to the constant changes (fine tuning, testing, last minute extensions and so on).

Therefore, we would like to find a "short" way to solve the Designer's needs. For example: We tried adding an "AssemblyResolve" handler, which was called correctly (on the server side), but we could not find a way to know the "compile output directory" of the assembly containing the form we were designing. The compile output directory, in our domain, also contains the "magic" assemblies we would like to copy.

Do you know if there is anything we can do in this direction, or something similar?

Thank you

maiosoft commented 1 year ago

Any suggestion?

Does the DesignToolsServer kwon anything about the project containing the form to be designed?

Shyam-Gupta commented 1 year ago

Unfortunately DesignToolsServer doesn't know anything about the VS project system.

I discussed this issue with my teammates and we are thinking to provide a way by which user can specify list of additional files in csproj file that needs to be shadow cached before DesignToolsServer starts. The additional files will still need to be loaded by user's code. I am looking into feasibility of the approach. Will it help in your scenario?

maiosoft commented 1 year ago

Yep, it will help for sure! It's not a problem to "manually copy" files via code (like an "adorned with attribute" method called by the Server or an event fired by it?). The important thing for me is to have info about the folder the Server is using to copy the assemblies it actually caches, because the additional assembly I need to copy are in the same folder. Thank you!

maiosoft commented 1 year ago

Hi Shyam, I'm back with a new (similar) question about DesignToolsServer and VS project... I made a TypeConverter that would need to know the folder where the project is located... this is because there are images that I address by name and are located in an "image" folder within the project folder. Obviously this approach doesn't work, because if I query in any mode for the current Assembly, I get "DesignToolsServer". Is there a way to find out this info or something I could use to extract it? Thank you for your time!

Shyam-Gupta commented 1 year ago

Sorry I couldn't reply sooner as I was sick. If you are using WinForms SDK NuGet package, it should be possible to obtain the VS project location from a design time assembly loaded in Visual Studio and then invoke an endpoint on DesignToolsServer to pass it the project location?

maiosoft commented 1 year ago

Hi Shyam, thanks for your feedback. I wasn't using the SDK, but at your suggestion I gave it a try. To practice, I started with a TypeEditor for a custom type I already had and which would need a design-time specific GUI, but I had avoided it for "the sake of simplicity" :D I created my package using the designer template availabe on GitHub... Now, everything seems to be fine, except that DesignToolsServer occasionally issues the warning message "Could not resolve type for mynamespace.MyCustomCodeDomDesigner" and the magic stops working, even the TypeEditor! I repeat "occasionally", as if sometimes it can resolve the type and sometimes it cannot. Any ideas about this strange behaviour?

Shyam-Gupta commented 1 year ago

Hi @maiosoft, could you please follow this wiki and share WinForms designer output window logs. It will provide more information about the issue.

Also you might want to follow this sample project for creating endpoints for reference. Thanks.

maiosoft commented 1 year ago

Hello Shyam, as always thank you for your always valuable feedback. I worked all day yesterday without the problem I reported to you. It was probably my fault, I had been playing around with recompilations without changing version numbers and clearing package caches by hand (the ones I know about), but it's possible VisualStudio has others that I ignore. Now my custom TypeEditor works for me, happy!!! :-) Back to my initial goal: to have, server-side, project information only available client-side. I realised that the top for me would be to be able to "pass" this information at the moment the form is displayed in the designer, say before the "InitializeComponent" method is invoked. The client-server data exchange that takes place when a TypeEditor is instantiated would be the right place to host the additional information as well. In fact, I tried passing the project path as an additional property to my custom TypeEditor and saw that when creating the server-side TypeEditorVM I can read this data. But to get this flow of information at the point where I told you (form creation, invocation of InitializeComponent), which Editor should I write? Would a Designer be more suitable? But Designer (or Editor or whatever) applied on what, on Forms? You don't happen to have some example code under your pillow that does this magic? :D

Thanks Shyam, have a nice day