So, Splat provides two ways to retrieve a service:
var s1 = Locator.Current.GetService<IMyService>();
var s2 = Locator.CurrentMutable.GetService<IMyService>();
Documentation is unclear about which way we should use.
So what is the difference between these two? Which one should we use? Which one should we avoid?
Locator.Current is ReadOnly version, should be used unless you are registering services.
Locator.CurrentMutable is read/write version, should only be used when registering services.
They both point towards the same locators, just based on use cases which variable you use.
Basically:
use CurrentMutable to register services,
use Current whenever you need to retrieve them.
Related
I am looking into using one or other method and in particular method 2. Can anyone tell me the advantages and disadavantages of using the 2nd method over the 1st.
Method 1 - ViewModel.cs
PTBtnCmd = new Command<Templates.WideButton>((btn) =>
MessagingCenter.Send<CFSPageViewModel, Templates.WideButton>(
this, "PTBtn", btn));
Method 1 - MyPage.xaml.cs (SetLang etc.. methods in this file )
MessagingCenter.Subscribe<CFSPageViewModel, Templates.WideButton>(
this, "PTBtn", (s, btn) =>
{
Utils.SetState(btn.Text, vm.PT);
SetLangVisible(btn.Text);
SetLangSelected(btn.Text);
vm.CFSMessage = Settings.cfs.TextLongDescription();
});
or
Method 2 - ViewModel.cs (SetLang etc.. methods in this file )
PTBtnCmd = new Command<string>(SetMode);
private void SetMode(string btnText)
{
Utils.SetState(btnText, PT);
SetLangVisible(btnText);
SetLangSelected(btnText);
CFSMessage = Settings.cfs.TextLongDescription();
}
Would also like to hear comments on the idea of adding methods into the ViewModel.cs code. Would it be better for these to be in another file?
The MessagingCenter
helps you keep your code decoupled. Sometimes you will find yourself in a position
that requires you create a reference between certain code, but by doing so, you have to
compromise on reusability and maintainability.
Try to use it as a last resort; usually there is
another way to achieve your desired functionality. While sending a message can be very
powerful, using it too much can really eat into your readability.
A use case example for MessagingCenter would be a case where you need to update values in multiple
parts of your app. You can subscribe to a message from multiple places and thus execute
code in multiple places when a message is received. Another use case could be if some
background process is done, it can send a message and you can then inform the user in
your UI.
I would not use the messaging in the VM layer because your VM layer can then only be used in Xamarin.Forms. Some Mvm frameworks, like mvvmlight, offer a messaging capability. I would opt for that instead as you could then reuse your VMs in Wpf, Uwp or other UI frameworks other than XF.
Also i wouldn't use the messaging like you have. If probably just use databinding and raise PropertyChanged events in the VM which the view can react to.
To pass data between VMs I'd suggest navigation params or rethinking how you are using this data in general (use some sort of service or dumb down the UI depending on how "fat" your client app must be).
Messaging center as #Andy mentioned would cause reusability issues but this does not mean that you cannot use it. My approach is wrapping it in a separate service and using it in implementation. This will let you to do two things: creating more convenient or better way to use it in accordance to your use case and an option to swap out the implementation of your messenger to any other pub-sub library (or your own impl.) if you will need to use these VMs in WPF project.
Of course using something more universal across platforms would be a great option too but it also depends on how much you are "allowed"/can use third party stuff. At least with MAUI this causes some problems, but this is for another topic.
I like the simplicity of Pundit gem and I would like to make policies dynamic by storing them to database.
Basically I'm looking for a way to be able to change policies without need to redeploy the application.
1st way
Pundit policy is pure ruby code, so if you don't want to keep code inside database and evaluate it dynamically, I'd say the answer is no. It's unsafe. You may give it a go, though.
2nd way
But nothing prevents you from creating model which keeps rules in simple json and compare them using Pundit, e.g.:
class PostPolicy < ApplicationPolicy
def update?
access_setting = PolicySetting.find_by(key: self.class_name)
user.role.in?(access_setting['roles'])
end
end
Of course, complexity and flexibility of the tool directly depends on each other.
3rd way
Is just work around. You may set you authorisation project apart from the main one, so that it's deploys (zero-downtime, of course) would not affect the main big project.
4th way
Create your own DSL to be stored in Database
5th way
Use something like json-logic-ruby to store logic in database
I couldn't find any reference with this functionality. Shall I just implement a helper method in the builder to read fields in StateTransition object and populate the chain configureTransition() call by myself??
Just to confirm not to reinvent the wheels.
UPDATE:
I'm trying to use StateMachineBuilder to configure with some pre-defined states and transitions in a properties file. In Builder, they use this chained call to generate configuration:
builder.configureTransitions().withExternal().source(s1)....
What I have in mind is, everything read from the file is stored in an object, the spring sm library has this StateTransition object. But as far as I know from the API, there is no way to use it directly to configure a state machine. Instead, I can read individual fields in the object and use the chained call above.
Thanks!
If you want to do it like that, what you mentioned is pretty much only option. Hopefully we get a real support for external state machine definition, i.e. tracked in https://github.com/spring-projects/spring-statemachine/issues/78.
Suppose there are two exported versions of an object, where both have property x but new one introduces a new property y.
How can I create bundle that can accept both versions of an object? Let's assume it will not clone objects, compare them, put into collections etc. Its interaction with object could be as simple as testing whether x != null.
Can serialization be avoided?
Osgi classloading rules are only active at classloading time. If your bundle for example publishs a service that takes an Object as parameter you can give it any instance. Even ones that come from package it does not import.
Christian is correct. To add to that, this is exactly why you should not share your objects directly, but share interfaces. Whilst that still won't make both versions of the interface available to a consumer, at least it will then try to do the right thing and choose the interface that both x and y are compatible with. In such cases, it would have to pick the lowest common denominator.
I would like to use ServiceTracker in order to consume the services published by our company.
Instead of creating new ServiceTracker for each service I want to consume I thought it would be better to create just one with a filter and then get the services from it:
Filter filter = ctx.createFilter("(" + Constants.OBJECTCLASS + "=com.mycomp*)");
tracker = new ServiceTracker(ctx, filter, null);
The problem with this approach is that I then need to iterate over the service references the tracker had found examine their objectClass property and see if I can assign it to the service object which is very cumbersome and error prone due to casting that is required.
Any other ideas how to cunsume multiple services using more elegant way?
I think it is the wrong question :-) From the question I infer that you have a method that takes a service from your company and you want that method called. That is, somewhere in your code you need to be informed about a specific type com.mycomp.X, that is, you're not interested in general services from your company, you have a clear type dependency. In your question you assume that they need to be dispatched centrally which is usually not robust, error prone, and a maintenance hotspot; every time you have a new company service you need to update the dispatch method.
A MUCH better solution seems to be to use Declarative services and use bndtools with annotations. In that model, each place where you need service:
#Component public class SomeMyCompComponent {
...
#Reference
void foo( com.mycomp.X x ) { ... }
...
}
In this model, you do not need to centrally maintain a dispatcher, any class can get the services it needs when they need it. This model also accurately handles multiple dependencies and lots more goodies.
Maybe I do not understand the problem correctly because I inferred the problem from the solution you required. However, I think you try to abuse the Service Tracker for a task it was not intended to do.
Unfortunately, DS is not build into the framework as we should have done :-(
You could subclass ServiceTracker and add methods to provide direct access to the service types in which you are interested. For example, you could store the services in a typesafe heterogeneous container [1]. Then you would be able to call method on your ServiceTracker subclass which take the type of the service you are interested in and they could be easily looked up in the typesafe heterogeneous container.
[1] Effective Java, 2nd Ed., Item 29.