HttpHandler not working
I have a custom HttpHandler for a specific URL (e.g. my.page), but SF keeps processing the request and giving a 404.
Any suggestions?
Hello Eric,
Could you provide some more description about the custom handler you have and what is its purpose? Generally you can create a new class that inheirits from PageRouteHandler.
Regards,
Ivan Dimitrov
the Telerik team
It takes querystring or post variables, stores them into the session or cookies, and redirects to another page. I'm not too familiar with PageRouteHandlers (just what I've read in the past five minutes) but I don't they would work in my situation. Do you agree?
Hi Eric,
There are two methods that you can override in PageRouteHandler to control the HTTP request.
BuildHandler - The request context.
GetHttpHandler - Provides the object that processes the request
If you want you can share your current code so we could see what is the best place to put it inside 4.0.
Greetings,
Ivan Dimitrov
the Telerik team
This is a simplified version of one of my handlers. It stores some values from the querystring and post into the session, then redirects to another page.
using
System.Web;
using
System.Web.SessionState;
namespace
MyWebSite.Classes.HttpHandlers
public
class
MyHandler : IHttpHandler, IRequiresSessionState
public
virtual
bool
IsReusable
get
return
false
;
public
void
ProcessRequest(HttpContext context)
context.Session[
"a"
] = context.Request.QueryString[
"a"
];
context.Session[
"b"
] = context.Request.Form[
"b"
];
if
(context.Request.QueryString[
"c"
] ==
"d"
)
context.Response.Redirect(
"/e"
,
true
);
else
context.Response.Redirect(
"/f"
,
true
);
Hello Eric,
I experimented with the handler you implemented below,added some aditional steps and it works fine.
1) Inherit PageRouteHandler and override GetHttpHandler :
Milena
public
class
MyPageRouteHandler : PageRouteHandler
public
override
IHttpHandler GetHttpHandler(RequestContext requestContext)
return
new
MyHandler();
2) At Bootstrapper.cs, method RegisterRootes, add to root collection "routes" the page route handler that will process the requests that contain "MyPage" at url.
routes.Add(
"MyPage"
,
new
Route(
"MyPage"
,
new
MyPageRouteHandler()));
Note: Be aware that the route handler that first match will serve the request, so MyPageRooteHandler should be added to "routes" collection before possible other matches.
Best wishes,
Hello Eric,
Since you don't have direct access to source of Bootsrapper.cs class. Following needs to be done:
1. Create a class that inherits from PageRouteHandler and inside GetHttpHandler call your HttpHandler
public override IHttpHandler GetHttpHandler(RequestContext requestContext)
var node = (SiteMapNode)requestContext.RouteData.DataTokens["SiteMapNode"];
if (node == null)
throw new ArgumentException("Invalid request for this route handler. Route data must contain SiteMapNode.");
//Here goes your condition for custom handler
if (node.Title == "MyPage")
return new MyHandler();
else
return base.GetHttpHandler(requestContext);
public static void RegisterType()
ObjectFactory.Container.RegisterType<
Telerik.Sitefinity.Web.PageRouteHandler
, MyPageRouteHandler>();
protected void Application_Start(object sender, EventArgs e)
Telerik.Sitefinity.Services.SystemManager.ApplicationStart += new EventHandler<
EventArgs
>(SystemManager_ApplicationStart);
void SystemManager_ApplicationStart(object sender, EventArgs e)
MyPageRouteHandler.RegisterType();
The RegisterType call gives me a red-squiggly underneat saying it does not have type parameters and is expecting parameters of Type, Type, string, LifetimeManager, and params InjectionMember[]. What should I put here?
Also, how do I get this to handle a request for a URL that's not in the SF sitemap? With HttpHandlers, I'd put a path of something like "*.mypage" to handle anything with the mypage extension.
Thanks
Hi Eric,
Sitefinity uses ASP.Net Routing Engine to handle incoming requests. This shouldn’t be preventing you from using mapped HttpHandlers, but it seems some Sitefinity route is catching all requests. We will investigate and fix this as soon as possible.
In the mean time you could register your own route with the system to handle that specific request. Please disregard the previously suggested steps and follow the once bellow:
1. Crate custom route handler like this:
public
class
MyRouteHandler : IRouteHandler
public
IHttpHandler GetHttpHandler(RequestContext requestContext)
// Return your HttpHandler implementation
return
new
MyHttpHandler();
2. Add Global.asax file to your project and modify it as shown below:
<
script
runat
=
"server"
>
void Application_Start(object sender, EventArgs e)
// Code that runs on application startup
Telerik.Sitefinity.Abstractions.Bootstrapper.Initialized += new EventHandler<
Telerik.Sitefinity.Data.ExecutedEventArgs
>(Bootstrapper_Initialized);
void Bootstrapper_Initialized(object sender, Telerik.Sitefinity.Data.ExecutedEventArgs args)
if (args.CommandName == "RegisterRoutes")
var routes = (System.Web.Routing.RouteCollection)args.Data;
routes.Add("MyRoute", new System.Web.Routing.Route("my.page", new MyRouteHandler()));
NOTE: "my.page" is the URL to which you want to map your HttpHandler. It could be a specific URL or URL pattern. Please see MSDN documentation how to specify URL patterns. Since routes are evaluated in the order they are defined in the route collection, you may need to rearrange them if other route is catching the request before yours. Let me know if you have further questions.
Best wishes,
Bob
the Telerik team
Hi Guys,
I have the same problem with custom routing handler.
I use Bob's solution from previous post. In the debug mode under VS I can see that handler has been added to routing table, but it did not fire when URL has been requested. It seems, Sitefinity still catch all requests.
Is there a way to make it work?
Best regards,
Anton.
Hi Eric,
Could you please specify the URL pattern that you want to handle?
You may try to put your route as the first item in the route table but be careful not to catch requests that you do not want to handle.
Best wishes,
Bob
the Telerik team
Hi Bob,
You are right, I just modified my code in Global.asax like this and my handler started to work:
void Application_Start(object sender, EventArgs e)
// Code that runs on application startup
Telerik.Sitefinity.Abstractions.Bootstrapper.Initialized +=
new EventHandler<
Telerik.Sitefinity.Data.ExecutedEventArgs
>(Bootstrapper_Initialized);
void Bootstrapper_Initialized(object sender, Telerik.Sitefinity.Data.ExecutedEventArgs args)
if (args.CommandName == "RegisterRoutes")
var routes = (System.Web.Routing.RouteCollection)args.Data;
routes.Insert(0, new System.Web.Routing.Route("catalog/Category.aspx", new Catalog.CatalogRouteHandler()));
GetHttpHandler
method:public IHttpHandler GetHttpHandler(RequestContext requestContext)
var page = BuildManager.CreateInstanceFromVirtualPath("~/catalog", typeof(Page)) as IHttpHandler;
foreach (KeyValuePair<
string
, object> token in requestContext.RouteData.Values)
requestContext.HttpContext.Items.Add(token.Key, token.Value);
return page;
The file '/catalog' does not exist.
at System.Web.UI.Util.CheckVirtualFileExists(VirtualPath virtualPath)
at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate)
at System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate)
at System.Web.Compilation.BuildManager.GetVirtualPathObjectFactory(VirtualPath virtualPath, HttpContext context, Boolean allowCrossApp, Boolean throwIfNotFound)
at System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(VirtualPath virtualPath, Type requiredBaseType, HttpContext context, Boolean allowCrossApp)
at System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(String virtualPath, Type requiredBaseType)
at Catalog.CatalogRouteHandler.GetHttpHandler(RequestContext requestContext) in C:\Inetpub\Sitefinity_4_0\lib\Catalog\CatalogRouteHandler.cs:line 32
at System.Web.Routing.UrlRoutingModule.PostResolveRequestCache(HttpContextBase context)
at System.Web.Routing.UrlRoutingModule.OnApplicationPostResolveRequestCache(Object sender, EventArgs e)
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
Hello Eric,
You do not need custom HttpHandler to achieve this, if I understand correctly what you need of course.
Please try the following example and let me know if this is what you need.
using
System;
using
System.IO;
using
Telerik.Sitefinity.Web;
public
partial
class
MyCatalogue : System.Web.UI.UserControl
protected
void
Page_Load(
object
sender, EventArgs e)
var requestContext =
this
.GetRequestContext();
var urlParams = (
string
[])requestContext.RouteData.Values[
"Params"
];
string
message;
if
(urlParams !=
null
&& urlParams.Length > 0)
message = Path.GetFileNameWithoutExtension(urlParams[0]);
else
message =
"No category specified."
;
this
.Category.Text = message;
Hi Bob,
Thank you for provided solution! Is seems, this is what I need.
As far as I understand non-existing parts of URL are added in RouteData, for instance, test-category.aspx.
I've asked about this behavior in this thread. Radoslav said this is a known bug.
Maybe I misunderstood something, but I'm wondering will your solution work in the future releases of Sitefinity?
I'm afraid that the bug will be fixed and this way will not work.
Best regards,
Anton.
Hello Eric,
Well, it is disputable whether it is a bug or not. Anyway, you will be able to set the behavior, so this solution will continue to work. Furthermore it will probably be extended to support URL patterns instead of blindly putting the rest of the URL as parms.
I tried the Last method (using a control) to accomplish Url Rerouting within the SiteFinity sitemap. It appears this method does not work in version 4.3.1885.0.
Please see my thoughts and attempts on this; here:
http://www.sitefinity.com/devnet/forums/sitefinity-4-x/bugs-issues/question-how-to-integrate-url-rerouting-with-sitefinity-virtual-folder-structure-version-4-3-1885-0.aspx
I am attempting to do this (url rerouting):
"Training/available-courses/Details/CourseId/CourseName"
Sitefinity is killing the * or wildcard in its track.
Sitefinity tries to handle all requests using its own site map; if the request is within the context of the sitemap. Anything after a defined Path within SiteMap is queried. If the exact path is not found in declines the request and produces an exception.
Notice: Details is a Virtual Page within the sitfinity map..
-doug lubey of louisiana
Any help would be appreciated.
Hi Doug,
To be able to use the built in Sitefinity functionality for routing you just need to get the URL parameters from the request URL and the pages on which you have your custom widgets must Allow parameter validation. This is all you need, you do not need to add an additional URL for the parameters. Bellow is a quick sample widget that shows blog posts in list and single mode. It resolves the item based on the url parameters. Essentially your widget should parse tha urlParams variable to determine if there is an item in the URL. Here is the widget code
ascx:
<%@ Control Language=
"C#"
AutoEventWireup=
"true"
CodeBehind=
"MyCatalogue.ascx.cs"
Inherits=
"SitefinityWebApp.MyCatalogue"
%>
<asp:Repeater runat=
"server"
ID=
"itemsRptr"
>
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<asp:HyperLink runat=
"server"
id=
"singleItemLink"
Text=
'<%#Eval("Title")%>'
></asp:HyperLink>
<br />
<asp:Literal runat=
"server"
ID=
"contentLtrl"
Text=
'<%#Eval("Content")%>'
></asp:Literal>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
protected
void
Page_Load(
object
sender, EventArgs e)
string
urlParams =
this
.GetUrlParameterString(
true
);
//display list mode
if
(String.IsNullOrEmpty(urlParams))
this
.itemsRptr.DataSource = App.WorkWith().BlogPosts().Publihed().Get().ToList();
this
.itemsRptr.ItemDataBound +=
new
System.Web.UI.WebControls.RepeaterItemEventHandler(itemsRptr_ItemDataBound);
this
.itemsRptr.DataBind();
//display single item
else
if
(urlParams.StartsWith(
"/Action/Edit"
) || urlParams.StartsWith(
"/Action/Preview"
))
return
;
BlogsManager blogsManager = BlogsManager.GetManager();
string
redirectUrl;
var item = blogsManager.GetItemFromUrl(
typeof
(BlogPost), urlParams,
true
,
out
redirectUrl);
//if an item cannot be resolved from the URL there will be a 404 error thrown
if
(item !=
null
)
RouteHelper.SetUrlParametersResolved(
true
);
this
.itemsRptr.DataSource =
new
List<IDataItem>() item ;
this
.itemsRptr.DataBind();
void
itemsRptr_ItemDataBound(
object
sender, System.Web.UI.WebControls.RepeaterItemEventArgs e)
if
(e.Item.ItemType == System.Web.UI.WebControls.ListItemType.AlternatingItem || e.Item.ItemType == System.Web.UI.WebControls.ListItemType.Item)
HyperLink link = e.Item.FindControl(
"singleItemLink"
)
as
HyperLink;
link.NavigateUrl = DataResolver.Resolve(e.Item.DataItem,
"Url"
);
It appears that RouteHelper.SetUrlParametersResolved(true); is now obsolete. What should we be using instead? I have already setup my own Route based on SitefinityRoute, but it would be much easier to handle the routing with this approach if there isn't a lot of logic needed for the route.
Hi,
This method is set as obsolete with its creation intentionally. Once we have a better way for setting this resolved parameter we will notify about the changes that need to be applied.
Kind regards,
Radoslav Georgiev
the Telerik team
I can't seem to get this to work. I have a user control with the code below in the Page_Load. I have it published to http://www.oumedicine.com/home/find-a-doctor/physician2/
and I was under the impression that if I did this GetUrlParameterString something like
http://www.oumedicine.com/home/find-a-doctor/physician2/test
would allow me to grab the parameters. It's instead giving me the Page not found error. The page it's published to has Allow parameter validation in the Advanced options under page properties.
protected
void
Page_Load(
object
sender, EventArgs e)
string
urlParams =
this
.GetUrlParameterString(
true
);
if
(!String.IsNullOrEmpty(urlParams))
lblURL.Text = urlParams;
else
lblURL.Text =
"No Params"
;
You have to remember to add the following in order to let SF know that it doesn't need to search any further for the page.
RouteHelper.SetUrlParametersResolved(
true
);
Yep I missed that! Thanks!
When we were on Sitefinity 5.0, we were able to add HttpHandlers directly, but as of 5.2 we couldn't anymore. We had to add RouteHandlers. We did this in Bootstrapper_Initialized via the following code, which worked fine locally, but not when we ran it in IIS.
var routes = ((EnumerableQuery<RouteBase>)args.Data).ToList();
routes.Add(...);
The fix seemed to be adding them to RouteTable.Routes directly instead.
I'm posting this for two reasons. First, if anyone sees any issue with this, please let me know. Second, hopefully this will help someone else out. This has only been tested in Sitefinity 5.4, so I can't speak for earlier versions.
Hi,
I am on Version 5.4 and I add my custom routes via "RouteTable.Routes directly".
My custom HttpHandler is triggered only once, on application_start but after that, when I navigate to other pages that make use of my custom HttpHandler, it gives me "Server Error in '/' Application.The resource cannot be found."
can someone please assist?
thank you in advance.
The issue is common is IIS 7 and it depends on the Pipeline mode the Application pool is configured. According to this, the handler configuration section will change.It's explained in this post: codeskaters.blogspot.ae/.../httphandler-error-404-not-found.htmlIt works for me. It says for Classic mode use:<system.web>
<httpHandlers>
</httpHandlers>
</system.web>
and integrated pipeline mode use
<system.webServer>
<handlers>
</handlers>
<system.webServer>
In case someone else is struggeling with this!
Registering custom routes has changed in newer versions of SF. In 7.2 the following works:
private
void
Bootstrapper_Initialized(
object
sender, ExecutedEventArgs e)
if
(e.CommandName ==
"RegisterRoutes"
)
Route myRoute =
new
Route(
"my.page"
,
new
MyRouteHandler());
RouteTable.Routes.Add(
"MyRouteName"
, myRoute);
OC