OYIon / LiveSharp

Public repository for the LiveSharp project
96 stars 4 forks source link

WASM + Server Hosted: TypeLoadException Due To Transient DLL Dependency #117

Closed warappa closed 3 years ago

warappa commented 3 years ago

Info

LiveSharp 2.0.9 LiveSharp.Server 2.0.6

Affected Versions

LiveSharp 1.6.x (or even ealier).

Issue

When using WASM Blazor with Kestrel hosting you need to reference the WASM project from the server project.

Usually it works, because the server tries not to load everything from the WASM project - in this case LiveSharp.Support.BlazorWASM.dll.

Cause

I changed the server's JsonOptions and got a TypeLoadException from Unknown Module. After some try-and-error I found that removing AddJsonOptions fixes the issue. Here's the service configuration:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews()
        //.AddJsonOptions(configure =>
        //{
        //    configure.JsonSerializerOptions.Converters.Add(new Client.TimeSpanConverter());
        //})
        ;

        ...
}

Root Cause

I think TimeSpanConverter causes the loading of LiveSharp.Support.BlazorWASM.dll and tries to load it. But in the server project it is not copied to the output folder.-

Proper Fix (Guess)

I guess it's how the DLL gets injected by the msbuild task. It should copy transient LiveSharp dependencies from client project to server project.

Workaround

Currently the only way to fix this is to take a direct dependency to the NuGet's DLL file in .csproj-file like this:

<ItemGroup>
    <Reference Include="LiveSharp.Support.BlazorWASM">
      <HintPath>C:\Users\spoil\.nuget\packages\livesharp\2.0.9\build\LiveSharp.Support.BlazorWASM.dll</HintPath>
    </Reference>
  </ItemGroup>

Exception

System.TypeInitializationException: 'The type initializer for '<Module>' threw an exception.'

Inner Exception
FileNotFoundException: Could not load file or assembly 'LiveSharp.Support.BlazorWASM, Version=1.6.2.0, Culture=neutral, PublicKeyToken=null'. Das System kann die angegebene Datei nicht finden.

Callstack (from Browser output)

TypeInitializationException: The type initializer for '<Module>' threw an exception.

    Shop.UI.Web.AspNetCore.Blazor.Server.Startup+<>c.<ConfigureServices>b__4_0(JsonOptions configure)
    Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>.Configure(string name, TOptions options)
    Microsoft.Extensions.Options.OptionsFactory<TOptions>.Create(string name)
    Microsoft.Extensions.Options.OptionsManager<TOptions>+<>c__DisplayClass5_0.<Get>b__0()
    System.Lazy<T>.ViaFactory(LazyThreadSafetyMode mode)
    System.Lazy<T>.ExecutionAndPublication(LazyHelper executionAndPublication, bool useDefaultConstructor)
    System.Lazy<T>.CreateValue()
    System.Lazy<T>.get_Value()
    Microsoft.Extensions.Options.OptionsCache<TOptions>.GetOrAdd(string name, Func<TOptions> createOptions)
    Microsoft.Extensions.Options.OptionsManager<TOptions>.Get(string name)
    Microsoft.Extensions.Options.OptionsManager<TOptions>.get_Value()
    Microsoft.AspNetCore.Mvc.MvcCoreMvcOptionsSetup.Configure(MvcOptions options)
    Microsoft.Extensions.Options.OptionsFactory<TOptions>.Create(string name)
    Microsoft.Extensions.Options.OptionsManager<TOptions>+<>c__DisplayClass5_0.<Get>b__0()
    System.Lazy<T>.ViaFactory(LazyThreadSafetyMode mode)
    System.Lazy<T>.ExecutionAndPublication(LazyHelper executionAndPublication, bool useDefaultConstructor)
    System.Lazy<T>.CreateValue()
    System.Lazy<T>.get_Value()
    Microsoft.Extensions.Options.OptionsCache<TOptions>.GetOrAdd(string name, Func<TOptions> createOptions)
    Microsoft.Extensions.Options.OptionsManager<TOptions>.Get(string name)
    Microsoft.Extensions.Options.OptionsManager<TOptions>.get_Value()
    Microsoft.Extensions.DependencyInjection.MvcCoreServiceCollectionExtensions+<>c.<AddMvcCoreServices>b__5_0(IServiceProvider s)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSite(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSite(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSite(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitNoCache(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSite(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSite(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSite(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitNoCache(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSite(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSite(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor<TArgument, TResult>.VisitCallSite(ServiceCallSite callSite, TArgument argument)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine+<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
    Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService<T>(IServiceProvider provider)
    Microsoft.AspNetCore.Builder.RazorPagesEndpointRouteBuilderExtensions.EnsureRazorPagesServices(IEndpointRouteBuilder endpoints)
    Microsoft.AspNetCore.Builder.RazorPagesEndpointRouteBuilderExtensions.MapRazorPages(IEndpointRouteBuilder endpoints)
    Shop.UI.Web.AspNetCore.Blazor.Server.Startup+<>c.<Configure>b__5_1(IEndpointRouteBuilder endpoints) in Startup.cs

                    endpoints.MapRazorPages();

Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseEndpoints(IApplicationBuilder builder, Action<IEndpointRouteBuilder> configure)
Shop.UI.Web.AspNetCore.Blazor.Server.Startup.Configure(IApplicationBuilder app, IWebHostEnvironment env) in Startup.cs

                app.UseEndpoints(endpoints =>

System.RuntimeMethodHandle.InvokeMethod(object target, object[] arguments, Signature sig, bool constructor, bool wrapExceptions)
System.Reflection.RuntimeMethodInfo.Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(object instance, IApplicationBuilder builder)
Microsoft.AspNetCore.Hosting.ConfigureBuilder+<>c__DisplayClass4_0.<Build>b__0(IApplicationBuilder builder)
Microsoft.AspNetCore.Hosting.GenericWebHostBuilder+<>c__DisplayClass15_0.<UseStartup>b__1(IApplicationBuilder app)
Microsoft.AspNetCore.Mvc.Filters.MiddlewareFilterBuilderStartupFilter+<>c__DisplayClass0_0.<Configure>g__MiddlewareFilterBuilder|0(IApplicationBuilder builder)
Microsoft.AspNetCore.Server.IIS.Core.IISServerSetupFilter+<>c__DisplayClass2_0.<Configure>b__0(IApplicationBuilder app)
Microsoft.AspNetCore.HostFilteringStartupFilter+<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder app)
Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)
Shop.UI.Web.AspNetCore.Blazor.Server.Program.Main(string[] args) in Program.cs

                CreateHostBuilder(args).Build().Run();
warappa commented 3 years ago

I'm adding LiveSharp.Support.BlazorWASM.dll as None and copying it to the output directory. I think this should be enough.

@ionoy Version 2.0.13 worked instantly! Thank you!