You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[API Proposal]: Add System.Web.IHtmlString and System.Web.HtmlString to System.Web.HttpUtility #83477
Edit by @antonfirsov: Made class HtmlString optional.
Background and motivation
We have created https://github.com/dotnet/systemweb-adapters to provide APIs people used from System.Web backed by ASP.NET Core types to enable quicker migration to ASP.NET Core. Many of the APIs are ones we can provide there. However, System.Web.IHtmlString was commonly used in ASP.NET Framework and expected HttpUtility.HtmlEncode(object) to special case it (see ReferenceSource).
This proposal is to add this type and the default implementation of it back and update HttpUtility.HtmlEncode to special case it so that code that is being migrated from ASP.NET Framework will continue to work without having to rewrite it (or find unexpected bugs at some point).
API Proposal
namespaceSystem.Web;publicinterfaceIHtmlString{stringToHtmlString();}// Consider//public class HtmlString : IHtmlString//{// public HtmlString(string value);// public string ToHtmlString();//}
@stephentoub@twsouthwick I think the class just makes porting code slightly easier, the interface and the realignment of the HttpUtility code is the more important part.
I think if the class isn't included in the runtime, it could be added to the systemweb adapters project instead and would be almost as easy to use for porting code.
It certainly might be useful, again from a porting and using the incremental approach, for Microsoft.AspNetCore.Html.HtmlString to also implement IHtmlString or provide some other mechanism to enable casting from the legacy class/interface to the new class/interface, but that is outside this scope and can be addressed by the issue already open in dotnet/systemweb-adapters#205 or opened in the aspnetcore project once this (blocking) part is in place.
Do we need the string ToHtmlString() method at all, or can this be a marker interface, where HttpUtility just hands you back the ToString()?
Yes - it's a .NET Framework API we'd like to enable for compat reasons to simplify migration. If we don't have that method, the interface would be different and wouldn't work for compat
Is the class necessary though? ASP.NET already has Microsoft.AspNetCore.Html.HtmlString... can it just implement IHtmlString if added?
It's not as necessary as the interface. As @CZEMacLeod mentioned, that's something we could put in the System.Web Adapters project or people could probably define it themselves. The goal of adding this is purely to simplify the challenges people have with migration without requiring them to bring in a whole new stack (ASP.NET Core) to potentially low levels of their project and then figure out how to keep support framework and core. This is the only API we've been trying to enable for users that has requirements in existing BCL types - everything else is just in the Microsoft.AspNetCore.SystemWebAdapters package, which has no other dependencies and easy to add at lower levels for migration.
I don't have context on this specific request. But I can speak to the backstory of this type.
HtmlString was invented to facilitate a migration away from WebForms's old <%= ... %> syntax in favor of everybody using <%: ... %>. At the time, XSS in WebForms due to misuse of <%= ... %> was a huge problem, and we didn't have much success in getting people to write <%= HtmlEncode(...) %>. At the same time, we were also iterating on MVC's HTML helpers, which used a syntax like <%= Html.TextBox(...) %>.
We basically set a goal for ourselves that we wanted to tell people to stop using <%= ... %> entirely and to prefer <%: ... %> everywhere instead, which would significantly lower the risk of XSS attack. But then writing <%: Html.TextBox(...) %> would emit <input type="text" ... /> instead of <input type="text" ... />. So we invented the HtmlString type in .NET Framework 4.0 and plumbed it through System.Web's HtmlEncode routine, which would make calls like <%: Html.TextBox(...) %> not double-encode and would help facilitate devs committing <%: ... %> syntax to muscle memory.
Later, when Razor came along, the @... syntax was created as a more "modern" equivalent of <%: ... %>. Razor did not introduce a <%= ... %> equivalent since it was deemed too dangerous.
The type we had always intended people to use within aspnet Full Framework was the concrete HtmlString type. The IHtmlString type was only exposed out of technical necessity, because MVC at the time targeted .NET Framework 3.5 and could not take a direct dependency on .NET Framework 4.0's new HtmlString type. The interface was an implementation detail which allowed the MVC runtime to bridge this gap and perform dynamic typing and type generation.
@halter73 Are default interface implementations used in public ASP.NET Core APIs? If so, the following would enable all implementations of IHtmlContent to get a default implementation of behavior (which can be overridden by others, i.e. HtmlString for a better implementation if needed):
namespace Microsoft.AspNetCore.Html;
public interface IHtmlContent
+ : System.Web.IHtmlString
{
void WriteTo(TextWriter writer, HtmlEncoder encoder);
+ string System.Web.IHtmlString.ToHtmlString()+ {+ using var writer = new StringWriter();+ WriteTo(writer, HtmlEncoder.Default);+ return writer.ToString();+ }
}
@stephentoub is this only in-box for .NET 8? Or is there a package that supports .NET Standard for this assembly? I don't see anything obvious on NuGet, but thought I'd check.
If not, then I'll look into adding an interface of IHtmlString to dotnet/systemweb-adapters and type forward to the inbox version for .NET Framework and .NET 8+.
Activity
joperezr commentedon Apr 26, 2023
cc: @karelz do you know who the right person to look into this is?
danroth27 commentedon Apr 26, 2023
@terrajobst Thoughts on this proposal? This is to facilitate ASP.NET to ASP.NET Core migration.
stephentoub commentedon Apr 26, 2023
Porting the interface (and the extra line or two in HttpUtility to recognize it) seems reasonable.
Is the class necessary though? ASP.NET already has Microsoft.AspNetCore.Html.HtmlString... can it just implement IHtmlString if added?
CZEMacLeod commentedon Apr 27, 2023
@stephentoub @twsouthwick I think the class just makes porting code slightly easier, the interface and the realignment of the
HttpUtilitycode is the more important part.I think if the class isn't included in the runtime, it could be added to the systemweb adapters project instead and would be almost as easy to use for porting code.
It certainly might be useful, again from a porting and using the incremental approach, for
Microsoft.AspNetCore.Html.HtmlStringto also implementIHtmlStringor provide some other mechanism to enable casting from the legacy class/interface to the new class/interface, but that is outside this scope and can be addressed by the issue already open in dotnet/systemweb-adapters#205 or opened in the aspnetcore project once this (blocking) part is in place.MihaZupan commentedon Apr 27, 2023
Do we need the
string ToHtmlString()method at all, or can this be a marker interface, whereHttpUtilityjust hands you back theToString()?twsouthwick commentedon Apr 27, 2023
Yes - it's a .NET Framework API we'd like to enable for compat reasons to simplify migration. If we don't have that method, the interface would be different and wouldn't work for compat
It's not as necessary as the interface. As @CZEMacLeod mentioned, that's something we could put in the System.Web Adapters project or people could probably define it themselves. The goal of adding this is purely to simplify the challenges people have with migration without requiring them to bring in a whole new stack (ASP.NET Core) to potentially low levels of their project and then figure out how to keep support framework and core. This is the only API we've been trying to enable for users that has requirements in existing BCL types - everything else is just in the Microsoft.AspNetCore.SystemWebAdapters package, which has no other dependencies and easy to add at lower levels for migration.
2 remaining items
twsouthwick commentedon Apr 28, 2023
@stephentoub I'm fine going forward with that. Sounds like to enable the scenarios we care about, we want to:
/cc @Tratcher @mjrousos
stephentoub commentedon Apr 28, 2023
main...stephentoub:runtime:ihtmlstring
Tratcher commentedon Apr 28, 2023
@GrabYourPitchforks @Eilon who might have more context on this.
GrabYourPitchforks commentedon May 2, 2023
I don't have context on this specific request. But I can speak to the backstory of this type.
HtmlStringwas invented to facilitate a migration away from WebForms's old<%= ... %>syntax in favor of everybody using<%: ... %>. At the time, XSS in WebForms due to misuse of<%= ... %>was a huge problem, and we didn't have much success in getting people to write<%= HtmlEncode(...) %>. At the same time, we were also iterating on MVC's HTML helpers, which used a syntax like<%= Html.TextBox(...) %>.We basically set a goal for ourselves that we wanted to tell people to stop using
<%= ... %>entirely and to prefer<%: ... %>everywhere instead, which would significantly lower the risk of XSS attack. But then writing<%: Html.TextBox(...) %>would emit<input type="text" ... />instead of<input type="text" ... />. So we invented theHtmlStringtype in .NET Framework 4.0 and plumbed it through System.Web'sHtmlEncoderoutine, which would make calls like<%: Html.TextBox(...) %>not double-encode and would help facilitate devs committing<%: ... %>syntax to muscle memory.Later, when Razor came along, the
@...syntax was created as a more "modern" equivalent of<%: ... %>. Razor did not introduce a<%= ... %>equivalent since it was deemed too dangerous.The type we had always intended people to use within aspnet Full Framework was the concrete
HtmlStringtype. TheIHtmlStringtype was only exposed out of technical necessity, because MVC at the time targeted .NET Framework 3.5 and could not take a direct dependency on .NET Framework 4.0's newHtmlStringtype. The interface was an implementation detail which allowed the MVC runtime to bridge this gap and perform dynamic typing and type generation.terrajobst commentedon May 2, 2023
Video
HttpUtility.HtmlEncode(object)will need to be updatedtwsouthwick commentedon May 2, 2023
@halter73 Are default interface implementations used in public ASP.NET Core APIs? If so, the following would enable all implementations of
IHtmlContentto get a default implementation of behavior (which can be overridden by others, i.e. HtmlString for a better implementation if needed):twsouthwick commentedon May 3, 2023
@stephentoub is this only in-box for .NET 8? Or is there a package that supports .NET Standard for this assembly? I don't see anything obvious on NuGet, but thought I'd check.
If not, then I'll look into adding an interface of
IHtmlStringto dotnet/systemweb-adapters and type forward to the inbox version for .NET Framework and .NET 8+.stephentoub commentedon May 3, 2023
Correct. We don't ship a separate package with HttpUtility.