5

I have a form as

<form id="form" action="" method="post" runat="server">

When accessing in C# code-behind via

HtmlForm form = (HtmlForm)this.FindControl("form");

and attempting to change the action with

form.Attributes.Add("action","./newpage.aspx?data=data");

or

form.Attributes["action"] = "./newpage.aspx?data=data");

no change is made. The form still routes to the same page. How can I dynamically change the form's action in codebehind?

EXTRA DETAILS: I have a page that has a get variable. That get variable needs to be sent in the action portion of the form. So, page1 response has getvar1. The form on page1 needs to send its post data and getvar1. I was going to adjust this via code-behind in the action of the form, but wanted to avoid using InnerHtml to write the whole form. Holly suggested javascript, but I haven't found a good way of getting GET vars with javascript. ..... just more information for the masses.

ANSWER EXPLANATION: I chose to go the route that @HollyStyles mentioned. I used javascript to change the form action after the ajax call completed. However, the answer marked correct is the right way to do this via code-behind.

steventnorris
  • 5,656
  • 23
  • 93
  • 174
  • Are you trying to have a *nested* HTML form? Have you looked at cross page posting? http://msdn.microsoft.com/en-us/library/ms178139(v=vs.100).aspx – aquinas Sep 24 '12 at 15:14
  • @aquinas Nope. Just a regular old form. The whole page is just a div with a form in it that I ajax into a little popup. – steventnorris Sep 24 '12 at 15:15
  • 1
    Just use a normal html page instead of an aspx, as you are ajaxing into a pop-up anyway, set the action at that point with javascript. – hollystyles Sep 24 '12 at 15:38
  • @HollyStyles Good point. Only issue is I have no way of getting a GET variable accurately with javascript. See added info above as to why I need that. I didn't think it pertinent, but now that you mention javascript.... – steventnorris Sep 24 '12 at 15:42

6 Answers6

5

You can use the Control Adapters of asp.net.

Here is a working example:

public class RewriteFormHtmlTextWriter : HtmlTextWriter
{
    public RewriteFormHtmlTextWriter(HtmlTextWriter writer)
        : base(writer)
    {
        this.InnerWriter = writer.InnerWriter;
    }
    public RewriteFormHtmlTextWriter(System.IO.TextWriter writer)
        : base(writer)
    {
        base.InnerWriter = writer;
    }

    public override void WriteAttribute(string name, string value, bool fEncode)
    {
        if (name == "action")
        {
            value = "Change here your value"            
        }

        base.WriteAttribute(name, value, fEncode);
    }
}

With the above code, and a declare on the App_Browsers with a file called Form.browser

<browsers>
  <browser refID="Default">
    <controlAdapters>
      <adapter controlType="System.Web.UI.HtmlControls.HtmlForm" adapterType="FormRewriterControlAdapter" />
    </controlAdapters>
  </browser>
</browsers>

you can change the form. Of course this code called in every form render.

Relative : http://weblogs.asp.net/scottgu/archive/2007/02/26/tip-trick-url-rewriting-with-asp-net.aspx

Aristos
  • 66,005
  • 16
  • 114
  • 150
  • I read up a little on Control Adapters. It seems they work fine for full renderings, creating a control completely on each render, but is there any way to just adjust a single attribute of a control without having to write all of it's render code, specifically the form action? I'd hate to have to write rendering code for a form just to change one small attribute. – steventnorris Sep 24 '12 at 15:36
  • Further research yields my own answer, nope use a control adapter. See post http://stackoverflow.com/questions/629488/how-to-change-action-attribute-of-the-aspnetform-on-masterpage-dynamically – steventnorris Sep 24 '12 at 15:48
  • @steventnorris I do not know what to tell you because actually I am not have the full image of what you try to do. Maybe you do not even need to change the form action. Anyway I just give you an idea hear. – Aristos Sep 24 '12 at 16:32
  • I couldn't get this code to work, but I found another on code project that went into a little more detail, link below – Terry Kernan Sep 13 '13 at 11:46
  • @TerryKernan I do not know why and what is fail to you, but I have the same code on my project many years now and work. – Aristos Sep 13 '13 at 16:50
1

You can change the form action like this:

protected void Page_Init(object sender, EventArgs e)
{
    Form.Attributes.Add("action", "/Registration/Signup.aspx");
}
Marcel
  • 7,909
  • 5
  • 22
  • 25
0

There is a class that I found in a KB article that helps achieve this, however, the article has been deleted it seems (originally here: http://www.codeproject.com/Articles/23033/Change-your-ASP-NET-Form-s-Action-attribute-with-R).

What follows is the class mentioned in that article. Basically if you use the following class and call the static SetFormAction(string url) method on it, you'll be able to set the <form action="url" /> attribute.

using System.IO;
using System.Text.RegularExpressions;
using System.Web;

/// 
/// The purpose of this class is to easily modify the form "action" of a given asp.net page.
/// To modify the action, call the following code in the code-behind of your page (or, better, your MasterPage):
/// Copied (and modified) from http://www.codeproject.com/KB/aspnet/ASP_Net_Form_Action_Attr.aspx
/// 
public class FormActionModifier : Stream
{
  private const string FORM_REGEX = "(]*>)";
  private Stream _sink;
  private long _position;
  string _url;
  public FormActionModifier(Stream sink, string url)
  {
    _sink = sink;
    _url = string.Format("$1{0}$3", url);
  }

  public override bool CanRead
  {
    get { return true; }
  }

  public override bool CanSeek
  {
    get { return true; }
  }

  public override bool CanWrite
  {
    get { return true; }
  }

  public override long Length
  {
    get { return 0; }
  }

  public override long Position
  {
    get { return _position; }
    set { _position = value; }
  }

  public override long Seek(long offset, System.IO.SeekOrigin direction)
  {
    return _sink.Seek(offset, direction);
  }

  public override void SetLength(long length)
  {
    _sink.SetLength(length);
  }

  public override void Close()
  {
    _sink.Close();
  }

  public override void Flush()
  {
    _sink.Flush();
  }

  public override int Read(byte[] buffer, int offset, int count)
  {
    return _sink.Read(buffer, offset, count);
  }

  public override void Write(byte[] buffer, int offset, int count)
  {
    string s = System.Text.UTF8Encoding.UTF8.GetString(buffer, offset, count);
    Regex reg = new Regex(FORM_REGEX, RegexOptions.IgnoreCase);
    Match m = reg.Match(s);
    if (m.Success)
    {
      string form = reg.Replace(m.Value, _url);
      int iform = m.Index;
      int lform = m.Length;
      s = string.Concat(s.Substring(0, iform), form, s.Substring(iform + lform));
    }
    byte[] yaz = System.Text.UTF8Encoding.UTF8.GetBytes(s);
    _sink.Write(yaz, 0, yaz.Length);
  }

  /// 
  /// Sets the Form Action to the url specified
  /// 
  public static void SetFormAction(string url)
  {
    if (HttpContext.Current != null)
      HttpContext.Current.Response.Filter = new FormActionModifier(HttpContext.Current.Response.Filter, url);
  } // SetFormAction()
} // class
tristankoffee
  • 670
  • 7
  • 8
  • Any idea how this actually works? It looks like it's reading a rendered page and changing the form action, what with all the regex, which is not going to work as the page isn't rendered yet in the code-behind. – steventnorris Sep 24 '12 at 15:32
  • It looks like it hooks into the rendering pipeline after all of the other events have run (`Page_Load()`, etc...) which means that, once the page markup is ready to be sent to the browser, it parses the generated output and replaces the form attribute. I've used it on a couple of projects and it seems to do what you're asking; lets you specify the form action. – tristankoffee Sep 24 '12 at 16:03
  • That's interesting. I may have to test a bit before I trust it, but it's worth a go. – steventnorris Sep 24 '12 at 16:06
0

That's just not the way ASP.NET works. You can selectively set certain controls to post to a different page, however. This is called Cross Page Posting. See: http://msdn.microsoft.com/en-us/library/ms178139(v=vs.100).aspx. To perform a cross page postback with a button for example see: http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.button.postbackurl.aspx. Basically, you simply set the PostBackUrl for the button.

aquinas
  • 23,318
  • 5
  • 58
  • 81
  • Hmm.. I'm not wanting to create any sort of multi-page form. I just want a simple way to post a form to different urls based on conditions met in the code-behind. IS there not a simple way to change the action attribute? – steventnorris Sep 24 '12 at 15:31
0

May be you can try redirecttoaction

Here is sample

public ActionResult LogOff() {
FormsAuth.SignOut();
return RedirectToAction("Index", "Home");
}

Hope this helps.

Arjun Shetty
  • 1,575
  • 1
  • 15
  • 36
0

I also had the same issue recently, when posting the form action attribute would use the rewritten path, but I wanted to show the raw url. I don't have any url rewriting libraries installed.

I found this page was very useful in getting my postbacks to work: http://www.codeproject.com/Articles/94335/TIP-How-to-Handle-Form-Postbacks-when-Url-Rewritin

Terry Kernan
  • 746
  • 5
  • 12