Routing in Web forms not working - asp.net

This is the code in Global.asax
void Application_Start(object sender, EventArgs e)
{
System.Web.Routing.RouteTable.Routes.MapPageRoute("Page1","{Param1}/{Param2}","~/FirstPage.aspx");
System.Web.Routing.RouteTable.Routes.MapPageRoute("Page2","Xyz/{Param3}","~/Second.aspx");
}
Now i'm trying to redirect to some page e.g. xyz/test1,xyz/test2,xyz/test3. It's always getting redirected to FirstPage, not the second page which is what is expected and i'm trying to do.
How to implement this? Any suggestions.

Please make sure below important things are met before you start creating routing,
•Define custom URL patterns that are not dependent on physical file names.
•Generate URLs based on route URL parameter values by using markup or code.
•In a routed page, retrieve values passed in URL segments by using markup or code.
Try below code to implement routing,
1. In Application_start method you can only register the routes as below,
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
Create below method after Session_End method in you global.asax file,
void RegisterRoutes(RouteCollection routes)
{
}
In the RegisterRoutes method, add the following code,
routes.MapPageRoute("SalesRoute",
"SalesReport/{locale}/{year}",
"~/sales.aspx");
This code adds a route that is named SalesRoute. You are naming this route because it has the same parameter list as the route that you will create in the following step. Assigning names to these two routes enables you to differentiate them when you generate URLs for them.
More details refer: https://msdn.microsoft.com/en-us/library/dd329551.aspx

Related

AsyncLocal Value is Null after being set from within Application_BeginRequest()

In the following example, I am setting a value to an AsyncLocal<string> variable on my HttpApplication subclass (i.e. Global.asax) from within Application_BeginRequest():
public class Global : System.Web.HttpApplication
{
public static AsyncLocal<string> AsyncLocalState = new AsyncLocal<string>();
protected void Application_BeginRequest(object sender, EventArgs e)
{
AsyncLocalState.Value = HttpContext.Current.Request.Path;
}
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
var path = AsyncLocalState.Value;
}
protected void Application_EndRequest(object sender, EventArgs e)
{
var path = AsyncLocalState.Value;
}
}
Later on, I will attempt to access the value of this AsyncLocal variable from within a handler, such as an MVC action method, or even just a plain IHttpHandler.
If I send a large enough request (e.g. a POST with more than 15KB of data -- the larger the request, the easier it is to observe), there is a very good chance that the value of AsyncLocalState is NULL when accessed from a handler even though it was set on BeginRequest.
This is reproducible from a brand-new ASP.NET project without any other libraries/modules/handlers loaded.
Is this a bug? Or maybe I'm doing something wrong? Or is ASP.NET just too unstable for this?
Addition note: the exact same behavior is observed if I instead use CallContext.LogicalGetData/CallContext.LogicalSetData.
Platform: ASP.NET, .NET 4.6.2, on Windows 7
Update: After trying to dig around, I've found a lot of references to, but nothing authoritatively saying that the ExecutionContext does not flow between ASP.NET pipeline events (except when it does?). And both AsyncLocal and the logical call context are based on the ExecutionContext.
The closest thing to an authoritative answer is this comment by David Fowl on GitHub.
The ExecutionContext does not flow between ASP.NET pipeline events if these events do not execute synchronously. Therefore, don't use AsyncLocal or the logical CallContext to persist state; use HttpContext.Items.
Update: .NET 4.7.1 adds a new callback method, HttpApplication.OnExecuteRequestStep, which per documentation "provides extensibility to the ASP.NET pipeline to make it easy for developers to implement features in ambient context scenarios and build libraries that care about ASP.NET execution flow (for example, tracing, profiling, diagnostics, and transactions)."
This is precisely what someone would need in order to restore the AsyncLocal state or the logical CallContext between ASP.NET pipeline events.

hook POST parameters in asp.net

I'm recently mining a website to build some database. I already built a python script parsing retrieved information but the problem is that it requrires a query word to retrieve web pages which contain information I want to see. And this page is in POST method so I cannot see how this page retrieves a page list.
To describe an outline for your clear understanding:
1. on inputKeyword.aspx : This contains a form to input a query(let's say ID)
When I input an ID and press search, it retrievs a
relevant list
2. Press Search
3. on inputKeyword.aspx : A relevant list is showed on the same aspx page
(which means POST method), so I cannot see how this query
works on inputKeyword.aspx page.
It would be so much easier if this webpage is in GET method, since I can simply hook a url with queries, but it's not possible in POST method.
Is there any way that I can open step #3 skipping step #1 and #2?
The webpage is built in asp.net but there's no restriction on languages as long as there's way to do this.
If I understand correctly you want to be able to accept a an ID as part of your query string. eg
http://your.domain.com/inputKeyword.aspx?ID=555
So in the pages load event you can check the request object for query params, ie Request.QueryString[param] as the following example shows
protected void Page_Load(object sender, EventArgs e)
{
string id = Request.QueryString["ID"];
if (!string.IsEmptyOrNull(id))
{
//do something with the requested identifier
}
}
Note: you can use Page.IsPostBack() to determine if the page is being hit for the first time or is posting back as a result of a button click.
To get your Search button to behave correctly you have a couple of options. For example; you can use javascript to capture the buttons onclick event and redirect the page to itself with the url amended to include the identifier from the id textbox.
But perhaps the following is the easiest, keeping the code all server-side:
private _identifer string;
protected void Page_Load(object sender, EventArgs e)
{
string id = Request.QueryString["ID"];
if (!string.IsEmptyOrNull(id))
{
_identifer = id;
}
}
protected void SearchButton_Click(object sender, EventArgs e)
{
_identifer = IdentiferTextbox.Text;
}
protected void Page_PreRender(object sender, EventArgs e)
{
if (!string.IsEmptyOrNull(_identifer))
{
PopulateListForidentifer(_identifer);
}
}
Basically the example shows that you can cope with scenarios. ASP.Net's page life cycle means that events are processed in the following order Page_Load -> Control Events (eg button click) -> Page PreRender.
If the page is hit for the first time without an identifier in the url, PopulateListForidentifer method isn't called since _identifer is never set.
But if the url contains an identifier then _identifer is set in the page load event, when the page pre-render is called PopulateListForidentifer will be called.
Finally if the page is posting back to itself because the search button has been hit then the click handler is called and _identifer is set to the content of the IdentiferTextbox; the pages prerender is called and also PopulateListForidentifer. Note this would override the point about ie when the identifer was passing as part of the url.
From what I understand, it seems you want to simulate the HTTP Post operation in your Search form, where by without entering the ID and clicking search, you directely want to have access to the search results.
Here is a Blog Post by Scott Hanselman, where he discusses a similar topic using WebClient.
You may also want to check this thread

Event handlers can only be bound to HttpApplication events during IHttpModule initialization

I am getting the following error
'Event handlers can only be bound to HttpApplication events during IHttpModule initialization.' at the following code (line in bold or double **)
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
**app.EndRequest += new EventHandler(Application_EndRequest);**
}
protected void Application_EndRequest(object sender, EventArgs e)
{
UnitOfWork.Commit();
}
which is mentioned in Global.asax file. Can anybody figure out, where I am lacking? Thanks.
The event handler lives the entire life of your application, so, you only need to add it once not add it every request. The event itself will fire every request, and the only-one handler will be called every time the event is raised.
Add it to Application_Start in global.asax not Application_BeginRequest, or better, create an HTTP Module instead.
Also, I think you may not even need an event handler. The method with current name will be called by convention similar to Page/Control AutoEventWireup (like Page_Load). Just note that this might have issues in ASP.NET MVC applications as some people report. So, my suggestion is to rename the function, add the event handler in Application_Start, or better in a new HTTP Module you create.
Try to comment out line marked with "**". Asp.Net will call appropriate methods by itself if followed by naming conventions: "{Scope}"_"{Event}", where "{Scope}" is Application if you want to handle application level events or "Session" if you want to handle session level events, and "{Event}" is name of the event, like Start, End, etc.
More info: http://msdn.microsoft.com/en-us/library/bb470252.aspx#Stages

ASP.NET Application Lifecycle - how to check configuration properties exist?

I've written a singleton class that exposes the web.config properties in a nice get property kind of way.
I want a Load method to parse the data in the config and set the public properties, and I want to throw exceptions (so they are logged in the EventLog) when a configuration key is missing or can't be parsed.
I tried placing the Load() code in Application_Start of the global.asax but then remembered this will only be run once, or until the application restarts.
Where is the best place to put code that you need to run 'everytime' your site is started/run by the user? I basically want the website to stop functioning if certain config properties cannot be loaded.
Thanks.
When you change your web.config file, the application pool is recycled. This means that the next hit will cause your Application_Start method to be called.
Altering the following files will also
trigger an immediate restart of the
application pool:
- web.config
- machine.config
- global.asax
- Anything in the bin directory or it's sub-directories
On that basis, as soon as your configuration is changed, it will be reloaded the next time a user hits the site, which should resolve the problem with the minimum number of configuration reloads, as opposed to reloading whenever a session starts for example. Therefore, you can do this (in your global.asax):
static bool configValid = false;
void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext context = base.Context;
HttpResponse response = context.Response;
HttpRequest request = context.Request;
// Redirect users to an alternate page if the current config is invalid
// I happen to pass the Url they were attempting to access in the query string
// that way you can give them a "try again" link
if ((!configValid) && (!request.Url.ToString().Contains("BadConfig.aspx")))
{
response.Redirect("BadConfig.aspx?originalUrl=" + context.Server.UrlEncode(request.Url.ToString()));
}
}
void Application_Start(object sender, EventArgs e)
{
// Load config and determine if it's valid, thus setting configValid to true/false
//
//
configValid = false;
}

Global.asax, global variables, and editing with code

I have two questions:
1) I have a few global variables for my website declared in my global.asax file. They are simple, small key/value pairs and there are only a few of them. Is this a good practice for values that are small and need to be accessed by almost every page on my website? Storing them in the database and requiring a db lookup seems as thought it would waste resources for values that don't change rapidly.
2) If one of the values changes once per week, is it possible to allow a user to edit the global variable with a form or some other means?
Example:
<script runat="server">
Overloads Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
Application("default_scoring_id") = 3
Application("week_current") = 3
End Sub
</script>
In the above example, the system needs to know which week (out of 15 of them) that the current date is within. So, once every Monday morning, the "week_current" value needs to change.
I can easily do this, but is there a way to give a user access to changing this value without touching the code?
The typical practice is to put these into the web.config, which can be edited. These <appSettings> values will then be available on every page, yet the file can be edited.
1) Good practice is usually to store those sort of values in the web.config. See here and here for some guides.
2) a) If you store this in the web.config it will be easily updatedable without the need for recompiling and the web application should immediatly pick up the changes.
b) Does updating something like the 'week number' really need to be a manual process? It sounds a bit error prone and i would suggest automating this if at all possible by calculating it based on the current date.
I would consider using the built in Cache (System.Web.Caching.Cache)
That way you can store them where ever you want (say in a database), change them from within the app easily, and have quick and cheap retrieval.
From within a class which inherits from BasePage use the given Cache object (eg Cache.Add(..)) and from elsewhere use HttpContext.Current.Cache (eg. HttpContext.Current.Cache.Remove(Key))
The other answers suggest the different ways this can be done, and must be done. But, even then if you want to allow the user to edit the global variable, you'll have to take a lock or Mutex on a shared object, change the value of your global variable, and release the lock or Mutex.
lock(globalsharedobject) //This is C# code.
{
Application("default_scoring_id") = 3;
}
Web.config is the .NET way, or ASP.NET way, it's not always the most efficent or most suitable.
You're Global.asax file is much more than some events, you can put static data in any class that subclass System.Web.HttpApplication and inherit that in your Global.asax file.
The HttpSessionState and HttpApplicationState are relics, from the classic ASP time and you would do well to avoid them, becuase the serve no real purpose.
Depending on the type (System.Type) of your objects you can design your own strongly typed objects that store information about your application and session, for application level data a bunch of static fields would be enough.
They have to be static becuase each HttpModule as well as HttpApplication instance are pooled object, so to avoid that confusion, make sure your persistent data is stored in a static or several static dicionaries. But be aware of concurrency issues when modyfying these collections. A good strategy is to lock the object, only for the duration you're modifying it and make sure you don't call any other code while modyfiny the collection, a simple swap idiom, might be helpful here, it's fast and it's a non-deadlock guarntee.
<%# Application Language="C#" %>
<script runat="server">
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
}
void Application_End(object sender, EventArgs e)
{
// Code that runs on application shutdown
}
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
}
void Session_Start(object sender, EventArgs e)
{
// Code that runs when a new session is started
}
void Session_End(object sender, EventArgs e)
{
// Code that runs when a session ends.
// Note: The Session_End event is raised only when the sessionstate mode
// is set to InProc in the Web.config file. If session mode is set to StateServer
// or SQLServer, the event is not raised.
}
protected void Application_BeginRequest(Object sender, EventArgs e)
{
Context.Items.Add("Request_Start_Time", DateTime.Now);
}
protected void Application_EndRequest(Object sender, EventArgs e)
{
TimeSpan tsDuration = DateTime.Now.Subtract((DateTime)Context.Items["Request_Start_Time"]);
Context.Response.Write("<b>Request Processing Time: From Global.asax file " + tsDuration.ToString());
Application["time"] = tsDuration.ToString();
}
</script>

Resources