umbraco / Umbraco.Headless.Client.Net

.NET Client Library and Samples for the Umbraco headless cms Cloud Service called Umbraco Heartcore
https://umbraco.com/products/umbraco-heartcore/
12 stars 14 forks source link

Unable to run web sample locally - Value cannot be null in ModelConverter.cs #35

Closed rhealefever closed 3 years ago

rhealefever commented 3 years ago

Gabriel, Dennis, Jakob and I all get this error when running the web sample. We have .NET Core SDK versions 2.2 and 3.1 installed. This is when using a project with published content and the content delivery API set to public. The result is the same across different aliases (with different content and content structures).

image

We've resorted to using a version of the code from July 2020, I believe that's before 3.1 was implemented: https://github.com/Jay-umbr/Umbraco.Headless.Client.Net

Full stack trace:

ArgumentNullException: Value cannot be null. (Parameter 'value')
Newtonsoft.Json.Utilities.ValidationUtils.ArgumentNotNull(object value, string parameterName)
Newtonsoft.Json.Linq.Extensions.Value<T, U>(IEnumerable<T> value)
Newtonsoft.Json.Linq.Extensions.Value<U>(IEnumerable<JToken> value)
Umbraco.Headless.Client.Net.Serialization.ModelConverter<TInterface, TImplementation>.ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) in ModelConverter.cs

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) =>
            throw new NotImplementedException();
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var obj = serializer.Deserialize<JObject>(reader);
            var contentTypeAlias = obj.GetValue(_aliasProperty).Value<string>();
            return _types.TryGetValue(contentTypeAlias, out var type) ?
                obj.ToObject(type, serializer) : obj.ToObject<TImplementation>();
        }
        public override bool CanConvert(Type objectType) =>
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, object existingValue)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, bool checkAdditionalContent)
Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)
Newtonsoft.Json.JsonSerializer.Deserialize<T>(JsonReader reader)
Refit.JsonContentSerializer.DeserializeAsync<T>(HttpContent content) in JsonContentSerializer.cs
Refit.RequestBuilderImplementation+<>c__DisplayClass14_0<T, TBody>+<<BuildCancellableTaskFuncForMethod>b__0>d.MoveNext() in RequestBuilderImplementation.cs
Umbraco.Headless.Client.Net.Delivery.ContentDelivery.Get<T>(Func<ContentDeliveryEndpoints, Task<ApiResponse<T>>> getResponse) in ContentDelivery.cs

            var result = await Get(x => x.Search(Configuration.ProjectAlias, culture, term, page, page)).ConfigureAwait(false);
            return result;
        }
        private async Task<T> Get<T>(Func<ContentDeliveryEndpoints, Task<ApiResponse<T>>> getResponse)
        {
            using (var response = await getResponse(Service).ConfigureAwait(false))
                return GetResponse(response);
        }
        private async Task<T> GetTyped<T>(Func<TypedContentDeliveryEndpoints<T>, Task<ApiResponse<T>>> getResponse) where T : IContent
        {
            var service = RestService.For<TypedContentDeliveryEndpoints<T>>(_httpClient, _refitSettings);
Umbraco.Headless.Client.Net.Delivery.ContentDelivery.GetByUrl(string url, string culture, int depth) in ContentDelivery.cs

            var result = await GetTyped<T>(x => x.GetById(Configuration.ProjectAlias, culture, id, contentType, depth)).ConfigureAwait(false);
            return result;
        }
        public async Task<Content> GetByUrl(string url, string culture, int depth)
        {
            var result = await Get(x => x.GetByUrl(Configuration.ProjectAlias, culture, url, depth)).ConfigureAwait(false);
            return result;
        }
        public async Task<T> GetByUrl<T>(string url, string culture, int depth) where T : IContent
        {
            var contentType = GetAliasFromClassName<T>();
Umbraco.Headless.Client.Net.Web.UmbracoRouter.RouteAsync(RouteContext context) in UmbracoRouter.cs

            var umbracoContext = context.HttpContext.RequestServices.GetService<IUmbracoContext>();
            var contentDeliveryService = context.HttpContext.RequestServices.GetService<IContentDeliveryService>();
            try
            {
                var content = await contentDeliveryService.Content.GetByUrl(context.HttpContext.Request.Path)
                    .ConfigureAwait(false);
                if (content != null)
                {
                    umbracoContext.CurrentContent = content;
Microsoft.AspNetCore.Routing.RouteCollection.RouteAsync(RouteContext context)
Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
Umbraco.Headless.Client.Samples.Web.Startup+<>c+<<Configure>b__5_0>d.MoveNext() in Startup.cs

                    var output = "User-agent: *  \nDisallow: /";
                    context.Response.ContentType = "text/plain";
                    await context.Response.WriteAsync(output);
                }
                else
                {
                    await next();
                }
            });
            app.UseRouting();
            app.UseAuthorization();
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
rasmusjp commented 3 years ago

I'm not able to reproduce this, have you tried with demo-headless?

The web sample pretty much requires using the same content as that site as all the models and views are setup to use that.

rhealefever commented 3 years ago

Just gave demo-headless a try and it gives the same error.

We tried this with projects that have the sample content installed as well (both the website and the blog). Same error.

rasmusjp commented 3 years ago

Okay, thats weird. Can you run dotnet --info and post the output?

λ dotnet --info
.NET SDK (reflecting any global.json):
 Version:   5.0.103
 Commit:    72dec52dbd

Runtime Environment:
 OS Name:     Mac OS X
 OS Version:  11.0
 OS Platform: Darwin
 RID:         osx.11.0-x64
 Base Path:   /usr/local/share/dotnet/sdk/5.0.103/

Host (useful for support):
  Version: 5.0.3
  Commit:  c636bbdc8a

.NET SDKs installed:
  3.1.406 [/usr/local/share/dotnet/sdk]
  5.0.103 [/usr/local/share/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 3.1.12 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.3 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 3.1.12 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]

To install additional .NET runtimes or SDKs:
  https://aka.ms/dotnet-download
rhealefever commented 3 years ago
.NET SDK (reflecting any global.json):
 Version:   5.0.103
 Commit:    72dec52dbd

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.19041
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\5.0.103\

Host (useful for support):
  Version: 5.0.3
  Commit:  c636bbdc8a

.NET SDKs installed:
  2.1.202 [C:\Program Files\dotnet\sdk]
  2.1.503 [C:\Program Files\dotnet\sdk]
  2.2.207 [C:\Program Files\dotnet\sdk]
  3.1.406 [C:\Program Files\dotnet\sdk]
  5.0.103 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.All 2.1.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.25 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.1.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.25 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.25 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.8 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.1.12 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
rasmusjp commented 3 years ago

That looks fine, you have the correct versions installed so I'm not sure why it's failing. It might be a Windows only problem, as I'm not able to reproduce it on either Linux or Mac.

I'll get back to you when I've been able to test it on Windows

rasmusjp commented 3 years ago

We've updated the sample to .Net 5 and I'm not able to reproduce the error.
Could you please try pulling the latest version and see if it working now?

Thanks

rhealefever commented 3 years ago

We're still unable to get the web sample to run. Now it's something with the ProjectAlias in ServiceCollectionExtensions.cs.

image

Jakob and I both get this issue. I see that Gabriel was able to get it to run, but he's using a Mac.

We first tried project alias "heartcore-demo" (it has the default content installed) first with the CDN set to public, then set to private and supplying the API Key, but we still hit this error. We tried a couple workarounds, but were unable to get it working.

Full stack trace:


Microsoft.Extensions.Options.OptionsValidationException: DataAnnotation validation failed for members: 'ProjectAlias' with the error: 'The ProjectAlias field is required.'.

   at Microsoft.Extensions.Options.OptionsFactory`1.Create(String name)

   at Microsoft.Extensions.Options.OptionsManager`1.<>c__DisplayClass5_0.<Get>b__0()

   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)

   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)

   at System.Lazy`1.CreateValue()

   at System.Lazy`1.get_Value()

   at Microsoft.Extensions.Options.OptionsCache`1.GetOrAdd(String name, Func`1 createOptions)

   at Microsoft.Extensions.Options.OptionsManager`1.Get(String name)

   at Microsoft.Extensions.Options.OptionsManager`1.get_Value()

   at Microsoft.Extensions.DependencyInjection.ServiceCollectionExtensions.<>c.<AddUmbracoHeartcore>b__0_0(IServiceProvider provider) in C:\Users\raele\Desktop\Umbraco.Headless.Client.Net-master\src\Umbraco.Headless.Client.Net.Web\DependencyInjection\ServiceCollectionExtensions.cs:line 32

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)

   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)

   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)

   at Microsoft.Extensions.DependencyInjection.ServiceCollectionExtensions.<>c__DisplayClass0_0.<AddUmbracoHeartcore>b__1(IServiceProvider provider) in C:\Users\raele\Desktop\Umbraco.Headless.Client.Net-master\src\Umbraco.Headless.Client.Net.Web\DependencyInjection\ServiceCollectionExtensions.cs:line 52

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)

   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)

   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)

   at Microsoft.Extensions.DependencyInjection.ServiceCollectionExtensions.<>c.<AddUmbracoHeartcore>b__0_3(IServiceProvider provider) in C:\Users\raele\Desktop\Umbraco.Headless.Client.Net-master\src\Umbraco.Headless.Client.Net.Web\DependencyInjection\ServiceCollectionExtensions.cs:line 56

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)

   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)

   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)

   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)

   at Umbraco.Headless.Client.Net.Web.Routing.UmbracoRouter.RouteAsync(RouteContext context) in C:\Users\raele\Desktop\Umbraco.Headless.Client.Net-master\src\Umbraco.Headless.Client.Net.Web\Routing\UmbracoRouter.cs:line 36

   at Microsoft.AspNetCore.Routing.RouteCollection.RouteAsync(RouteContext context)

   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)

   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)

   at Umbraco.Headless.Client.Samples.Web.Startup.<>c.<<Configure>b__5_0>d.MoveNext() in C:\Users\raele\Desktop\Umbraco.Headless.Client.Net-master\samples\Umbraco.Headless.Client.Samples.Web\Umbraco.Headless.Client.Samples.Web\Startup.cs:line 65

--- End of stack trace from previous location ---

   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)```
rasmusjp commented 3 years ago

Is your configuration correct? It changed with the latest version, so instead the root key being Umbraco it's now called Heartcore (because the CMS uses Umbraco and there is a published schema for it, so most IDEs complained about the config being incorrect). This is updated in the appsettings{.development}.json files.

rhealefever commented 3 years ago

The root key is Heartcore. I have the latest version and haven't made any changes to it aside from adding my project alias.

image

rasmusjp commented 3 years ago

Ahh.. I think I know what's happening. The sample has an appsettings.Development.json file which contains the ProjectAlias and ApiKey keys, the'll overwrite the configuration when running in development mode. So either adding the project alias to that config or removing the whole Heartcore section should fix it

rhealefever commented 3 years ago

That was exactly what was going on, thank you Rasmus! Got it up and running now.

rasmusjp commented 3 years ago

Cool 👍 I'm going to close this then