CON-841 - DefaultValue for {member.email} throws NullReferenceException on form rendering

Created by Marcel Hogenstein 08 Oct 2015, 09:05:25 Updated by Warren Buckley 11 Oct 2016, 14:06:42

Im running into the issue that with the new UmbracoForms setting member properties as default value throw a NullReferenceException when the form is rendered.

Steps to reproduce:

Create a new form and use the Contact form template

For name or emailaddress set the DefaultValue to

Open the form after logging in and a NullReferenceException occurs.

[NullReferenceException: Object reference not set to an instance of an object.] Umbraco.Core.Cache.HttpRuntimeCacheProvider.GetCacheItem(String cacheKey, Func1 getCacheItem, Nullable1 timeout, Boolean isSliding, CacheItemPriority priority, CacheItemRemovedCallback removedCallback, CacheDependency dependency) +825 Umbraco.Core.CacheHelper.GetCacheItem(String cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan timeout, Func1 getCacheItem) +364 umbraco.cms.businesslogic.cache.Cache.GetCacheItem(String cacheKey, Object syncLock, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan timeout, GetCacheItemDelegate1 getCacheItem) +126 umbraco.cms.businesslogic.cache.Cache.GetCacheItem(String cacheKey, Object syncLock, CacheItemRemovedCallback refreshAction, TimeSpan timeout, GetCacheItemDelegate1 getCacheItem) +112 Umbraco.Forms.Core.Services.CacheService.GetCacheItem(String cacheKey, Object syncLock, TimeSpan timeout, GetCacheItemDelegate1 getCacheItem) +162 Umbraco.Forms.Data.StringHelper.(String , Object ) +1669 Umbraco.Forms.Data.StringHelper.ParsePlaceHolders(HttpContext Context, Record record, String value) +813 Umbraco.Forms.Data.StringHelper.ParsePlaceHolders(HttpContext Context, String value) +62 Umbraco.Forms.Core.Extensions.StringExtensions.ParsePlaceHolders(String text) +65 Umbraco.Forms.Mvc.Models.FormViewModel.FetchDefaultValue(Field field) in f:\TeamCity\buildAgent\work\133677a4e37ceece\Umbraco.Forms.Mvc\Models\FormViewModel.cs:249 Umbraco.Forms.Mvc.Models.FormViewModel.Build(Form form) in f:\TeamCity\buildAgent\work\133677a4e37ceece\Umbraco.Forms.Mvc\Models\FormViewModel.cs:143 Umbraco.Forms.Web.Controllers.UmbracoFormsController.Render(Guid formId, Int32 recordId, String view, String mode) in f:\TeamCity\buildAgent\work\133677a4e37ceece\Umbraco.Forms.Mvc\Controllers\UmbracoFormsController.cs:33

I've reported this earlier in the Forum, but no response yet. However, I can't believe I'm the only one running into this.

Comments

Marcel Hogenstein 16 Nov 2015, 09:39:15

I managed to solve the issue, with what I would call a "palliative". Or workaround.

The issue is that we're using a bunch of custom property editors for a member that do not store a value, but rather act as a viewport to some custom datatables. The moment the-artist-formerly-known-as-contour reads a member's properties and stores them in the cache dictionary, these null values (which they are), are not accounted for. When retrieving the dictionary, this leads to the error message shown above. That's probably the reason why nobody has reported this issue before, because usually property editors store a value (although I can image that for some property editors the default is a null value, in some cases).

The palliative here is simple but effective. In the OnMemberSaving event of the MemberService, for any property that uses this kind of propertyeditor, a non-null value is set.

I haven't figured out where (or when) these properties are stored in the cache. But it's there that this should be solved.

See also https://our.umbraco.org/forum/umbraco-pro/contour/70575-nullreferenceexception-on-umbraco-forms-with-defaultvalue-for-logged-in-member


Michael Powell 14 Jun 2016, 12:50:59

I'm seeing the same behavior in 7.4.3, Forms 4.3.2. Decompiling the Umbraco.Forms.Core assembly shows the following in the ParseMemberPlaceholders(string, object) method:

foreach (Property property in member.Properties) dictionary.Add(XmlHelper.XmlName("member." + property.Alias), property.Value.ToString());

That property.Value.ToString call at the end is throwing the NullReferenceException for any property whose value is null.


Marcel Hogenstein 21 Jun 2016, 10:51:40

@mpowell@iihs.org indeed, I'm having the same issue here, on another solution with a fresh Umbraco 7.4.3 and Forms 4.3.2 install. Show stopper here, or did you manage to find a solution?


Marcel Hogenstein 21 Jun 2016, 13:10:56

Steps to reproduce in a plain vanilla Umbraco 7.4.3 (all defaults) and Forms 4.3.2 (all defaults) with the Fanoe starter kit:

  1. In Developer, Data Types sdd the Forms Picker datatype editor
  2. In Settings, Document Types
  1. add a Forms document type with a Forms Picker editor
  2. for document type Home under permissions, allow the Form document type
  1. In Settings, Templates add a template Form with the following: @inherits Umbraco.Web.Mvc.UmbracoTemplatePage @{ Layout = "Master.cshtml"; var form = Model.Content.GetPropertyValue("form"); }

Hi there!

@{Html.RenderAction("Render", "UmbracoForms", new { formId = form });} {code} 4) In Forms, add a new Contact form with two text fields (eg name and email) 5) In Content, a. under Home add new Form b. select the Contact form in the Form picker

Open the page, see the form rendered and submit the form. All is fine and life is good.

Now, lets reproduce the issue: 6) In Members, create a new Member with username whatever and password whatever 7) In Settings, Templates, edit the Form template and change it to the following: @inherits Umbraco.Web.Mvc.UmbracoTemplatePage @{ Layout = "Master.cshtml"; var form = Model.Content.GetPropertyValue("form");

var result = Members.Login("whatever","whatever");
var member = Members.GetCurrentMember();

}

Hi @member.Name

@{Html.RenderAction("Render", "UmbracoForms", new { formId = form });} {code}

Open the page, see the form rendered with a logged-in user and submit the form. Bang and bummer! Object reference not set to an instance of an object. 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.NullReferenceException: Object reference not set to an instance of an object.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:

[NullReferenceException: Object reference not set to an instance of an object.] Umbraco.Core.Cache.HttpRuntimeCacheProvider.GetCacheItem(String cacheKey, Func1 getCacheItem, Nullable1 timeout, Boolean isSliding, CacheItemPriority priority, CacheItemRemovedCallback removedCallback, CacheDependency dependency) +1047 Umbraco.Core.Cache.HttpRuntimeCacheProvider.GetCacheItem(String cacheKey, Func1 getCacheItem, Nullable1 timeout, Boolean isSliding, CacheItemPriority priority, CacheItemRemovedCallback removedCallback, String[] dependentFiles) +155 Umbraco.Core.Cache.DeepCloneRuntimeCacheProvider.GetCacheItem(String cacheKey, Func1 getCacheItem, Nullable1 timeout, Boolean isSliding, CacheItemPriority priority, CacheItemRemovedCallback removedCallback, String[] dependentFiles) +182 Umbraco.Forms.Core.Cache.CacheProviderExtensions.GetCacheItem(IRuntimeCacheProvider provider, String cacheKey, Func1 getCacheItem, Nullable1 timeout, Boolean isSliding, CacheItemPriority priority, CacheItemRemovedCallback removedCallback, String[] dependentFiles) +305 Umbraco.Forms.Data.StringHelper.ParseMemberPlaceholders(String value, Object memberKey) +1860 Umbraco.Forms.Data.StringHelper.ParsePlaceHolders(HttpContext context, Record record, String value) +455 Umbraco.Forms.Data.StringHelper.ParsePlaceHolders(Record record, String value) +86 Umbraco.Forms.Core.Services.WorkflowService.ExecuteWorkflows(List1 workflows, RecordEventArgs e) +1101 Umbraco.Forms.Core.Services.WorkflowService.ExecuteWorkflows(Record record, Form form, FormState state, Boolean editMode) +348 Umbraco.Forms.Web.Services.RecordService.Submit(Record record, Form form) +662 Umbraco.Forms.Web.Controllers.UmbracoFormsController.SubmitForm(Form form, FormViewModel model, Dictionary2 state, ControllerContext context) +2601 Umbraco.Forms.Web.Controllers.UmbracoFormsController.GoForward(Form form, FormViewModel model, Dictionary2 state) +261 Umbraco.Forms.Web.Controllers.UmbracoFormsController.HandleForm(FormViewModel model, Boolean captchaIsValid) +969 lambda_method(Closure , ControllerBase , Object[] ) +195 System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary2 parameters) +229 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary2 parameters) +35 System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState) +39 System.Web.Mvc.Async.WrappedAsyncResult2.CallEndDelegate(IAsyncResult asyncResult) +67 System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) +42 System.Web.Mvc.Async.AsyncInvocationWithFilters.b__3d() +72 System.Web.Mvc.Async.<>c__DisplayClass46.b__3f() +386 System.Web.Mvc.Async.<>c__DisplayClass46.b__3f() +386 System.Web.Mvc.Async.<>c__DisplayClass46.b__3f() +386 System.Web.Mvc.Async.<>c__DisplayClass46.b__3f() +386 System.Web.Mvc.Async.<>c__DisplayClass46.b__3f() +386 System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) +42 System.Web.Mvc.Async.<>c__DisplayClass2b.b__1c() +38 System.Web.Mvc.Async.<>c__DisplayClass21.b__1e(IAsyncResult asyncResult) +186 System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +38 System.Web.Mvc.Controller.b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +29 System.Web.Mvc.Async.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult) +65 System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +53 System.Web.Mvc.Async.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult) +36 System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +38 System.Web.Mvc.MvcHandler.b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +44 System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +65 System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +38 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +399 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +137


Michael Powell 22 Jun 2016, 03:08:04

@marcel@highstone.nl I did manage to cobble together a workaround, with the caveat that it works well enough on my not-yet-live installation but is totally untested on a live installation and in particular may not work well on a high traffic site. Basically I'm preloading the application cache with a delegate that loads the currently logged-in member but also scrubs it of any null property values:

        public static void AddMemberToCache(string memberId)
        {
            int id;
            if (!int.TryParse(memberId, out id)) return;
            Func<object> getMember = () =>
            {
                var member = ApplicationContext.Current.Services.MemberService.GetById(id);
                foreach (var prop in member.Properties)
                {
                    if (prop.Value != null) continue;
                    // Really need a better check for properties of type Date? here
                    if (prop.Alias.EndsWith("Date"))
                        prop.Value = DateTime.MinValue;
                    else
                        prop.Value = "";
                }
                return member;
            };
            // GetCacheItem will only execute the load function if the item doesn't already exist.
            var m = ApplicationContext.Current.ApplicationCache.RuntimeCache
                .GetCacheItem($"Forms.Member{id}", getMember, TimeSpan.FromHours(1.0));
        }

I call this from inside ''~/Views/MacroPartials/InsertUmbracoForm.cshtml'' to preload the cache right before the form is rendered. For good measure I also call it on the Umbraco.Forms.Web.Services.RecordService.RecordSubmitted event using an ApplicationEventHandler as well, just in case the form is submitted after the originally cached delegate has expired.


Marcel Hogenstein 23 Jun 2016, 08:51:30

Massive thanks @mpowell@iihs.org for providing this workaround! H5yR! I ended up putting the script in ''~/Views/Partials/Forms/Form.cshtml'' partial that renders the form, as we don't use macro's to insert forms in this project.

Now I hope that @warren.buckley and his Umbraco Forms core team resolves this nasty line of code in ParseMemberPlaceholders, so that we can keep our code clean. The offending property.Value.ToString() in this code block foreach (Property property in (Collection) member.Properties) dictionary.Add(XmlHelper.XmlName("member." + property.Alias), property.Value.ToString()); return dictionary;


Warren Buckley 28 Jun 2016, 07:51:21

Hello @marcel@highstone.nl Apologies for the delay in response. With a busy period leading up to CodeGarden this got missed.

With this sprint almost over I cannot look at this until next sprint which starts on Monday 4th July, where this will get schedule in for me to look at.

Thanks for all the detailed notes & steps to reproduce.

Thanks, Warren :)


Marcel Hogenstein 28 Jun 2016, 08:26:32

Thanks @warren.buckley for picking this up! If you need any help just reach out.


Warren Buckley 11 Jul 2016, 09:40:38

Ready for review here as a PR - https://github.com/umbraco/Forms/pull/85 With the detailed notes & steps above to reproduce please use this for testing notes when reviewing this.


Rob Smith 21 Jul 2016, 09:38:55

Is there a nightly build or similar I could test?


Warren Buckley 21 Jul 2016, 09:41:44

@xanf unfortunately not until this gets reviewed internally & due to it being Summer the team is alot smaller & the review column backlog is taking a little longer than normal at this time of year.

As soon as it gets set to fixed & the PR is merged in then it will be available in a nightly build.


Paul Wright 21 Jul 2016, 10:19:37

@warren.buckley Frustrating, considering this is a "paid for" plugin for Umbraco. It should be fast tracked for immediate attention. Just looks like poor customer service, especially with clients "asking questions" why the thing I told them to buy aint working like it should OOTB.

Any chance you can sort out the documentation too? or maybe upload them workflow providers? - Give us something to be excited about :-)


Warren Buckley 21 Jul 2016, 12:23:11

Hello @suedeapple this has been reviewed by @sebastiaan and merged in, so after tonight a nightly will contain this fix. The HQ & development team listen to all feedback, I am sorry you feel that this has not gotten the attention it has deserved.

In regards to the other two questions. Documentation does need to be addressed in some areas but for content editors we have updated Umbraco.TV since the 4.3 release & updated documentation around this on our.umbraco.org

I need to discuss with the team on best approach to ensure the codebase for the fieldtypes, workflows & other providers stay upto date & published than the very manual & out of date process that is in place.


Paul Wright 21 Jul 2016, 16:19:34

@warren.buckley Totally appreciate your efforts - Sometimes it feels like I'm the only one nagging, but hopefully I'm just voicing the opinions of the masses who don't post, and have already given up/gone silent. On the whole I'm pleased with UF, so a big thumbs up :-)

The sample workflows/fieldtypes would be a god send, as it would possibly harness the need for overly verbose developer documentation - and save you time and sanity. Just access to example code of the basic field/workflows would be good. I'm not implying or expecting to be spoon fed all the answers. I do like to "dev" as well :)

Alarms bells must be ringing when Umbraco Devs are having to "crack open the DLL'S" and break license agreements in order to fix stuff that shouldn't be broken. I think Umbraco in general has pushed too hard in introducing "new features", rather than making sure the core things are working.

Thanks for the nightly - I'll see if it works, and hopefully I can tell the client that the lovely guys "warren and seb" at Umbraco HQ, made everything hunky dory with UF in super fast time :)


Priority: Show-stopper

Type: Bug

State: Fixed

Assignee:

Difficulty:

Category:

Backwards Compatible: True

Fix Submitted:

Affected versions: 4.1.2, 4.2.0, 4.1.3, 4.1.4, 4.1.5, 4.2.1, 4.3.0, 4.3.1, 4.3.2

Due in version: 4.4.0

Sprint: Sprint 38

Story Points:

Cycle: