Closed lscorcia closed 2 years ago
That's probably because this is a not yet supported use case :-)
I don't even see the option to "add a web form" on a SystemWeb project. I have tried it in a regular .NET Framework project, and I see that this gets added to the csproj file when adding a web form:
<ItemGroup>
<Compile Include="WebForm1.aspx.cs">
<DependentUpon>WebForm1.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="WebForm1.aspx.designer.cs">
<DependentUpon>WebForm1.aspx</DependentUpon>
</Compile>
<Content Include="WebForm1.aspx" />
</ItemGroup>
When I create an empty SystemWeb project, and add the webform files (like you describe), the Compile Items and DependentUpon logic already seems to be baked into the sdk, but the aspx file isn't a Content Item, and the aspx.cs file doesn't have the SubType (probably as I can't see that in Visual Studio in the UI), so I tried adding this to the project file:
<ItemGroup>
<Content Include="WebForm1.aspx" />
<Compile Update="WebForm1.aspx.cs">
<SubType>ASPXCodeBehind</SubType>
</Compile>
</ItemGroup>
But unfortunately that doesn't seem to have done the trick. The .designer.cs file is still not regenerated.
This is as far as my knowledge goes... but maybe it's a start ;-)
@lscorcia Unfortunately this looks like some Visual Studio magic which we don't have access to. It isn't even triggered with a custom tool entry - it just seems to be part of the editor and web application project handling. It is probably the same reason that the View Code Gen and View Designer menu entries are missing. I would normally only recommend using this project for managing applications where the content is not 'under development' and the most likely changes required are to CSS, or just updating text etc. It does work quite well for MVC, especially if combined with RazorGenerator where you can move the MVC classes and views to a class library, but I will admit I converted the last of my old aspx webforms applications to MVC quite a while ago, so this is not something I have tested with. If you can get any input from the VS team, or find a way to make this work, please provide the feedback. In the meantime, you will have to manually add/remove/update the appropriate CodeBehind entries for any elements you change. I would probably recommend copying the contents of the .aspx.designer.cs file into the .aspx.cs file and deleting the designer file, to make sure you remember that it is not generated/updated for you.
Thanks for the additional investigation @fretje and @CZEMacLeod ! Maybe it's worth mentioning those limitations in the readme?
Maybe it's just finally time to convert those project to MVC. It would be easier if I could just port them directly to .net core, unfortunately they depend on some Microsoft libraries that aren't still available on netstandard/netcore (SharePoint CSOM, Exchange API), and they're still actively developed so there's lots of moving parts. I just hate this new Microsoft that jumped on the bandwagon of "move fast, break things"... anyway, feel free to close this issue whenever you want.
I am looking to try and capture information from the issues into documentation. It looks like this is a limitation that does not have a solution for us just now (barring some help from the VS team on the designer side). This would obviously go into a 'known limitations' area of the documentation. Documentation?
@CZEMacLeod Not sure if this is something you could/would integrate, but there is an open source .designer.cs generator tool: https://github.com/seanofw/Redesigner
Seems like an interesting project. I myself thought it would be nice if it were possible to use a source generator to generate the designer files. Maybe even it might be possible to reimplement the Redesigner project as a source generator. Not sure if it would actually be possible, given that, as far as I know, source generators execute in a .NET 5 runtime, and I'm not sure what dependencies on .NET Framework are required.
@AvremelM @TheJayMann I would have thought it could maybe run as an MSBuild task a bit like RazorGenerator's RazorGenerator.MSBuild package. The designer files would be generated on demand as part of the build process. Unfortunately, I'm not sure that is entirely possible for these specific files; especially as that project requires that the assembly can build first to regenerate the files. It seems likely that it would be possible to make this project into a visual studio extension though, which could be invoked manually as and when required.
It seems likely that there's a way this could be done programmatically via System.Web.Compilation, I just can't figure out if the functionality for generating the designer source is built-in, or if it just builds the type and then VS generates the source from that.
For all the ReSharper users: We had exactly the same issue and solved it by adding an explicit Update ASP.NET Designer File command to the ReSharper Roflcoper extension (requires the current R# 2021.2 and can be installed in the ReSharper extension manager).
See: https://github.com/ulrichb/Roflcopter/blob/master/README.md#update-aspnet-designer-file-r-only
RE: @CZEMacLeod @AvremelM
The .designer.cs
files can be generated by the old System.Web compiler used in (deprecated) Web Site projects (which is also why they don't have/need these files).
To test this I have used an old Web Site project that does not have .designer.cs
files.
This is the example code that generates the designer file:
var cbm = new System.Web.Compilation.ClientBuildManager("~", @"<project dir>");
var code = cbm.GenerateCode("~/Menu.aspx", File.ReadAllText(@"<project dir>\Menu.aspx"), out var tbl);
The variable code
now contains the code for Menu.aspx.designer.cs
.
Unfortunately, this example is not suitable for source generators or most design-time tooling because it will compile the application partially and will read many other files in the background. In fact, it might be identical to the Build Page
action in VS (for Web Site projects).
The source code of this compiler is available here as part of .NET Framework. In particular, PageCodeDomTreeGenerator
is the class that generates designer code for aspx
files. Even so, for use as a source generator this might need to be completely rewritten, including the aspx
parser (System.Web.UI.PageParser
).
Update: I was wrong about System.Web.Compilation, which turned out to be a good thing.
The .designer.cs
files generates in VS contain only field definitions, while the files generated by the System.Web compiler contains all of the required code at runtime (such as event handler wiring and control initialization).
Even when published, the main DLL is compiled against these incomplete designer files while the "real" code is generated at
runtime. Only precompiling the app can skip this runtime step (and fortunately precompiling still works via MSBuild publish so I don't need to reimplement it).
This means that the task of generating .designer.cs
files is relatively easy.
I am now using AspxParser (with a minor modification) to parse the pages and some logic lifted from the reference source to determine the types of fields to generate. Here are the basics:
The target project must contain the following in the csproj:
<ItemGroup>
<AdditionalFiles Include="**\*.aspx" Exclude="$(DefaultWebFormsItemExcludes)" />
<AdditionalFiles Include="**\*.ascx" Exclude="$(DefaultWebFormsItemExcludes)" />
<AdditionalFiles Include="**\*.master" Exclude="$(DefaultWebFormsItemExcludes)" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Web.Extensions" />
</ItemGroup>
Parse web.config
section /configuration/system.web/pages/controls/add
Add the entries after the following list of defaults (taken from here)
<add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<add tagPrefix="mobile" namespace="System.Web.UI.MobileControls" assembly="System.Web.Mobile, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
[TagPrefix(...)]
attributes on assemblies must be added to the list (such as from System.Web.Extensions)Register
directives which must be considered first.Register
directives from the master page must also be usedDFS traversal of the ASPX syntax nodes is required with the following logic to detect and skip multiple instance templates
runat="server"
is encountered:
runat="server"
, generate a fieldITemplate
and does not have [TemplateInstance(TemplateInstance.Single)]
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
, skip all children entirelyWhat works:
What does not work:
App_WebReferences
. Tooling in VS uses dotnet-svcutil
which works but requires major code changes.Many things weren't tested yet because my source generator is very incomplete and not optimized.
@OronDF343 This looks like interesting stuff. Should we perhaps move this over to a new issue or a discussion; specifically something like "Add a source generator to enable .designer.cs
updates"?
Are you thinking of making your code public? And would you like to add it to this repository or maintain it yourself?
As this would not be relevant for all users of this SDK, I would suggest that we move it to its own package - perhaps MSBuild.SDK.SystemWeb.WebForms' or similar. Then either add it as a package reference, or we could make it a standalone top level SDK (probably relying on
MSBuild.SDK.SystemWeb` underneath it).
I'm not quite sure if VS can handle injecting new 'add item' types from an SDK or other nuget package; I know that project types can be done via the templates package: MSBuild.SDK.SystemWeb.Templates
.
It might be that to enable that would require building a VSExtension which would need to be installed. (Not my favourite solution as then you need to ensure that the extension is installed on any machine you are using to work on the project).
@CZEMacLeod Sure, I'll open a discussion once I have more to share. It might take a while for me to have an update on this, and the decision to make the code public partly depends on my employer as this all started as an internal tool to improve maintainability of older applications. In testing my proof of concept against a very large Web Forms project, I have found many more smaller issues that need to be addressed before it is usable for real-world projects.
Should this be closed? This is still unresolved / a known issue
@jeffjmc Unfortunately, this is a known limitation, and is not something that can be addressed within the SDK. It would require input from the Visual Studio team to wire up the designer system to work with CPS and this SDK type, which is unlikely to happen for a deprecated technology.
This SDK makes it easy to continue to maintain existing projects, and potentially to work on migrating to ASPNet Core, perhaps using something like the https://github.com/dotnet/systemweb-adapters project. It is not intended for use in 'green field' development as Net 4.x is not the place for that.
If you need to work on webforms code, and require designer support, then I would suggest keeping a branch of your project in the legacy format where you can do such work.
Technically Web Forms isn't officially deprecated (though obviously, it de-facto is), so maybe a feature request to just expose the existing functionality for generating designer files wouldn't be completely crazy?
And also, they still haven't closed https://github.com/dotnet/project-system/issues/2670 yet, so theoretically... 😅
(Or maybe JetBrains would open source their implementation, which they developed just a couple years ago for Rider, but that seems less likely somehow.)
Hi, let me first tell you this project is awesome. I'm testing it on our rather complex solution and it seems to work as smooth as Visual Studio should just do. This is great!
I am however experiencing an issue with aspx pages (no MVC here, plain old Web Forms). To reproduce it, create a new project using the Empty C# template (sdk 4.0.47), then add a web form called
Default.aspx
, complete with its codebehindDefault.aspx.cs
and its designer fileDefault.aspx.designer.cs
.Add a new
<asp:Label runat="server" id="myLabel"></asp:Label>
control and save the .aspx file. The control member variable should be available in the .designer.cs now, but it's not. It seems like the file is never regenerated.Do you have any idea why?