Qite / Umbraco-Inception

A code first approach for Umbraco (7)
MIT License
26 stars 9 forks source link

Fatal error, while attempting to start umbraco #5

Closed mmisztal1980 closed 10 years ago

mmisztal1980 commented 10 years ago

While attempting to CreateOrUpdateEntity : I'm getting the following error :

Server Error in '/' Application.
Value cannot be null.
Parameter name: parent
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.ArgumentNullException: Value cannot be null.
Parameter name: parent

Source Error:

Line 33:         {
Line 34:             UmbracoCodeFirstInitializer.CreateOrUpdateEntity(typeof(PageBase));
Line 35:             UmbracoCodeFirstInitializer.CreateOrUpdateEntity(typeof(HomePage));
Line 36:         }
Line 37:     }

Source File: d:\Checkout\Umbraco.Experimental\Umbraco.Experimental\Events\RegisterEvents.cs    Line: 35

Stack Trace:

[ArgumentNullException: Value cannot be null.
Parameter name: parent]
   Umbraco.Core.Mandate.That(Boolean condition, Func`1 defer) +27
   Umbraco.Core.Mandate.ParameterNotNull(T value, String paramName) +104
   Umbraco.Core.Models.ContentTypeBase..ctor(IContentTypeBase parent) +108
   Umbraco.Core.Models.ContentTypeCompositionBase..ctor(IContentTypeComposition parent) +90
   Umbraco.Inception.CodeFirst.UmbracoCodeFirstInitializer.CreateContentType(IContentTypeService contentTypeService, IFileService fileService, UmbracoContentTypeAttribute attribute, Type type, IDataTypeService dataTypeService) +270
   Umbraco.Inception.CodeFirst.UmbracoCodeFirstInitializer.CreateOrUpdateEntity(Type type) +225
   Umbraco.Experimental.Events.RegisterEvents.RegisterModels() in d:\Checkout\Umbraco.Experimental\Umbraco.Experimental\Events\RegisterEvents.cs:35
   Umbraco.Experimental.Events.RegisterEvents.ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext) in d:\Checkout\Umbraco.Experimental\Umbraco.Experimental\Events\RegisterEvents.cs:17
   Umbraco.Core.ApplicationEventHandler.OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext) +37
   Umbraco.Core.CoreBootManager.<Complete>b__5(IApplicationEventHandler x) +19
   Umbraco.Core.EnumerableExtensions.ForEach(IEnumerable`1 items, Action`1 action) +141
   Umbraco.Core.CoreBootManager.Complete(Action`1 afterComplete) +94
   Umbraco.Web.WebBootManager.Complete(Action`1 afterComplete) +38
   Umbraco.Core.UmbracoApplicationBase.StartApplication(Object sender, EventArgs e) +157
   Umbraco.Core.UmbracoApplicationBase.Application_Start(Object sender, EventArgs e) +9

[HttpException (0x80004005): Value cannot be null.
Parameter name: parent]
   System.Web.HttpApplicationFactory.EnsureAppStartCalledForIntegratedMode(HttpContext context, HttpApplication app) +9905689
   System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers) +118
   System.Web.HttpApplication.InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context) +172
   System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr appContext, HttpContext context) +336
   System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr appContext) +296

[HttpException (0x80004005): Value cannot be null.
Parameter name: parent]
   System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +9885044
   System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +101
   System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +254

Below are my content types, I don't see anything wrong with them but I might be wrong - can you please advise on what is going on?

[UmbracoContentType("PageBase", "Home/PageBase", new[] { typeof(HomePage) }, true, BuiltInUmbracoContentTypeIcons.IconUniversal, "~/Views/Shared/_Layout", true, true)]
    public class PageBase : UmbracoGeneratedBase
    {
        [UmbracoTab("Generic Properties")]
        public GenericPropertiesTab GenericProperties { get; set; }
    }
    [UmbracoContentType("HomePage", "Home/HomePage", null, true, BuiltInUmbracoContentTypeIcons.IconHome, "~/Views/Shared/_Layout", true, true)]
    public class HomePage : PageBase
    {
        [UmbracoTab("Primary Message")]
        public MessageTab PrimaryMessage { get; set; }

        [UmbracoTab("Secondary Message")]
        public MessageTab SecondaryMessage { get; set; }

        [UmbracoTab("Tertiary Message")]
        public MessageTab TertiaryMessage { get; set; }
    }
public class GenericPropertiesTab
    {
        [UmbracoProperty("SEOTitle", "sEOTitle", BuiltInUmbracoDataTypes.Textbox)]
        public string SeoTitle { get; set; }

        [UmbracoProperty("SEODescription", "sEODescription", BuiltInUmbracoDataTypes.TextboxMultiple)]
        public string SeoDescription { get; set; }
    }
public class MessageTab : TabBase
    {
        [UmbracoProperty("Message", "message", BuiltInUmbracoDataTypes.Textbox)]
        public string Message { get; set; }

        [UmbracoProperty("Content", "content", BuiltInUmbracoDataTypes.TextboxMultiple)]
        public string Content { get; set; }
    }

Another curious thing I've noticed, below is a fragment of my project's folder structure

+---Views
|   |   HomePageBase.cshtml <--- Why is this being generated?
|   |   Web.config
|   |   
|   +---Home
|   |       HomePage.cshtml
|   |       PageBase.cshtml
|   |       
|   +---MacroPartials
|   +---Partials
|   \---Shared
|           _Layout.cshtml
|           _NavigationPartial.cshtml
|           
\---xslt
        Web.config
nojaf commented 10 years ago

Hello mmisztal1980,

All looks good actually. The last question is the easiest so I'll start with that. That view was generated because you set the parameter createMatchingView to true in the UmbracoContentType attribute of HomePage.

As for the first issue I'm not really sure. Could you try to only execute

 UmbracoCodeFirstInitializer.CreateOrUpdateEntity(typeof(PageBase));

And let me know if this works. At first sight HomePage is have trouble of finding it's parent. So make sure that PageBase is created.

If all goes well try added the second create rule.

Also, did you install through nuget? Which version are you on?

mmisztal1980 commented 10 years ago

Hello,

Yes, I've installed everything via NuGet (Had to upgrade Microsoft.AspNet.WebApi manually because Umbraco ships with a broken dependency.

For your reference, here is my full packages.config file :

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="AutoMapper" version="3.0.0" targetFramework="net45" />
  <package id="bootstrap" version="3.0.1" targetFramework="net45" />
  <package id="ClientDependency" version="1.7.0.3" targetFramework="net45" />
  <package id="ClientDependency-Mvc" version="1.7.0.3" targetFramework="net45" />
  <package id="HtmlAgilityPack" version="1.4.6" targetFramework="net45" />
  <package id="jQuery" version="1.9.0" targetFramework="net45" />
  <package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
  <package id="Microsoft.AspNet.Mvc" version="4.0.20710.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.Mvc.FixedDisplayModes" version="1.0.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.Razor" version="2.0.20710.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi" version="4.0.30506.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.Client" version="4.0.20710.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.Core" version="4.0.20710.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.WebHost" version="4.0.20710.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebPages" version="2.0.20710.0" targetFramework="net45" />
  <package id="Microsoft.Net.Http" version="2.0.20710.0" targetFramework="net45" />
  <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
  <package id="MiniProfiler" version="2.1.0" targetFramework="net45" />
  <package id="MySql.Data" version="6.6.5" targetFramework="net45" />
  <package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
  <package id="SharpZipLib" version="0.86.0" targetFramework="net45" />
  <package id="Twitter.Bootstrap" version="3.0.1.1" targetFramework="net45" />
  <package id="Umbraco.Inception" version="1.0.0.5" targetFramework="net45" />
  <package id="UmbracoCms" version="7.0.4" targetFramework="net45" />
  <package id="UmbracoCms.Core" version="7.0.4" targetFramework="net45" />
  <package id="xmlrpcnet" version="2.5.0" targetFramework="net45" />
</packages>

If I only execute :

UmbracoCodeFirstInitializer.CreateOrUpdateEntity(typeof(PageBase));

All goes well, however subsequent attempts to execute line #2 will result in the same error - and umbraco's back office will show multiple instances of DocumentTypes/Templates (actually as many as failed attempts there will be)

nojaf commented 10 years ago

I think it's the slash in your contentType alias in the second param of the UmbracoContentType attribute of your HomePaga class.

Try:

    [UmbracoContentType("HomePage", "HomePage", null, true, BuiltInUmbracoContentTypeIcons.IconHome, "_Layout", true, true)]

With this change I was able to create what you want.

mmisztal1980 commented 10 years ago

Could be...

What if I wanted to "control" where the generated views would appear? In my case I wanted it to be ~/Views/Home ?

nojaf commented 10 years ago

Hmm, this is starting to make some more sense now. Where you enter "~/Views/Shared/_Layout" as the layout, we expect the name of a template stored in Umbraco. You entered the location of the view. This might be the reason why a parent couldn't be set.

It's currently not possible to decide where the generated views are placed.

mmisztal1980 commented 10 years ago

Can I make this a feature request ? I find it prudent to have the ability to control the overall "layout" of the project :)

nojaf commented 10 years ago

You certainly can, however I can't promise I'll get back to you soon. I'm also waiting for Umbraco 7.1 to rewrite some off the template generation code.

mmisztal1980 commented 10 years ago

I don't know much about umbraco's internals, but if you point me in the right direction I can certainly try and contribute :)

nojaf commented 10 years ago

The piece of code you are interested is the function is CreateView

    private static void CreateMatchingView(IFileService fileService, UmbracoContentTypeAttribute attribute, Type type, IContentType newContentType)
    {
        Template currentTemplate = fileService.GetTemplate(attribute.ContentTypeAlias) as Template;
        if (currentTemplate == null)
        {
            currentTemplate = new Template("~/Views/" + attribute.ContentTypeAlias + ".cshtml", attribute.ContentTypeName, attribute.ContentTypeAlias);
            CreateViewFile(attribute.ContentTypeAlias, attribute.MasterTemplate, currentTemplate, type, fileService);
        }

        newContentType.AllowedTemplates = new ITemplate[] { currentTemplate };
        newContentType.SetDefaultTemplate(currentTemplate);

        //TODO: in Umbraco 7.1 it will be possible to set the master template of the newly created template
        //https://github.com/umbraco/Umbraco-CMS/pull/294
    }

You would need to add an extra parameter in the Umbraco ContentType attribute, f.ex string templateLocation.

Then where we do:

 currentTemplate = new Template("~/Views/" + attribute.ContentTypeAlias + ".cshtml", 

Instead of '~/Views/ + alias + cshtml you want to add the location parameter you provided.

And don't forget to add the same logic to the function CreateViewFile, that's where we create the physical file with a Stringbuilder.