Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC: Uri to usable route data

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?

like image 857
mkedobbs Avatar asked Dec 10 '09 17:12

mkedobbs


3 Answers

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; } }
    }
}
like image 82
mkedobbs Avatar answered Nov 03 '22 09:11

mkedobbs


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" );
}
like image 2
tvanfosson Avatar answered Nov 03 '22 10:11

tvanfosson


Depending on if you are okay with changing the path of the current request (In my case I am) here is a very easy solution that doesn't involve mocking up anything:

HttpContext httpContext = HttpContext.Current;
httpContext.RewritePath(URL);
RouteData route = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));
like image 1
John Culviner Avatar answered Nov 03 '22 11:11

John Culviner