Changing the generated ASP.Net <form> id? - asp.net

In my ASP.Net page I have
<form id="MasterPageForm" runat="server">
However, whenever the markup is generated, it turns into
<form name="aspnetForm" method="post" action="SomePage.aspx..." id="aspnetForm">
Is it possible to set what the generated HTML id for the form is?

Note: you are seeing "aspnetForm" because you are using a master page.
I found your solution in this thread...
http://forums.asp.net/p/883974/929349.aspx
In short, this is what the answer is from that link:
Here's the responsible code for that error:
public override string UniqueID
{
get
{
if (this.NamingContainer == this.Page)
{
return base.UniqueID;
}
return "aspnetForm";
}
}
As you can see, when the naming container is different from the current page (something that happens when you use a master page) the UniqueID property return "aspnetForm". this property is rendered into the name attribute that is sent to the client in the form tag. so, if you really need to, you can create your own form by inheriting from htmlform and then override the UniqueID property or the Name property (this may be a better option).
An example custom HtmlForm class could be like this:
public class Form : System.Web.UI.HtmlControls.HtmlForm
{
public Form() : base() { }
public override string UniqueID
{
get {
if (this.NamingContainer == this.Page)
{ return base.UniqueID; }
return "f";
}
}
}
Note: You can certainly change the name of the form from "f" to something else, or have it read a dynamic value, say from a web.config file or so.
and used like so
<%#Register tagprefix="LA" Namespace="Mynamespace"%>
...
<LA:form runat="server" id="frm">
...
</LA:form>

Set the "clientidmode" attribute to "static" on the form tag to prevent the framework from overriding it with "aspnetForm". This was driving me nuts for hours.

I am agree with #Sumo's comment under accepted answer and I had the same situation.
In ASP.NET 4.0, master page, if a is not given an id, the rendered html will be automatically assigned one, such as .
Otherwise, the rendered html will have its original defined id.

change in web config
<pages controlRenderingCompatibilityVersion="4.5" clientIDMode="AutoID"/>
to
<pages controlRenderingCompatibilityVersion="4.5"/>

Related

How to create shared form in ASP.NET CORE Razor Pages?

I have to create a reusable form in my page header. It should be displayed on each page. Simple input and submit button that will send a POST request.
Options that I'm aware of are partial views or view components.
I checked a documentation about view components but there is no mention that it works with forms. Only InvokeAsync method is available to initialize a view.
With partial view, it may be hard to define its page model and I don't understand where to put its POST handler.
One other option I see, somehow to place a form directly on _Layout.cshtml, but, again, it doesn't have its page model (afaik),
So what is a way to create a shared form, and where POST request should be handled?
You should use a view component, as this allows you to have a somewhat self-contained model and view interaction.
public class SharedFormViewComponent : ViewComponent
{
public Task<IViewComponentResult> InvokeAsync() =>
Task.FromResult(View(new SharedFormViewModel()));
}
Then, put your form HTML code in Views\Shared\Components\SharedForm\Default.cshtml. For your form's action, you'll need to specify a route. More on that in a sec. Then, to display your form:
#await Component.InvokeAsync("SharedForm")
Now, as you've somewhat discerned, view components can't be posted to. It's not an issue of "not supporting forms"; they're literally not part of the request pipeline, and therefore can't respond to requests such as a POST. You'll need a distinct action that will handle the POST on some controller. On your component's form tag, then:
<form asp-action="SharedFormHandlerAction" asp-controller="Foo" asp-area="" method="post">
The asp-area attribute should be provided just in case this is used in the context of different areas.
You'll also need a "return URL". This will be the URL of the current page, so that after the user successfully posts the form, they'll go back to the page they submitted it from. You can achieve that by adding a hidden input to your form:
<input type="hidden" name="returnUrl" value="#(Context.Request.Query["returnUrl"].FirstOrDefault() ?? (Context.Request.Path + Context.Request.QueryString))" />
Your handler action should then take a param like string returnUrl = null, and on success you should do:
return !string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl)
? Redirect(returnUrl)
: RedirectToAction("SomeDefaultAction");
Where things get a little tricky is in handling validation errors. Since you're posting to a different action, you can't return the previous view the user was on to show the validation errors within the from in the layout or whatever. Instead, you'll want a view specific to this handler action which will simply be your shared form. You can use the view for your view component here as a partial:
<partial name="~\Views\Shared\Components\SharedForm\Default.cshtml" />
If you want to use a PageModel, you could do so in a BasePageModel class that inherits from PageModel and that all your pages inherit from. You can use a named handler (https://www.learnrazorpages.com/razor-pages/handler-methods#named-handler-methods) in the BasePageModel class to process the form submission. Add the form directly to the Layout, which will need an #model directive for your BasePageModel type.
public class BasePageModel : PageModel
{
[BindProperty]
public string SearchString { get; set; }
public void OnPostBaseSearch()
{
// process the search
}
}

How to POST from one Page Handler to another?

I am working on a ASP.NET Core 2.0 project using Razor Pages (not MVC).
I have the following flow:
User fills out form and POSTs
This page's POST handler validates the info and returns Page() if there are issues. If not, handler saves data to database.
From here, I want the handler to POST to a different page's POST handler with the validated and saved data from Step 2.
How do I POST to another page from within a page handler? Is this the appropriate way to do this kind of thing? The reason I don't want to RedirectToPage() is because I don't want the final page in the sequence to be navigable via GET. The final page should not be accessible via a direct link but should only return on a POST.
I thought about validating/saving the data and setting a boolean "IsValid" and returning the page, checking for that IsValid, and immediately POSTing to the final page via JS. However this feels dirty.
Set the "asp-page" property of the form to your other page. Then set values in the standard way.
<form method="post" asp-page="/pathto/otherpage">
Select Example:<select name="DataForOtherPage">
Then in your controller, bind the value...
[BindProperty]
public string DataForOtherPage { get; set; }
You don't need to cross post!
If possible, you should avoid the cross-post. Do it all under the original action. The action can return a different view by specifying the view name in the View call.
If the target of the cross-post contains complicated logic that you don't want to duplicate, extract it to a common library, and call it from both actions.
For example, instead of
ActionResult Action1()
{
if (canHandleItMyself)
{
return View("View1");
}
else
{
return //Something that posts to action2
}
}
ActionResult Action2()
{
DoSomethingComplicated1();
DoSomethingComplicated2();
DoSomethingComplicated3();
DoSomethingComplicated4();
return View("View2");
}
Do something like this:
class CommonLibrary
{
static public void DoSomethingComplicated()
{
DoSomethingComplicated1();
DoSomethingComplicated2();
DoSomethingComplicated3();
DoSomethingComplicated4();
}
}
ActionResult Action1()
{
if (canHandleItMyself)
{
return View("View1");
}
else
{
CommonLibrary.DoSomethingComplicated();
return View("View2");
}
}
ActionResult Action2()
{
CommonLibrary.DoSomethingComplicated();
return View("View2");
}
If you really want to cross-post
If you insist on using a cross-post, you will have to render a page that does the post, e.g.
<HTML>
<BODY>
<IMG Src="/Images/Spinner.gif"> <!-- so the user doesn't just see a blank page -->
<FORM name="MyForm" Action="Action2" Method="Post">
<INPUT type="hidden" Name="Argument1" Value="Foo">
<INPUT type="hidden" Name="Argument2" Value="Bar">
</FORM>
<SCRIPT type="text/javascript>
document.getElementById("MyForm").submit(); //Automatically submit
</SCRIPT>
</BODY>
</HTML>

Why is my validation firing on the get request before the post in MVC3?

I have a MVC3 view that enables the user to create a couple different things. Within the parent view the forms to do so are broken up via jquery ui tabs like the following:
<div id="tabs">
<ul>
<li>New Thing 1</li>
<li>Different New Thing</li>
</ul>
<div id="tabs-1">#Html.Action("CreateNewThing", "NewThingController")</div>
<div id="tabs-2">#Html.Action("CreateDifferentThing", "DifferentThing")</div>
<div></div>
</div>
<script type="text/javascript">
$(function () {
$("#tabs").tabs();
});
</script>
Within the partial view I have:
#model NewThingViewModel
#using (Html.BeginForm("CreateNewThing", "NewThingController", FormMethod.Post, new { id = "frmCreateNewThing" }))
{
...
with input fields, a submit button, etc. This seems to work well: it renders everything and posts just fine to the right controller action method.
However I'm now wiring in the validation and I've got an issue.
In the controller it is rendering the view like so:
public ActionResult CreateNewThing(NewThingViewModel model)
{
... initializing model fields, drop downs etc.
return PartialView("CreateNewThing", model);
}
I have a seperate post method like so:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateNewThing(NewThingViewModel newThingViewModel, FormCollection collection)
{
.....
}
Sample Model:
public class NewThingViewModel
{
[Required]
[StringLength(50)]
[Display(Name = "Display Name:")]
public string DisplayName { get; set; }
}
The trouble is, when the page first comes up the fields marked as [Required] through DataAnnotations in the model are showing up red as well as the validation summary showing them invalid when the page initially shows. I.E. it's acting like it's already been posted before the user gets to enter anything on the initial load or even put anything in the text boxes.
I know the first non-post CreateNewThing is firing because I can catch it in the debugger and I know the 2nd one does not on the initial load.
What would cause my validations to fire on the Get?
Is it due to the way Html.Action works and the fact that I'm rendering partial views onto another view?
I'm using UnobtrusiveJavaScriptEnabled and ClientValidationEnabled = true in web.config.
I can't find anyone else that has run into this particular problem. Every other example just seems to work, then again I don't find an example where the view is broken into three partials contained within jquery ui tabs.
How do I fix this?
Options:
Do I need to manually manipulate the Model.IsValid as a workaround?
Use a different mechanism to render the partial views on the parent view instead of Html.Action?
Use some javascript/jquery to catch the validation and stop it?
Don't have method parameters on your GET controller action. You can initialize an empty model and pass it to the view but you dont need a model to be passed into the method
You're passing in an "empty" model (which I assume has default values set for your required properties), when you should be passing in null.

ASP.NET MVC2: modifying master css property depending on query string parameter

I am migrating a web site to a new one using ASP .NET MVC2.
In the original site, master page has code-behind to check a query string parameter value. Depending on this value, code-behind dynamically modify some CSS property to hide / display master page elements.
As MVC2 has no code-behind because we are supposed to perform everything in the controllers, how should I proceed in this case ?
I see this : asp.net mvc modifying master file from a view
It partially answers my needs but the query string processing is common to all pages. How can I move this processing in a common code section ?
Regards.
A helper method looks like a good place:
public static class HtmlHelperExtensions
{
public static string GetCss(this HtmlHelper htmlHelper)
{
// read some request parameter
// here you also have access to route data so the
// parameter could be part of your custom routes as well
var foo = htmlHelper.ViewContext.HttpContext.Request["foo"];
// based on the value of this parameter
// return the appropriate CSS class
return (foo == "bar") ? "barClass" : "fooClass";
}
}
And somewhere in your master page:
<body class="<%= Html.GetCss() %>">
Or if you are always going to apply it to the body tag only it might be more appropriate to do this in order to reduce the tag soup:
public static class HtmlHelperExtensions
{
public static MvcHtmlString StartBody(this HtmlHelper htmlHelper)
{
var body = new TagBuilder("body");
var foo = htmlHelper.ViewContext.HttpContext.Request["foo"];
var bodyClass = (foo == "bar") ? "barClass" : "fooClass";
body.AddCssClass(bodyClass);
return MvcHtmlString.Create(body.ToString(TagRenderMode.StartTag));
}
}
and in your master page at the place of the body tag:
<%= Html.StartBody() %>
I can think of two solutions to this:
Derive your controllers from one controller base and set the ViewData parameter there depending on posted Form values
Don't use ViewData at all, but simply look for the form value in the view (using HttpContext.Current)
The second method violates the MVC pattern. IMO it is still acceptable in some scenarios, for example I am using this approach to highlight the currently selected item in a navigation menu.

How do I make a custom ASP.NET control based/subclassed on an existing one?

I want to make a custom ASP.NET control that is a subclasse of System.Web.UI.WebControls.Calendar. I need it to add a few data members and set up a few event handlers in it's constructor.
Is this possible? If so How?
So far I have tried using add new item to add a default web user control and tried editing in Calendar in a few different places. None have worked so far.
Edit: it seems I'm totally missing how this stuff is supposed to work.
Does anyone known of a demo project that I can look at? Something that already exists. (Unless you are really board, don't go out and make one for me.)
Unless I'm misunderstanding the question, you can just create a new class file and inherit from Calendar. Add in the properties you need, and the event handlers you want to set up.
public class MyCalendar : System.Web.UI.WebControls.Calendar
{
public MyCalendar()
{
// set up handlers/properties
}
}
Then anywhere you'd like to add a Calendar to your pages, you can simply create a MyCalendar instead. If you need to do so in the designer, you can look at several good tutorials about how to make your inherited controls show their new properties in the designer, like this one.
In a new class file you need to inherit from System.Web.UI.WebControls.Calendar instead of System.Web.UI.UserControl.
namespace MyNamespace
{
[ToolboxData("<{0}:UserCalendar runat=\"server\" />")]
public class UserCalendar : System.Web.UI.WebControls.Calendar
{
private string property1;
public UserCalendar() { }
public string Property1 { get { return property1;} set { property1 = value; } }
}
}
Then on your .aspx page (or in another control .ascx):
<%# Register TagPrefix="userControl" namespace="MyNamespace" assembly="MyProjectAssembly" %>
<userControl:UserCalendar runat="server" ID="myCalendar" property1="some value" />
Stuff to read: Developing Custom ASP.NET Server Controls.

Resources