UWP: throw/raise not crashing the application, exception silently ignored - asynchronous

I've found that my application is silently ignoring exceptions and I don't understand why.
I'll explain first the case that works: you create a blank UWP app, then reference an external library (in particular this library is implemented in F#), this way:
namespace MyApp.Frontend.UWP
{
public sealed partial class MainPage
{
public MainPage()
{
this.InitializeComponent();
MyApp.Frontend.App.Throw(); // <- I insert this here
var app = new MyApp.Frontend.XF.App();
LoadApplication(app);
}
}
}
The implementation of the method Throw in the F# side is pretty simple:
namespace MyApp.Frontend.XF
open System
open Xamarin.Forms
type App() =
inherit Application(MainPage = MainPage())
static member Throw(): unit =
raise (new Exception ("foo"))
...
This works well: the app crashes as expected.
However, if in a Xamarin.Forms app I throw the exception from within an async workflow, later capturing it in order to send it to the main thread (to make sure the app crashes), the exception gets ignored! (its exception type AggregateException just gets printed to the output, nothing else). The code for this new version of Throw is as follows:
namespace MyApp.Frontend.XF
open System.Threading.Tasks
open Xamarin.Forms
type App() =
inherit Application(MainPage = MainPage())
static member private CaptureException<'T> (task: Task<'T>) =
let nextTaskDelegate (prevTask: Task<_>) =
Device.BeginInvokeOnMainThread(fun _ ->
raise prevTask.Exception
)
raise prevTask.Exception
task.ContinueWith(nextTaskDelegate, TaskContinuationOptions.OnlyOnFaulted)
|> ignore
static member Throw(): unit =
async {
raise (System.Exception("blah"))
}
|> Async.StartAsTask
|> App.CaptureException
...
This method of crashing the app (bringing it to the main thread with Device.BeginInvokeOnMainThread, and also throwing it in the current thread, just in case) works perfectly fine in other platforms (e.g. Xamarin.Android), but somehow it doesn't in UWP and I'm not sure why. How should I bring the exception to light?

Related

Cannot modify managed objects outside of a write transaction || Realm .Net SDK

Realms.Exception.RealmInvalidTransactionException: Cannot modify managed objects outside of a write transaction
I was using Ream .Net SDK 10.13 and recently updated it to 10.19.0. After, the update I am frequently getting the above error.
Here is an example of how I am using it in my Xamarin Forms project
public class TestClass: RealmObject
{
//Class properties are defined
// as per the realm docs, proper attributes
//are added for Kets and mapping
}
Now in some class/view models, where I have an instance of the TestClass injected through the constructor
public async Task<SomeUserDefinedType> SomeMethod(TestClass item){
var realm = Realms.Realm.GetInstance();
await realm.WriteAsync(async()=>{
// setting property of the TestClass
item.SomeProperty = "Some Value";
});
return <Instance of SomeUserDefinedType>;
}
The above method call gives an exception. Above code is modified as per the new version.
The below code was as per the older version which was working fine but it started giving the same exception after the update
public async Task<SomeUserDefinedType> SomeMethod(TestClass item){
await item.WriteAsync(async i =>{
// setting property of the TestClass
i.SomeProperty = "Some Value";
});
return <Instance of SomeUserDefinedType>;
}
I tried many ways to resolve this issue but none is working.
Any Suggestions/Help will be highly appreciated.

Re-instantiate a singleton with Prism in Xamarin Forms

How can I dispose and re-instantiate a singleton with Prism/DryIoC in Xamarin Forms?
I'm working with Azure Mobile Apps for offline data. Occasionally, I need to delete the local sqlite database and re-initialize it. Unfortunately the MobileServiceClient occasionally holds the db connection open and there's no method exposed to close it. The suggested solution (https://github.com/Azure/azure-mobile-apps-net-client/issues/379) is to dispose of MobileServiceClient. Only problem is that is registered with DryIoC as a singleton.
I'm not overly familiar with DryIoC, or Prism and Forms for that matter... But for the life of me, I can't see a way to do this.
I did cook up a pretty elaborate scheme that almost worked.
In my ViewModel method, when I needed the db freed up, I fired off an event -
_eventAggregator.GetEvent<RegisterDatabaseEvent>().Publish(false);
Then in App.xaml.cs, I wired up a listener and a handler like so -
_eventAggregator.GetEvent<RegisterDatabaseEvent>().Subscribe(OnRegisterDatabaseEventPublished);
private void OnRegisterDatabaseEventPublished()
{
Container.GetContainer().Unregister<IAppMobileClient>();
Container.GetContainer().Unregister<IMobileServiceClient>();
Container.GetContainer().Register<IMobileServiceClient, AppMobileClient>(new SingletonReuse());
Container.GetContainer().Register<IAppMobileClient, AppMobileClient>(new SingletonReuse());
_eventAggregator.GetEvent<RegisterDatabaseCompletedEvent>().Publish(register);
}
Lastly, back in the ViewModel constructor, I had a final listener that handled the event coming back from App.xaml and finished processing.
_eventAggregator.GetEvent<RegisterDatabaseCompletedEvent>().Subscribe(OnRegisterDatabaseCompletedEventPublished);
So the amazing thing is that this worked. The database was able to be deleted and all was good. But then I navigated to a different page and BOOM. DryIoC said it couldn't wire up the ViewModel for that page. I assume the unregister/register jacked up DryIoC for all injection... So how can I accomplish what needs to be done?
FINAL SOLUTION
Thanks so much to dadhi for taking the time to help. You are certainly a class act and I'm now considering using DryIoC elsewhere.
For anyone who stumbles on this, I'm posting the final solution below. I'll be as verbose as I can to avoid any confusion.
First, in my App.xaml.cs, I added a method for registering my database.
public void RegisterDatabase(IContainer container)
{
container.RegisterMany<AppMobileClient>(Reuse.Singleton,
setup: Setup.With(asResolutionCall: true),
ifAlreadyRegistered: IfAlreadyRegistered.Replace,
serviceTypeCondition: type =>
type == typeof(IMobileServiceClient) || type == typeof(IAppMobileClient));
}
I simply add a call to that method in RegisterTypes in place of registering the types in there directly.
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.GetContainer().Rules.WithoutEagerCachingSingletonForFasterAccess();
...
RegisterDatabase(containerRegistry.GetContainer());
...
}
Note also the added rule for eager caching, per dadhi.
Later on when I need to release the database in the ViewModel... I kick things off by resetting my local db variable and sending an event to App.xaml.cs
_client = null;
_eventAggregator.GetEvent<RegisterDatabaseEvent>().Publish(true);
In App.xaml.cs, I have subscribed to that event and tied it to the following method.
private void OnRegisterDatabaseEventPublished()
{
RegisterDatabase(Container.GetContainer());
_eventAggregator.GetEvent<RegisterDatabaseCompletedEvent>().Publish(register);
}
Here I just call RegisterMany again, exactly the same as I do when the app starts up. No need to unregister anything. With the setup and ifAlreadyRegistered arguments (thanks, dadhi!), DryIoC allows the object to be replaced. Then I raise an event back to the VM letting it know the database has been released.
Finally, back in the ViewModel, I'm listening for the completed event. The handler for that event updates the local copy of the object like so.
_client = ((PrismApplication)App.Current).Container.Resolve<IAppMobileClient>();
And then I can work with the new object, as needed. This is key. Without setting _client to null above and resolving it again here, I actually ended up with 2 copies of the object and calls to methods were being hit 2x.
Hope that helps someone else looking to release their Azure Mobile Apps database!
I am not sure how exactly XF handles these things.
But in DryIoc in order for service to be fully deleted or replaced it need to be registered with setup: Setup.With(asResolutionCall: true). Read here for more details: https://bitbucket.org/dadhi/dryioc/wiki/UnregisterAndResolutionCache#markdown-header-unregister-and-resolution-cache
Update
Here are two options and considerations that work in pure DryIoc and may not work XF. But it probably may help with solution.
public class Foo
{
public IBar Bar { get; private set; }
public Foo(IBar bar) { Bar = bar; }
}
public interface IBar {}
public class Bar : IBar {}
public class Bar2 : IBar { }
[Test]
public void Replace_singleton_dependency_with_asResolutionCall()
{
var c = new Container(rules => rules.WithoutEagerCachingSingletonForFasterAccess());
c.Register<Foo>();
//c.Register<Foo>(Reuse.Singleton); // !!! If the consumer of replaced dependency is singleton, it won't work
// cause the consumer singleton should be replaced too
c.Register<IBar, Bar>(Reuse.Singleton,
setup: Setup.With(asResolutionCall: true)); // required
var foo = c.Resolve<Foo>();
Assert.IsInstanceOf<Bar>(foo.Bar);
c.Register<IBar, Bar2>(Reuse.Singleton,
setup: Setup.With(asResolutionCall: true), // required
ifAlreadyRegistered: IfAlreadyRegistered.Replace); // required
var foo2 = c.Resolve<Foo>();
Assert.IsInstanceOf<Bar2>(foo2.Bar);
}
[Test]
public void Replace_singleton_dependency_with_UseInstance()
{
var c = new Container();
c.Register<Foo>();
//c.Register<Foo>(Reuse.Singleton); // !!! If the consumer of replaced dependency is singleton, it won't work
// cause the consumer singleton should be replaced too
c.UseInstance<IBar>(new Bar());
var foo = c.Resolve<Foo>();
Assert.IsInstanceOf<Bar>(foo.Bar);
c.UseInstance<IBar>(new Bar2());
var foo2 = c.Resolve<Foo>();
Assert.IsInstanceOf<Bar2>(foo2.Bar);
}

How to load Spring Application Context in Non Main method

I want to load Spring initial context inside a AWS lambda handler class. This class is the starting point of my application. I did it in the below way.
#SpringBootApplication
public class LambdaFunctionHandler implements RequestHandler<KinesisEvent, Object> {
#Override
public Object handleRequest(KinesisEvent input, Context context) {
AnnotationConfigApplicationContext appContext = new AnnotationConfigApplicationContext(LambdaFunctionHandler.class);
LambdaFunctionHandler lambdaHandlerBean = appContext.getBean(LambdaFunctionHandler.class);
// some business logic call
return null;
}
}
This is working fine but I'm getting warning on appContext that it should be closed as it is resource leak. this can be fixed by calling appContext.close() but my doubt is whether this way of initializing Spring application context in a non main method is correct ? Most recommended way to do in a main method is like below
SpringApplication app = new SpringApplication(LambdaFunctionHandler.class);
ConfigurableApplicationContext context = app.run(args);
LambdaFunctionHandler lambdaFunctionHandler =
context.getBean(LambdaFunctionHandler.class);
But I don't have the value to replace the args in my case. can anyone suggest the right way of doing this
You can simple class with main method for #SpringBootApplication and
use CommandLineRunner for loading AWS lambda handler. Just implement the run to load the bean
https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/CommandLineRunner.html

How do I process a request for a web page of a pre-compiled web application which is referenced in another web application?

Our company would like to give a pre-compiled version of our web application to a 3rd party so they can add their own pages and modules to it.
In trying to accomplish this, I've so far done the following:
Compiled our main web app as a Web Deployment Project
Created a POC web app which references the DLL resulting from step 1 above.
I then added the following static method to our main web app, which should hopefully process requests to its pre-compiled aspx pages:
public static bool TryProcessRequest(HttpContext context)
{
string rawUrl = context.Request.RawUrl;
int aspxIdx = rawUrl.IndexOf(".aspx");
if (aspxIdx > 0)
{
string aspxPagePath = rawUrl.Substring(0, aspxIdx + 5);
string aspxPageClassName = aspxPagePath.Substring(1).Replace('/','_').Replace(".aspx","");
Assembly website = Assembly.GetAssembly(typeof(MCLLogin));
Type pageClass = website.GetType(aspxPageClassName);
ConstructorInfo ctor = pageClass.GetConstructor(new Type[] { });
IHttpHandler pageObj = (IHttpHandler)ctor.Invoke(new object[] { });
context.Server.Execute(pageObj, context.Response.Output, false);
//alternative: invoking the page's ProcessRequest method - same results
//System.Reflection.MethodInfo method = pageClass.GetMethod("ProcessRequest");
//method.Invoke(pageObj, new object[] { context });
return true;
}
return false; //not handled
}
I am then calling this method in the ProcessRequest() method of a HttpHandler of the POC web app whenever I want our main web app to handle the request. This code indeed successfully instantiates a page of the correct class and starts to process the request.
The problem:
Code in my Page_PreLoad handler throws an exception because Page.Form is null. I've also found out the Page.Controls collection is empty.
What am I doing wrong? Should I go down a different path to achieve this?

Can I create custom global methods in my Android Application class?

I currently have an app that has many activities and needs to have a way of maintaining state between these activities.
I use the Application class to do this, declaring my global variables and using getters and setters to interact with my activities.
I was hoping to place a few custom methods in there, so that when I want to do a common task like, for instance, display an error message, I can declare the method in my application class and call it from any activity that uses it
EscarApplication application = (EscarApplication) this.getApplication();
EscarApplication being the name of my application class above.
I have tried to include this method in my application class:
public void showError(String title, String message) {
Log.i("Application level",message);
this.alertDialog.setTitle(title);
alertDialog.setMessage(message);
alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int which) {
return;
}
});
alertDialog.show();
}
In the hope that I can call this method from activity without having to redeclare it, but when I call it using something like below I get an null pointer exception:
Visit.this.application.showError("Update error", "An error has occurred while trying to communicate with the server");
Visit being the name of my current activity above.
Should this work, or can I only use getters and setters to change global vars in an Application Class.
Stack Trace:
java.lang.RuntimeException: Unable to start activity ComponentInfo{escar.beedge/escar.beedge.HomeScreen}: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2401)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2417)
at android.app.ActivityThread.access$2100(ActivityThread.java:116)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4203)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549)
at dalvik.system.NativeStart.main(Native Method)
ERROR/AndroidRuntime(375): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
at android.view.ViewRoot.setView(ViewRoot.java:460)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
at android.app.Dialog.show(Dialog.java:238)
at escar.beedge.EscarApplication.showError(EscarApplication.java:98)
at escar.beedge.HomeScreen.onCreate(HomeScreen.java:30)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364)
The dialog is declared as such in the application class:
AlertDialog alertDialog;
Created in that same class:
alertDialog = new AlertDialog.Builder(this).create();
and the method to call it in that class is as follows:
public void showError(String title, String message) {
alertDialog.setTitle(title);
alertDialog.setMessage(message);
alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int which) {
return;
}
});
alertDialog.show();
}
And finally, it is called from an activity like so:
EscarApplication application;
application = (EscarApplication) this.getApplication();
application.showError("test", "display this message");
If you need to maintain state between activities, then use a service. Anything else is a hack
Someone correct me if Im wrong, but an Application class wont be able to execute view related objects as they need to be bound to a view which needs to be bound to an activity.
In that sense, you could use your Application class to implement a static method that customises the dialog
public static void setDialog(String title, String message,AlertDialog alertDialog){
alertDialog.setTitle(title);
alertDialog.setMessage(message);
alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int which) {
return;
}
});
}
but you would have to create the dialog and call the show method on the activities themselves (actually maybe even the button to be set in the dialog would need to be created on the activity)
Another option could be to implement a class that extends the AlertDialog class and whose button is pre-set to the behavior you want.
You could use the Singleton pattern.
I'm looking to achieve something similar to you.
I haven't found an official answer, but it looks like you shouldn't be using the application context for Toast and Dialogs. Instead, try using the context of an Activity like so :
// From inside your activity
Dialog dialog = new Dialog(this);
instead of this:
// From inside your Application instance
Dialog dialog = new Dialog(getApplicationContext());
Read this :
Android: ProgressDialog.show() crashes with getApplicationContext

Resources