Setting an alternate controller folder location in ASP.NET MVC
Asked Answered
M

4

13

We can an MVC app that uses the default folder conventions for the HTML views, but we'd like to set up alternate "Services" folder with controllers used only for web services returning xml or json.

So the route "/Services/Tasks/List" would be routed to "/Services/TaskService.cs", while "/Tasks/List" would be routed to the standard "/Controllers/TaskController.cs"

We'd like to keep the service controllers separate from the view controllers. We don't think areas or using another project will work. What would be the best way to approach this?

Monastery answered 7/12, 2010 at 1:15 Comment(0)
T
14

You can do this using Routing, and keeping the controllers in separate namespaces. MapRoute lets you specify which namespace corresponds to a route.

Example

Given this controllers

namespace CustomControllerFactory.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
           return new ContentResult("Controllers");
        }
    }
}

namespace CustomControllerFactory.ServiceControllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
           return new ContentResult("ServiceControllers");
        }
    }
}

And the following routing

 routes.MapRoute(
           "Services",
           "Services/{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            new string[] { "CustomControllerFactory.ServiceControllers" } // Namespace
        );


        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            new string[] { "CustomControllerFactory.Controllers"} // Namespace
        );

You should expect the following responses

/Services/Home

ServiceController

/Home

Controllers

Tafia answered 7/12, 2010 at 2:14 Comment(2)
You can do this and return a ContentResult or any non-view result, just remember if you decide to return any sort of view, you will need to create a custom view engine.Owl
Yes, the answer above only solves the routing part of the problem. If you return a ViewResult, you'll need to modify conventions for choosing the view. If you choose to implement a custom view engine,this might help. You can also try basing your service controllers on a base class which overrides View(), and implement your conventions there. It would be nice to know which path you take.Tafia
I
2

In Asp.Net Core: I used AreaFeature library ServiceCollectionExtensions

First set your middleware;

    services.AddMvc(options => 
        options.EnableEndpointRouting = false).
        AddFeatureFolders().SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Latest);

In the extenssion:

return AddFeatureFolders(services, new FeatureFolderOptions());

implement as according your requirement:

 public static IMvcBuilder AddFeatureFolders(this IMvcBuilder services, FeatureFolderOptions options)
        {
            if (services == null)
                throw new ArgumentNullException(nameof(services));

            if (options == null)
                throw new ArgumentException(nameof(options));

            var expander = new FeatureViewLocationExpander(options);

            services.AddMvcOptions(o => o.Conventions.Add(new FeatureControllerModelConvention(options)))
                .AddRazorOptions(o =>
                {
                    o.ViewLocationFormats.Clear();
                    o.ViewLocationFormats.Add(options.FeatureNamePlaceholder + @"\{0}.cshtml");
                    o.ViewLocationFormats.Add(options.FeatureNamePlaceholder + @"\_Views\{0}.cshtml");
                    o.ViewLocationFormats.Add(options.FeatureFolderName + @"\Shared\{0}.cshtml");
                    o.ViewLocationFormats.Add(options.DefaultViewLocation);

                    o.ViewLocationExpanders.Add(expander);
                });

            return services;
        }

In my case i preferred a separated _View folder for views in the features folders like that

~/Features/Account/_Views/login.cshtml
~/Features/Account/AccountController.cs
~/Features/Account/AccountModel.cs
Irrelevancy answered 23/4, 2020 at 16:34 Comment(0)
M
0

You'll want to create your own controller factory implementing IControllerFactory.

Check out http://nayyeri.net/custom-controller-factory-in-asp-net-mvc for an example.

Marduk answered 7/12, 2010 at 1:22 Comment(1)
the link is broken :(Anticipatory
W
0

If you see yellow folder names Add folder Name in root

After, you have to modify routes.MapRoute into "App_Start > RouteConfig"

Modify Default route

routes.MapRoute(
          "Default",
          "{controller}/{action}/{id}",
          new { controller = "Home", action = "Index", id =     UrlParameter.Optional },
          new string[] { "mvcPartialView.HomeController" } // Namespace 
      );

and Add this

routes.MapRoute(
       "ApiControllerOne", // Name of folder
       "ApiControllerOne/{controller}/{action}/{id}",
        new { controller = "ApiFactory", action = "callFactoryOne", id = UrlParameter.Optional },
        new string[] { "mvcPartialView.ApiControllerOne" } // Namespace
    );
Weihs answered 2/8, 2016 at 16:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.