I have just added routing in a new asp.net 4 web forms application, and have got my route table set up ok and page requests are working fine.
What I now want to do is use the Page.GetRouteUrl method whenever I need to generate one of my seo friendly Url's. I started to implement this across various pages then thought it might cut down on code a bit if I had a method in one of my own helper classes, that constructs this url (using the Page.GetRouteUrl method) as I might have several parameters that need to be specified against the Page.GetRouteUrl method each time.
However, within my helper class, it doesn't know what 'Page' is. I was thinking I could pass in 'Page' from the page that wants a routed url to be generated, but in some cases I want to construct one of these Url's in another class which doesn't know what 'Page' is, and in that scenario wouldn't be able to pass it in as a param (and therefore wouldn't be able to use the Page.GetRouteUrl within my helper class).
What is the normal approach when wanting to use Page.GetRouteUrl within classes that don't have an instance of the Page object?
You can pass Page as a constructor parameter, or this is actually the page reference:
var page = HttpContext.Current.Handler as Page;
You can cast it to the page type. Depending on the type of requests you are making, it may not always be page (say from a web service call, etc.).
HTH.
Related
I am currently learning JSF and was rather amazed and puzzled when I realized that whenever we use <h:form>, the standard behavior of JSF is to always show me the URL of the previous page in the browser, as opposed to the URL of the current page.
I understand that this has to do with the way JSF always posts a form to the same page and then just renders whatever page the controller gives it back to the browser which doesn't know the page location has changed.
It seems like JSF has been around for long enough that there must be a clean, solid way to deal with this. If so, would you mind sharing?
I have found various workarounds, but sadly nothing that seems like a real solid solution.
Simply accept that the URL is misleading.
Append "?faces-redirect=true" to the return value of every bean's action and then
figure out how to replace #RequestScoped with something else (Flash Scopes, CDI conversation, #SessionScoped, ...).
accept to have two HTTP round trips for every user action.
Use some method (e.g. 3rd party library or custom code) to hide the page name in the URL, always using the same generic URL for every page.
If "?faces-redirect=true" is as good as it gets, is there a way do configure an entire application to treat all requests this way?
Indeed, JSF as being a form based application targeted MVC framework submits the POST form to the very same URL as where the page with the <h:form> is been requested form. You can confirm it by looking at the <form action> URL of the generated HTML output. This is in web development terms characterized as postback. A navigation on a postback does by default not cause a new request to the new URL, but instead loads the target page as content of the response. This is indeed confusing when you merely want page-to-page navigation.
Generally, the right approach as to navigation/redirection depends on the business requirements and the idempotence (read: "bookmarkability") of the request (note: for concrete code examples, see the "See also" links below).
If the request is idempotent, just use a GET form/link instead of POST form (i.e. use <a>, <form>, <h:link> or <h:button> instead of <h:form> and <h:commandXxx>).
For example, page-to-page navigation, Google-like search form, etc.
If the request is non-idempotent, just show results conditionally in the same view (i.e. return null or void from action method and make use of e.g. <h:message(s)> and/or rendered).
For example, in-page data entry/edit, multi-step wizard, modal dialog, confirmation form, etc.
If the request is non-idempotent, but the target page is idempotent, just send a redirect after POST (i.e. return outcome with ?faces-redirect=true from action method, or manually invoke ExternalContext#redirect(), or put <redirect/> in legacy XML navigation case).
For example, showing list of all data after successful editing, redirect after login, etc.
Note that pure page-to-page navigation is usually idempotent and this is where many JSF starters fail by abusing command links/buttons for that and then complain afterwards that URLs don't change. Also note that navigation cases are very rarely used in real world applications which are developed with respect to SEO/UX and this is where many JSF tutorials fail by letting the readers believe otherwise.
Also note that using POST is absolutely not "more secure" than GET because the request parameters aren't immediately visible in URL. They are still visible in HTTP request body and still manipulatable. So there's absolutely no reason to prefer POST for idempotent requests for the sake of "security". The real security is in using HTTPS instead of HTTP and checking in business service methods if currently logged-in user is allowed to query entity X, or to manipulate entity X, etc. A decent security framework offers annotations for this.
See also:
What is the difference between redirect and navigation/forward and when to use what?
JSF implicit vs. explicit navigation
What URL to use to link / navigate to other JSF pages
Bookmarkability via View Parameters feature
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
When should I use h:outputLink instead of h:commandLink?
Creating master-detail pages for entities, how to link them and which bean scope to choose
Retaining GET request query string parameters on JSF form submit
Pass an object between #ViewScoped beans without using GET params
I have Homepage presenter i want to view what inside it in homepage. how can i open it in webaddress ? i already try to open it
with this http://localhost/sandbox/www/homepage/action it wont open
What the different between method action and render.. forexample i have this two method…
actionOut() and renderOut() in the Homepage Presenter when i route it it nette cannot make any different between two..
This depends on your routing. The default one allows you to access all presenters by pattern <module>.<presenter>/<action>. So the question is if the Homepage presenter is in any module, what's the routing, ... You can take a look at debugbar, where you can find a routing panel that may help you understand which route was matched. Also, you didn't specify, what is the exact error.
I encourage you take a look at the lifecycle of the Presenter. Basically, the action method is run always, even if you redirect in a signal method. The render method is run only when the presenter is going to render the current action. The action method should take care of getting the primary resource and "storing" it to the presenter's property, not the template! The render method takes the resource and pushes it to the template. If the resource method is not available, you should call $this->error() in your action method.
My page route mapping changes depending on certain criteria. To determine this criteria I need access to HttpRequest which means I can't do my route mapping in Application_Start(). On that note I have done it on PreInit() on my default page and it seems to work without an issue. However, all the examples I have seen with Route Tables are doing it in Application_Start, is this purely to avoid clearing the route list and adding them again? Will there it cause any harm to my web application doing in the way I am doing it?
EDIT: Example:
I load controls from different folders based on the project number and whether the website is being viewed on a mobile device, on that note I need to know this information before mapping my routes, like so:
RouteCollection.MapPageRoute("OneParam", "{Action}.html", String.Format("~/{1}{2}/Default.aspx", ProjectNumber, MobilePathStr));
which would map to something like ~/1234/Mobile/Default.aspx or could map to ~/1234/Default.aspx.
Don't do that.
Instead, you should create your own RouteBase class which looks up that information for each request and runs the appropriate handler.
To send to an ASPX page, you can either return BuildManager.CreateInstanceFromVirtualPath(virtualPath, typeof(Page)) as Page; or create a PageRouteHandler and delegate to it.
Short:Is there a way to have a route-definition that will pass the "CONTROLLER/ACTION" string value to a JavaScript function in stead of actually going straight for the controller action?
More:I have a masterpage which contains the navigation of the site. Now, all the pages need this navigation wrapped around it at all times, but because I didn't want the navigation to constantly load with each pagecall, I changed all my pages to partialviews.
These partial views are loaded via the JQuery.Load() method whenever a menu item is clicked in the navigation.
This all worked very good, up till now because I noticed it's also a requirement of the website to be able to link directly to page X, rather then default.aspx.
So, as an example:The main page is my "default.aspx" page, this utilizes my master page with the navigation around it. And each call to a new page uses a javascript function that loads that particular partial view inside a div that is known in my masterpage. So, the url never changes away from "default.aspx", but my content changes seemlesly.
The problem is, those url's also need to be available when typed directly into the address bar. But, they're partial views, so loading them directly from the address bar makes them display without any masterpages around them. Therefore my question if it might be possible to capture the route typed into the address bar and pass that on to my JavaScript function that will load that route in the content div.
(I hope I explained it ok enough, if not, feel free to ask more information)
You are 100% correct to not want to hard code your URLs in your javascript code as it demolishes one of the primary tenants of MVC to do so. I'm one of those "separation of concerns" guys who will not write a single line of javascript outside of a dedicated .js file so I cannot dynamically specify the URL the way tuanvt has. What I do is use MVCs Url.Action method to emit my service URLs into hidden inputs on the master page (or the specific page if it is not used in multiple places). Then my script file simply pulls the value out of that hidden input and uses it just fine.
ASP.NET MVC View Source
<input id="serviceUrl" type="hidden" value="<%= Url.Action("Action", "Controller") %>" />
JS Source
$.getJSON($("#serviceUrl").val(), function(data) {
//write your JS success code here to parse the data
});
First challenge, as you are using AJAX to load the partial pages you need client accessible URLs for the javascript to call. Second challenge, you need URLs that will load the HomeController and pass the 'page' portion of the URL into the javascript.
For the first aspect I'd create some abstracted routes, i.e. "/ajaxaccess/{controller}/{action}/{id}" for the partial pages. That would be the first registered route. A second route would accept any controller/action reference and always get processed by the HomeController Index action.
In the /Home/Index action you grab the requested URL and slice it up, take the /{controller}/{action}/... section and pass that into your default.aspx using TempData. In your page check for the existence of the TempData and if it exists use the value therein to trigger your AJAX page load for the partial page (don't forget that you'll need to prepend '/ajaxaccess' (or whatever you choose) to the URL before it's passed to your page.
I'm not going to provide code here as I think the information you'll gain from working through this yourself will be invaluable to you moving forward.
You could use hash anchor (#) on your url and read it with javascript.
var url = document.location.toString();
if (url.match('#')) {
anchor = url.split('#');
// do whatever with anchor[1] ..
}
You can do something like this, put this in your javascript code on the view:
var szUrl=<%= ViewContext.RouteData.Route.ToString()%>;
Then the current route will be stored on the variable szUrl.
Like in Windows Forms:
Dim myForm as New AForm(Constr-arg1, Constr-arg2)
myForm.Show
... is there a similar way to Load a Page in ASP.Net. I would like to overload the Page Constructor and instantiate the correct Page Contructor depending on the situation.
Can you just link to the page passing parameters in the QueryString (after the ? in the URL) and then use them in the constructor (more likely PageLoad)
I think the best approach here for ASP.NET is to write User Control (*.ascx file) that represents page content, and load different controls based on current situation using Page.LoadControl() method. This solution is flexible enough, because only reference to control is its name. And this approach is much more useful than page constructor overloading as soos as you're not related on strong types, only on controls' names.
This isn't really the "correct" way to redirect to a page in .Net web programming.
Instead, you should call either Request.Redirect("~/newpage.aspx") or Server.Transfer("~/newpage.aspx"). You should then handle the request in the new page's Page_Load handler.
You can pass state between the pages by adding to the query string of the redirected URL (i.e. ~/newpage.aspx?q1=test), or by assiging values to the Session store (i.e Session["q1"] = value).