Frage

I have a situation where I need to override methods in an old HttpHandler API in an ASP.NET WebForms application. I'm using WebAPI as the base for the new API and it's been working great except I need the routing to fallback when an action is not found in the new API. This is not true currently, instead I get a "404: Not Found" whenever the WebAPI controller does not have a matching Action.

My routing for the new API is as follows:

var apiroute = routes.MapHttpRoute(
    "API Default",
    "api/{language}-{country}/{controller}/{action}/{id}",
    new { id = RouteParameter.Optional }
);

The old Httphandler APIs register their routes as follows (order is after WebAPI route):

var route = new Route("api/{language}-{country}/Person/{command}", this);
RouteTable.Routes.Add(route);

I want /api/en-US/Person/List to match the first route if theres a PersonController with a List action but to fallback to the old api if there is not.

Question: Is it possible to add a filter to the first route to only match if the Action is indeed available on the controller? How else could I accomplish this?

War es hilfreich?

Lösung

Update

You may also want to investigate attribute based routing this may be a cleaner solution only the actions you annotate with the routing attributes will be matched to the route and that may help you achieve what you want.

Or

Although there may be better ways than this, it is possible if you implement a custom IRouteConstraint e.g. this article.

A highly rough and ready approach you could improve upon is below:

public class IfActionExistsConstraint : IRouteConstraint
{
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        var actionName = values["Action"] as string;

        if (actionName == null)
        {
            return false;
        }

        var controllerName = values["Controller"] as string;
        var controllerTypeResolver = GlobalConfiguration.Configuration.Services.GetHttpControllerTypeResolver();
        var controllerTypes = controllerTypeResolver.GetControllerTypes(GlobalConfiguration.Configuration.Services.GetAssembliesResolver());
        var controllerType = controllerTypes.SingleOrDefault(ct => ct.Name == string.Format("{0}Controller", controllerName));

        if(controllerType == null)
        {
            return false;
        }

        return controllerType.GetMethod(actionName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) != null;
    }
}

Registration:

var apiroute = routes.MapHttpRoute(
    name: "API Default",
    routeTemplate: "api/{language}-{country}/{controller}/{action}/{id}",
    defaults: new { id = RouteParameter.Optional },
    constraints: new { IfActionExistsConstraint = new IfActionExistsConstraint() }
);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top