iOS: Registering ServiceStack license key crashes app in release mode

Hello,

we are using ServiceStack in our app development for iOS and Android (.dotnet MAUI). In Debug, everything works as expected, however, in release mode, the app crashes. Looking into the crash reason, we’ve found that calling

ServiceStack.Licensing.RegisterLicense(@“”); // Register ServiceStack licence key

crashes the app.

For MAUI iOS, we are aware of different behavior in release builds vs debug builds (i.e. AOT-compliation, no JIT-support,…). So we tried to mimic a debug build like so

<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-ios|AnyCPU'">
	<MtouchUseLlvm>False</MtouchUseLlvm>
	<MtouchLink>SdkOnly</MtouchLink>
	<AotAssemblies>False</AotAssemblies>
	<UseIntepreter>True</UseIntepreter>
</PropertyGroup>

Unfortuntely, the app still crashes when calling Licensing.RegisterLicense();

We’ve also added

<ItemGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-ios|AnyCPU'">
  <TrimmerRootAssembly Include="ServiceStack.Text" />
</ItemGroup>

based on this guide here though that also doesn’t solve the crash issue.

Additional observations

  1. Calling Licensing.RegisterLicense() with an invalid key like “abc” does not crash the app and instead throws a LicenseException with the message “This license is invalid. […]”. However, specifying a license key which matches our valid license key in all but a single character (i.e. replacing an ‘e’ with an ‘f’) does not throw this exception but crashes the app right away.

Are we missing something here to be able to sucessfully register OrmLite on iOS in release-mode for .dotnet MAUI or is that just not a supported scenario?

Thanks

The only libraries that could be used in Mobile Apps are the ServiceStack.Client and its dependent libraries, which don’t require registering a License Key, as such a LicenseKey should never be registered in Client Apps since they’re only for enabling unlimited restrictions of Server libraries (i.e. which can’t be used in Mobile Apps). Which includes OrmLite, that’s very unlikely to work in iOS/AOT.

The other issue being that AOT isn’t a supported platform, however since the latest versions of ServiceStack now supports System.Text.Json APIs, you’ll likely have the least issues with Microsoft’s serializer which should be designed to support AOT platforms. To enable it on the client you need to set it before using the JsonApiClient, e.g:

ClientConfig.UseSystemJson = UseSystemJson.Always;

var client = new JsonApiClient(BaseUrl);

Thank you for the quick reply!

Unfortunately, we are using ServiceStack.OrmLite on mobile as well because we are storing data in a local SQLite database and are using ServiceStack.OrmLite as our ORM to access and manipulate that data. Which requires us, as you have pointed out, to register our ServiceStack license key.

So based on your reply, it seems we are out of luck here regarding ServiceStack.OrmLite on iOS (even if we were somehow able to fix the license key issue)?

Out of interest, do yo have any idea as to why registering the license key on iOS in release mode crashes the app?

And thank you for the System.Text.Json suggestion.

During development iOS runs in interpreted mode, whilst for release iOS runs a trimmed AOT build, which is where most of the issues for running from iOS are caused by, as such I don’t expect Reflection dependent libraries like OrmLite will ever work on iOS/AOT.

Correct.

Which is why we were hoping that explicitly enabling the interpreter in Release mode on iOS like so:

<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-ios|AnyCPU'">
	<MtouchUseLlvm>False</MtouchUseLlvm>
	<MtouchLink>SdkOnly</MtouchLink>
	<AotAssemblies>False</AotAssemblies>
	<UseIntepreter>True</UseIntepreter>
</PropertyGroup>

would allow us

  • to successfully register the service stack license key and
  • run OrmLite

though as the app still crashes when registering the license key, it doesn’t look very promising right now.

You may also need to add <MtouchInterpreter>-all,MyAssembly</MtouchInterpreter> and include ServiceStack.Text/Client/OrmLite assemblies so they’re intepreted.

If you’re still having issues with the registering the License Key, the latest v8.2.3+ on Pre Release packages should now let you register the License Key on iOS/AOT. Still not expecting OrmLite to work without issues, but hopefully it will pass the License Key step.

Looks like adding

<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-ios|AnyCPU'">
	<!-- Interpret everything, exceptServiceStack libraries -->
	<MtouchInterpreter>-all,ServiceStack.Text,ServiceStack.Client,ServiceStack.OrmLite</MtouchInterpreter>
</PropertyGroup>

solved the crash issue with registering the license key. Thanks for that! (Though I wonder why <UseIntepreter>true</UseInterpreter> did not do the trick…)

Having said that though, it seems your expectation regarding OrmLite and AOT is spot on, as we are now getting a PlatformNotSupportedException when calling ServiceStack.OrmLite.OrmLiteConfig.GetModelMetadata(Type modelType). Namely, the exception is raised in
ServiceStack.Text.EmitReflectionOptimizer.CreateDynamicGetMethod(MemberInfo memberInfo)

which ends up calling

System.Reflection.Emit.DynamicMethod.Init()

(Source Browser)

We suspect the exception happens in line 215 of that file when asserting:

AssemblyBuilder.EnsureDynamicCodeSupported();

as that throws a PlatformNotSupportedException: Source Browser

Any ideas what we could do here? Would that require code changes to ServiceStack.OrmLite so that the specific code path will not be called? Would that even be a possible/feasable change?

Thanks again for all your help so far.


Crash log (as screenshot):

Yeah these platform issues are expected, and why you can’t just run Server Libraries in iOS/AOT. You would need to use an ORM that’s designed from the start to support AOT.

Not tried it, but something like Dapper.AOT could work: https://aot.dapperlib.dev

As a alternative to switching to another ORM, we are thinking whether it would be possible to modify the codepath in ServiceStack.Text itself to not call System.Reflection.Emit APIs. The code to modify would be - at least for the case we are hitting - the following:

public override GetMemberDelegate<T> CreateGetter<T>(PropertyInfo propertyInfo)
{
    var getter = CreateDynamicGetMethod<T>(propertyInfo);

    var gen = getter.GetILGenerator();
    var mi = propertyInfo.GetGetMethod(true);
    if (mi == null)
        return null;

    if (typeof(T).IsValueType)
    {
        gen.Emit(OpCodes.Ldarga_S, 0);

        if (typeof(T) != propertyInfo.DeclaringType)
        {
            gen.Emit(OpCodes.Unbox, propertyInfo.DeclaringType);
        }
    }
    else
    {
        gen.Emit(OpCodes.Ldarg_0);

        if (typeof(T) != propertyInfo.DeclaringType)
        {
            gen.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
        }
    }

    gen.Emit(mi.IsFinal ? OpCodes.Call : OpCodes.Callvirt, mi);

    if (propertyInfo.PropertyType.IsValueType)
    {
        gen.Emit(OpCodes.Box, propertyInfo.PropertyType);
    }

    gen.Emit(OpCodes.Isinst, typeof(object));

    gen.Emit(OpCodes.Ret);

    return (GetMemberDelegate<T>) getter.CreateDelegate(typeof(GetMemberDelegate<T>));
}

(ReflectionOptimizer.Emit.cs in ServiceStack.Text)

Here, we an API like RuntimeFeature.IsDynamicCodeSupported could be used to not run the above code which is using System.Reflection.Emit.DynamicMethod.

Would it be be possible for ServiceStack to look into supporting iOS (AOT)?

If not, assuming we would be able to write code for GetMemberDelegate() supporting non-AOT platforms as well - would you be willing to take that as a contribution and integrate that code into the official ServiceStack.Text package?

Having said that, it’s possible this is not the only place where such a code addition would be required. How do you view the situation? Would there be many more places in ServiceStack which would have to be modified for them to run on AOT platforms?

Thanks again.

This would just be kicking the can down the road until the next issue.

You’re welcome to create a custom build of of OrmLite from ServiceStack’s public code base:

https://github.com/ServiceStack/ServiceStack/

Each Solution has a build.bat and build.sh which can be used to build packages for each project in the solution, e.g. for OrmLite: ServiceStack.OrmLite/build.

I’m not expecting using OrmLite in iOS/AOT to be viable, but if you are able to get a working version you can submit a PR that we can consider rolling back into the main code-base if it’s not too disruptive.

I see, thanks for the reply. So to summarize, the recommended (and perhaps only practically feasable) option here would be to really do switch to a different ORM which supports our AOT scenario.

Yeah for the least issues I’d only consider ORMs that are designed to support iOS/AOT.

Alright, thanks again for all the help & suggestions.

1 Like