Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Edwin van Koppen 156 posts 270 karma points
    Nov 16, 2012 @ 14:41
    Edwin van Koppen
    0

    MVC views not in subfolder?

    Why are view's build in the Umbraco not set in his own directory? I want to do this http://our.umbraco.org/wiki/codegarden-2009/open-space-minutes/working-in-visual-studio-when-developing-umbraco-solutions with a MVC project and then copy the view directory to Umbraco but there all the files are directly under the views folder..

  • Shannon Deminick 1508 posts 5162 karma points hq
    Nov 20, 2012 @ 01:08
    Shannon Deminick
    0

    Hi, 

    what do you mean by "not set in his own directory"

    We put the views directly in the ~/Views folder because this makes sense to regular Umbraco devs. People that don't know or don't care to know MVC and how it all works, etc... would be confused if their views had to be stored in ~/Views/RenderMvcController

    Of course if you are hijacking Umbraco routes, you can store your views in the controller named folder. For example, if you have a controller that Hijacks a route called "MyHomeController" and you returned views from it, you could store your views in:

    ~/Views/MyHome

    just like how normal MVC works. However, there will be no UI tooling support for this in the back office (at least not currently)

    I'm not familiar with the approach taken in the "Working in Visual Studio when developing umbraco solutions" post that you've mentioned so I'm not sure if this answers your question or not?

  • Edwin van Koppen 156 posts 270 karma points
    Nov 20, 2012 @ 13:59
    Edwin van Koppen
    0

    Hi Shannon,

    First i want to thank you for replying to all my questions! I really want to do it good because we are firm with alot of big customers and if i want to say that Umbraco is a good system i must understand how everything works.

    My idea was that i made 2 projects, 1 with umbraco and 1 with mvc so i can have the source code in source control (that's what is read on forums that it is a good way to do sourcecontrol in umbraco). Then i make a reference to umbraco so that the project build and as an afterbuild proces i copy all the files and dll's to the umbraco dir. If umbraco keeps the code just like microsoft mvc you can use all the visual studio tools that mvc gives you (right mouse click > add view, etc). That was the idea so you can use mvc like microsoft want to use it.But after more trying out i now understand that if you copy the files to the view directory that is not directly a template you can use, you must add it to the database also.. is it a idea to build a directory watcher as a umbraco plugin and add it with sql automatic or do i get alot of problems then?

    Now you know what i'm trying to do maybe you know better why i asked the question, i still think it's a good idea to keep everything the same as microsoft so the dev's that uses visual studio can work faster with umbraco and for the direct umbraco users, they don't see the directory structure so that wouldn't be a problem for them..

    Ed

     

     

     

     

  • Edwin van Koppen 156 posts 270 karma points
    Nov 20, 2012 @ 17:09
    Edwin van Koppen
    0

    First question i got fixed, i have now a module with a directory watcher so after copy i do this.. (is a try, could be better)

     

    public virtual void LoadWatch(Object p_objContext) {
                FileSystemWatcher l_objWatcher = new FileSystemWatcher();
                HttpContext l_objContext = (HttpContext)p_objContext;

                l_objWatcher.IncludeSubdirectories = true;
                l_objWatcher.Path = l_objContext.Server.MapPath("~/Views/");
                l_objWatcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName;
                l_objWatcher.Filter = "*.cshtml";
                l_objWatcher.Created += new FileSystemEventHandler(OnCreated);
                l_objWatcher.EnableRaisingEvents = true;
            }
            private void OnCreated(object sender, FileSystemEventArgs e) {
                string l_strFilename = e.Name.Substring(0, e.Name.LastIndexOf("."));
                if (Template.GetTemplateIdFromAlias(l_strFilename) == 0) {
                    Template.MakeNew(l_strFilename, new umbraco.BusinessLogic.User(0));
                }
            }

     

    and this is loaded as a module in Umbraco. But is still need curious why Umbraco builders choose not to keep it the microsoft way..

     

    p.s. this has an endless loop, look next page for a better version

  • Edwin van Koppen 156 posts 270 karma points
    Nov 25, 2012 @ 12:20
    Edwin van Koppen
    0

    But my second question is still a problem, most of our sites exists out of 30 or more template, if they are all in the root i can be messy. Someone else got that problem? 

    Maybe someone can tell how this work with the masterpages in the old way, are there any subfolders you can use?

  • Shannon Deminick 1508 posts 5162 karma points hq
    Nov 26, 2012 @ 02:51
    Shannon Deminick
    0

    Yes, we have an issue on the tracker to remove the db dependencies for templates, but this will mean large breaking changes:

    http://issues.umbraco.org/issue/U4-684

    https://groups.google.com/d/topic/umbraco-dev/Yso2jtzn1PU/discussion

    We have also discussed auto-creating the database entries like you have done (nice work!). However, we cannot use a file system watcher in the core as this requries Full Trust. We could use a timer however, or just create the db entries on app startup however, neither of these are great solutions until we actually get this task completed.

    There is still much legacy code in the Umbraco codebase that we need to slowly phase out and this is one of them. We cannot just change these things because it will break everyone's builds.

  • Shannon Deminick 1508 posts 5162 karma points hq
    Nov 26, 2012 @ 02:57
    Shannon Deminick
    0

    One way you could have views in subfolders is to hijack a route for each of your doc types:

    http://our.umbraco.org/documentation/master/Reference/Mvc/custom-controllers

    Then you can store your views for each of your document types in sub folders that match your controllers name just like normal MVC. For example if you have a doc type called "Home" and you hijack a route for it, you would have a controller called "HomeController". You could then simply return base.Index(model); (if you don't want to do anything fancy in your controller) and you could then store your view at

    ~/Views/Home/

    since the controller that is rendering the view is called HomeController. 

  • Edwin van Koppen 156 posts 270 karma points
    Nov 26, 2012 @ 11:08
    Edwin van Koppen
    0

    Hi Shannon,

    I do the something like hijacking, but i still use the path's from Umbraco, not the one from MVC. I still want the good SEO path's so i'll keep that. For the problem with path's i was thinking of overriding your code in Umbraco and writing code the uses the path's also but i just looked over the Umbraco code very fast so i need to see if it's possible. 

    On the other thing, i understand you need to have backward compatiblity but i don't have to! I will try it, if it works i'll maybe build it one day to a module for other users.. do you have maybe any pointers that i keep in mind when building this?

    Ed

    p.s. thx for your anwser again Shannon!

  • Edwin van Koppen 156 posts 270 karma points
    Nov 26, 2012 @ 15:00
    Edwin van Koppen
    0

    fast a update what i found out: the cms understands a path without any change in the code! I've just changed the path in the database from test to /test/ed and the with the Umbraco i can edit that file in the template part in Umbraco. But the frontend doesn't find that path.. only a empty page.

    I see that the file RenderViewEngine parses the pages.. let see if i can change that :)

  • Edwin van Koppen 156 posts 270 karma points
    Nov 26, 2012 @ 20:25
    Edwin van Koppen
    0

    damm.. don't think this is gonna work, i see that there is a own RenderViewEngine and that i must write my own thing... maybe you know a simpler way Shannon?

  • Edwin van Koppen 156 posts 270 karma points
    Nov 30, 2012 @ 10:54
    Edwin van Koppen
    0

    if i see the RenderViewEngine i see this

    private readonly IEnumerable<string> _supplementedViewLocations = new[] { "/{0}.cshtml" };

    and

    var replaceWithUmbracoFolder = _supplementedViewLocations.ForEach(location => templateFolder + location);

    if the location in the database is "test/ed" i would be replace to the right position but still a empty page... can't see to find where's the problem.

    @Shannon, can you please help me, i now understand why from Umbraco viewpoint controller directories are not needed but as a developer friendly CMS i find it strange that all the views are in one directory. Big sites with 50 or more views are normal for us you can understand we then need the directories. I can understand that this is a problem for more companies that build big sites so it would be a nice addon. If you don't have the time or so can you then give me pointers so i can implement this because without it i don't think we are gonna use Umbraco as our CMS in the future :(

     

  • Edwin van Koppen 156 posts 270 karma points
    Nov 30, 2012 @ 13:43
    Edwin van Koppen
    0

    ...it was there all the time! our.umbraco.org/.../custom-controllers i just didn't get it right away...

  • Edwin van Koppen 156 posts 270 karma points
    Nov 30, 2012 @ 16:47
    Edwin van Koppen
    0

    I've made a change to the viewwatcher for ppl who dive into this..

     

    public class ViewWatcher : IHttpModule {
            static object m_objLockObject = new object();
            static bool Initialized = false;

            public virtual void Init(HttpApplication p_objApplication) {
                if (!Initialized) {
                    lock (m_objLockObject) {
                        if (!Initialized) {
                            ParameterizedThreadStart l_objPTS = new ParameterizedThreadStart(LoadWatch);
                            Thread l_objThread = new Thread(l_objPTS);
                            l_objThread.Start(p_objApplication.Context);
                            Initialized = true;
                        }
                    }
                }
            }
            public void Dispose() {
            }

            public virtual void LoadWatch(Object p_objContext) {
                FileSystemWatcher l_objWatcher = new FileSystemWatcher();
                m_objContext = (HttpContext)p_objContext;
                 
                l_objWatcher.IncludeSubdirectories = true;
                l_objWatcher.Path = m_objContext.Server.MapPath("~/Views/");
                l_objWatcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName;
                l_objWatcher.Filter = "*.cshtml";
                l_objWatcher.Created += new FileSystemEventHandler(OnCreated);
                l_objWatcher.EnableRaisingEvents = true;
            }
            private HttpContext m_objContext;

            private void OnCreated(object sender, FileSystemEventArgs e) {
                if (e.Name.IndexOf('\\') > -1) {
                    try {
                        //string l_strFilename = Path.GetFileNameWithoutExtension(e.Name).Replace('\\', '/');
                        string l_strFilename = e.Name.Substring(0, e.Name.LastIndexOf(".")).Replace('\\', '-');
                        if (Template.GetTemplateIdFromAlias(l_strFilename) == 0) {
                            Template.MakeNew(l_strFilename, new umbraco.BusinessLogic.User(0));
                            //clean umbraco file that is generated
                            File.Delete(m_objContext.Server.MapPath(String.Format("~/Views/{0}.cshtml", l_strFilename)));
                        }
                    } catch {
                    }
                }
            }
        }

     

    Umbraco also make a file (i wish that he didn't do that!) so you had an endless loop.. now it's fixed and the Umbraco file is deleted. I this way you cannot edit the file in the CMS anymore but that's not really a problem because you got visual studio if you do url hijacking :)

  • Edwin van Koppen 156 posts 270 karma points
    Jan 22, 2013 @ 16:07
    Edwin van Koppen
    0

    And i think it is broken again... code for the RenderMvcController has been changed so that you must have the views in the /views/ directory, damm that's not acceptable for us. What i said earlier, we have 20/30 templates per site so no structure any more in our projects. Shannon, can't you give just a warning in the log and not return Content("")? Something like this?

    protected ActionResult CurrentTemplate<T>(T model)
            {
                var template = ControllerContext.RouteData.Values["action"].ToString();
                if (!EnsurePhsyicalViewExists(template))
                {
                    LogHelper.Warn<RenderMvcController>("No physical template file was found for template " + template + " in the Views directory");
                }
                return View(template, model);
            }

     

     

  • Shannon Deminick 1508 posts 5162 karma points hq
    Jan 22, 2013 @ 22:28
    Shannon Deminick
    0

    Yes, we can put a log message in there but the RenderMvcController's logic has not changed in 6.0. The only thing that was changed is in this revision:

    35fc4486c9d4

    Which just adds some properties to the controller. Previous changes were in 4.11 in revision:

    4703906d9c52

    Which just moves the exact same logic from the 'Index' method into a new protected method called: CurrentTemplate<T>

  • Anthony Halliday 5 posts 32 karma points
    Sep 30, 2014 @ 15:40
    Anthony Halliday
    0

    I know this is an old post but having recently started working with Umbraco and found the lack of folders in the view folder a similar issue i wanted to share my solution.

    Having tried the route hi-jacking i found little success when the view contained a form posting to a surface controller as the view engine always seemed to return the view stored in the DB which as the template alias didnt correspond to the physical view path caused the response of all SurfaceCotrollers to be blank (maybe I missed something?).

    On application start up i am registering a custom default controller with a controller that overrides the Index method with a local implementation of the CurrentTemplate method (taken from the Umbraco source), the only difference is that before using the template path i am replacing any instance of an underscore with a slash which allows a naming convention of template alias's such as 'MyAccount_Bookings' to match the view '/Views/MyAccount/Bookings.cshtml'.

    The only issue now is to prevent Umbraco from generating the physical view files...

     

     Anthony

  • Shannon Deminick 1508 posts 5162 karma points hq
    Oct 01, 2014 @ 00:50
    Shannon Deminick
    0

    In MVC you can always render a view by it's full virtual path:

    ~/Views/WhateverYouWant/Something/Blah.cshtml

    With route hijacking, you are using your own controller so views will be found by normal MVC convention if you don't specify the entire virtual path. For example if you have a controller called HomeController, and you return a view called "Hello" then the view engines will look in:

    ~/Views/{Controller}/{ViewName}.cshtml

    it will also look in various other places too and finally will try the default umbraco path of ~/Views/{ViewName}.cshtml

    I'm not sure what you mean by your second paragraph:

    Having tried the route hi-jacking i found little success when the view contained a form posting to a surface controller as the view engine always seemed to return the view stored in the DB which as the template alias didnt correspond to the physical view path caused the response of all SurfaceCotrollers to be blank (maybe I missed something?).

    When you post to a SurfaceController you generally always return either

     return CurrentUmbracoPage();
    

    or

     return RedirectToCurrentUmbracoPage();
    

    You never return a view from a POST to a SurfaceController because that will literally just return a view - the same way as normal MVC would.

Please Sign in or register to post replies

Write your reply to:

Draft