diff --git a/.squad/agents/jubilee/history.md b/.squad/agents/jubilee/history.md
index e3273590..c629f92b 100644
--- a/.squad/agents/jubilee/history.md
+++ b/.squad/agents/jubilee/history.md
@@ -473,3 +473,16 @@ This wave establishes **documentation patterns** that will guide future control
- **Page uses `@inject ClientScriptShim ClientScript`** — injected as scoped service. Calls `FlushAsync(JS)` in `OnAfterRenderAsync` since the page doesn't inherit BaseWebFormsComponent.
- **Pattern:** Source code section at bottom showing complete `@code` block with escaped `@@` directives for display. Follows established migration demo conventions.
- **Build verified:** 0 errors, pre-existing BL0005 warnings only.
+
+### PostBack & ScriptManager Demo Page (ClientScript Phase 2)
+
+- **Created** `samples/AfterBlazorServerSide/Components/Pages/ControlSamples/PostBackDemo/Index.razor` — three-section demo page for Phase 2 ClientScript postback shims.
+- **Section 1: GetPostBackEventReference** — button with `onclick="@_postBackScript"` fires `__doPostBack` from JS. PostBack event on WebFormsPageBase receives it server-side. Stable IDs: `postback-button`, `postback-script`, `postback-result`.
+- **Section 2: GetPostBackClientHyperlink** — anchor `href="@_postBackHyperlink"` triggers postback via `javascript:__doPostBack(...)` URL. Stable IDs: `postback-link`, `hyperlink-script`, `hyperlink-result`.
+- **Section 3: ScriptManager.GetCurrent** — uses `ScriptManagerShim.GetCurrent(this)` to register startup script that writes into `#scriptmanager-target`. Same Web Forms code pattern.
+- **Source Code section** at bottom with escaped `@@` directives.
+- **Inherits WebFormsPageBase** (not `@inject`) — gives access to `ClientScript`, `PostBack` event, and `ScriptManagerShim.GetCurrent(this)`. This differs from the ClientScriptShim demo which uses `@inject`.
+- **Updated** `ComponentCatalog.cs` — added "PostBack Demo" entry in "Migration Helpers" category after "IsPostBack".
+- **Updated** `ComponentList.razor` — added PostBack & ScriptManager link in Migration Helpers section.
+- **Build verified:** 0 errors, pre-existing BL0005 warnings only.
+- **Lesson:** Pages that need the PostBack event must `@inherits WebFormsPageBase`. The ClientScript property is available via inheritance (no separate `@inject` needed). `OnAfterRenderAsync` in WebFormsPageBase handles `FlushAsync` automatically.
diff --git a/docs/Analyzers/BWFC022.md b/docs/Analyzers/BWFC022.md
index 17118ca7..3704ca9a 100644
--- a/docs/Analyzers/BWFC022.md
+++ b/docs/Analyzers/BWFC022.md
@@ -78,7 +78,7 @@ If you prefer to modernize your code now, rewrite to `IJSRuntime` directly. The
| `RegisterStartupScript()` | `ClientScriptShim` (⭐ Easy) or `OnAfterRenderAsync()` + `IJSRuntime` (⭐⭐ Moderate) | ⭐ Easy |
| `RegisterClientScriptInclude()` | `ClientScriptShim` (⭐ Easy) or `", true);
+
+ clientScript.IsStartupScriptRegistered(typeof(ScriptManagerShimTests), "tagged").ShouldBeTrue();
+ }
+
+ #endregion
+
+ #region Delegation — RegisterClientScriptBlock
+
+ [Fact]
+ public void RegisterClientScriptBlock_DelegatesToClientScript()
+ {
+ var clientScript = CreateClientScriptShim();
+ var sm = new ScriptManagerShim(clientScript);
+
+ sm.RegisterClientScriptBlock(typeof(ScriptManagerShimTests), "block1", "var x = 1;", false);
+
+ clientScript.IsClientScriptBlockRegistered(typeof(ScriptManagerShimTests), "block1").ShouldBeTrue();
+ }
+
+ #endregion
+
+ #region Delegation — RegisterClientScriptInclude
+
+ [Fact]
+ public void RegisterClientScriptInclude_DelegatesToClientScript()
+ {
+ var clientScript = CreateClientScriptShim();
+ var sm = new ScriptManagerShim(clientScript);
+
+ sm.RegisterClientScriptInclude(typeof(ScriptManagerShimTests), "inc1", "https://cdn.example.com/lib.js");
+
+ clientScript.IsClientScriptIncludeRegistered("inc1").ShouldBeTrue();
+ }
+
+ #endregion
+}
diff --git a/src/BlazorWebFormsComponents/ClientScriptShim.cs b/src/BlazorWebFormsComponents/ClientScriptShim.cs
index df05bead..da4530b6 100644
--- a/src/BlazorWebFormsComponents/ClientScriptShim.cs
+++ b/src/BlazorWebFormsComponents/ClientScriptShim.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Logging;
using Microsoft.JSInterop;
@@ -192,45 +193,46 @@ public async Task FlushAsync(IJSRuntime jsRuntime)
_scriptIncludes.Clear();
}
- // ─── Unsupported Methods ───────────────────────────────────────────
+ // ─── PostBack / Callback Methods ──────────────────────────────────
///
- /// Not supported in Blazor. Throws
- /// with migration guidance.
+ /// Returns a JavaScript string that triggers a postback, mirroring the
+ /// Web Forms ClientScriptManager.GetPostBackEventReference behavior.
+ /// The returned string calls __doPostBack(eventTarget, eventArgument),
+ /// which is defined in bwfc-postback.js.
///
- /// Always thrown.
+ /// The control initiating the postback (used to resolve an ID).
+ /// The event argument string.
+ /// A JavaScript expression string, e.g. __doPostBack('Button1', '').
public string GetPostBackEventReference(object control, string argument)
{
- throw new NotSupportedException(
- "GetPostBackEventReference is not supported in Blazor. " +
- "Use @onclick / EventCallback instead. " +
- "See: docs/Migration/ClientScriptMigrationGuide.md");
+ var id = ResolveControlId(control);
+ return $"__doPostBack('{EscapeJsString(id)}', '{EscapeJsString(argument ?? string.Empty)}')";
}
///
- /// Not supported in Blazor. Throws
- /// with migration guidance.
+ /// Returns a javascript: URL that triggers a postback, mirroring
+ /// ClientScriptManager.GetPostBackClientHyperlink.
///
- /// Always thrown.
+ /// The control initiating the postback.
+ /// The event argument string.
+ /// A javascript:__doPostBack(...) URL string.
public string GetPostBackClientHyperlink(object control, string argument)
{
- throw new NotSupportedException(
- "GetPostBackClientHyperlink is not supported in Blazor. " +
- "Use NavigationManager or instead. " +
- "See: docs/Migration/ClientScriptMigrationGuide.md");
+ return $"javascript:{GetPostBackEventReference(control, argument)}";
}
///
- /// Not supported in Blazor. Throws
- /// with migration guidance.
+ /// Returns a JavaScript expression that invokes the BWFC callback bridge,
+ /// mirroring ClientScriptManager.GetCallbackEventReference.
+ /// The returned expression calls __bwfc_callback defined in
+ /// bwfc-postback.js.
///
- /// Always thrown.
- public string GetCallbackEventReference(object control, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync)
+ public string GetCallbackEventReference(object control, string argument,
+ string clientCallback, string context, string clientErrorCallback, bool useAsync)
{
- throw new NotSupportedException(
- "GetCallbackEventReference is not supported in Blazor. " +
- "Use IJSRuntime / EventCallback for JS-to-.NET interop. " +
- "See: docs/Migration/ClientScriptMigrationGuide.md");
+ var id = ResolveControlId(control);
+ return $"__bwfc_callback('{EscapeJsString(id)}', '{EscapeJsString(argument ?? string.Empty)}', {clientCallback ?? "null"}, '{EscapeJsString(context ?? string.Empty)}', {clientErrorCallback ?? "null"})";
}
// ─── Helpers ───────────────────────────────────────────────────────
@@ -250,4 +252,18 @@ private static string EscapeJsString(string value)
{
return value.Replace("\\", "\\\\").Replace("'", "\\'");
}
+
+ ///
+ /// Resolves a control reference to an ID string suitable for use in
+ /// JavaScript postback/callback expressions.
+ /// Prefers when available.
+ ///
+ private static string ResolveControlId(object control)
+ {
+ if (control is BaseWebFormsComponent bwfc && !string.IsNullOrEmpty(bwfc.ID))
+ return bwfc.ID;
+ if (control is ComponentBase)
+ return control.GetType().Name;
+ return control?.GetType().Name ?? "unknown";
+ }
}
diff --git a/src/BlazorWebFormsComponents/PostBackEventArgs.cs b/src/BlazorWebFormsComponents/PostBackEventArgs.cs
new file mode 100644
index 00000000..44e06056
--- /dev/null
+++ b/src/BlazorWebFormsComponents/PostBackEventArgs.cs
@@ -0,0 +1,23 @@
+using System;
+
+namespace BlazorWebFormsComponents;
+
+///
+/// Event arguments for postback events, mirroring the Web Forms postback model.
+/// Contains the (control ID) and
+/// that were passed to __doPostBack(eventTarget, eventArgument).
+///
+public class PostBackEventArgs : EventArgs
+{
+ /// The ID of the control that initiated the postback.
+ public string EventTarget { get; }
+
+ /// The argument string associated with the postback.
+ public string EventArgument { get; }
+
+ public PostBackEventArgs(string eventTarget, string eventArgument)
+ {
+ EventTarget = eventTarget;
+ EventArgument = eventArgument;
+ }
+}
diff --git a/src/BlazorWebFormsComponents/ScriptManagerShim.cs b/src/BlazorWebFormsComponents/ScriptManagerShim.cs
new file mode 100644
index 00000000..2b1bea41
--- /dev/null
+++ b/src/BlazorWebFormsComponents/ScriptManagerShim.cs
@@ -0,0 +1,66 @@
+using System;
+
+namespace BlazorWebFormsComponents;
+
+///
+/// Compatibility shim for System.Web.UI.ScriptManager.
+/// Provides the static factory method that Web Forms
+/// code uses to obtain a ScriptManager instance from the page, and
+/// delegates all RegisterXxx calls to .
+///
+public class ScriptManagerShim
+{
+ private readonly ClientScriptShim _clientScript;
+
+ ///
+ /// Initializes a new instance backed by the specified .
+ ///
+ public ScriptManagerShim(ClientScriptShim clientScript)
+ {
+ _clientScript = clientScript ?? throw new ArgumentNullException(nameof(clientScript));
+ }
+
+ ///
+ /// Static factory matching the Web Forms ScriptManager.GetCurrent(Page) pattern.
+ /// Resolves the from the page/component instance.
+ ///
+ ///
+ /// A or instance.
+ ///
+ /// A wrapping the component's ClientScript.
+ ///
+ /// Thrown when is not a recognized BWFC type or has no ClientScript.
+ ///
+ public static ScriptManagerShim GetCurrent(object page)
+ {
+ if (page is BaseWebFormsComponent component && component.ClientScript != null)
+ return new ScriptManagerShim(component.ClientScript);
+ if (page is WebFormsPageBase pageBase && pageBase.ClientScript != null)
+ return new ScriptManagerShim(pageBase.ClientScript);
+
+ throw new InvalidOperationException(
+ "ScriptManager.GetCurrent() requires a component derived from " +
+ "BaseWebFormsComponent or WebFormsPageBase with a registered ClientScriptShim.");
+ }
+
+ // ─── Delegated Registration Methods ───────────────────────────────
+
+ ///
+ public void RegisterStartupScript(Type type, string key, string script, bool addScriptTags)
+ => _clientScript.RegisterStartupScript(type, key, script, addScriptTags);
+
+ ///
+ /// Overload accepting a control reference (ignored) to match the Web Forms
+ /// ScriptManager.RegisterStartupScript(Control, Type, String, String, Boolean) signature.
+ ///
+ public void RegisterStartupScript(object control, Type type, string key, string script, bool addScriptTags)
+ => _clientScript.RegisterStartupScript(type, key, script, addScriptTags);
+
+ ///
+ public void RegisterClientScriptBlock(Type type, string key, string script, bool addScriptTags)
+ => _clientScript.RegisterClientScriptBlock(type, key, script, addScriptTags);
+
+ ///
+ public void RegisterClientScriptInclude(Type type, string key, string url)
+ => _clientScript.RegisterClientScriptInclude(type, key, url);
+}
diff --git a/src/BlazorWebFormsComponents/ServiceCollectionExtensions.cs b/src/BlazorWebFormsComponents/ServiceCollectionExtensions.cs
index 32c760f3..fe57087f 100644
--- a/src/BlazorWebFormsComponents/ServiceCollectionExtensions.cs
+++ b/src/BlazorWebFormsComponents/ServiceCollectionExtensions.cs
@@ -43,6 +43,7 @@ public static IServiceCollection AddBlazorWebFormsComponents(this IServiceCollec
services.AddScoped();
services.AddScoped();
services.AddScoped();
+ services.AddScoped(sp => new ScriptManagerShim(sp.GetRequiredService()));
var options = new BlazorWebFormsComponentsOptions();
configure?.Invoke(options);
diff --git a/src/BlazorWebFormsComponents/WebFormsPageBase.cs b/src/BlazorWebFormsComponents/WebFormsPageBase.cs
index 1cbd00e7..894555e9 100644
--- a/src/BlazorWebFormsComponents/WebFormsPageBase.cs
+++ b/src/BlazorWebFormsComponents/WebFormsPageBase.cs
@@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
+using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Logging;
+using Microsoft.JSInterop;
namespace BlazorWebFormsComponents;
@@ -12,10 +14,10 @@ namespace BlazorWebFormsComponents;
/// Base class for converted ASP.NET Web Forms pages. Provides Page.Title,
/// Page.MetaDescription, Page.MetaKeywords, IsPostBack, Response.Redirect,
/// Response.Cookies, Request.Cookies, Request.QueryString, Request.Url,
-/// ViewState, and GetRouteUrl compatibility so that Web Forms code-behind
-/// patterns survive migration with minimal changes.
+/// ViewState, GetRouteUrl, ClientScript, and PostBack compatibility so that
+/// Web Forms code-behind patterns survive migration with minimal changes.
///
-public abstract class WebFormsPageBase : ComponentBase
+public abstract class WebFormsPageBase : ComponentBase, IAsyncDisposable
{
[Inject] private IPageService _pageService { get; set; } = null!;
[Inject] private NavigationManager _navigationManager { get; set; } = null!;
@@ -25,6 +27,25 @@ public abstract class WebFormsPageBase : ComponentBase
[Inject] private SessionShim _sessionShim { get; set; } = null!;
[Inject] private IWebHostEnvironment _webHostEnvironment { get; set; } = null!;
[Inject] private CacheShim _cacheShim { get; set; } = null!;
+[Inject] private IJSRuntime _jsRuntime { get; set; } = null!;
+[Inject] private ClientScriptShim _clientScriptShim { get; set; } = null!;
+
+///
+/// Provides access to client script registration methods, emulating
+/// Page.ClientScript from ASP.NET Web Forms.
+///
+public ClientScriptShim ClientScript => _clientScriptShim;
+
+// ─── PostBack Support ─────────────────────────────────────────────
+
+private DotNetObjectReference? _postBackRef;
+private string? _postBackTargetId;
+
+///
+/// Raised when a postback is triggered from JavaScript via __doPostBack().
+/// Subscribe to this event in derived pages to handle postback actions.
+///
+public event EventHandler? PostBack;
///
/// Provides dictionary-style Session["key"] access, emulating
@@ -237,4 +258,105 @@ private void RequireHttpContext(string memberName)
$"rendering (WebSocket mode). Use {nameof(IsHttpContextAvailable)} to guard " +
$"calls to this member, or ensure the page runs in SSR mode.");
}
+
+// ─── PostBack JS Interop ──────────────────────────────────────────
+
+// Inline bootstrap ensures __doPostBack and registration functions exist
+// before any postback target is registered. The standalone bwfc-postback.js
+// file is also available for manual ");
@@ -50,7 +49,7 @@ protected override async Task OnInitializedAsync()
ClientScript.RegisterStartupScript(this.GetType(), "smScript", "alert('hello');", true);
// Pattern 6: ScriptManager.GetCurrent
- // TODO(bwfc-general): ScriptManager.GetCurrent() has no Blazor equivalent. Use IJSRuntime directly.
+ var sm = ScriptManager.GetCurrent(this);
}
}
}
diff --git a/tests/BlazorWebFormsComponents.Cli.Tests/TransformUnit/ClientScriptTransformTests.cs b/tests/BlazorWebFormsComponents.Cli.Tests/TransformUnit/ClientScriptTransformTests.cs
index 2809dd47..cb3ac137 100644
--- a/tests/BlazorWebFormsComponents.Cli.Tests/TransformUnit/ClientScriptTransformTests.cs
+++ b/tests/BlazorWebFormsComponents.Cli.Tests/TransformUnit/ClientScriptTransformTests.cs
@@ -229,10 +229,10 @@ void Page_Load()
#endregion
- #region TC38 — GetPostBackEventReference and ScriptManager.GetCurrent
+ #region TC38 — GetPostBackEventReference and ScriptManager.GetCurrent (Phase 2: shim-preserving)
[Fact]
- public void TC38_GetPostBackEventReference_EmitsTodoWithEventCallbackGuidance()
+ public void TC38_GetPostBackEventReference_StripsPagePrefix()
{
var input = @"namespace MyApp
{
@@ -246,13 +246,14 @@ void DoWork()
}";
var result = _transform.Apply(input, TestMetadata(input));
- Assert.Contains("TODO(bwfc-general)", result);
- Assert.Contains("@onclick", result);
- Assert.Contains("EventCallback", result);
+ Assert.Contains("ClientScript.GetPostBackEventReference(btnSubmit", result);
+ Assert.DoesNotContain("Page.ClientScript", result);
+ Assert.DoesNotContain("// TODO(bwfc-general): Replace __doPostBack", result);
+ Assert.DoesNotContain("// Original:", result);
}
[Fact]
- public void TC38_GetPostBackEventReference_PreservesOriginalAsComment()
+ public void TC38_GetPostBackEventReference_StripsThisPrefix()
{
var input = @"namespace MyApp
{
@@ -260,18 +261,38 @@ public partial class MyPage
{
void DoWork()
{
- var postbackRef = Page.ClientScript.GetPostBackEventReference(btnSubmit, ""validate"");
+ var postbackRef = this.ClientScript.GetPostBackEventReference(btnSubmit, ""validate"");
}
}
}";
var result = _transform.Apply(input, TestMetadata(input));
- Assert.Contains("// Original:", result);
- Assert.Contains("GetPostBackEventReference", result);
+ Assert.Contains("ClientScript.GetPostBackEventReference(btnSubmit", result);
+ Assert.DoesNotContain("this.ClientScript", result);
+ Assert.DoesNotContain("// Original:", result);
}
[Fact]
- public void TC38_ScriptManagerGetCurrent_EmitsTodo()
+ public void TC38_GetPostBackEventReference_BareCall_SetsShimFlag()
+ {
+ var input = @"namespace MyApp
+{
+ public partial class MyPage
+ {
+ void DoWork()
+ {
+ var postbackRef = ClientScript.GetPostBackEventReference(btnSubmit, ""validate"");
+ }
+ }
+}";
+ var result = _transform.Apply(input, TestMetadata(input));
+
+ Assert.Contains("ClientScript.GetPostBackEventReference(btnSubmit", result);
+ Assert.Contains("ClientScriptShim", result);
+ }
+
+ [Fact]
+ public void TC38_ScriptManagerGetCurrent_ConvertsPageToThis()
{
var input = @"namespace MyApp
{
@@ -285,13 +306,32 @@ void Page_Load()
}";
var result = _transform.Apply(input, TestMetadata(input));
- Assert.Contains("TODO(bwfc-general)", result);
- Assert.Contains("ScriptManager.GetCurrent()", result);
- Assert.Contains("IJSRuntime", result);
+ Assert.Contains("ScriptManager.GetCurrent(this)", result);
+ Assert.DoesNotContain("ScriptManager.GetCurrent(Page)", result);
+ Assert.DoesNotContain("ScriptManager.GetCurrent() has no Blazor equivalent", result);
+ }
+
+ [Fact]
+ public void TC38_ScriptManagerGetCurrent_WithThisDotPage_ConvertsToThis()
+ {
+ var input = @"namespace MyApp
+{
+ public partial class MyPage
+ {
+ void Page_Load()
+ {
+ var sm = ScriptManager.GetCurrent(this.Page);
+ }
+ }
+}";
+ var result = _transform.Apply(input, TestMetadata(input));
+
+ Assert.Contains("ScriptManager.GetCurrent(this)", result);
+ Assert.DoesNotContain("this.Page", result);
}
[Fact]
- public void TC38_ScriptManagerGetCurrent_WithThis_EmitsTodo()
+ public void TC38_ScriptManagerGetCurrent_PreservesThis()
{
var input = @"namespace MyApp
{
@@ -305,8 +345,49 @@ void Page_Load()
}";
var result = _transform.Apply(input, TestMetadata(input));
- Assert.Contains("TODO(bwfc-general)", result);
- Assert.Contains("ScriptManager.GetCurrent()", result);
+ Assert.Contains("ScriptManager.GetCurrent(this)", result);
+ Assert.DoesNotContain("ScriptManager.GetCurrent() has no Blazor equivalent", result);
+ Assert.Contains("ScriptManagerShim", result);
+ }
+
+ [Fact]
+ public void TC38_ScriptManagerGetCurrent_AddsScriptManagerShimComment()
+ {
+ var input = @"namespace MyApp
+{
+ public partial class MyPage
+ {
+ void Page_Load()
+ {
+ var sm = ScriptManager.GetCurrent(Page);
+ }
+ }
+}";
+ var result = _transform.Apply(input, TestMetadata(input));
+
+ Assert.Contains("ScriptManagerShim", result);
+ Assert.Contains("ClientScriptShim", result);
+ }
+
+ [Fact]
+ public void TC38_ScriptManagerGetCurrent_FullPattern_Preserved()
+ {
+ var input = @"namespace MyApp
+{
+ public partial class MyPage
+ {
+ void Page_Load()
+ {
+ ScriptManager sm = ScriptManager.GetCurrent(Page);
+ sm.RegisterStartupScript(this.GetType(), ""key"", ""script"", true);
+ }
+ }
+}";
+ var result = _transform.Apply(input, TestMetadata(input));
+
+ Assert.Contains("ScriptManager sm = ScriptManager.GetCurrent(this)", result);
+ Assert.Contains("sm.RegisterStartupScript(this.GetType()", result);
+ Assert.Contains("ScriptManagerShim", result);
}
#endregion
@@ -342,10 +423,12 @@ void Page_Load()
Assert.Contains("ClientScript.RegisterClientScriptBlock", result);
// ScriptManager.RegisterStartupScript → ClientScript.RegisterStartupScript
Assert.DoesNotContain("ScriptManager.RegisterStartupScript", result);
- // Postback → TODO with EventCallback
- Assert.Contains("@onclick", result);
- // ScriptManager.GetCurrent → TODO
- Assert.Contains("ScriptManager.GetCurrent() has no Blazor equivalent", result);
+ // Postback → preserved with prefix stripped
+ Assert.Contains("ClientScript.GetPostBackEventReference", result);
+ Assert.DoesNotContain("Page.ClientScript.GetPostBackEventReference", result);
+ // ScriptManager.GetCurrent → Page replaced with this
+ Assert.Contains("ScriptManager.GetCurrent(this)", result);
+ Assert.DoesNotContain("ScriptManager.GetCurrent(Page)", result);
// ClientScriptShim comment injected (not IJSRuntime)
Assert.Contains("ClientScriptShim", result);
Assert.DoesNotContain("[Inject] private IJSRuntime JS", result);
@@ -367,7 +450,7 @@ public partial class MyPage
}
[Fact]
- public void DoesNotAddShimComment_WhenOnlyPostbackRef()
+ public void AddsShimComment_WhenOnlyPostbackRef()
{
var input = @"namespace MyApp
{
@@ -381,7 +464,7 @@ void DoWork()
}";
var result = _transform.Apply(input, TestMetadata(input));
- Assert.DoesNotContain("ClientScriptShim", result);
+ Assert.Contains("ClientScriptShim", result);
}
[Fact]