10

I'm trying to determine if it is possible (or practical) to implement Uncle Bob's Screaming Architecture in ASP.NET MVC 5 rather than using the default folder structure.

Here's a link to a description of the Screaming Architecture: http://blog.8thlight.com/uncle-bob/2011/09/30/Screaming-Architecture.html

A hypothetical folder structure would look something like this:

Root

  • Customers
    • Controllers
      • CustomerController.cs
    • Models
      • Customer.cs
    • Views
      • Index.cshtml
      • Details.cshtml
      • Update.cshtml
  • Employees
    • Controllers
      • EmployeesController.cs
    • Models
      • Employee.cs
    • Views
      • Index.cshtml
      • Details.cshtml
      • Update.cshtml
  • Shared
    • Views
      • _Layout.cshtml
      • Error.cshtml
  • _ViewStart.cshtml
  • Web.config

The corresponding URL routes would look like this:

I've created a custom RazorViewEngine and added the appropriate view location formats (e.g. "~/{1}/Views/{0}.cshtml") and partial view location formats (e.g. "~/Shared/Views/{0}.cshtml"). I've also moved the shared _ViewStart.cshtml to the root and merged the Views/Shared folder's web.config with the root-level web.config to avoid having to duplicate these two files in all of the View folders.

Everything works great, however, if I try navigating to an index page (e.g. http://www.example.com/employees/) I get a 403.14 Error (Forbidden). All other routes (including http://www.example.com/employees/index) work just fine.

My guess is that IIS is explicitly blocking the route to the controller's index method because the URL coincides with a folder in the filesystem and directory browsing is disabled by default. If I enable directory browsing, however, it actually takes me to the actual directory listing rather than routing to the controller's index method.

I can move the Customers and Employees folders into a subfolder (i.e. move them out of the root) and everything works fine, but I'd like to try to keep these folders at the top level (per the Screaming Architecture guidelines).

Does anyone have a solution for this issue?

Please note that MVC Areas is not the solution I'm looking for as it does not allow for the folder structure described above (i.e. top-level folders named after high-level use cases and views contained directly within the Views folder rather than in a subfolder).

Matthew Renze
  • 634
  • 1
  • 6
  • 17
  • Did you map a route for `http://www.example.com/employees/`? – jamesSampica Apr 14 '15 at 21:09
  • Yes, I'm using the default route (i.e. "{controller}/{action}/{id}") with the default action mapped to "Index" and id as an optional parameter, which should map to the controller. – Matthew Renze Apr 14 '15 at 21:28
  • Came up with a possible solution after some testing. Let me know if that works. :) – jamesSampica Apr 15 '15 at 02:56
  • 1
    To help others overcome this obstacle, I wrote a step-by-step article on how to implement Uncle Bob's Screaming Architecture in ASP.NET MVC 5. http://www.matthewrenze.com/articles/clean-architecture-in-asp-net-mvc-5/ – Matthew Renze Apr 27 '15 at 13:17

1 Answers1

6

I'm betting you are right about IIS then. If you have two paths mapped to the same resource, the physical path is checked first on the IIS side.

I was digging around the routes configuration and found the property RouteExistingFiles on RouteCollection and think this could work.

I set the value to true and tested locally with an empty folder in the project, a route redirecting to Home/Index, and navigating to localhost:xxx/MyFolder. It worked correctly.

So then all you should need to do is set this property to true for it to choose Asp.net routes first instead of physical routes.

jamesSampica
  • 12,230
  • 3
  • 63
  • 85
  • That appears to do the trick. So far I don't see any issues with your solution. I'm going to to play around with my test project a bit more and look for any potentially negative side effects from your proposed solution and if I don't see any by the end of the day, I'll mark this as the accepted answer. Thanks for all your help and your prompt response! – Matthew Renze Apr 15 '15 at 14:20
  • 1
    I haven't run into any issues at all with your solution. In fact, it works very well and has no significant side effects. I've marked your solution as the accepted answer. Thanks again! – Matthew Renze Apr 16 '15 at 14:19
  • 2
    Good to hear. The only "downside" should be that in the case where you want to serve the physical file instead of the action when a physical file is on the same route as a mapped route. Can't think of many circumstances where you'd want that to happen, though. – jamesSampica Apr 16 '15 at 14:32