Giter VIP home page Giter VIP logo

Comments (20)

KallynGowdy avatar KallynGowdy commented on May 5, 2024 1

I think part of the issue is the large amount of "magic" that RxUI has during initialization.

Sure you can implement your own IMutableDependencyResolver, but my guess is that most people don't know that can work. Instead, many will just assume RxUI doesn't let them change their DI provider simply because they don't know how DI works in RxUI.

For example, as a RxUI consumer, I have no way to control how RxUI initializes itself. Instead, I need to trust that all of the RxUI services have been registered properly via the static constructor on RxApp.

If I don't reference RxApp in my app, then it's possible I'm missing some RxUI services in my DI container. Alternatively, if I reference RxApp after I've setup some custom dependencies (like a custom IActivationForViewFetcher) then RxApp will just siliently replace my services.

In most scenarios I think the current system works fine, but I would like to see an API that encourages developers to manually initialize RxUI so these sort of issues are easier to track down.

It doesn't need to be complicated, maybe just something like RxApp.Initialize(). Something that is easy to document while at the same time indicating where RxUI's "main" function happens.

Maybe that API can also include convienence options so it is obvious where to go when you want to customize RxUI's behaviour.

e.g:

var rxAppOptions = new RxAppOptions();
rxAppOptions.DependencyResolver = new MyCustomDependencyResolver();
RxApp.Initialize(rxAppOptions);

Also (and this is really just from an engineering perspective), I'm pretty sure there's also an opportunity here to convert RxApp into a normal class so that multiple RxApp instances can exist in a single AppDomain. Of course, there's really only one practical reason to want this, which is multi-threaded unit testing. But that would just be icing on the cake, it's not really relevant to this conversation.

from rfcs.

nesterenko-kv avatar nesterenko-kv commented on May 5, 2024

The idea could be the same as in Caliburn.Micro which comes with pre-bundled DI-container and allows switch it to any of existing containers.
It uses Func factories to resolve dependencies.

from rfcs.

glennawatson avatar glennawatson commented on May 5, 2024

Well in theory we do already support different DI containers

You can swap inside the Locator class:

       /// <summary>
        /// Convenience property to return the DependencyResolver cast to a
        /// MutableDependencyResolver. The default resolver is also a mutable
        /// resolver, so this will be non-null. Use this to register new types
        /// on startup if you are using the default resolver
        /// </summary>
        public static IMutableDependencyResolver CurrentMutable {
            get { return Current as IMutableDependencyResolver; }
            set { Current = value; }
        }

So you would provide an adapter to your preferred DI.

What does Caliburn Micro do differently that would make it easier to interact with your preferred DI?

from rfcs.

nesterenko-kv avatar nesterenko-kv commented on May 5, 2024

This does not negate the fact that ReactiveUI refers to Splat.
Talking about Caliburn.Micro - It has built-in support for composition root aka BaseBootstrapper

from rfcs.

glennawatson avatar glennawatson commented on May 5, 2024

A bit of the magic kinda has to exist due to different platforms needing different schedulers and also for testing.

I think it's been compounded more in recent versions due to increasing our nuget package space for different Platforms, and it not being transparent to the user if they failed to add that package that something is wrong.

from rfcs.

RLittlesII avatar RLittlesII commented on May 5, 2024

Added an issue to the website repository to document this. I actually just added Autofac using this technique last week.

from rfcs.

glennawatson avatar glennawatson commented on May 5, 2024

I think this is a two step approach I guess. Maybe use a extension method approach like asp net core for rxapp initialisation or similar helpers.

Short term and long term we should act the referenced documentation task from Rodney

from rfcs.

RLittlesII avatar RLittlesII commented on May 5, 2024

I think we should go to the drawing board on this. @KallynGowdy brings up good points about the registration lifecycle. I explicitly still need to use Locator.Current in some manner because IViewLocator has need of it (if I am remembering correctly).

The following methods are not intuitive, I personally strayed away from them because I didn't understand them.

InitializeSplat();
InitializeReactiveUI();

I agree with you @glennawatson if this is a feature people want, we should come up with a long term strategy and get it on our road map. But we shouldn't halt documentation of what currently works. We should note in the documentation the limitations, and express our interest in making it more user friendly.

from rfcs.

glennawatson avatar glennawatson commented on May 5, 2024

Was talking to Rodney offline so here are some of my thoughts.

I like the idea of RxUIOptions due to the fact we can have registrations happen in any order and not have registration side effects.

I'd like some standard extension methods on those to make it more obvious what's going on.

Eg

RxUIOptions options = new RxUIOptions();
options.UsePlatformSchedulers(); 
options.DependencyResolver = new AutofacResolver();

RxApp.Start(options);

So the above with RxUIOptions because you register the dependency resolver after the UsePlatformSchedulers() it won't matter. That won't happen until we hit the RxApp.Start();

Also be useful just to have a simple "as current" type option, which would register all the current settings we do by automagic, which should be simply as easy as:

RxApp.Start();

I think the other thing we consider is having some premade templates for the different scenarios, other projects such as Polly/DynamicData have a really nice in-depth samples project with snippets they keep up to date.

Thoughts?

from rfcs.

KallynGowdy avatar KallynGowdy commented on May 5, 2024

So instead of something like options.UseDefaults() we would add some additional verbosity by splitting options out into their own functions?

Like

RxUIOptions options = new RxUIOptions();
options.UsePlatformSchedulers();
options.UsePlatformBindingConverters();
options.UsePlatformActivationForViewFetcher();
// etc..

Presumably the equivalent to options.UseDefaults() is simply RxApp.Start()? So what's the difference between this:

RxApp.Start(new RxUIOptions());

and this:

RxApp.Start();

or even this:

RxApp.Start(null);

Is the first just an "empty" RxApp whereas the second is an RxApp with all of the default platform registrations? (and the last is an ArgumentNullException?) I think if that's the case we might want to look at something like RxApp.StartDefault() instead of RxApp.Start() just to help make the behavior less surprising.

Also, would we be able to call RxApp.Start() multiple times with different options? What sort of bugs would we run into if that was supported? I would like to be able to call Start() multiple times so I can use different options for different unit tests, but calling Start() twice in a normal application seems like something that we probably don't want to support.

from rfcs.

glennawatson avatar glennawatson commented on May 5, 2024

StartDefault() sounds good.

.Start(null) l agree should be a exception I agree.

I have in the past had need to replace the standard view fetcher etc so having the ability to specify those like above seems like a good idea. Pick and choose as you go type thing if needed for a advance configuration.

In terms of .Start(new RxOptions()) I would imagine nothing registered? A nice warning to the user would be appropriate.

from rfcs.

RLittlesII avatar RLittlesII commented on May 5, 2024

I think these are great. Do either of you know all the various hooks for allowing a consumer of ReactiveUI override defaults? I think next steps are to get the list and start designing how to override the platform defaults, if it is not possible for that option already.

I think a RxApp.StartWith(RxOptions options) is an option. I wouldn't want to mess with the current public API surface if there isn't a need. That way the current default isn't broken when I upgrade to new versions. But if I am looking forward to this feature I will know to use the new Start method.

from rfcs.

vector-man avatar vector-man commented on May 5, 2024

Definitely need this. Was using a custom container, by setting Locator. Updating RUI broke it somehow (my main WinForms dialog was getting disposed after changing its visibility)

from rfcs.

glennawatson avatar glennawatson commented on May 5, 2024

@vector-man want to lodge a issue to the main rxui GitHub page and we will see if we can help fix that to get you back up and running?

from rfcs.

Slesa avatar Slesa commented on May 5, 2024

@RLittlesII Do you still have the example with autofac? I don't know how to translate the IEnumerable GetServices() to _container.Resolve<IEnumerable>, as autofac does not recognize collections...

from rfcs.

glennawatson avatar glennawatson commented on May 5, 2024

Check out here https://reactiveui.net/docs/handbook/dependency-inversion/custom-dependency-inversion

ReactiveUI is a composable, cross-platform model-view-viewmodel framework for all .NET platforms that is inspired by functional reactive programming which is a paradigm that allows you to express the idea around a feature in one readable place, abstract mutable state away from your user interfaces and improve improve the testability of your application.

from rfcs.

Slesa avatar Slesa commented on May 5, 2024

Thanks a lot.

Grrr... I already was on that page, but did not notice it.

from rfcs.

Slesa avatar Slesa commented on May 5, 2024

The problem is, that you update the container's registration, but the update function is obsolete. "You should consider the registration as immutable". Also, the calls to

            resolver.InitializeSplat();
            resolver.InitializeReactiveUI();

are not recognized. Is it possible to use the ContainerBuilder somehow? I guess this is only possible if registration and resolving are separated.

from rfcs.

vector-man avatar vector-man commented on May 5, 2024

So, I was using this to add a custom DI, but it no longer works, as Locator.Current is now read only:

Locator.Current = new GriffinDependancyResolver(container);

Any idea on how I can update that line with the newest release?

from rfcs.

RLittlesII avatar RLittlesII commented on May 5, 2024

Locator.SetLocator(new MyCustomLocator())

from rfcs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.