-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ViewLocator conflict with trimming functionality in Visual Studio when publishing #14507
Comments
You should avoid reflection based ViewLocator at any cost, if you want to use trimming. Which most apps need to do.
Yes, registration mechanism is a safe way to do it. But in their/your example there is a problem with Activator.CreateInstance reflection call which is still unsafe. Consider something like this using factory methods in ViewLocator class: private static Dictionary<Type, Func<Control>> Registration = new Dictionary<Type, Func<Control>> ();
public static void Register<TViewModel, TView>() where TView : new()
{
Registration.Add(typeof(TViewModel), () => new TView());
}
public static void Register<TViewModel, TView>(Func<TView> factory)
{
Registration.Add(typeof(TViewModel), factory);
}
public Control Build(object data) {
var type = data.GetType();
if (Registration.TryGetValue(type, out var factory)) {
return factory();
}
else {
return new TextBlock { Text = "Not Found: " + type };
}
} This way there is no reflection, and all types should be statically preserved. I think there should be no other changes in your code, as Initialize method looks good already. |
Thank you! This really helps. I'm using ReactiveCommand to respond to button click and then switch page for user. Before this I'm using reflection to get ViewModel by its full name. Since reflection is not suitable, which means I can't use name string to find viewmodel, what's a better CommandParamter for the click command? I tried to pass the class name of viewmodel, but it just treat it as a string. *edit: Write individual commands for every button seems an easy way, but it's redundant and not flexible if there are many views. |
Problem solved by following guide on https://docs.avaloniaui.net/docs/guides/data-binding/how-to-bind-to-a-command-with-reactiveui, thanks again! |
The problem with reflection is the trimmer has no idea what code you need at compile time. So it will remove any code it's not sure about. If you don't need trimming just turn it off. It's generally only used for AOT/web assembly. That said, there are ways to tell the trimmer about some things it needs to keep. https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/incompatibilities |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
Hi I'm new to Avalonia and trying to use view locator for switching views. But I encountered some unexpected consequence when publishing the app.
Describe the bug
I'm using the view locator code available on Avalonia documentation: https://docs.avaloniaui.net/zh-Hans/docs/tutorials/todo-list-app/locating-views. It works good under IDE debugging and running, but when I publish my app with trimming code option checked, the result is that app launched but just displaying not found message on screen. Below are my actions trying to solve this issue, but unfortunately none of them worked:
When I firstly encountered the issue, I believe there must be some difference between debugging in IDE and publishing. So I turned to search engine and added an option to my project file:
<PreserveCompilationContext>true</PreserveCompilationContext>
which means to preserve all things in runtime considered when debugging. But this didn't work, view locator still return the 'not found' textblock.
Then I turned to some apps recorded in Awesome Avalonia for references. I found they are using the registration mechanism which register mapping of viewmodels to views. This may be a better solution and I tried, following are the modified view locator
Build()
method:And below is the registration dictionary, included in
ViewLocator.cs
:And
App.xaml.cs
, the modifiedInitialize()
Method:The type templates are all my viewmodels and views.
Then the result became even worse, as app started to fail to launch. For this I turned on console window for published app, and received the error message below:
Unhandled exception. System.MissingMethodException: Cannot dynamically create an instance of type 'Calmy.Views.HomeView' Reason: No parameterless constructor defined.
Where Calmy.Views is the namespace for my views. Accroding to stack trace, I believe view locator found corresponding view, but due to some reason the app was unable to display it. To get a better understanding, I printed all class names in the assembly with this:and found something strange. The views classes are not printed. Then I realized it may be caused by trmming code option. Views code-behind and xamls are trimmed, since they are accessed by reflection in my previous view locator(the one doesn't use registration). So I turned to find a way to preserve my views not to be trimmed. Finally I found this blog: https://devblogs.microsoft.com/dotnet/customizing-trimming-in-net-core-5/ and followed some steps described. But this time, the condition get even worse, as the xml indicating trimming for preserving didn't work, the view classes names still not printed.
In addition, there was a warning from ViewLocator when publishing:
Using member 'System.Reflection.Assembly.GetTypes()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Types might be removed.
After doing these research, I believe there are two major issues:
whole stacktrace for my issue 2:
is this due to the dependance injection progress happened behind scenes are also trimmed?
Expected behavior
Views display properly with code trimmed.
Environment
As trimming will impressingly reduce my app size from > 300MB to about 130MB, I don't want to abandon it. Please help me.
The text was updated successfully, but these errors were encountered: