MobileBlazorBindings
MobileBlazorBindings copied to clipboard
Known Issues with ShellNavigationManager
Known issues with ShellNavigationManager
These are intended as notes for future research and we're not planning on acting on them immediately. If anyone comes across bugs in ShellNavigationManager that affect how they use it, please create a new issue.
There are a handful off issues with the ShellNavigationManager, for now we're saying it's good enough for an experimental project, but these will all need to be investigated later.
Some of them may require changes inside ASP.NET Core or Xamarin.Forms, others may just need more research.
The two overloads of AddComponent in MobileBlazorBindingsHostExtensions could share more code
Find Routes
Upon constuction ShellNavigationManager calls FindRoutes, which scans the assembly for routes declared with the @page directive, and it registers the routes with Shell for navigation and keeps its own list of routes for setting parameters when shell navigates.
This call has a few issues:
- Assembly scanning can be very slow and this call is on the critical path for app startup
- It does not handle multiple routes with the same form but different argument types
- There must be something like this in ASP.NET CORE already does this, it's probably more efficient, handles all the different parameter types and route forms better and is already stable, tested and mature.
NavigateTo - find best match
When you navigate with a URL, we try to match it with the best match from the registered route.
- This find best match does not have support for different argument types.
- This is probably duplicating code that exists in ASP.NET Core.
Shell
Shell Navigation routes can do lots of things and I've only tested it for a few of the most common scenarios. I think most of the route navigation features will work.
NavigationManager inheritance
In ASP.NET Core there in an AbstractClass called NavigationManager, it has various navigation managers that extend it depending on how it's being used. Ideally the ShellNavigatationManager should extend this too but when I try I can't get it to initialize because it doesn't like my URIs.
ContentViews instead of ContentPages as Navigation Targets
When navigating the target page needs to have a content view as the only child, which will then be wrapped in a ContentPage by the ShellNavigationManager. It would make more sense to have the ContentPage declared in each component.
- Filed as #298 (fixed in Preview 6)
Component Extensions
We have two fairly similar methods here, we can probably refactor things a little nicer to prevent code duplication but I didn't want to rip apart a method that is used in lots of places.
NavigateTo vs NavigateToAsync
Shell navigation is asynchronous so the ShellNavigationManager exposes the method NavigateToAsyn
. This is at odds with the ASP.NET CORE Navigation
Unable to differentiate web and MBB components
If you have an app that uses Shell and BlazorWebView you willl have @page "..."
directive in web components. Shell will build happily create the route, but if you try to use Shell to navigate to a web page, something weird will happen.
Is there a way we can tell the difference between a component that is meant for WebView and a component that is meant for native Xamarin Forms Views?
ContentViews instead of ContentPages as Navigation Targets
Having to use ContentView instead of ContentPage is indeed not really convenient - e.g. you cannot set page Title easily. I've tried to fix this issue, but was able to achieve that in quite an ugly way.
- Problem 1. How to get rendered ContentPage instance?
Currently an empty ContentPage is created, and this page is used as a root for renderer. I've created an fake parent element handler with the sole purpose to be able to get elements from it. So I create this fake handler, use it as a root for renderer, and retrieve rendered page from there.
- Problem 2. RouteFactory.GetOrCreate method is non-async.
While Shell.GoToAsync method is asynchronous, GetOrCreate method (which creates the page) is not. Blazor renderer is async though. Currently empty ContentPage is created synchronously, and populated via renderer via fire-and-forget task. We cannot use this approach if ContentPage itself is rendered. I've tried simply waiting the task (sync-over-async), but it either deadlocks, or fails because of UI interaction from wrong thread (depending on how I create the task).
I was able to workaround that by creating the page asynchronously before Shell.GoToAsync is invoked (in ShellNavigationManager.NavigateToAsync), and storing it inside corresponding RouteFactory. And when GetOrCreate method is called - simply return already created instance.
And a side note.
- Is that OK to create another MobileBlazorBindingsRenderer on every Shell navigation?
ShellNavigationManager.PopulatePage
uses MobileBlazorBindingsHostExtensions.AddComponent
, and it creates new renderer (and it's never disposed).
Would it make sense to register it as a singletone in DI container instead?
Not sure how Blazor renderers are supposed to be used properly.
Do you have any better ideas how to solve issues above?
Thank for looking at this @Dreamescaper, hopefuly we can fix up a few of these things I couldn't work out. It's been a while since I've looked at this code, but just had a look again and I think I remember what's going on.
Currently an empty ContentPage is created, and this page is used as a root for renderer. I've created an fake parent element handler with the sole purpose to be able to get elements from it. So I create this fake handler, use it as a root for renderer, and retrieve rendered page from there.
I don't think I follow, but if it works then that's cool. Is there any weird code in the final app, or only in the MBB library?
- Problem 2. RouteFactory.GetOrCreate method is non-async. Yeah, it's an override of the Xamarin.Forms GetOrCreate(), so there's not much we can do about that. Your work around sounds like it makes sense, especially if we can get rid of the nasty fire and forget in BuildPage()
- Is that OK to create another MobileBlazorBindingsRenderer on every Shell navigation?
ShellNavigationManager.PopulatePage
usesMobileBlazorBindingsHostExtensions.AddComponent
, and it creates new renderer (and it's never disposed).
Good point. I think we only need one, which should be the one that's created in host.AddComponent() which is called when the app is created. In that version of AddComponent(), we deliberately don't dispose because that method is called in a Fire-and-Forget way(not ideal) and would dispose of it too soon.