Copied to clipboard

Flag this post as spam?

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


  • Jules 269 posts 560 karma points
    Jun 22, 2016 @ 09:18
    Jules
    1

    Models built by ModelsBuilder not available to other projects (Circular Dependency)

    Hi everybody

    I am used to building Umbraco projects using a minimum of 2 separate projects, MyProj.Umbraco and MyProj.Umbraco.Core.

    Umbraco.Core will generally contain all the Models, ViewModels, Controllers as well as all the helpers and other logic that is outside of the main Umbraco install.

    The Umbraco project will have all of the Views of course.

    When using the ModelsBuilder in Dll mode, the dll is built into the Umbraco project but, of course, the Umbraco.Core project needs a reference to the models built by the ModelsBuilder so they can be used in the Controllers.

    And there we have the problem: If I put a reference to the Umbraco project in Umbraco.Core, then Visual Studio complains about a circular dependency because of course the Umbraco project MUST have a reference to the Umbraco.Core project (which is where my Controllers etc are).

    Does anybody else have a similar setup? Any good ways of working around this?

    J

  • Michaël Vanbrabandt 863 posts 3348 karma points c-trib
    Jun 22, 2016 @ 12:28
    Michaƫl Vanbrabandt
    0

    Change the ModelsBuilder setup from dll to appdata, then generate the models using the tab in the developer section of your umbraco backend.

    This wil generate all models under AppData/Models in your project.

    Then you can place this Models folder into your other project.

    /Michael

  • Jules 269 posts 560 karma points
    Jun 22, 2016 @ 13:16
    Jules
    0

    Well it's set to dll at the moment and temporarily I have referenced the output dll in the .Umbraco project directly in the .Umbraco.Core project. As it is referencing the dll directly and not the project there is not Circular Dependency.

    However, still not ideal as really I want to have all this happen on build of the solution.

    Anybody know how I could do that? I've been warned away from Post-Build events in the past but is there any other way to achieve this?

    J

  • Sotiris Filippidis 286 posts 1501 karma points
    Nov 27, 2016 @ 21:08
    Sotiris Filippidis
    0

    I am also interested in what should be the "best practice" regarding this. At the moment, I also reference the dll directly from other projects, which is not very best practice-y.

  • Jules 269 posts 560 karma points
    Nov 27, 2016 @ 21:22
    Jules
    2

    We have sorted this now. Our solution works well but there may well be a better solution out there.

    Basically we use Dll mode.

    <add key="Umbraco.ModelsBuilder.ModelsMode" value="Dll" />
    

    Then we have a Library folder into which we copy the generated dll. The external project can then reference the dll in the Library so we don't get a circular reference.

    Project structure is something like

    MySolution
       UmbracoProject
       ExternalProject
       Library
    

    We don't want to have to copy the dll to the Library every time we run the modelsbuilder so we created a Pre-Build event to copy the dll for us on every build.

    To create the Pre-Build event right click the Umbraco Project in Visual Studio and choose Properties. Select Build Events and add the following to Pre-Build assuming your project structure is as above.

    IF EXIST "$(ProjectDir)bin\Umbraco.Web.PublishedContentModels.dll" xcopy "$(ProjectDir)bin\Umbraco.Web.PublishedContentModels.dll" "$(SolutionDir)Library"  /y
    

    Using Dll mode, you will have to explicitly run the models builder from Umbraco whenever you change your DocTypes.

    Good luck

    Jules

  • Sotiris Filippidis 286 posts 1501 karma points
    Nov 27, 2016 @ 22:01
    Sotiris Filippidis
    0

    This is a good approach but it is, in my opinion, not much different that directly referencing the DLL. It just moves the reference outside of the main project (which you could continue to have without circular referencing, provided that you referenced the DLL and not the project itself).

    Having said that, I agree it's more clear this way and it's actually what I was thinking too (having the dll copied somewhere, then referencing the dll). I'm curious, though - has anyone devised a different approach, not necessarily using DLL mode?

  • Lars-Erik Aabech 349 posts 1100 karma points MVP 7x c-trib
    Nov 27, 2016 @ 23:52
    Lars-Erik Aabech
    3

    You should use a combination of these four settings from the config docs: https://github.com/zpqrtbnk/Zbu.ModelsBuilder/wiki/Install-And-Configure

    Umbraco.ModelsBuilder.ModelsMode = "AppData"
    Umbraco.ModelsBuilder.ModelsNamespace = "YourNamespace"
    Umbraco.ModelsBuilder.ModelsDirectory = "../../OtherProject/Models"
    Umbraco.ModelsBuilder.AcceptUnsafeModelsDirectory = true
    

    Which basically makes you able to put your models in any project, any place on your disk. Should be relative to project though, so you can put it in source control in the same solution.

    Remember you have to build each time.

    Although, you should be able to create compositions and classes that implement interfaces only from your core business logic assemblies. There isn't really a problem keeping your concrete models in the web project if you structure your code accordingly.

    Happy modelling. :)

  • Sotiris Filippidis 286 posts 1501 karma points
    Nov 28, 2016 @ 08:32
    Sotiris Filippidis
    0

    This is indeed a very interesting approach! Let's see what's "bad" and what's "good" in this approach compared with "dll mode and referencing the dll from other projects" (not taking into account the option to add own interfaces to the models):

    AppData mode with generating models in other directory:

    • GOOD: Source control generated files
    • GOOD: Models can be generated in a separate project which can then be - referenced by all other projects
    • BAD: A change in a doctype requires building models from within Umbraco as well as building the project models are generated in
    • BAD: The aforementioned security risk with UnsafeModelsDirectory

    DLL mode with referencing the dll from other projects:

    • GOOD: A change in a doctype requires just building models from within Umbraco, perfect for end users - front end devs
    • BAD: DLL in source control if you really want to have it as part of your source
    • BAD: Have to reference the DLL directly from other projects or use a pre-build action to copy it somewhere and reference it from there.

    So, as far as I can understand, it's a matter of how it's going to be used.

    For example, I'm using ModelsBuilder in my Starter Kit. If I want to make life easy for others then I should keep on using DLL mode (since it's easier for other users of the starter kit to update their models from within Umbraco and use new properties in their views without having to add the whole thing to Visual Studio and compile).

    If, on the other hand, want to have total control over what's being generated and reference things the "right way" then it's app_data and a separate directory.

    Is my thinking correct?

  • Lars-Erik Aabech 349 posts 1100 karma points MVP 7x c-trib
    Nov 28, 2016 @ 08:39
    Lars-Erik Aabech
    2

    Our front-enders have VS and got used to building when changing doctypes years ago.

    We keep the generated models in the "classic" MVC folder "~/Models", but we decorate them with common interfaces that resides in an assembly we reuse across sites.

    As far as I'm concerned, that's the only way to go. :)

    In order not to repeat myself, I'll just link to myself for the rest of the argument. ;)

    http://skrift.io/articles/archive/stop-mapping-start-adapting/
    http://blog.aabech.no/archive/getting-real-business-value-from-strongly-typed-models-in-umbraco/

  • Sotiris Filippidis 286 posts 1501 karma points
    Feb 18, 2017 @ 14:06
    Sotiris Filippidis
    0

    I think I have found a way to:

    Have models on an external project which can be referenced by other projects and added to source control

    Not face any issues with MSBuild

    Be able to switch to DLL mode after deploying, allowing others to be able to generate models if they add more doctypes/properties. This is important, because it provides the freedom to extend the site using ModelsBuilder even if there is no access to the original source code.

    What I did was based on Lars-Erik's suggestion. So it goes like this:

    I created a new project inside my solution (ModelsOrSomethingDoesntReallyMatter) and I set the following:

    <add key="Umbraco.ModelsBuilder.ModelsMode" value="AppData" />
    <add key="Umbraco.ModelsBuilder.ModelsDirectory" value="~/../../MyProjFolder/ModelsOrSomethingDoesntReallyMatter" /> 
    <add key="Umbraco.ModelsBuilder.AcceptUnsafeModelsDirectory" value="true" />
    

    The trick was that I set my project's assembly name and default namespace to...Umbraco.Web.PublishedContentModels. Note that I didn't use the key for a custom namespace, so models go under that namespace by default. So, my models get their own project, can be referenced from other projects, can go into source control BUT when deployed I can easily switch to DLL mode and continue using the site. Since all my references are to Umbraco.Web.PublishedContentModels, this will continue to function even after a new (now DLL-mode) model generation since Umbraco.Web.PublishedContentModels.dll will just be replaced.

    Any thoughts?

  • Micha Somers 134 posts 597 karma points
    Feb 18, 2017 @ 14:48
    Micha Somers
    0

    That sounds interesting enough to try ...

    Did you also investigate the usage of the ModelsBuilder API (where ModelModes=Nothing and the classes are generated in your class library using UmbracoModelsBuilder as custom tool)?

    If so, do you have thoughts about the Goods and Bads compared to this AppData approach?

  • Sotiris Filippidis 286 posts 1501 karma points
    Feb 18, 2017 @ 16:11
    Sotiris Filippidis
    0

    No, I haven't tried the API yet. But I'll give it a try and compare the two methods.

  • Emma Garland 41 posts 123 karma points MVP 6x c-trib
    Mar 29, 2017 @ 16:11
    Emma Garland
    0

    I'm currently using an existing project using ModelsBuilder. Moving to Visual Studio 2017, the ModelsBuilder tool is not yet compatible so I keep swapping back to 2015 to generate them - cant wait till https://marketplace.visualstudio.com/items?itemName=ZpqrtBnk.UmbracoModelsBuilderCustomTool is updated for 2017. For now I will stick to the custom tool in 2015 and generating them to be created in the separate data project (i.e. not website).

  • Jules 269 posts 560 karma points
    Jun 18, 2017 @ 09:34
    Jules
    0

    Hi Emma

    This is a great reason to avoid the external dependency that the ModelsBuilderCustomTool creates in your project.

    I used to use the Dll method which we had working well as described in this thread but am now using the AppData method which Lars-Erik describes as it completely removes the need to add generated dlls to source control.

    Unless I'm mistaken, the only advantage that the custom tool adds is that you are able to exclude certain properties on a doc type that you don't need in your model.

    With the AppData method all models are generated as partial classes so you can at least add properties, methods etc to your classes by creating additional partial class files that reference the same generated model class.

    It strikes me that the ability to exclude doc type properties on your model should probably be a part of the backoffice - so an additional flag excludeFromModel on each property on your doctype in the backoffice, would be very useful.

    Don't know the current status of VS2017 and the Models Builder Custom tool but my advice would always be to reduce the external dependencies in your project.

    Of course if you're a single developer on a project then the dependency issue is less crucial immediately but if the project is passed to anybody else or you are working in a larger team with contractors coming and going then undocumented external dependencies can be a royal pain !!!

  • Micha Somers 134 posts 597 karma points
    Jun 23, 2017 @ 13:21
    Micha Somers
    0

    Jules,

    Interesting to see you are using AppData the way Lars-Erik describes.

    Especially the parts about following Dependency Inversion and Interface Segregation principles, sound like the way to go.

    However, what I found a bit less attractive, is the example in getting-real-business-value-from-strongly-typed-models-in-umbraco where code is moved out of the site, by creating a reusable component using an extension class that returns HTML:

    public static IHtmlString Promotion(this IPromotable promotable)
    {
        return String.Format(@"
            <div class="" promotion"">
                <a href="" {0}"">
                    <img src="" {4}"" />
                    <h2>{2}</h2>
                    <p>{3}</p>
                </a>
            </div>
            ",
            promotable.Url,
            promotable.Image,
            promotable.Title,
            promotable.Summary
            );
        }
    }
    

    This is typically the content I would like to manage in Umbraco ... without having to adjust source code if it needs eg. a slightly different markup (which is very likely).

    What approach do you use?

    Interested to see how are you dealing with this!

  • Sotiris Filippidis 286 posts 1501 karma points
    Jun 18, 2017 @ 09:39
    Sotiris Filippidis
    0

    By the way, I wrote an article detailing the solution I mentioned earlier on.

    http://www.dot-see.com/en/blog/how-to-use-modelsbuilder-in-a-multi-project-umbraco-solution/

  • Jules 269 posts 560 karma points
    Jun 18, 2017 @ 09:41
    Jules
    0

    Awesome :)

  • Emma Garland 41 posts 123 karma points MVP 6x c-trib
    Jun 18, 2017 @ 11:17
    Emma Garland
    1

    Agreed,

    Since I last used it the other day the tool now works in 2017 (yay!) so I am still generating the models in a separate "data" project, using AppData config, and allowing me the ability to create my own partial class and property of the same name, for the instances where I want to change the default return type of the models builder properties. Then regeneration with the tool knows to ignore these properties.

    For instance if I have a Person content picker that returns an IPublished content by default, I can map it to a strongly-typed class e.g. a Person doctype mapped from the IPublishedContent object (I'm using Ditto for the mapping). This is the approach I'm using now and seems to work rather than mapping higher up in the view, so everything is strongly-typed further down. Can't think of any issues with this approach after reading the documentation, but if you know of any I'm happy to hear it.

  • Biagio Paruolo 1593 posts 1824 karma points c-trib
    Jun 23, 2017 @ 10:56
    Biagio Paruolo
    0

    Very Good Post!!!!!!

Please Sign in or register to post replies

Write your reply to:

Draft