Skip to content

Commit 72704a4

Browse files
EditForm specifies handler via hidden field
1 parent 4a45fd8 commit 72704a4

File tree

5 files changed

+41
-60
lines changed

5 files changed

+41
-60
lines changed

src/Components/Endpoints/src/RazorComponentEndpointInvoker.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,17 +111,17 @@ private async Task<RequestValidationState> ValidateRequestAsync(IAntiforgery? an
111111
{
112112
_context.Response.StatusCode = StatusCodes.Status400BadRequest;
113113
}
114-
var formValid = TrySetFormHandler(out var handler);
114+
var formValid = TryGetFormHandler(out var handler);
115115
return new(valid && formValid, isPost, handler);
116116
}
117117

118118
return new(true, false, null);
119119
}
120120

121-
private bool TrySetFormHandler([NotNullWhen(true)] out string? handler)
121+
private bool TryGetFormHandler([NotNullWhen(true)] out string? handler)
122122
{
123123
handler = "";
124-
if (_context.Request.Query.TryGetValue("handler", out var value))
124+
if (_context.Request.Form.TryGetValue("handler", out var value))
125125
{
126126
if (value.Count != 1)
127127
{

src/Components/Web/src/Forms/EditForm.cs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -135,26 +135,20 @@ protected override void BuildRenderTree(RenderTreeBuilder builder)
135135

136136
if (BindingContext != null)
137137
{
138-
// This is clearly not right but will be removed shortly anyway
139-
var action = !string.IsNullOrEmpty(BindingContext.MappingContextId)
140-
? CombineStrings(BindingContext.MappingContextId, FormHandlerName)
141-
: !string.IsNullOrEmpty(FormHandlerName) ? TempNav!.ToBaseRelativePath(TempNav!.GetUriWithQueryParameter("handler", FormHandlerName)) : null;
142-
if (!string.IsNullOrEmpty(action))
143-
{
144-
builder.AddAttribute(1, "action", action);
145-
}
146-
138+
// TODO: Remove bindingcontext.id concept
147139
builder.AddAttribute(2, "method", "post");
148140
}
149141

150142
builder.AddMultipleAttributes(3, AdditionalAttributes);
151143
builder.AddAttribute(4, "onsubmit", _handleSubmitDelegate);
152144

145+
// In SSR cases, we register onsubmit as a named event and emit other child elements
146+
// to include the handler and antiforgery token in the post data
153147
if (BindingContext != null)
154148
{
155-
var submitEventName = CombineStrings(BindingContext.Name, FormHandlerName);
156-
builder.AddNamedEvent(5, "onsubmit", submitEventName ?? string.Empty);
157-
RenderSSRFormHandlingChildren(builder, 6);
149+
var submitEventName = CombineStrings(BindingContext.Name, FormHandlerName) ?? string.Empty;
150+
builder.AddNamedEvent(5, "onsubmit", submitEventName);
151+
RenderSSRFormHandlingChildren(builder, 6, submitEventName);
158152
}
159153

160154
builder.OpenComponent<CascadingValue<EditContext>>(7);
@@ -171,7 +165,7 @@ protected override void BuildRenderTree(RenderTreeBuilder builder)
171165
private static string? CombineStrings(string? a, string? b)
172166
=> string.IsNullOrEmpty(a) ? b : string.IsNullOrEmpty(b) ? a : $"{a}.{b}";
173167

174-
private void RenderSSRFormHandlingChildren(RenderTreeBuilder builder, int sequence)
168+
private void RenderSSRFormHandlingChildren(RenderTreeBuilder builder, int sequence, string submitEventName)
175169
{
176170
builder.OpenRegion(sequence);
177171

@@ -182,6 +176,12 @@ private void RenderSSRFormHandlingChildren(RenderTreeBuilder builder, int sequen
182176
builder.OpenComponent<AntiforgeryToken>(3);
183177
builder.CloseComponent();
184178

179+
builder.OpenElement(4, "input");
180+
builder.AddAttribute(5, "type", "hidden");
181+
builder.AddAttribute(6, "name", "handler");
182+
builder.AddAttribute(7, "value", submitEventName);
183+
builder.CloseElement();
184+
185185
builder.CloseRegion();
186186
}
187187

src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/FormWithParentBindingContextTest.cs

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ public void CanDispatchToTheDefaultForm(bool suppressEnhancedNavigation)
3535
{
3636
Url = "forms/default-form",
3737
FormCssSelector = "form",
38-
ExpectedActionValue = null,
3938
SuppressEnhancedNavigation = suppressEnhancedNavigation,
4039
};
4140
DispatchToFormCore(dispatchToForm);
@@ -50,7 +49,6 @@ public void CanBindParameterToTheDefaultForm(bool suppressEnhancedNavigation)
5049
{
5150
Url = "forms/default-form-bound-parameter",
5251
FormCssSelector = "form",
53-
ExpectedActionValue = null,
5452
InputFieldId = "Parameter",
5553
InputFieldCssSelector = "input[name=Parameter]",
5654
InputFieldValue = "stranger",
@@ -68,7 +66,7 @@ public void MultipleParametersMultipleFormsDoNotConflict(bool suppressEnhancedNa
6866
{
6967
Url = "forms/multiple-forms-bound-parameter-no-conflicts",
7068
FormCssSelector = "form[name=bind-integer]",
71-
ExpectedActionValue = "forms/multiple-forms-bound-parameter-no-conflicts?handler=bind-integer",
69+
ExpectedHandlerValue = "bind-integer",
7270
InputFieldId = "Id",
7371
InputFieldCssSelector = "form[name=bind-integer] input[name=Id]",
7472
InputFieldValue = "abc",
@@ -94,7 +92,7 @@ public void MultipleParametersMultipleFormsBindsToCorrectForm(bool suppressEnhan
9492
{
9593
Url = "forms/multiple-forms-bound-parameter-no-conflicts",
9694
FormCssSelector = "form[name=bind-guid]",
97-
ExpectedActionValue = "forms/multiple-forms-bound-parameter-no-conflicts?handler=bind-guid",
95+
ExpectedHandlerValue = "bind-guid",
9896
SubmitButtonId = "send-guid",
9997
UpdateFormAction = () =>
10098
{
@@ -121,7 +119,6 @@ public void CanBindMultipleParametersToTheDefaultForm(bool suppressEnhancedNavig
121119
{
122120
Url = "forms/default-form-bound-multiple-primitive-parameters",
123121
FormCssSelector = "form",
124-
ExpectedActionValue = null,
125122
UpdateFormAction = () =>
126123
{
127124
Browser.Exists(By.CssSelector("input[name=Parameter]")).Clear();
@@ -147,7 +144,6 @@ public void CanChangeFormParameterNames(bool suppressEnhancedNavigation)
147144
{
148145
Url = "forms/default-form-bound-multiple-primitive-parameters-changed-names",
149146
FormCssSelector = "form",
150-
ExpectedActionValue = null,
151147
UpdateFormAction = () =>
152148
{
153149
Browser.Exists(By.CssSelector("input[name=UpdatedParameter]")).Clear();
@@ -173,7 +169,6 @@ public void CanDisplayErrorsFromMultipleParametersToTheDefaultForm(bool suppress
173169
{
174170
Url = "forms/default-form-bound-multiple-primitive-parameters",
175171
FormCssSelector = "form",
176-
ExpectedActionValue = null,
177172
UpdateFormAction = () =>
178173
{
179174
Browser.Exists(By.CssSelector("input[name=Parameter]")).Clear();
@@ -211,7 +206,6 @@ public void CanHandleBindingErrorsBindParameterToTheDefaultForm(bool suppressEnh
211206
{
212207
Url = "forms/default-form-bound-primitive-parameter",
213208
FormCssSelector = "form",
214-
ExpectedActionValue = null,
215209
InputFieldId = "Parameter",
216210
InputFieldCssSelector = "input[name=Parameter]",
217211
InputFieldValue = "abc",
@@ -651,7 +645,7 @@ public void CanHandleBindingErrorsBindParameterToNamedForm(bool suppressEnhanced
651645
{
652646
Url = "forms/named-form-bound-primitive-parameter",
653647
FormCssSelector = "form[name=named-form-handler]",
654-
ExpectedActionValue = "forms/named-form-bound-primitive-parameter?handler=named-form-handler",
648+
ExpectedHandlerValue = "named-form-handler",
655649
InputFieldId = "Parameter",
656650
InputFieldCssSelector = "input[name=Parameter]",
657651
InputFieldValue = "abc",
@@ -680,7 +674,6 @@ public void CanReadFormValuesDuringOnInitialized(bool suppressEnhancedNavigation
680674
Url = "forms/default-form-with-body-on-initialized",
681675
FormCssSelector = "form",
682676
InputFieldValue = "stranger",
683-
ExpectedActionValue = null,
684677
SuppressEnhancedNavigation = suppressEnhancedNavigation,
685678
};
686679
DispatchToFormCore(dispatchToForm);
@@ -695,7 +688,7 @@ public void CanDispatchToNamedForm(bool suppressEnhancedNavigation)
695688
{
696689
Url = "forms/named-form",
697690
FormCssSelector = "form",
698-
ExpectedActionValue = "forms/named-form?handler=named-form-handler",
691+
ExpectedHandlerValue = "named-form-handler",
699692
SuppressEnhancedNavigation = suppressEnhancedNavigation,
700693
};
701694
DispatchToFormCore(dispatchToForm);
@@ -710,7 +703,7 @@ public void CanBindFormValueFromNamedFormWithBody(bool suppressEnhancedNavigatio
710703
{
711704
Url = "forms/named-form-bound-parameter",
712705
FormCssSelector = "form",
713-
ExpectedActionValue = "forms/named-form-bound-parameter?handler=named-form-handler",
706+
ExpectedHandlerValue = "named-form-handler",
714707
InputFieldId = "Parameter",
715708
InputFieldCssSelector = "input[name=Parameter]",
716709
InputFieldValue = "stranger",
@@ -728,7 +721,7 @@ public void CanDispatchToNamedFormInNestedContext(bool suppressEnhancedNavigatio
728721
{
729722
Url = "forms/nested-named-form",
730723
FormCssSelector = "form",
731-
ExpectedActionValue = "forms/nested-named-form?handler=parent-context.named-form-handler",
724+
ExpectedHandlerValue = "parent-context.named-form-handler",
732725
SuppressEnhancedNavigation = suppressEnhancedNavigation,
733726
};
734727
DispatchToFormCore(dispatchToForm);
@@ -743,7 +736,7 @@ public void CanBindFormValueFromNestedNamedFormWithBody(bool suppressEnhancedNav
743736
{
744737
Url = "forms/nested-named-form-bound-parameter",
745738
FormCssSelector = "form",
746-
ExpectedActionValue = "forms/nested-named-form-bound-parameter?handler=parent-context.named-form-handler",
739+
ExpectedHandlerValue = "parent-context.named-form-handler",
747740
InputFieldId = "Parameter",
748741
InputFieldCssSelector = "input[name=Parameter]",
749742
InputFieldValue = "stranger",
@@ -761,7 +754,6 @@ public void CanDispatchToFormDefinedInNonPageComponent(bool suppressEnhancedNavi
761754
{
762755
Url = "forms/form-defined-inside-component",
763756
FormCssSelector = "form",
764-
ExpectedActionValue = null,
765757
SuppressEnhancedNavigation = suppressEnhancedNavigation,
766758
};
767759
DispatchToFormCore(dispatchToForm);
@@ -774,7 +766,6 @@ public void CannotRenderAmbiguousForms()
774766
{
775767
Url = "forms/ambiguous-forms",
776768
FormCssSelector = "form",
777-
ExpectedActionValue = null,
778769
DispatchEvent = false,
779770
ShouldCauseInternalServerError = true,
780771
};
@@ -788,7 +779,6 @@ public void CanDispatchToFormRenderedAsynchronously()
788779
{
789780
Url = "forms/async-rendered-form",
790781
FormCssSelector = "form",
791-
ExpectedActionValue = null
792782
};
793783
DispatchToFormCore(dispatchToForm);
794784
}
@@ -800,7 +790,6 @@ public void FormThatDisappearsBeforeQuiesceDoesNotBind()
800790
{
801791
Url = "forms/disappears-before-dispatching",
802792
FormCssSelector = "form",
803-
ExpectedActionValue = null,
804793
SubmitButtonId = "test-send",
805794
ShouldCauseInternalServerError = true,
806795
};
@@ -860,7 +849,6 @@ public void FormNoAntiforgeryReturnBadRequest(bool suppressEnhancedNavigation)
860849
{
861850
Url = "forms/no-antiforgery",
862851
FormCssSelector = "form",
863-
ExpectedActionValue = null,
864852
ShouldCauseBadRequest = true,
865853
SuppressEnhancedNavigation = suppressEnhancedNavigation,
866854
};
@@ -876,7 +864,6 @@ public void FormAntiforgeryCheckDisabledOnPage(bool suppressEnhancedNavigation)
876864
{
877865
Url = "forms/disable-antiforgery-check",
878866
FormCssSelector = "form",
879-
ExpectedActionValue = null,
880867
SuppressEnhancedNavigation = suppressEnhancedNavigation,
881868
};
882869
DispatchToFormCore(dispatchToForm);
@@ -889,7 +876,6 @@ public void FormCanAddAntiforgeryAfterTheResponseHasStarted()
889876
{
890877
Url = "forms/antiforgery-after-response-started",
891878
FormCssSelector = "form",
892-
ExpectedActionValue = null,
893879
SuppressEnhancedNavigation = true,
894880
};
895881
DispatchToFormCore(dispatchToForm);
@@ -904,7 +890,6 @@ public void FormElementWithAntiforgery(bool suppressEnhancedNavigation)
904890
{
905891
Url = "forms/form-element-antiforgery",
906892
FormCssSelector = "form",
907-
ExpectedActionValue = null,
908893
SuppressEnhancedNavigation = suppressEnhancedNavigation,
909894
};
910895
DispatchToFormCore(dispatchToForm);
@@ -951,10 +936,12 @@ private void DispatchToFormCore(DispatchToForm dispatch)
951936

952937
Browser.Exists(By.Id(dispatch.Ready));
953938
var form = Browser.Exists(By.CssSelector(dispatch.FormCssSelector));
954-
var formTarget = form.GetAttribute("action");
955-
var actionValue = form.GetDomAttribute("action");
956-
Assert.Equal(dispatch.ExpectedTarget, formTarget);
957-
Assert.Equal(dispatch.ExpectedActionValue, actionValue);
939+
940+
if (dispatch.ExpectedHandlerValue != null)
941+
{
942+
var handlerInput = form.FindElement(By.CssSelector("input[type=hidden][name=handler]"));
943+
Assert.Equal(dispatch.ExpectedHandlerValue, handlerInput.GetAttribute("value"));
944+
}
958945

959946
if (!dispatch.DispatchEvent)
960947
{
@@ -1023,7 +1010,7 @@ private void DispatchToFormCore(DispatchToForm dispatch)
10231010
{
10241011
// Verify the same form element is still in the page
10251012
// We wouldn't be allowed to read the attribute if the element is stale
1026-
Assert.Equal(dispatch.ExpectedTarget, form.GetAttribute("action"));
1013+
Assert.Equal("post", form.GetAttribute("method"));
10271014
}
10281015
}
10291016
}
@@ -1040,11 +1027,9 @@ public DispatchToForm(FormWithParentBindingContextTest test) : this()
10401027
public string SubmitPassId = "pass";
10411028
public string Ready = "ready";
10421029
public string FormCssSelector;
1043-
public string ExpectedActionValue;
1030+
public string ExpectedHandlerValue;
10441031
public string InputFieldValue;
10451032

1046-
public string ExpectedTarget => $"{Base}/{ExpectedActionValue ?? Url}";
1047-
10481033
public bool DispatchEvent { get; internal set; } = true;
10491034

10501035
public string SubmitButtonId { get; internal set; } = "send";

src/Components/test/E2ETest/ServerRenderingTests/FormHandlingTests/NamedFormNoParentBindingContextTest.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,7 @@ public void CanDispatchToNamedFormNoParentBindingContext()
3232
Browser.Exists(By.Id("ready"));
3333

3434
var form = Browser.Exists(By.CssSelector("form"));
35-
var formTarget = form.GetAttribute("action");
36-
var actionValue = form.GetDomAttribute("action");
37-
var baseUri = new Uri(_serverFixture.RootUri, ServerPathBase).ToString();
38-
39-
Assert.Equal($"{baseUri}/?handler=named-form-handler", formTarget);
40-
Assert.Equal("?handler=named-form-handler", actionValue);
35+
Browser.Equal("named-form-handler", () => form.FindElement(By.CssSelector("input[name=handler]")).GetAttribute("value"));
4136

4237
Browser.Click(By.Id("send"));
4338
Browser.Exists(By.Id("pass"));

src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/Forms/ActionForm.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,20 @@ void RenderFormContents(RenderTreeBuilder builder, FormMappingContext? bindingCo
4747
{
4848
builder.OpenElement(0, "form");
4949
builder.AddAttribute(1, "name", bindingContext.Name);
50-
51-
if (!string.IsNullOrEmpty(bindingContext?.MappingContextId))
52-
{
53-
builder.AddAttribute(2, "action", bindingContext.MappingContextId);
54-
}
55-
56-
builder.AddAttribute(3, "method", "POST");
57-
builder.AddAttribute(4, "onsubmit", async () => await OnSubmit.InvokeAsync(bindingContext));
50+
builder.AddAttribute(6, "method", "POST");
51+
builder.AddAttribute(7, "onsubmit", async () => await OnSubmit.InvokeAsync(bindingContext));
5852

5953
if (bindingContext != null)
6054
{
6155
builder.AddNamedEvent(5, "onsubmit", bindingContext.Name);
56+
57+
builder.OpenElement(2, "input");
58+
builder.AddAttribute(3, "type", "hidden");
59+
builder.AddAttribute(4, "name", "handler");
60+
builder.AddAttribute(5, "value", bindingContext.Name);
61+
builder.CloseElement();
6262
}
63+
6364
builder.AddContent(6, ChildContent?.Invoke(bindingContext));
6465

6566
builder.CloseElement();

0 commit comments

Comments
 (0)