views:

602

answers:

2

My problem is pretty simple. I've got a Uri and I want to figure out which route it maps to so I can do some checks on the various pieces of the route: controller, action, etc.

How do I go from Uri to RouteData or Route?

+2  A: 

You might try extending HttpRequestBase and override the Uri property so that you can assign your Uri to the property on the request. Then override HttpContextBase to allow you to set the Request property on the context. You can then use the GetRouteData() method on the RouteCollection class to get a suitable RouteValueDictionary. Note that the RouteCollection is available as a static property on the RouteTable class.

var myRequest = new MyRequest( myUri );
var myContext = new MyContext( myRequest );
var routeData = RouteTable.Routes.GetRouteData( myContext );

Update:

For your use case (comments), you might be able to simply match on the controller/action:

if (myUri.ToString().ToLower().Contains( "/controller/action" ))
{
     return RedirectToAction( action, controller, new { ...route data } );
}
else
{
     return Redirect( "http://www.example.com/default" );
}
tvanfosson
Wow. Seems like there should really be a less convoluted way than that...
mkedobbs
I've never actually needed to do it as the framework handles it. What exactly is your use case?
tvanfosson
All I've got to deal with is a Uri and I need to redirect if that Uri meets certain criteria (map to a specific controller with a specific action), otherwise redirect to a default Uri.
mkedobbs
How about simply matching the string "controller/action" in the Uri rather than parsing it into route data? I'll update with an example.
tvanfosson
I don't like hard-coding URL values like that for one, and for another, the conditions may go beyond just controller and action for some cases. I've got it working now... I'll post the result below. +1 for all your help.
mkedobbs
+1  A: 

Based on @tvanfosson's direction, I came up with a class that does what I need. Note that the GetRouteData actually looks at the AppRelativeCurrentExecutionFilePath and the PathInfo properties on the RequestContextBase class, not the Url property.

public class RouteInfo
{
    public RouteInfo(RouteData data)
    {
        RouteData = data;
    }

    public RouteInfo(Uri uri, string applicationPath)
    {
        RouteData = RouteTable.Routes.GetRouteData(new InternalHttpContext(uri, applicationPath));            
    }

    public RouteData RouteData { get; private set; }

    //********************
    //Miscellaneous properties here to deal with routing conditionals... (e.g. "CanRedirectFromSignIn")
    //********************

    private class InternalHttpContext : HttpContextBase
    {
        private HttpRequestBase _request;

        public InternalHttpContext(Uri uri, string applicationPath) : base()
        {
            _request = new InternalRequestContext(uri, applicationPath);
        }

        public override HttpRequestBase Request { get { return _request; } }
    }

    private class InternalRequestContext : HttpRequestBase
    {
        private string _appRelativePath;
        private string _pathInfo;

        public InternalRequestContext(Uri uri, string applicationPath) : base()
        {
            _pathInfo = uri.Query;

            if (String.IsNullOrEmpty(applicationPath) || !uri.AbsolutePath.StartsWith(applicationPath, StringComparison.OrdinalIgnoreCase))
            {
                _appRelativePath = uri.AbsolutePath.Substring(applicationPath.Length);
            }
            else
            {
                _appRelativePath = uri.AbsolutePath;
            }
        }

        public override string AppRelativeCurrentExecutionFilePath { get { return String.Concat("~", _appRelativePath); } }
        public override string PathInfo { get { return _pathInfo; } }
    }
}
mkedobbs
Note: This should probably have some additional checking to make sure the Uri is absolute... otherwise this craps out.
mkedobbs