I'm trying to develop my first site in ASP.Net using Web Forms.
I have a form with some controls and a TextBox control. While now I use GETrequest. When user submits a form his browser expects to get long URL, something like
http://mysite.com/search.aspx?__VIEWSTATE=%2FwEPDwUJNTE2NjY5jMY4D2QWAgICD2QWAgIDDW8wAh4EVGV4dAUBMWRkZKthQ0zeIP5by49qIHwSuW6nOj8iLTdoCUzpH369xyg8&__EVENTVALIDATION=%2FwEWAwLnrcHhBQLs0bLrBgKM54rGBjGtX5fJOylLy4qRbt6DqPxO%2FnfcMOkHJBRFqZTZdsBD&TextBox1=sfs&Button1=Button
if his input is a word sfs in TextBox1.
So I need to return him response. I would like to show this response on a user-friendly URL like
http://mysite.com/search.aspx?TextBox1=sfs
or
http://mysite.com/sfs
or
http://mysite.com/search/sfs
How can I do that? If I use Response.Redirect, it first returns 302, and only then work on short URL. Server.Transfer doesn't change URL and user sees ugly long URL in browser.
It seems to me that it is possible to solve via RouteCollection.MapPageRoute which appeared in 4.0 Framework but it's unclear to me how I can use it.
Any help is appreciated.
UPDATE. It is not a problem to use POST instead of GET. But in this way URL will always look like http://mysite.com/search.aspx
UPDATE2. The form MUST be server control and it has another controls except submit and textbox. It would be good (though, still, not necessary if this parameters don't appear in URL showing in the browser.
Using GET requests with ASP.NET server forms will unfortunately always yield those "ugly" URLs.
One thing that you can do is change the form to not be a server form and instead be a regular form:
<form method="get" action="Search.aspx">
<input type="text" name="query" />
<input type="submit" name="SearchButton" value="Search" />
</form>
One limitation of this solution is that you can no longer place certain ASP.NET controls within this form. For example, the <asp:Button> control will not work in this form because it must be contained within a server form (that is, a form that has runat="server" on it).
Since its a GET request you can also use javascript, setting the
location.href = 'http://mysite.com/search/' + query;
Then on the ASP.NET side you can use the URL Rewriting feature to redirect that url to a specific ASPX page as a query string parameter.
Let me know if you would like a more detailed sample.
Sample:
Here is a sample, please note I haven't tested it, but this should get you started.
<html>
<head>
<script type="text/javascript">
function searchRedirect()
{
var query = $get('query');
location.href = "/search/" + query.value;
}
</script>
</head>
<body>
<div class="search">
<input type="text" id="query" /><br />
<input type="button" id="search" value="Search" onclick="searchRedirect();" />
</div>
</body>
</html>
Then on the redirect side you have have a RouteModule like this:
public class UrlRewriter : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.AuthorizeRequest += new EventHandler(OnBeginRequest); //this ensures the login page has the vitual url not the mapped url
}
private void OnBeginRequest(object sender, EventArgs e)
{
var application = sender as HttpApplication;
if (application != null)
{
var requestPath = application.Request.AppRelativeCurrentExecutionFilePath;
if (requestPath.ToLower().StartsWith("/search/"))
{
var query = requestPath.Substring(8);
application.Context.RewritePath("Search.aspx", null, "query=" + query, false);
}
// .. Other Routes
}
}
}
And assuming the code is in your App_Code folder you could use this in your web.config
<system.web>
<!-- ... -->
<httpModules>
<add name="UrlRewriter" type="UrlRewriter, __code"/>
</httpModules>
</system.web>
<!-- If IIS7 -->
<system.webServer>
<modules>
<add name="UrlRewriter" type="UrlRewriter, __code" />
</modules>
</system.webServer>
Well, the main thing that's making that 'look bad', is you're using ViewSate and GET; so don't do that (either disable the ViewSate and adjust code accordingly, or use POST).
What you may also be interested in, however, is URL Re-Writing. You can do that in a few ways, I typically do it with a wildcard mapping in IIS and appropriate changes to the Global.asax file. Searching will reveal how to do this.
Related
I am attempting to implement a Captcha on a partial view of a page in my application. I have the captcha being refrenced through web.config as a control. I have used the GenericHandler and Class file from this forum post: http://forums.asp.net/t/1871186.aspx/1
How can I reference the user's input if i am using a simple input tag? Should I use an HtmlHelper instead?
<div class="captcha">
<rhcap:Captcha ID="Captcha1" runat="server"></rhcap:Captcha>
<input type="text" id="UserCaptchaText"><input/>
<%= Html.TextAreaFor(m => m.UserCaptcha) %>
</div>
<%if(Captcha1.Text != /* How can get the users input here?*/ ) {
//display error
}else{
//proceed
}%>
Use NuGet and install Recaptcha for .NET (supports MVC as well)
http://nuget.org/packages/RecaptchaNet/
Documentation is on the site:
http://recaptchanet.codeplex.com/
There are other captchas:
http://captchamvc.codeplex.com/
EDIT:
This project has moved to GitHub
https://github.com/tanveery/recaptcha-net
NuGet Google reCAPTCHA V2 for MVC 4 and 5
NuGet Package
Demo And Document
Web.config File in the appSettings section of your web.config file, add the keys as follows:
<appSettings>
<add name="reCaptchaPublicKey" value="Your site key" />
<add name="reCaptchaPrivateKey" value="Your secret key" />
</appSettings>
Add Recaptcha in your view.
#using reCAPTCHA.MVC
#using (Html.BeginForm())
{
#Html.Recaptcha()
#Html.ValidationMessage("ReCaptcha")
<input type="submit" value="Register" />
}
Verifying the user's response.
[HttpPost]
[CaptchaValidator]
public ActionResult Index(RegisterModel registerModel, bool captchaValid)
{
if (ModelState.IsValid)
{
}
return View(registerModel);
}
EDIT:
You should also add this in your head tag or you might see improper captcha
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
First off, it looks like you are mixing standard ASP.NET and ASP.NET MVC. If you want to do MVC, the standard way to do it is the Html.TextBoxFor() type of stuff, and then you handle the value of that in a controller action method rather than write something inline in the page. So you have something like this:
Page.aspx
<rhcap:Captcha ID="Captcha1" runat="server"></rhcap:Captcha>
<%= Html.TextBoxFor(m => m.UserCaptcha) %>
and then in:
SomeController.cs
[HttpGet]
public ActionResult Page()
{
// generate captcha code here
ControllerContext.HttpContext.Session["Captcha"] = captchaValue;
return View(new PageViewModel());
}
[HttpPost]
public ActionResult Page(PageViewModel model)
{
if (model.UserCaptcha == ControllerContext.HttpContext.Session["Captcha"])
{
// do valid captcha stuff
}
}
To take this to the next level would be to implement it in a FilterAttribute. But this should work for most uses.
I would recommend you to use Google reCAPTCHA, is the best and easy to implement plus it comes with the trust of Google.
Very very effective and easy to implement.
Read this article written by me on implementing Google reCAPTCHA in ASP.NET MVC
Thanks
I have a html application with Textbox and a button. (static application)
I need to transfer the textbox value on the button click,
which will take me to another asp.net application.
(Where I can retrieve that in query string) is that possible?
2 applications are in different servers.
make the method of your form get and and the action of the form the url of the other website you want to hit eg
<form action="http://www.google.co.uk" method="get">
<input type="text" name="test" />
</form>
when submitted will post to http://www.google.co.uk?test=ValueOfInput
EDIT
Just noticed you are using asp.net - this is not static html! As your have an asp button you can add a button click event so your code looks like this:
<input ID="btnsrch" type="button"value="Search" runat="server" onclick="btnsrch_click" />
then in your corresponding cs file you can add the following function:
protected void btnsrch_click (object sender, EventArgs e)
{
Response.Redirect(string.Format("http://www.urltogoto.com?variable={0}", txtsrch.Text));
}
Yes this is possible.
You can give a postback url and can get the value in request object over their.
I've got an ASP.NET 4 site on which I want to allow people to put '<' in their password. However, .NET gets in the way by blocking (what it sees as) an attempt to put HTML in a form field. I know I can turn off input validation entirely, but I only want to turn it off for this one field. Does anyone know an easy way to do that?
This is now possible with .NET 4.5.
Update your Web.config:
<httpRuntime targetFramework="4.5" requestValidationMode="4.5" />
Then set ValidateRequestMode="Disabled" on your password controls:
<asp:YourControl id="YourControl" runat="server" ValidateRequestMode="Disabled"/>
Note - after updating web.config, you might run into the error WebForms UnobtrusiveValidationMode requires a ScriptResourceMapping for 'jquery'. See ASP.Net 2012 Unobtrusive Validation with jQuery for more info on that.
More info on RequestValidationMode 4.5: requestValidationMode 4.5 vs 2.0
You can only turn off input validation for the entire page. The only solution I can think of is to turn off the input validation, and then scrub all the other (non-password) input fields using something like Anti-XSS.
You can turn input validation off for the single MVC action using the ValidateInputAttribute. Since you're only accepting username/password (I would assume) you should be able to scrub input yourself of any invalid characters. Use the Microsoft Web Protection Library to do that.
Note in ASP.NET 4 and higher to get ValidateRequest in the #Page directive to work you need to add <httpRuntime requestValidationMode="2.0" /> to web.config. See this page for details:
http://www.asp.net/whitepapers/aspnet4/breaking-changes
But this is my preferred approach:
namespace Controls
{
public class HtmlTextBox : TextBox
{
protected override bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
{
bool res = base.LoadPostData(postDataKey, postCollection);
Text = Text.Replace("<", "<").Replace(">", ">").Replace("&", "&");
return res;
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
ScriptManager.RegisterOnSubmitStatement(this, this.GetType(), "htmlTextBox" + UniqueID, "try { var item = document.getElementsByName('" + UniqueID + "')[0]; item.value = item.value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); } catch (err) {}");
}
}
}
And then register the control in web.config:
<system.web>
<pages>
<controls>
<add tagPrefix="uc1" namespace="Controls" />
</controls>
</pages>
</system.web>
This way you can just use <uc1:HtmlTextBox runat="server" /> if you want to allow the textbox to post html, but other controls on the page will still be blocked from posting html unlike the approach of turning ValidateRequest off.
This is possible. Just add [AllowHtml] on the property that should not be validated.
see ValidateInputAttribute does not contain a definition for Exclude
Im using intelligencia urlrewriter as my url rewrite module. I have one very strange problem which only occurs when an url is rewritten but to make it more fun, not on all rewritten pages.
Edit: Forgot to tell you what's the problem boing boing. the problem is that my Page_Load event gets fired 2 times.
This is how my form rewrite adapter looks like:
using System;
using System.Web.UI;
using System.Web;
using System.Web.UI.WebControls;
public class FormRewriterControlAdapter : System.Web.UI.Adapters.ControlAdapter
{
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
base.Render(new RewriteFormHtmlTextWriter(writer));
}
}
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 the attribute we are writing is the "action" attribute, and we are not on a sub-control,
// then replace the value to write with the raw URL of the request - which ensures that we'll
// preserve the PathInfo value on postback scenarios
if ((name == "action"))
{
HttpContext Context = default(HttpContext);
Context = HttpContext.Current;
if (Context.Items["ActionAlreadyWritten"] == null)
{
// Because we are using the UrlRewriting.net HttpModule, we will use the
// Request.RawUrl property within ASP.NET to retrieve the origional URL
// before it was re-written. You'll want to change the line of code below
// if you use a different URL rewriting implementation.
value = Context.Request.RawUrl;
// Indicate that we've already rewritten the <form>'s action attribute to prevent
// us from rewriting a sub-control under the <form> control
Context.Items["ActionAlreadyWritten"] = true;
}
}
base.WriteAttribute(name, value, fEncode);
}
}
And this is how my web.config looks like
<!-- Here the double page_load occurs -->
<rewrite url="~/car-parts/(\d+)/(.+)" to="~/Products.aspx?type=parts&iid=$1&cid=9" />
<rewrite url="~/car-stereo/(\d+)/(.+)" to="~/Products.aspx?type=stereo&iid=$1&cid=10" />
<!-- this is working correctly -->
<rewrite url="~/car-parts/browse-by-type/(\d+)/(.+)/(\d+)/(\d+)" to="~/Browse.aspx?cid=9&type=country&countryid=$1&p=$3&filter=$4" />
I have no idea where to look anymore, i checked my html markup since i've read that could couse this problem.
Kind regards,
Mark
when I'm using this rewrite rule in my rules,this problem has been solved:
<rewrite url="^(/.+(\.gif|\.flv|\.swf|\.png|\.jpg|\.ico|\.pdf|\.doc|\.xls|\.css|\.zip|\.rar|\.js|\.xml|\.mp3)(\?.+)?)$" to="$1" processing="stop" />
but remember to use this rule after all of your .css/.js/.jpg/... rules.
Finally I found it, it was not having anything to do with the rewrite module , this is which caused the problem:
In one of my usercontrols i've used updateprogress
<asp:UpdateProgress runat="server" AssociatedUpdatePanelID="upNewsletter" DisplayAfter="0">
<ProgressTemplate>
<asp:Image runat="server" ID="imgLoading" ImageUrl="~/Images/Template/loading.gif" />
</ProgressTemplate>
</asp:UpdateProgress>
Now thats where the problem is , in the asp:Image tag. I've replaced it with a regular img tag and now everything works fine again. Took me some time to figure this out and I hope I can save you headache.
Kind regards
I've found this post searching for multiple page_loads, but I had the problem using a dynamically created CollapsePanel using a dynamically created Image. By filling the ImageUrl to a default image, the problem was solved.
header.Controls.Add( new Image
{
ID = string.Format( "headerImage_{0}", panelId ),
EnableViewState = false,
ImageUrl = "~/Images/collapse.jpg"
} );
Let's say I have a search page called Search.aspx that takes a search string as a url parameter ala Google (e.g. Search.aspx?q=This+is+my+search+string).
Currently, I have an asp:TextBox and an asp:Button on my page. I'm handling the button's OnClick event and redirecting in the codebehind file to Search.aspx?q=
What about with ASP.NET MVC when you don't have a codebehind to redirect with? Would you create a GET form element instead that would post to Search.aspx? Or would you handle the redirect in some other manner (e.g. jQuery event attached to the button)?
You need to understand that MVC doesn't directly reference .aspx pages like WebForms in its URLs. Its main purpose is to separate concerns, that is model (data), controller (logic), and view (presentation).
First, you'd have to create a route matching your URLs, which would now look like this for example : /home/search/This+is+my+search+string
This would call the Search action method of the Home controller, which would get "This is my search string" as an input parameter. This action is responsible for accessing the model and pulling the results probably from a database.
Typically, your search action would then return a ViewResult containing the view placed in the folder /Views/Home/Search.aspx. Here, you can use neither the Postback functionality nor the events of your Web controls like in WebForms, because MVC applications are stateless and not event-driven. It's more like a request/dispatch way of doing things.
Read more about MVC here.
Create a user control called Search.ascx with a form:
<% using (Html.BeginForm ("Search", "Home")) { %>
<input name="search" type="text" size="16" id="search" />
<input type="image" name="search-image" id="search-image" src="search.gif" />
<% } %>
And in your search action all you need is the following:
public class HomeController : Controller
{
public ActionResult Search (string search)
{
throw new Exception (string.Format ("Search: {0}", search));
}
}
In your master page or wherever you can then add
<% Html.RenderPartial ("Search"); %>
You can use a simple javascript in the button's onclick to redirect to the search page:
Search <input type="text" id="go" size="4" /><input type="button" value="<%=Html.Encode(">>") %>" onclick="javascript:window.location='<%=Url.Action("Search", "Home") %>/' + document.getElementById('go').getAttribute('value')" />