TypeLoadException when constraints added to AppHost

So we are upgrading SS from 5.5 to 5.6 in preparation for 5.7 (NetCore3.1). Something changed that broke our ability to put constraints on our app host.

    public abstract class DefaultAppHost<TServiceInterfaceAssembly> : AppHostBase where TServiceInterfaceAssembly : IServiceInterfaceAssembly

This code worked in 5.5, but now in 5.6 we get the following error:

System.TypeLoadException: GenericArguments[0], 'System.Object', on 'IM.ServiceStack.Features.AwsLambdaServerFeature.DefaultAppHost`1[TServiceInterfaceAssembly]' violates the constraint of type parameter 'TServiceInterfaceAssembly'.
   at System.RuntimeTypeHandle.Instantiate(RuntimeTypeHandle handle, IntPtr* pInst, Int32 numGenericArgs, ObjectHandleOnStack type)
   at System.RuntimeTypeHandle.Instantiate(Type[] inst)
   at System.RuntimeType.MakeGenericType(Type[] instantiation)

Our workaround was to remove the constraint, but that feels a little dirty as logically we want that constraint on our DefaultAppHost.

What would be the proper workaround for this issue going forward?

I’ve no idea what this Exception is, or who/where is throwing it as ServiceStack never tries to instantiate the AppHost. Find out what the source of the Exception is and what line in ServiceStack Startup is throwing it, I’m assuming the source of the Exception is in a nested InnerException.

I have isolated the code in question. It’s actually all related to the ModularStartup codes introduced in 5.6 and is giving us other issues as well with regard to abstract classes. (I was in the middle of submitting that post; but I’ll follow up here first since they originate in the same code block)

So the new error is:

System.MemberAccessException: Cannot create an abstract class.
   at System.Runtime.Serialization.FormatterServices.nativeGetUninitializedObject(RuntimeType type)
   at System.Runtime.Serialization.FormatterServices.GetUninitializedObject(Type type)
   at System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject(Type type)
   at System.Runtime.Serialization.FormatterServices.GetUninitializedObject(Type type)
   at ServiceStack.Text.EmitReflectionOptimizer.<>c__DisplayClass18_0.<CreateConstructor>b__0() in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\ReflectionOptimizer.Emit.cs:line 276
   at ServiceStack.ReflectionExtensions.CreateInstance(Type type) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\ReflectionExtensions.cs:line 476
   at ServiceStack.ReflectionExtensions.CreateInstance(Type type) in C:\BuildAgent\work\912418dcce86a188\src\ServiceStack.Text\ReflectionExtensions.cs:line 476
   at ServiceStack.ModularStartup.CreateStartupInstance(Type type) in C:\BuildAgent\work\3481147c480f4a2f\src\ServiceStack\ModularStartup.cs:line 115
   at ServiceStack.ModularStartup.GetPriorityInstances() in C:\BuildAgent\work\3481147c480f4a2f\src\ServiceStack\ModularStartup.cs:line 143
   at ServiceStack.ModularStartup.ConfigureServices(IServiceCollection services) in C:\BuildAgent\work\3481147c480f4a2f\src\ServiceStack\ModularStartup.cs:line 162
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.Initialize()

This is the same location that throws the exception about the constraint.

As for the abstract issue I think it can be fixed by changing ModularStartup (line 131):

var types = TypeResolver().Where(x =>
    !typeof(ModularStartup).IsAssignableFrom(x) // exclude self
    && (
        x.HasInterface(typeof(IStartup)) ||
        x.HasInterface(typeof(IConfigureServices)) ||
        x.HasInterface(typeof(IConfigureApp)))
    && LoadType(x)
);

to

var types = TypeResolver().Where(x =>
    !typeof(ModularStartup).IsAssignableFrom(x) // exclude self
    && !x.IsAbstract // exclude abstract
    && (
        x.HasInterface(typeof(IStartup)) ||
        x.HasInterface(typeof(IConfigureServices)) ||
        x.HasInterface(typeof(IConfigureApp)))
    && LoadType(x)
);

As for the constraint issue, the problem occurs because you try to create the instance with a System.Object which doesn’t have the same constraints as we defined.

ModularStartup needed to be changed to support .NET Core 3.x which got stricter about the type of Startup classes it can support which forced the creation of an inner Startup class that adheres to its stricter rules and loading the Modular Startup interfaces within that inner Startup class.

Yeah the ASP.NET Core AppHostBase does implement IConfigureServices which allows you to override void Configure(IServiceCollection services) to register dependencies in ASP.NET Core’s IOC so it does try to create an instance.

The !x.IsAbstract added in this commit should resolve it as I was able to create an AppHost with a constraint. This should resolve it, it doesn’t try to create an AppHost instance from object, it tried to create an instance from the AppHost Type which does have the constraints, but it shouldn’t try to create an instance from your abstract AppHost Type.

Running it through CI now, will let you know when a new version with this change is available.

This fix is now available on the latest v5.7.1 on MyGet.

BTW if you’re not using Modular Startup support you can just remove it, i.e. change .UseModularStartup<T> back to .UseStartup<T> and don’t have your Startup class inherit from anything.

Awesome! One more question. 5.7 I know is geared for NetCore3. Does this mean that NetCore2 support is stuck at 5.6?

The reason I ask is we encountered some issues running 5.7 up in AWS Lambda that seemed to resolve themselves when down grading to 5.6 both of which running NetCore21

Assuming this was the case we were planning on moving to 5.7 once AWS published their NetCore31 Lambda template. (any day now, but no ETA) but we also need these new changes in 5.7.1 today.

No, all of ServiceStack .NET Core packages (Except for the new gRPC support in ServiceStack.Extensions) are .NET Standard 2.0 builds which can run on .NET Core 2.1+, ASP.NET Core 2.1 on .NET Framework and .NET Core 3.x.

Okay good to know. We will try again with the latest 5.7.1 and see how far we get.

Off topic. What are your plans for Blazor WebAssembly support? We are looking to move that direction as the ability to create front end UI using C# and store them in shareable assemblies (i.e Features) seems mighty appealing and I’m curious on how deeply you plan on integrating with it.

Not expecting deep integration should be required, just a working ServiceClient and starting templates. Not planning of porting any of ServiceStack’s Server libraries like OrmLite/Redis. Would be nice for ServiceStack.Text/.Client/.Common (with #Script) to work, but if it doesn’t would likely need to create a new Service Client using ASP .NET Core’s built-in System.Json.

It all depends how well Blazor/WASM supports reflection, if it has poor support then porting wont be possible. Historically reflection support in .NET AOT builds has been fraught with issues. If that’s the case a gRPC client would have the best support (since client proxies are all code-gen’ed / no reflection), but that depends on ASP.NET Core providing support for it.

Hmm. I would almost think that since net-core is running on top of mono inside the wasm then you would get the level of reflection that dot net core natively gives you.

Would your starting templates integrate with your security via the service client?

As its still front-end I would expect to keep all things secured by the back-end and communicate over secure restful endpoints via the service client (just as we do with Aurelia today).

What would be nice is to be able to log in the blazor app via your auth provider, which would hit your auth endpoints to return a JWT where we re-create the ClaimsPrincipal/Identity that we use in the blazor AuthenticationStateProvider.

I can almost see a solution where back-end code and front-end blazor code is packed up nicely in bundled reusable ServiceStack.Features that can simply be plugged in. Each blazor feature would be responsible for it’s front end navigation items and blazor components, and just as you can currently plug in api features to build up an api (each feature adding more routes and endpoints), you could plug in blazor features to build up the blazor app (each feature extending the navigation menu and exposing the service models for the service client). Marrying the two together nicely creating a dynamic ServiceStack plug-in development stack. Dare to dream right?

I’d want the templates and Service Client to have the parity with other Auth integrated SPA Templates but wont know what’s possible until integration work has started.

I’m not familiar with Blazor’s componentization model but I’d expect it to have a well-designed one, it would depend if it can all be done in code but as Blazor uses Razor it’s dependent on heavy tooling and lots of layers of complexity to achieve its WASM compilation target, which is the reason why I dislike Razor so much, it’s inflexible outside of the use-cases it’s been explicitly designed to support.

Which was the reason for creating #Script which is vastly cleaner, simpler, minimal dependencies with no reliance on external tooling making it far more flexible where it’s virtually hostable in every major .NET platform, including restrictive .NET platforms like Unity.

So I don’t know how flexible Blazor will end up being, but they’d have to add support for everything they want to make possible, e.g. your dream for App UI + Logic Plugins / UI Components would need to be explicitly supported in a library component package that supports pre-compilation in a package that I’m assuming would need to have both .NET + WASM builds targets.

By contrast doing a App UI Logic + UI components with #Script is trivial even though it didn’t explicitly have to design support for it, e.g. you could have all UI and #Script code as embedded resources that your plugin just registers along with the backend Services. Or you could also have all UI + #Script assets in a serialized gist that you load on demand from a remote source like a GitHub Gist, which is how Gist Desktop Apps works where you can have entire Apps loaded on-the-fly at runtime without installation. This is a good example of how flexible things can be the simpler it is, by contrast Blazor is built on top a tonne of complexity in order to work.