Why documentt.data.getValue() gives empty string? [duplicate] - kotlin

A custom object that takes a parameter of (DocumentSnapShot documentsnapShot). also is an inner object from Firebase that retrieves a snapshot and set the values to my custom model also have its argument (DocumentSnapShot documentsnapShot). However, I wish to get the data from Firebase and pass it to my custom argument because mine takes multiple data not only Firebase. And it's not possible to iterate Firestore without an override.
Here's the code:
public UserSettings getUserSettings(DocumentSnapshot documentSnapshot){
Log.d(TAG, "getUserSettings: retrieving user account settings from firestore");
DocumentReference mSettings = mFirebaseFirestore.collection("user_account_settings").document(userID);
mSettings.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
UserAccountSettings settings = documentSnapshot.toObject(UserAccountSettings.class);
settings.setDisplay_name(documentSnapshot.getString("display_name"));
settings.setUsername(documentSnapshot.getString("username"));
settings.setWebsite(documentSnapshot.getString("website"));
settings.setProfile_photo(documentSnapshot.getString("profile_photo"));
settings.setPosts(documentSnapshot.getLong("posts"));
settings.setFollowers(documentSnapshot.getLong("followers"));
settings.setFollowing(documentSnapshot.getLong("following"));
}
});
}

You cannot return something now that hasn't been loaded yet. Firestore loads data asynchronously, since it may take some time for this. Depending on your connection speed and the state, it may take from a few hundred milliseconds to a few seconds before that data is available. If you want to pass settings object to another method, just call that method inside onSuccess() method and pass that object as an argument. So a quick fix would be this:
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
UserAccountSettings settings = documentSnapshot.toObject(UserAccountSettings.class);
yourMethod(settings);
}
One more thing to mention is that you don't need to set the those values to object that already have them. You are already getting the data from the database as an object.
So remember, onSuccess() method has an asynchronous behaviour, which means that is called even before you are getting the data from your database. If you want to use the settings object outside that method, you need to create your own callback. To achieve this, first you need to create an interface like this:
public interface MyCallback {
void onCallback(UserAccountSettings settings);
}
Then you need to create a method that is actually getting the data from the database. This method should look like this:
public void readData(MyCallback myCallback) {
DocumentReference mSettings = mFirebaseFirestore.collection("user_account_settings").document(userID);
mSettings.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
UserAccountSettings settings = documentSnapshot.toObject(UserAccountSettings.class);
myCallback.onCallback(settings);
}
});
}
In the end just simply call readData() method and pass an instance of the MyCallback interface as an argument wherever you need it like this:
readData(new MyCallback() {
#Override
public void onCallback(UserAccountSettings settings) {
Log.d("TAG", settings.getDisplay_name());
}
});
This is the only way in which you can use that object of UserAccountSettings class outside onSuccess() method. For more informations, you can take also a look at this video.

Use LiveData as return type and observe the changes of it's value to execute desired operation.
private MutableLiveData<UserAccountSettings> userSettingsMutableLiveData = new MutableLiveData<>();
public MutableLiveData<UserAccountSettings> getUserSettings(DocumentSnapshot documentSnapshot){
DocumentReference mSettings = mFirebaseFirestore.collection("user_account_settings").document(userID);
mSettings.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
UserAccountSettings settings = documentSnapshot.toObject(UserAccountSettings.class);
settings.setDisplay_name(documentSnapshot.getString("display_name"));
settings.setUsername(documentSnapshot.getString("username"));
settings.setWebsite(documentSnapshot.getString("website"));
settings.setProfile_photo(documentSnapshot.getString("profile_photo"));
settings.setPosts(documentSnapshot.getLong("posts"));
settings.setFollowers(documentSnapshot.getLong("followers"));
settings.setFollowing(documentSnapshot.getLong("following"));
userSettingsMutableLiveData.setValue(settings);
}
});
return userSettingsMutableLiveData;
}
Then from your Activity/Fragment observe the LiveData and inside onChanged do your desired operation.
getUserSettings().observe(this, new Observer<UserAccountSettings>() {
#Override
public void onChanged(UserAccountSettings userAccountSettings) {
//here, do whatever you want on `userAccountSettings`
}
});

Related

Hangfire - DisableConcurrentExecution - Prevent concurrent execution if same value passed in method parameter

Hangfire DisableConcurrentExecution attribute not working as expected.
I have one method and that can be called with different Id. I want to prevent concurrent execution of method if same Id is passed.
string jobName= $"{Id} - Entry Job";
_recurringJobManager.AddOrUpdate<EntryJob>(jobName, j => j.RunAsync(Id, Null), "0 2 * * *");
My EntryJob interface having RunAsync method.
public class EntryJob: IJob
{
[DisableConcurrentExecution(3600)] <-- Tried here
public async Task RunAsync(int Id, SomeObj obj)
{
//Some coe
}
}
And interface look like this
[DisableConcurrentExecution(3600)] <-- Tried here
public interface IJob
{
[DisableConcurrentExecution(3600)] <-- Tried here
Task RunAsync(int Id, SomeObj obj);
}
Now I want to prevent RunAsync method to call multiple times if Id is same. I have tried to put DisableConcurrentExecution on top of the RunAsync method at both location inside interface declaration and also from where Interface is implemented.
But it seems like not working for me. Is there any way to prevent concurrency based on Id?
The existing implementation of DisableConcurrentExecution does not support this. It will prevent concurrent executions of the method with any args. It would be fairly simple to add support in. Note below is untested pseudo-code:
public class DisableConcurrentExecutionWithArgAttribute : JobFilterAttribute, IServerFilter
{
private readonly int _timeoutInSeconds;
private readonly int _argPos;
// add additional param to pass in which method arg you want to use for
// deduping jobs
public DisableConcurrentExecutionAttribute(int timeoutInSeconds, int argPos)
{
if (timeoutInSeconds < 0) throw new ArgumentException("Timeout argument value should be greater that zero.");
_timeoutInSeconds = timeoutInSeconds;
_argPos = argPos;
}
public void OnPerforming(PerformingContext filterContext)
{
var resource = GetResource(filterContext.BackgroundJob.Job);
var timeout = TimeSpan.FromSeconds(_timeoutInSeconds);
var distributedLock = filterContext.Connection.AcquireDistributedLock(resource, timeout);
filterContext.Items["DistributedLock"] = distributedLock;
}
public void OnPerformed(PerformedContext filterContext)
{
if (!filterContext.Items.ContainsKey("DistributedLock"))
{
throw new InvalidOperationException("Can not release a distributed lock: it was not acquired.");
}
var distributedLock = (IDisposable)filterContext.Items["DistributedLock"];
distributedLock.Dispose();
}
private static string GetResource(Job job)
{
// adjust locked resource to include the argument to make it unique
// for a given ID
return $"{job.Type.ToGenericTypeString()}.{job.Method.Name}.{job.Args[_argPos].ToString()}";
}
}

Can I change my response data in OutputFormatter in ASP.NET Core 3.1

I'm trying to create a simple feature to make the first action act like the second one.
public IActionResult GetMessage()
{
return "message";
}
public IActionResult GetMessageDataModel()
{
return new MessageDataModel("message");
}
First idea came to my mind was to extend SystemTextJsonOutputFormater, and wrap context.Object with my data model in WriteResponseBodyAsync, but the action is marked sealed.
Then I tried to override WriteAsync but context.Object doesn't have protected setter, either.
Is there anyway I can achieve this by manipulating OutputFormatter?
Or I have another option instead of a custom OutputFormatter?
for some reason they prefer every response in a same format like {"return":"some message I write.","code":1}, hence I want this feature to achieve this instead of creating MessageDataModel every time.
Based on your description and requirement, it seems that you'd like to generate unified-format data globally instead of achieving it in each action's code logic. To achieve it, you can try to implement it in action filter, like below.
public class MyCustomFilter : Attribute, IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
// implement code logic here
// based on your actual scenario
// get original message
// generate new instance of MessageDataModel
//example:
var mes = context.Result as JsonResult;
var model = new MessageDataModel
{
Code = 1,
Return = mes.Value.ToString()
};
context.Result = new JsonResult(model);
}
Apply it on specific action(s)
[MyCustomFilter]
public IActionResult GetMessage()
{
return Json("message");
}

Struggling with passing messages through MVVM Light

I have two view and their corresponding ViewModels and i want to send text from one view to another using MVVM Light as follows
in first viewmodel i am calling the following method
public void NavigatePage()
{
string temp = "temp value";
Messenger.Default.Send("temp");
Frame frame = Window.Current.Content as Frame;
if (frame != null) frame.Navigate(typeof(MyPage), temp);
}
while in page 2 view model i am having the following code
public MyViewModel()
{
Messenger.Default.Register<string>(this, MessageReceived);
}
private string test;
public string Test
{
get { return test; }
set { test = value; RaisePropertyChanged("Test");}
}
private void MessageReceived(string message)
{
Test = message;
}
when i debug my code the ctor of this viewmodel is getting called but the MessageReceived is not getting called hence property Test is never getting set, I am missing something, please help
Is the SecondViewModel actually created before you send the message? You can specify this in the ViewModelLocator class.
In the locator you have to register your viewmodel and CREATE it when the applications starts.
Like this:
SimpleIoc.Default.Register<SecondViewModel>(true);
With the true parameter the SecondViewModel will be created when the application is started! :)

How does Undo work?

How does undo work? Does it copy all the managed objects every time any of the values change? Or does it only copy the actual changes together with an information which objects were affected? Is that heavy or lightweight?
The 'undo' mechanism for pretty much any language that supports Object-Oriented constructs uses the Memento Design Pattern to make it happen.
Here's a rough implementation to get you thinking. This handles your stack of undoable operations. (It doesn't handle redo, but that's easy to support by replacing the stack with a list and keeping track of the current item.)
public class Undoable {
public static void Do(Action do, Action undo) {
do();
sUndoStack.Push(new Undoable(do, undo));
}
public static void Undo() {
sUndoStack.Pop().mUndoCallback();
}
private Undoable(Action doCallback, undoCallback) {
mDoCallback = doCallback;
mUndoCallback = undoCallback;
}
private Action mDoCallback, mUndoCallback;
// note: using a global stack here is lame, but works for demo purposes
private static readonly Stack<Undoable> sUndoStack = new Stack<Undoable>();
}
To use this, let's say the user can change a value in some object like this:
public class Foo {
public string Bar {
get { return mBar; }
set {
if (mBar != value) {
mBar = value;
}
}
}
private string mBar;
}
To make that operation undoable, we just change the setter to:
set {
if (mBar != value) {
string oldValue = mBar;
Undoable.Do(() => mBar = value,
() => mBar = oldValue);
}
}
Now, if you call Undoable.Undo() from anywhere in the application, your instance of Foo will restore the previous value of Bar. If Foo also raises an event when Bar changes (not shown here), the UI will also properly refresh on undo too.

Is it possible to set a property value of object during Expect.Call in RhinoMocks?

I have a method that should only be called when a property of a specific object is set to false. This is its initial value. After the first call, the property is set to true, ensuring that the call is only ever made once.
However, when I mock the class that performs this change, the mock object does not change the property of the underlying object.
Is there a way to force a change of a property on an object is response to an Expectation being met?
Something along the lines of...
Expect.Call(mockedObject.TestMethod(underlyingObject)).NowDoThis(delegate() { underlyingObject.Processed = true; });
Yes,
instead of your NowDoThis() call try Do()
Finally home so I can try out some code.
The trick is to cast the anonymous delegate to type Action that derrives from System.Delegate (type MethodInvoker should also work but that type is only available in System.Windows.Forms)
Here's the code. I'm more comfortable with the rhino mocks AAA syntax. Let me know if I have to convert it to Expect.Call syntax. I'm also using xunit.net, [Fact] just means [Test]
public interface Thingie
{
bool Flag { get; set; }
void DoSomething();
}
[Fact]
public void Test()
{
var thingie = MockRepository.GenerateStub<Thingie>();
thingie.Stub(x => x.DoSomething()).Do((Action) delegate { thingie.Flag = true; });
Assert.False(thingie.Flag);
thingie.DoSomething();
Assert.True(thingie.Flag);
}
Assuming mockedObject is, in fact, a mock object, you can simply set a return value for your property after the test method has been called:
bool isProcessed = false;
Expect.Call(mockedObject.TestMethod(underlyingObject))
.Do(new Action(() => isProcessed = true));
SetupResult.For(mockedObject.Processed).Return(isProcessed);