Changing ASP.Net MVC directory structure - asp.net-mvc

I've been working with ASP.Net MVC (3) for some time now and i like it a lot. But one thing i find a bit annoying is having to browse between the controllers / views / model / script directory all the time. So i'm wondering if there's a way to tell MVC to look for the files in a different location?
Maybe someone can tell me how to simply group the files together by controller like:
Directory: /Membership
MembershipController
LogOnView
LogOnModel
RegisterView
RegisterModel
Kind regards
Olav

I know exactly what you're talking about. Here are the conditions where I find the default MVC folder structure to be onerous:
I'm using a model-per-view approach
My controller basically only works with that one particular view
I have some javascript that only pertains to that view
Why do I want to put each of these pieces in a different folder?
I create a folder for the view in the Views folder, so you have a folder ~/Views/MyEntityList (just like the traditional MVC approach), but I put everything that pertains to that component there:
~/Views/MyEntityList/
MyEntityListController.cs
MyEntityListModel.cs
MyEntityList.js
MyEntityList.aspx
I find this structure leads all the developers to keep views decoupled from one another. No special MVC configuration is required, except for allowing browsers to access the .js resources directly.
There are some architectural patterns where this might not be a good way to go. For a model-per-view approach (see Los Techies for more description) I really like this structure.

I think you need to get the Solution Navigator extensions via Power Tools update for VS 2010.
That way, you can display in the Solution Navigator, as opposed to the solution explorer, only the open files, for example. Makes it easier.
By the way, delete all the model folders and create a separate model project, eg:
MyApp.Domain
Any solution that is beyond basic will benefit from this.
As stated in the comments to your question, Areas will also reduce your navigation requirements.

The only "looking of files" going on is with views, everything else is just a convention, so if you want you could have:
Directory: /Membership
MembershipController
LogOnView
LogOnModel
RegisterView
RegisterModel
... but the views must be in ~/Views/Membership

It looks like you have to override some behavior in the view engine. You can See this question to get a better idea.

One way I can think of to achieve this is by writing your custom view engine. You can place all these below files in Controllers/Membership
MembershipController
LogOnView
LogOnModel
RegisterView
RegisterModel
Models will not be a problem you can simply change the namespace for the models, the only problem is with the views. For this write your custom view engine so that your mvc application knows the physical location of the view files as follows.
public class CustomViewEngine : RazorViewEngine
{
public CustomViewEngine()
{
ViewLocationFormats = new[]
{
"~/Controllers/{1}/{0}.cshtml",
};
}
}
In global.asax.cs add the ViewEngine in Application_Start() by including the following code
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CustomViewEngine());
You may also have to take care of various other factors like updating the Layout attribute depending on where you place the _Layout.cshtml.
In case you are using areas, add the AreaViewLocationFormats string array as well.
You can do further customization by overriding some of the methods like FileExists, CreateView, CreatePartialView.
Note: Do not forget to copy web.config in the views folder to the Membership controller. Otherwise application does not find the required mvc namespaces and it does not find the symbols like viewbag, model etc.

Related

How to make module base structure for asp .net mvc 3 project?

I want to create module based structure, Like in zend framework. Suppose I have 2 controllers like student and teacher and I want to put all these in one folder say shchool. Same way I want the view files for each controller in school folder for e.g
For Controller:
D:\aspprojects\Project1\Project1\Controllers\School\TeacherController.cs
D:\aspprojects\Project1\Project1\Controllers\School\StudentController.cs
and for view files:
D:\aspprojects\Project1\Project1\Views\School\Teacher\all CRUD files(*.cshtml)
D:\aspprojects\Project1\Project1\Views\School\Student\all CRUD files(*.cshtml)
Current structure is like as below,
for Controllers:
D:\aspprojects\Project1\Project1\Controllers\TeacherController.cs
D:\aspprojects\Project1\Project1\Controllers\StudentController.cs
For view files
D:\aspprojects\Project1\Project1\Views\Teacher\all CRUD files(*.cshtml)
D:\aspprojects\Project1\Project1\Views\Student\all CRUD files(*.cshtml)
What changes do I need to do?
The problem you are facing is that MVC doesn't care what folder the controller is in. In fact, it doesn't even have to be in a folder called Controllers. MVC only looks for classnames with Controller in the name. Once compiled, the folder structure is lost, and as such, no way for the framework to know to look in a subfolder for a view, because that information is no longer present in the compiled code.
You can still do it, however.. but you can no longer rely on MVC to find your view files automatically, you will have to pass each view name directly.
This means you will have to do this:
return View("~/Views/School/Teacher/Index.cshtml");
Rather than this.
return View();
Another option is to use areas, which allows you to create a School area, and then you can create a teacher and student controllers within the school area.

How to implement a custom view engine in ASP.Net MVC that (sorta) isn't file-based?

I've created a fairly generic view engine that I created initially without aiming toward ASP.Net MVC. Now though, I think it would be a good idea to have it to where it can at least be easily used by MVC projects. I'm wondering if my project would map well to the ASP.Net MVC style though.
The problem I'm having is that my view engine generates everything at compile-time via T4 templates. This means that everything is statically typed for the most part. Most of MVC seems to be a bit loosely typed however.
So for some view you might have this code generated:
class MyView{
public string Foo{get;set;}
public int Bar{get;set;}
public string Render(){
return "This is my view: "+Foo+(string)Bar;
}
}
And because of how it works, even if there is a views/FooView.html file, it may get processed into a class named MyView.
So how exactly is the best way to assign ViewData to say Foo and Bar of MyView? Should I just impose the limitation that you can only use a single field in the views(basically being a ViewData) or?
The other major problem I see is that MVC is almost completely file based. When you say RenderView("MyView",data); it will look in /views/ for a file named MyView.aspx or whatever(you can change where it looks and the file extension of course). The problem is that MyView could have been compiled from a file named FooView.html. Should I basically just generate a huge list for every view available with their mappings from class name to filesystem name? Or is there a better way?
Note: Because I generate all the views(and possibly could generate the MVC view engine) from a T4 template, this means I could write huge lists and other extremely tedious or bad code. But I feel like there is a better way than a huge list in this case, and that there will be underlying problems with only keeping a list.
You may extend my T4 based view engine to create your class file from your model, compile it in memory and cache it, and pass your view model to the compiled assembly via reflection.
http://mvct4viewengine.codeplex.com/

DataAnnotations and Resx in class library

For my application (ASP.NET MVC 3.0 RTM, Razor View Engine), I would like to use DataAnnotations for my models. If I keep the model classes within the web project, I can have resx resources in App_GlobalResources or App_LocalResources without embedding the .resx into .resources files.
Ignoring newly spawned AppDomains and other considerations, this is ideal because changing something minor in a localized resource like a typo or incorrect translation doesn't require compilation.
However, after moving my models to a class library I don't see any way to keep .resx files as the output and still use DataAnnotations attributes. Am I missing something?
The problem lies in the way the attributes find resources. For instance, a "Name" property might look like this:
[Display(Name = "MyEntity_Name", ResourceType = typeof(Validations))]
[Required(ErrorMessageResourceName="MyEntity_Name_Required",
ErrorMessageResourceType = typeof(Validations))]
[StringLength(150, MinimumLength = 2)]
public string Name { get; set; }
This requirement for a strongly-typed resource wrapper has become the bane of my existence over the past 24 hours.
I've tried to genericize the wrapper, but it seems like the validation attributes specifically look for a property on the wrapper called MyEntity_Name for the DisplayAttribute and MyEntity_Name_Required for the RequiredAttribute. I haven't dug any deeper into the DataAnnotations code to see if there is some magic I can pull off. I was hoping someone else encountered this and had any ideas.
The Question
Is it possible to use DataAnnotations ValidationAttributes (including DisplayAttribute) in a class library without embedding the resx files into .resources files?
The Gotchas :(
In the future, I'd like to move from resx to database-driven resources with very minimal coding effort. I can't do that right now because of limited resources (no pun intended). So, I want to avoid bypassing the ResourceProvider. Also, I want to avoid rewriting or wrapping all of the attributes in the System.ComponentModel.DataAnnotations namespace.
Am I missing something?
Yes, you are missing View Models. Controller actions take/pass view models from/to views and not models. View models are classes which are specifically tailored to the needs of a given view. They contain the only the required properties and the proper formatting for the given view. A view model could be a subset of a model or an aggregation of multiple models (it depends on the requirements of the view). View models are always defined in the web project because they are very tightly coupled to views. So it is view models that you should localize/globalize with resources.
Example of workflow:
The controller action is invoked and it queries the repository to fetch a model
The controller maps the model to the corresponding view model (AutoMapper could you here)
The controller passes the view model to the view and the view displays it with the proper formating/localization.
Conclusion: models should not be formatted/localized or they become more difficult to reuse.

How to organize views, partial views and their view models?

I'm developing in asp.net mvc2. I am beginning to create a lot of views and partial views, for most of which I've had to create a view model. This is looking like soon it's going to become unmanageable to remember what view goes with what model. I've tried to use inheritance in my view models as much as possible.
I'm wondering how others manage this in their projects?
I place my PV's inside a PV folder within the Views folder.
so Views/Home/PartialViews;
I then register that path in my global.asax file;
public static void RegisterViewEngine()
{
ViewEngines.Engines.Clear();
WebFormViewEngine viewEngine = new WebFormViewEngine();
viewEngine.PartialViewLocationFormats = (new[] {
"~/Views/Shared/PartialViews/{0}.ascx",
"~/Views/{1}/PartialViews/{0}.ascx"
}).Concat(viewEngine.PartialViewLocationFormats).ToArray();
ViewEngines.Engines.Add(viewEngine);
}
I'm also these days leaning towards putting the FormViewModels within the views folder.
/Views/Home/IndexFormViewModel.cs
The above is recent as before this I put them in a Models project but found that sometimes I could end up with a cyclic reference situation with my Model and DataRepository.

ASP.NET MVC "Convert to Web Application" option is missing in Visual Studio

I'm working with Visual Studio 2008 SP1 and ASP.NET MVC v1. When right clicking on a view I do not get the option "Convert to Web Application" that I would need to generate code behind .cs classes. I see that option for the actual project and folders, but not for views (aspx files). I've checked the ProjectTypeGuids to have the "right" (?) values:
{603c0e0b-db56-11dc-be95-000d561079b0};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}
Any other suggestions as to what I could look for?
Thanks.
(I am aware of design implications of using code behind classes with MVC)
P.S. To do it manually all you have to do is:
Add a file with the same name as your view and the .cs (or .vb) extension, for example Index.aspx.cs. Make sure you modify your class to inherit from System.Web.Mvc.ViewPage or some other class that inherits from that.
Edit the aspx file and add to the #Page directive CodeBehind="Index.aspx.cs" and change Inherits to "MyNamespace.Views.Home.Index" (obviously you need to have the right code behind and namespace there).
Right click on the aspx file and choose Convert to Web Application. This will create the design file and also modify your .cs class and mark it as "partial".
"Convert to web application" is a project/file-level command. You can't use it on a single ASPX file.
Also, there is no alternative automated way (that I know of :-)) to add code-behind files to an ASPX file. You have to do it manually, by adding the relevant files yourself and then adding them to the .csproj.
There's no need to use 'code-behind' with ASP.NET MVC.
If you use a 'code-behind', you're not following the convention of ASP.NET MVC.
The question is, why do you want a code-behind? Answering that will help us to determine what you really need.
If you really want to do this, you can do it by mixing Webforms and ASP.NET MVC together. There are lots of resources on this, but here's just one.
The MVC development model does not need code behind.
Read a good Blog Post on this Here
If you're trying to reuse some controls, maybe a good approach is to create and render them inside a helper method and than call that method from the view.
What I'm thinking about would be something like this:
public static string HelperMethod(param_list)
{
var control = new ControlType();
//set up control properties according to param_list
//get the html as string - one way to do it would be like this
StringWriter stringWriter = new StringWriter();
HtmlTextWriter htmlWriter= new HtmlTextWriter(stringWriter);
control.RenderControl(htmlWriter);
string result= stringWriter.ToString();
}
And then call it from the view like this:
<%= HelperClass.HelperMethod(params) %>
I'm not sure if this approach will work, I don't know even if it makes sense. It's more of I hack than a proper solution. I haven't done anything like this before, it's just an idea, try to see if it helps you. You should also have in mind that ASP.NET controls usually use the ViewState for state management and that there is no such thing in ASP.NET MVC.

Resources