Problems creating two routes that will not generate 404 error in ASP.NET MVC

I am trying to create my training project with routing. My main goal is to build two routes that in any case will not generate a 404 error. By this, I mean that if the path is wrong, I want the routing to use the / Home / Index path. I have the following two routes:

    routes.MapRoute("Default", "{controller}/{action}", 
                        new {controller = "Home", action = "Index"}
                        );

    routes.MapRoute("Second", "{*catchall}",
                        new {controller = "Home", action = "Index", id = UrlParameter.Optional}
                        );

It works fine when I use a non-existent path that does not match the first route, for example:

Missing path 1

But if so, then I have the following -

enter image description here

or

enter image description here

I understand the reason why this is happening. However, at the moment I was able to find a "some" solution. Adding the following file to the web.config file -

<customErrors mode="On">
      <error statusCode="404" redirect="~/Home/Index"/>
</customErrors>

, . , , , . , .

-, , . .

+4
6

, , "" , :

  • .
  • "id", .

. AFAIK, . , , id , 3 .

routes.MapRoute(
   name: "DefaultWithID",
   url: "{controller}/{action}/{id}",
   defaults: new { controller = "Home", action = "Index" },
   constraints: new { action = new ActionExistsConstraint(), id = new ParameterExistsConstraint() }
);

routes.MapRoute(
   name: "Default",
   url: "{controller}/{action}",
   defaults: new { controller = "Home", action = "Index" },
   constraints: new { action = new ActionExistsConstraint() }
);

routes.MapRoute(
    name: "Second",
    url: "{*catchall}",
    defaults: new { controller = "Home", action = "Index" }
);

ActionExistsConstraint

public class ActionExistsConstraint : IRouteConstraint
{
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (routeDirection == RouteDirection.IncomingRequest)
        {
            var action = values["action"] as string;
            var controller = values["controller"] as string;

            var thisAssembly = this.GetType().Assembly;

            Type[] types = thisAssembly.GetTypes();

            Type type = types.Where(t => t.Name == (controller + "Controller")).SingleOrDefault();

            // Ensure the action method exists
            return type != null && type.GetMethod(action) != null;
        }

        return true;
    }
}

ParameterExistsConstraint

public class ParameterExistsConstraint : IRouteConstraint
{
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (routeDirection == RouteDirection.IncomingRequest)
        {
            var action = values["action"] as string;
            var controller = values["controller"] as string;

            var thisAssembly = this.GetType().Assembly;

            Type[] types = thisAssembly.GetTypes();

            Type type = types.Where(t => t.Name == (controller + "Controller")).SingleOrDefault();
            var method = type.GetMethod(action);

            if (type != null && method != null)
            {
                // Ensure the parameter exists on the action method
                var param = method.GetParameters().Where(p => p.Name == parameterName).FirstOrDefault();
                return param != null;
            }
            return false;
        }

        return true;
    }
}
+2

, RouteConstraint.

:

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            constraints: new { controller = new ControllerNameConstraint() }

        );

        routes.MapRoute(
            name: "Second",
            url: "{*wildcard}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }

ControllerNameConstraint. , , , ( , )

public class ControllerNameConstraint : IRouteConstraint
{
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (values[parameterName].ToString() == "Home" || values[parameterName].ToString() == "Account")
        {
            //the route is matched and will run the constrained ("Default") route
            return true;
        }
        //the route is not matched to the constraint and will fall through to your wildcard route
        return false;
    }
}
0

- , , . , , , , , URL- , -, . , httpErrors Web.config:

<system.webServer>
    ...
    <httpErrors errorMode="Custom" existingResponse="Replace">
        <remove statusCode="404" />
        <error statusCode="404" responseMode="ExecuteURL" path="/error/404" />
    </httpErrors>

ErrorController 404s. URL- , , . , , 404, . URL-, 404. Mine /error/404, , . , 404, - /error/http404 /error/notfound.

0

, , - /, . URL-, , , .

    routes.MapRoute(
        name: "Default",
        url: "Home/Index/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );

, , . , .

0

NightOwl888 , ActionExistsConstraint ParameterExistsConstraint , . ,

public class ActionExistsConstraint : IRouteConstraint
{
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (routeDirection == RouteDirection.IncomingRequest)
        {
            var action = values["action"] as string;
            var controller = values["controller"] as string;

            var thisAssembly = this.GetType().Assembly;

            Type[] types = thisAssembly.GetTypes();

            Type type = types.FirstOrDefault(t => t.Name.Equals(controller + "Controller", StringComparison.OrdinalIgnoreCase));

            // Ensure the action method exists
            return type != null &&
                   type.GetMethods().Any(x => x.Name.Equals(action, StringComparison.OrdinalIgnoreCase));
        }

        return true;
    }
}

public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (routeDirection == RouteDirection.IncomingRequest)
        {
            var action = values["action"] as string;
            var controller = values["controller"] as string;

            var thisAssembly = this.GetType().Assembly;

            Type[] types = thisAssembly.GetTypes();

            Type type = types.FirstOrDefault(t => t.Name .Equals(controller + "Controller", StringComparison.OrdinalIgnoreCase));
            var method = type.GetMethods().FirstOrDefault(x => x.Name.Equals(action, StringComparison.OrdinalIgnoreCase));

            if (type != null && method != null)
            {
                // Ensure the parameter exists on the action method
                var param = method.GetParameters().FirstOrDefault(p => p.Name.Equals(parameterName, StringComparison.OrdinalIgnoreCase));
                return param != null;
            }
            return false;
        }

        return true;
    }
0
source

Change the route declaration with

 routes.MapRoute("Second", "{*catchall}",
                        new {controller = "Home", action = "Index", id = UrlParameter.Optional}
                        );

routes.MapRoute("Default", "{controller}/{action}", 
                        new {controller = "Home"`enter code here`, action = "Index"}

                    );
-2
source

Source: https://habr.com/ru/post/1610076/


All Articles