views:

823

answers:

4

I have the pattern User/{domain}/{username} set up via Routing. Everything works except for one thing. I can't figure out how to get the domain and username variables passed to my redirected page. Below is my GetHttpHandler method from my IRouteHandler implementation.

    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        string basePath;
        basePath = "~/UserPage.aspx";
        string domain = requestContext.RouteData.GetRequiredString("domain");
        string username = requestContext.RouteData.GetRequiredString("username");

        string virtualPath =
            string.Format(basePath + "?domain={0}&username={1}", domain, username);
        return (Page)BuildManager.CreateInstanceFromVirtualPath(virtualPath, typeof(Page));

    }

I get the error from the last line of code: UserPage.aspx?domain=SOMEDOMAIN&username=SOMEUSER is not a valid virtual path.

So how are you supposed to pass variables to the target page? what am I missing?

+1  A: 

I think I solved this one myself. Found this loop

  foreach (KeyValuePair<string, object> token in requestContext.RouteData.Values)  
     {                  
         requestContext.HttpContext.Items.Add(token.Key, token.Value);  
     }

from http://www.codethinked.com/post/2008/08/20/Exploring-SystemWebRouting.aspx Its like the 4th code sample down.

UPDATE:
Not sure if this will work... requestContext.HttpContext seems to be "readonly". Back to the drawing board.

UPDATE 2:
Looks like this will work if you add in a reference to System.Web.Abstractions

tyndall
+1  A: 

Started mucking around with things and saw the IHttpHandler interface provides the RequestContext to the GetHttpHandler method.

So, I modified my base page class (I always put a layer between System.Web.UI.Page and my own pages, calling it BasePage or similar just for the purpose). So I added a public property on PVBasePage to receive a RequestContext object.

public RequestContext RequestContext { get; set; }

Then, my Routing class code is as follows:

IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
{
    // create the page object as my own page...
    var page = BuildManager.CreateInstanceFromVirtualPath(VirtualPath
        , typeof(PVBasePage)) as PVBasePage;
    // pass in the request context
    page.RequestContext = requestContext;
    // return this page in the form of a IHttpHandler
    return page as IHttpHandler;
}

So instead of, as in the sample code, creating the instance directly as the IHttpHandler, I create it as my own page. Set the request context property, and then return the page to the caller AS a IHttpHandler.

Tested and it works. WOO HOO!

Then in the instance page, you can hit the RequestContext.GetValues collection to read out your passed in parameters.

HTH

peiklk
+1  A: 

@B.Tyndall

I just got this working with a solution similar to yours.

found at: http://msmvps.com/blogs/luisabreu/archive/2008/03/12/using-the-routing-mvc-api-with-classic-asp-net.aspx

foreach (var aux in requestContext.RouteData.Values)
{
    HttpContext.Current.Items[aux.Key] = aux.Value;
}

So in effect you're no longer using the Request.QueryString but instead Context.Items collection

HttpContext.Current.Items["RouteName"]

or

Context.Items["RouteName"]
mdmullinax
+1  A: 

It appears as though other are also taking the route (no pun intended) of putting the parameters in the context Items collection.

http://bbits.co.uk/blog/archive/2008/05/19/using-asp.net-routing-independent-of-mvc---passing-parameters-to.aspx

I combined a couple of these approaches for pages that have a specific parameter, I created a UserNameRouteHandler for pages that accept that type of parameter. In my PageBase class I checked the context items for that parameter and then set a property so that my pages that inherit from PageBase can use it.

public class UserNameRouteHandler : IRouteHandler
{
    #region Implementation of IRouteHandler

    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        string pageName = requestContext.RouteData.GetRequiredString("PageName");

        string employeeUserName = requestContext.RouteData.GetRequiredString("UserName");

        if(!string.IsNullOrEmpty(employeeUserName))
        {
            requestContext.HttpContext.Items["UserName"] = employeeUserName;
        }

        pageName = pageName.ToLower() == "home" ? "default" : pageName;

        string virtualPath = string.Format("~/{0}.aspx", pageName);

        return (Page)BuildManager.CreateInstanceFromVirtualPath(virtualPath, typeof(Page));

    }

    #endregion
}

And in my OnLoad of PageBase I set the property to pages that need it can have it...definitely looking for a more elegant solution though.

protected override void OnLoad(EventArgs e)
{
    if (!IsPostBack)
    {
        if (Context.Items["UserName"] != null)
        {
            EmployeeUserName = Context.Items["UserName"].ToString();
        }
    }

    base.OnLoad(e);
}
Daryl