ASP.Net Routing with WebForms - asp.net

I am trying to cut over an existing WebForms app to use Routing, and want to do it in phases. However, I am running into some issues with a particular route:
//I want to catch existing calls to .aspx pages, but force them through
// a route, so I can eventually drop the .aspx extension
new Route("{page}.aspx", new MyCustomRoute());
This isn't working at all, as calls to [SomePage].aspx are never tripping this route... If I change the route to look like this:
//Same thing sans .aspx extension
new Route("{page}", new MyCustomRoute());
All calls to [SomePage] are getting picked up. Any ideas?

Ok, so now I feel stupid...
Turns out there is this little property on the RouteCollection class called RouteExistingFiles which is false by default. Apparently ASP.Net routing gives precedence to existing files before turning them over to routing, so any calls to existing pages would obviously not be handled by my routes. Setting this property to true resolves my issue, all though it may have unintended side effects to which I am as of yet unaware.

Related

Sitecore controller rendering causing StackOverflowException

I am trying to do a simple controller rendering with Sitecore 8 and for some reason it's producing a StackOverflowException on the line within the main layout markup that contains the reference to the placeholder it is to be rendered in. This seems to crash the worker process, but you can see the stack overflow on debugging the process:
Here is my very basic controller:
And here is my controller rendering definition:
Reproduction notes:
This is occurring in a vanilla Sitecore 8 installation (rev. 150427 -installed via SIM).
The MVC project is also vanilla -created with empty ASP.NET project, then NuGetting in MVC 5.1.
Web.config & Global added to project from the Sitecore site root in wwwroot.
FYI - everything is absolutely fine doing a view rendering - it's just controller renderings that seem to be causing a problem
So the problem was actually pretty simple in the end.
Returning a ViewResult when the view is intended as a partial view (which all Sitecore renderings will be) then you must set the layout property in the markup to null:
#{
Layout = null;
}
Otherwise MVC will try to wrap the layout file around it, which of course contains your Sitecore placeholder, which causes an infinite loop and crashes the worker process with a StackOverflowException.
So in the context of Sitecore, either return a PartialViewResult or return a ViewResult with the layout set as null.
I guess there is something missing in placeholder setting, could you check in path sitecore/layout/placeholder setting?
There should be a placeholder key which you are trying to use.
Hope this will help
Cheers!!
I think the issue can be with method View() being called without any parameters which can cause re-rendering the whole Sitecore page again.
Try to add parameter to View() like that:
return View("/Views/Courses/Index.cshtml");
Or whatever is the path of the view you want to return.
EDIT:
As #David Masters found, for some reason the issue is with calling View instead of PartialView method with the full path as a parameter. The correct code is:
return PartialView("/Views/Courses/Index.cshtml");

Mapping RouteTable on PreInit() - Will it cause any problems?

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.

Output caching a custom control (server control)

I've come across hints about output caching a server control, but have yet to find a definitive answer to: Can the output of a server control be cached (in the same way that user controls are cached)?
The suggestions I've come across involve caching the data (not true output caching), or suggest setting the response.cache options. Ideally, I'd like to be able to drag a server control on to the page and set properties with the same names as the outputcache directive:
Example:
<cc1:MyCustomControl ID="ctl1" runat="server" CacheDuration="200" VaryByCustom="user" />
I was going to dig into the framework to see how output caching really works, but was hoping to find some information to get me started. From my limited understanding, the parser decides whether or not a page/usercontrol is cached. Since server controls are not parsed, there would be no way to stop the code from executing. I suppose I could initialize an "IsInCache" boolean and make sure that all methods check that var before executing the code. This would not entirely eliminate the server control from being executed, but it might improve performance enough by avoiding calls to the database and binding data to controls.
I'm still using .NET 3.5, and haven't had much time to explore the OutputCache provider model in .NET 4.0. Maybe there's a solution in the latest version of the framework?
Any thoughts?
I was looking for this as well and I figured I'd add the solution to this page since it came up in my web search. There is an attribute called PartialCaching that is applied to the server-side/custom control to achieve the same effect as the OutputCache directive used in ascx and aspx templates. It takes the same parameters (VaryByParameter, etc) as well. For example:
[PartialCaching(1000, "foo", null, null)]
public class ClientScriptVariableBlock : Control {
...
}
The ASP plumbing treats this the same as the template attribute, so the end result is the same. This is valuable (in my case) because I get to create common server controls outside of the web project itself that can be cached. ASCX templates don't work very well in external assemblies :)

Flex + Mate + WebServiceInvoker : Changing the WSDL according to FlashVars

I have a Mate project with a WebService tag instance in the EventMap (which I'm using within various event handlers). I'd quite like to be able to set the wsdl property of the WebService via flashvars, but I'm not entirely sure where or how I could do that.
I know I can access flashvars via the Application.application.parameters collection, but I don't seem to have access to the Application instance during the load event of the WebService...
I suspect there's either something subtle or something blatantly obvious that I'm managing to overlook :(
Partly this was due to me not putting the parameter in the correct section of index.template.html (if everything's fine, it's the SECOND section that gets called, not the first), and partly it was my misunderstanding the behaviour of the Application and WebService classes (why oh why does it not cache the wsdl?)
I ended up adding a bindable public variable on the event map instance, then setting that variable in the creationComplete handler of the main application. I could probably have done this entirely within the event map, but it would have been a little more convoluted.

I have to integrate an existing asp.net web app into another page by using jQuery's load() method

I have to integrate an existing, simple asp.net web forms app including postbacks etc. into another external site with a jQuery load() call., an app that was intended to be integrated through an iframe. I doubt that's possible without a rewrite of the app.
The app is a basic questionnaire that leads the user to a product suggestion at the end.
Does anyone have any pointers to how I could solve this? I guess I will probably have to rewrite the app with web services and dynamic calls to RenderUserControls, I will also need access to the page that calls the load() and write additional jQuery methods to handle the user input... I will probably have to remove all of asp.net's postback calls and rewrite the handling of the user input?
First of all you should note that the load() function, like all ajax, can only work on the same domain. So if the 'external site' is on another domain ajax is the wrong choice.
It does sounds like a lot of hard work, depending on the complexity of the page. Postbacks can occur in many places - image clicks, combo selects, etc. Also, there are hidden fields to worry about, like the View State and Event handler - those have the same names on both pages. You'll have an easier time if the external site has no state and postbacks.
If the pages are relatively simple this can probably be done. It's been my experience that forms don't work well in other forms, so you'll have to remove one of them (probably the loaded page's form), or place them one after the other. As you've mentioned, you'll have to rewrite postbacks, you'll want to serialize the data. You may be able to change this string to fit the names on the original page (if you've changed the name of the viewstate, etc, it's easier to change it back on the serialized string than to mess with IDs), post it to the original page, and load again.
Personally, as much as I like jQuery, and as much as this project sounds interesting (and it is), I'd probably go for a server-side solution. It sounds much easier to create a user control (that may use ajax itself), or to the expose the page's functionality using web services or better, generic handlers.

Resources