Reputation: 102
I'm writing Blazor WASM app in .NET 6.
The app works as it should in Debug
when running from Visual Studio 2022, but when I deploy it as a static site using dotnet publish -c Release --nologo
and access the bin/Release/net6.0/publish/wwwroot
folder on localhost
I get the following error:
Unhandled exception rendering component: Cannot provide a value for property 'ScopeFactory' on type 'MySolution.Pages.MyComponent' because the property has no setter.
My component looks like this:
public class MyComponent : OwningComponentBase
{
public IOptions Option { get; set; } = Options.Default;
protected override async Task OnInitializedAsync()
{
Options = await ScopedServices.GetRequiredService<Task<IOptions>>();
}
}
I add the service in Program.cs
like this
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddScoped<Task<IOptions>>(async op => await Options.Create(op.GetRequiredService<HttpClient>()));
and the Options.Create()
looks like this
public static async Task<IGameOptions> Create(HttpClient client)
{
var json = await client.GetStringAsync("/gameOptions.json");
var options = JsonConvert.DeserializeObject<Options>(json);
if (options is null)
{
throw new InvalidDataException("Given path contains invalid JSON object.");
}
return options;
}
I've already done a lot of testing and searching, but I couln't find anything. I tried to only request the HttpClient
service in my component, but even that throws the same error.
I see that it is some problem in DI, but I manage the DI scope using the OwningComponentBase
, as it is stated in the ASP.NET Core Blazor dependency injection.
What could cause it?
Thank you in advance
Upvotes: 1
Views: 7589
Reputation: 1335
I have attempted both current answers given on this post and wanted to share my findings in case they help someone.
The answer from Jesse Good works to resolve this issue but gave me other issues related to performance. It also doubled the length of time of the build.
The answer from Steffan Ossendorf worked for me as well, and despite requiring slightly more tinkering and an extra file, is definitely worth that extra effort.
If it helps anyone, here is exactly what i did after reading through the article on trimming that Steffan mentioned.
I created a new XML file called "Trimmer.xml" in the route of my Blazor project with the following contents -
<linker>
<assembly fullname="Microsoft.AspNetCore.Components">
<type fullname="Microsoft.AspNetCore.Components.OwningComponentBase" preserve="all" />
</assembly>
</linker>
I then added this into the .csproj file of my Blazor project -
<ItemGroup>
<TrimmerRootDescriptor Include="Trimmer.xml" />
</ItemGroup>
Upvotes: 1
Reputation: 801
The marked answer can only be used as long as you don't want to trim your app on publish which is not always desirable. If you want to publish with trimming you have to exclude the type from trimming.
<assembly fullname="Microsoft.AspNetCore.Components">
<type fullname="Microsoft.AspNetCore.Components.OwningComponentBase" preserve="all" />
</assembly>
Because the whole trimming stuff is a topic of itself I can recommend this page for starting with adjusting the trimming process: .Net Blog - Customizing Trimming The blog post was written for .Net5 but I'm using it for .Net6 as well.
Upvotes: 2
Reputation: 52365
Thanks for posting the real code in the comments. After looking at it, this looks to be a result of trimming.
Try adding <PublishTrimmed>false</PublishTrimmed>
to your project file and I think it will work.
Basically when you run the command dotnet publish -c Release --nologo
, it is optimizing the assemblies for size (trimming).
In your case, it appears to be changing the following code in OwningComponentBase from:
[Inject] IServiceScopeFactory ScopeFactory { get; set; }
to:
[Inject] IServiceScopeFactory ScopeFactory { get; }
i.e. its removing the setter during trimming.
I would consider this a bug with the implementation
Upvotes: 4