seanofw/Redesigner

Support for UpdatePanel control

Closed this issue · 9 comments

Hi, is it relatively easy to add support for ASP.NET UpdatePanel controls? This is the error I get on pages that have this control in them:

DescribeImage.aspx: Failed to load markup file:
Line 32: Class for control <asp:UpdatePanel> could not be loaded:
No matching type for <asp:updatepanel> was found in any of the loaded assemblies.

I created a small test project just now with an UpdatePanel in it, and Redesigner handles parsing it just fine. Do you have something strange in your web.config that is remapping assemblies or doing something that Redesigner wouldn't be able to discover?

Have you run Redesigner with the --verbose option to see if it had difficulties loading the System.Web.Extensions assembly?

When I run with --verbose, I get this output, which, as you can see, references System.Web.Extensions correctly, and does correctly generate the UpdatePanel:

- Redesigner.exe begin.

- Action: Generate new designer files.

- Loading and processing "C:\Code\WebFormsTest\web.config"...
-- "C:\Code\WebFormsTest\web.config" loaded as an XDocument.
-- Found 2 <add> declarations.
-- Registering namespace: <asp:*> now includes "System.Web.UI" in assembly "System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
-- Registering namespace: <asp:*> now includes "System.Web.UI.WebControls" in assembly "System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
- Finished processing "C:\Code\WebFormsTest\web.config".

- Loading assemblies for reflection.
-- Loading assembly "System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
--- Found it in the GAC.
-- Loading assembly "System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35".
--- Found it in the GAC.
-- Loading assembly "C:\Code\WebFormsTest\bin\WebFormsTest.dll".
--- Assembly is not in GAC, trying again as a file in directory of website DLL.
--- Found it in the website directory.
- Loaded all assemblies.

...

--- Line 11: Found server tag <asp:ScriptManager ID="ScriptManager1">.
--- Line 11: Adding System.Web.UI.ScriptManager ScriptManager1 to the list of declared controls.
--- Line 16: Found server tag <asp:UpdatePanel ID="UpdatePanel1">.
--- Line 16: Adding System.Web.UI.UpdatePanel UpdatePanel1 to the list of declared controls.
---- Line 16: This server control has ParseChildren(true), either explicitly or implicitly (by being part of a collection).
---- Line 16: Beginning special parse of children as properties.
---- Line 17: Found <contenttemplate> tag that matches a property in class System.Web.UI.UpdatePanel.
---- Line 17: This control property uses [TemplateInstance(TemplateInstance.Single)]; recursing.
---- Line 19: Found server tag <asp:TextBox ID="TextBox1">.
---- Line 19: Adding System.Web.UI.WebControls.TextBox TextBox1 to the list of declared controls.

...

-- Adding control declaration: System.Web.UI.HtmlControls.HtmlForm form1.
-- Adding control declaration: System.Web.UI.ScriptManager ScriptManager1.
-- Adding control declaration: System.Web.UI.UpdatePanel UpdatePanel1.
-- Adding control declaration: System.Web.UI.WebControls.TextBox TextBox1.
-- Adding control declaration: System.Web.UI.WebControls.Button SubmitButton1.
-- Adding control declaration: System.Web.UI.WebControls.Label Label1.
-- End generation of designer file.

- End processing "Default.aspx".

Hmm, nothing weird in the web.config that I can see. I've attached the full verbose output from redesigner for you below. I also checked my project has a reference to System.Web.Extensions which is does (see attached). I've also included my web.config (minus connection strings) in case that has any clues.

sketch

Redesigner verbose output

- Redesigner.exe begin.

- Action: Generate new designer files.

- Loading and processing "C:\Users\marty\Documents\Visual Studio 2017\Projects\LP412-SelfExpression\LP412-SelfExpression\web.config"...
-- "C:\Users\marty\Documents\Visual Studio 2017\Projects\LP412-SelfExpression\LP412-SelfExpression\web.config" loaded as an XDocument.
-- Found 1 <add> declarations.
-- Registering namespace: <webopt:*> now includes "Microsoft.AspNet.Web.Optimization.WebForms" in assembly "Microsoft.AspNet.Web.Optimization.WebForms"
- Finished processing "C:\Users\marty\Documents\Visual Studio 2017\Projects\LP412-SelfExpression\LP412-SelfExpression\web.config".

- Loading assemblies for reflection.
-- Loading assembly "System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
--- Found it in the GAC.
-- Loading assembly "Microsoft.AspNet.Web.Optimization.WebForms".
--- Assembly is not in GAC, trying again as a file in directory of website DLL.
--- Trying again with '.dll' added onto the end of the assembly name.
--- Found it in the website directory.
-- Loading assembly "C:\Users\marty\Documents\Visual Studio 2017\Projects\LP412-SelfExpression\LP412-SelfExpression\bin\LP412SelfExpression.dll".
--- Assembly is not in GAC, trying again as a file in directory of website DLL.
--- Found it in the website directory.
- Loaded all assemblies.

- Resolving user controls declared in the web.config.

- Begin processing "C:\Users\marty\Documents\Visual Studio 2017\Projects\LP412-SelfExpression\LP412-SelfExpression\DescribeImage.aspx"...

-- Reading markup file into memory.
-- Line 1: Found main directive: <%@ Page Title="Describe an Image Using Taxonomies (Categories)" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="DescribeImage.aspx.cs" Inherits="LP412_SelfExpression.DescribeImage" %>
-- Line 3: Found server tag <asp:Content ID="Content1">.
-- Line 3: Adding System.Web.UI.WebControls.Content Content1 to the list of declared controls.
--- Line 17: Found opening <script> tag.  Skipping all directives and controls until closing </script> tag...
--- Line 17: Found closing </script> tag.
--- Line 20: Found server tag <asp:Panel ID="pnlInfo">.
--- Line 20: Adding System.Web.UI.WebControls.Panel pnlInfo to the list of declared controls.
---- Line 21: Found server tag <asp:Label ID="lblInfoHeader">.
---- Line 21: Adding System.Web.UI.WebControls.Label lblInfoHeader to the list of declared controls.
---- Line 24: Found server tag <asp:Label ID="lblInfoTitle">.
---- Line 24: Adding System.Web.UI.WebControls.Label lblInfoTitle to the list of declared controls.
---- Line 25: Found server tag <asp:MultiView ID="Information">.
---- Line 25: Adding System.Web.UI.WebControls.MultiView Information to the list of declared controls.
----- Line 26: Found server tag <asp:View ID="viewTaxonomy">.
----- Line 26: Adding System.Web.UI.WebControls.View viewTaxonomy to the list of declared controls.
----- Line 27: Found server tag <asp:View ID="viewIdentity">.
----- Line 27: Adding System.Web.UI.WebControls.View viewIdentity to the list of declared controls.
----- Line 28: Found server tag <asp:View ID="viewEmployer">.
----- Line 28: Adding System.Web.UI.WebControls.View viewEmployer to the list of declared controls.
--- Line 32: Found server tag <asp:UpdatePanel ID="UpdatePanel1">.

**********
Redesigner.exe: C:\Users\marty\Documents\Visual Studio 2017\Projects\LP412-SelfExpression\LP412-SelfExpression\DescribeImage.aspx: Failed to load markup file:
Line 32: Class for control <asp:UpdatePanel> could not be loaded:
No matching type for <asp:updatepanel> was found in any of the loaded assemblies.
**********

--- Stopping file processing due to exception.  Stack trace:
   at Redesigner.Library.MarkupReader.Error(String format, Object[] args)
   at Redesigner.Library.MarkupReader.ProcessServerTag(Tag tag, IEnumerable`1 requiredTagTypes)
   at Redesigner.Library.MarkupReader.ProcessTag(Match match, IEnumerable`1 requiredTagTypes)
   at Redesigner.Library.MarkupReader.ParseText(String untilEndTag, IEnumerable`1 requiredTagTypes)
   at Redesigner.Library.MarkupReader.LoadMarkupInternal(String filename)
   at Redesigner.Library.MarkupReader.LoadMarkup(ICompileContext compileContext, String filename, IEnumerable`1 tagRegistrations, AssemblyLoader assemblies, String assemblyDirectory, String rootPath)
   at Redesigner.Library.Common.GenerateDesignerForFilename(ICompileContext compileContext, String filename, IEnumerable`1 tagRegistrations, AssemblyLoader assemblies, String assemblyDirectory, String rootPath)


-- End processing "C:\Users\marty\Documents\Visual Studio 2017\Projects\LP412-SelfExpression\LP412-SelfExpression\DescribeImage.aspx".

Web.config

<?xml version="1.0" encoding="utf-8"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->
<configuration>
  <configSections>
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
  </configSections>
  <!--
    For a description of web.config changes see http://go.microsoft.com/fwlink/?LinkId=235367.

    The following attributes can be set on the <httpRuntime> tag.
      <system.Web>
        <httpRuntime targetFramework="4.6.1" />
      </system.Web>
  -->
  <system.webServer>
    <modules>
      <add name="CuteWebUI.UploadModule" type="CuteWebUI.UploadModule,CuteWebUI.AjaxUploader" />
    </modules>
  </system.webServer>
  <system.web>
    <!-- Set the session state timeout to 90 minutes -->
    <sessionState timeout="90" />
    <compilation debug="true" targetFramework="4.6.1" />
    <httpRuntime targetFramework="4.5.2" />
    <pages>
      <namespaces>
        <add namespace="System.Web.Optimization" />
      </namespaces>
      <controls>
        <add assembly="Microsoft.AspNet.Web.Optimization.WebForms" namespace="Microsoft.AspNet.Web.Optimization.WebForms" tagPrefix="webopt" />
      </controls>
    </pages>
  </system.web>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" />
        <bindingRedirect oldVersion="0.0.0.0-11.0.0.0" newVersion="11.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="WebGrease" culture="neutral" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-1.6.5135.21930" newVersion="1.6.5135.21930" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Antlr3.Runtime" publicKeyToken="eb42632606e9261f" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.5.0.2" newVersion="3.5.0.2" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <connectionStrings>
-------------
</connectionStrings>
  <entityFramework>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="mssqllocaldb" />
      </parameters>
    </defaultConnectionFactory>
  </entityFramework>
  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:1659;1699;1701" />
      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+" />
    </compilers>
  </system.codedom>
</configuration>

Figured it out. I'll have to include a patch shortly.

Between ASP.NET 3.5 and ASP.NET 4.0, among the breaking changes introduced is which assemblies should be included in the web.config. Previously, the rule was that you had to list all the assemblies you needed in the web.config. In WebForms 4.0 and later, the rule is that certain assemblies, like System.Web.Extensions are "magically" always available; in Microsoft's upgrade document, in the section on "How to manually upgrade an application" —

  1. In the system.web section, in the compilation collection, remove every add element that refers to an assembly of the .NET Framework. [emphasis added]

This means that I'll have to teach Redesigner to guess some assemblies it should automatically add for .NET 4.0+ applications, since it appears that ASP.NET is automatically adding those assemblies behind your back.

For now, you can use the really dubious workaround of temporarily adding a reference to System.Web.Extensions under <system.web> --> <pages> --> <controls>, like this:

        <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

That's not a very good solution, but it's why our websites work in Redesigner and yours don't: When we upgraded ours to .NET 4, our people left behind references in the web.config that they shouldn't have!

Okay, I have created a .NET 4.0+ branch that includes the System.Web.Extensions fix:
https://github.com/seanofw/Redesigner/tree/branches/net40

It will only kick in the automatic inclusion of System.Web.Extensions for .NET 4.0+, since that seems to be the same behavior ASP.NET has.

Please give that branch a try and let me know how it behaves on your codebase; if it behaves well, I'll merge it into master.

Hi, thanks for looking into this and providing an updated .NET 4 branch. I will test today and report back here.

Hi,

I've Built the .NET 4+ branch (I had to change the project target framework to .NET 4.0+ from .NET 3.5) and tested it against my code. Still getting some problems with the UpdatePanel as shown below. I can probably isolate in your code where the error originates, but it won't be in the next couple of days as I'm rather busy at work at the moment.

Redesigner.exe --verbose -r "C:\Users\marty\Documents\Visual Studio 2017\Projects\LP412-SelfExpression\LP412-SelfExpression" -w "C:\Users\marty\Documents\Visual Studio 2017\Projects\LP412-SelfExpression\LP412-SelfExpression\bin\LP412SelfExpression.dll" "C:\Users\marty\Documents\Visual Studio 2017\Projects\LP412-SelfExpression\LP412-SelfExpression\Experiment1.aspx"
- Redesigner.exe begin.

- Action: Generate new designer files.

- Loading and processing "C:\Users\marty\Documents\Visual Studio 2017\Projects\LP412-SelfExpression\LP412-SelfExpression\web.config"...
-- "C:\Users\marty\Documents\Visual Studio 2017\Projects\LP412-SelfExpression\LP412-SelfExpression\web.config" loaded as an XDocument.
-- Found 1 <add> declarations.
-- Registering namespace: <webopt:*> now includes "Microsoft.AspNet.Web.Optimization.WebForms" in assembly "Microsoft.AspNet.Web.Optimization.WebForms"
- Finished processing "C:\Users\marty\Documents\Visual Studio 2017\Projects\LP412-SelfExpression\LP412-SelfExpression\web.config".

- Loading assemblies for reflection.
-- Loading assembly "System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
--- Found it in the GAC.
-- Loading assembly "Microsoft.AspNet.Web.Optimization.WebForms".
--- Assembly is not in GAC, trying again as a file in directory of website DLL.
--- Trying again with '.dll' added onto the end of the assembly name.
--- Found it in the website directory.
-- Loading assembly "C:\Users\marty\Documents\Visual Studio 2017\Projects\LP412-SelfExpression\LP412-SelfExpression\bin\LP412SelfExpression.dll".
--- Assembly is not in GAC, trying again as a file in directory of website DLL.
--- Found it in the website directory.
- Loaded all assemblies.

- Resolving user controls declared in the web.config.

- Begin processing "C:\Users\marty\Documents\Visual Studio 2017\Projects\LP412-SelfExpression\LP412-SelfExpression\Experiment1.aspx"...

-- Reading markup file into memory.
-- Line 1: Found main directive: <%@ Page Title="Activity Preparation" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Experiment1.aspx.cs" Inherits="LP412_SelfExpression.Experiment1" %>
-- Line 3: Found server tag <asp:Content ID="Content1">.
-- Line 3: Adding System.Web.UI.WebControls.Content Content1 to the list of declared controls.
--- Line 13: Found server tag <asp:UpdatePanel ID="updPnlChecks">.

**********
Redesigner.exe: C:\Users\marty\Documents\Visual Studio 2017\Projects\LP412-SelfExpression\LP412-SelfExpression\Experiment1.aspx: Failed to load markup file:
Line 13: Class for control <asp:UpdatePanel> could not be loaded:
No matching type for <asp:updatepanel> was found in any of the loaded assemblies.
**********

--- Stopping file processing due to exception.  Stack trace:
   at Redesigner.Library.MarkupReader.Error(String format, Object[] args)
   at Redesigner.Library.MarkupReader.ProcessServerTag(Tag tag, IEnumerable`1 requiredTagTypes)
   at Redesigner.Library.MarkupReader.ProcessTag(Match match, IEnumerable`1 requiredTagTypes)
   at Redesigner.Library.MarkupReader.ParseText(String untilEndTag, IEnumerable`1 requiredTagTypes)
   at Redesigner.Library.MarkupReader.LoadMarkupInternal(String filename)
   at Redesigner.Library.MarkupReader.LoadMarkup(ICompileContext compileContext, String filename, IEnumerable`1 tagRegistrations, AssemblyLoader assemblies, String assemblyDirectory, String rootPath)
   at Redesigner.Library.Common.GenerateDesignerForFilename(ICompileContext compileContext, String filename, IEnumerable`1 tagRegistrations, AssemblyLoader assemblies, String assemblyDirectory, String rootPath)


-- End processing "C:\Users\marty\Documents\Visual Studio 2017\Projects\LP412-SelfExpression\LP412-SelfExpression\Experiment1.aspx".

Okay, once more, with feeling!

I committed some fixes to the branches/net40 branch. Please git pull to update your local copy (or clone a fresh copy from https://github.com/seanofw/Redesigner/tree/branches/net40 ).

This time, I made sure to carefully test against an example website structured similar to yours, in .NET 4.0, and everything works locally for me. (This will teach me to not-really-test when I share some code. You'd think after thirty years of writing software, I'd know that rule by now, but no...)

I also upgraded the error messages, so if it can't find a control, it will tell you what it searched through when it was trying to find that control, which may help to diagnose any problems you may encounter after this.

Let me know how this works for you: If it's good, I'll merge this logic back to master, since it is an improvement over what's there.

Hi,

Many thanks for the update. It works with one caveat - before the project is built in Visual Studio, you need to change the target framework to 4.0 (from 3.5) - see image below. Otherwise, it works brilliantly now - great work!

sketch

Right, right. The feature branch doesn't upgrade the .csproj itself; it merely fixes the code to work correctly on multiple versions of .NET. I'm inclined to leave the .csproj at 3.5, since it's easy to upgrade a project to newer versions of .NET, but a lot harder to downgrade it, and some places will still have old WebForms applications running on .NET 3.5 (we have a few at my company).

Ideally, this should use some kind of automated CI build to generate .NET 3.5 and .NET 4.0 builds, so you wouldn't have to compile it yourself. But at least the code does what it's supposed to now.