InvalidCastException in OutArgument<T>.Set() - workflow-foundation-4

Strange exception, this was working fine before.
System.InvalidCastException: Cannot convert object 'Waiting' to type 'System.Activities.Statements.Pick+PickState'.
at System.Runtime.TypeHelper.Convert[T](Object source)
at System.Activities.Location`1.set_ValueCore(Object value)
at System.Activities.ActivityContext.SetValueCore[T](LocationReference locationReference, T value)
at System.Activities.ActivityContext.SetValue[T](OutArgument`1 argument, T value)
at System.Activities.OutArgument`1.Set(ActivityContext context, T value)
at MyApplication.WaitForStatusChange.OnBookmarkResumed(NativeActivityContext context, Bookmark bookmark, Object value)
at System.Activities.Runtime.BookmarkCallbackWrapper.Invoke(NativeActivityContext context, Bookmark bookmark, Object value)
at System.Activities.Runtime.BookmarkWorkItem.Execute(ActivityExecutor executor, BookmarkManager bookmarkManager)
MyApplication.WaitForStatusChange is a custom NativeActivity, the error occurs when the workflow is resumed on the bookmark for this activity, whith an enum for bookmar argument.
The WaitForStatusChange activity is placed inside a Pick activity (with another NativeActivity on the other branch)
Activity code
public class WaitForPartnerIntegrationStatusChange : NativeActivity
{
public OutArgument<PartnerSoftwareIntegrationStatus> Status { get; set; }
protected override void Execute(NativeActivityContext context)
{
context.CreateBookmark(DocumentStatusChangeWatcher.DocumentPartnerSoftwareIntegrationStatusChangedBookmark, OnBookmarkResumed);
}
private void OnBookmarkResumed(NativeActivityContext context, Bookmark bookmark, object value)
{
if (value is PartnerSoftwareIntegrationStatus)
{
Status.Set(context, (PartnerSoftwareIntegrationStatus)value);
}
}
protected override bool CanInduceIdle
{
get { return true; }
}
}

You see these kinds of strange exceptions often when you make a change to a workflow definition and try to resume a persisted workflow.
Basically you can't make any changes to running workflows.

Related

.NET MAUI Overriding Window Class Fatal Exception

while overriding Window, I came across a fatal exception:
System.InvalidOperationException: MauiContext is null
I was trying to ovveride Window Class so that everytime the app is open or closed I use messenger to notify the base class to logout the user and request verification to login back.
This is my class where I inherit from Window. And in App.xaml.cs I ovveride it and returning MyWindow using as a parameter MainPage.
I think that when App is in the background and then opened again there is an issue. So guidance on how to handle this exception?
public class Message : ValueChangedMessage<string>
{
public Message(string message) : base(message)
{
}
}
public class MyWindow : Window
{
public MyWindow() : base()
{
}
public MyWindow(Page page) : base(page)
{
}
protected override void OnStopped()
{
WeakReferenceMessenger.Default.Send(new Message("Stopped"));
}
protected override void OnResumed()
{
WeakReferenceMessenger.Default.Send(new Message("Resumed"));
}
protected override MyWindow CreateWindow(IActivationState activationState)
{
return new MyWindow(MainPage);
}
Fatal Exception: android.runtime.JavaProxyThrowable:
System.InvalidOperationException: MauiContext is null.
at Microsoft.Maui.Controls.Window.get_MauiContext()
at Microsoft.Maui.Controls.Platform.AlertManager.Subscribe(Window window)
at Microsoft.Maui.Controls.Platform.AlertManager.Subscribe()
at Microsoft.Maui.Controls.Window.<>c__DisplayClass206_0.g__OnPageHandlerChanged|0(Object sender, EventArgs e)
at Microsoft.Maui.Controls.Window.OnPageChanged(BindableObject bindable, Object oldValue, Object newValue)
at Microsoft.Maui.Controls.BindableObject.SetValueActual(BindableProperty property, BindablePropertyContext context, Object value, Boolean currentlyApplying, SetValueFlags attributes, Boolean silent)
at Microsoft.Maui.Controls.BindableObject.SetValueCore(BindableProperty property, Object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes)
at Microsoft.Maui.Controls.BindableObject.SetValue(BindableProperty property, Object value, Boolean fromStyle, Boolean checkAccess)
at Microsoft.Maui.Controls.BindableObject.SetValue(BindableProperty property, Object value)
at Microsoft.Maui.Controls.Window.set_Page(Page value)
at Microsoft.Maui.Controls.Window..ctor(Page page)
at name.ViewModels.MyWindow..ctor(Page page)
at name.App.CreateWindow(IActivationState activationState)
at Microsoft.Maui.Controls.Application.Microsoft.Maui.IApplication.CreateWindow(IActivationState activationState)
at Microsoft.Maui.Platform.ApplicationExtensions.CreatePlatformWindow(Activity activity, IApplication application, Bundle savedInstanceState)
at Microsoft.Maui.MauiAppCompatActivity.OnCreate(Bundle savedInstanceState)
at name.MainActivity.OnCreate(Bundle savedInstanceState)
at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_(IntPtr , IntPtr , IntPtr )
at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PPL_V(_JniMarshal_PPL_V , IntPtr , IntPtr , IntPtr )
at crc64790243dcc0ae3d15.MainActivity.n_onCreate(MainActivity.java)
at crc64790243dcc0ae3d15.MainActivity.onCreate(MainActivity.java:40)
at android.app.Activity.performCreate(Activity.java:7994)
at android.app.Activity.performCreate(Activity.java:7978)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1534)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3439)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3632)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2067)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7701)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)`

Axon Event Deserialization Issue?

I have an eventsourced aggregate and use Jackson as eventserializer. Now, when I apply an event A in a command handler, I can see it's event sourcing handler called immediately, with all the expected event fields (event is the same instance as I created in the command handler). One of the fields in the event is the aggregateId.
However, when the (read side) event handler is called, the event object is a different instance, but the field I filled with the aggregateId has a wrong value! Debugging shows it is filled with the event identifier. When I set a breakpoint in the event constructors, I see it called and a wrong field value being set.
When I switch to XStream as event serializer, everything is fine. No additional even instantion is done, and the event created in the command handler is the same as being processing in the eventhandler.
What is going on here?
After an hour of debugging, I found my own mistake ;-). As the Axon docs say, when using Jackson as EventSerializer, you have to stick to the Jackson conventions, which I didn't. All my aggregate id's are subclasses of this AggregateId:
public abstract class AggregateId {
private final UUID id;
public AggregateId() {
this(UUID.randomUUID());
}
public AggregateId(UUID id) {
this.id = id;
}
public String toString() {
return id.toString();
}
public UUID getValue() {
return id;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AggregateId that = (AggregateId) o;
return id.equals(that.id);
}
#Override
public int hashCode() {
return Objects.hash(id);
}
}
Having a private field id with no getter and a getValue that returns that id is the perfect way to fool Jackson (and myself).
After renaming id to value all tests are green.

Glide doesn't fire any result and stuck loading

I'm using glide to load images. But When loading images in activities, Glide simply will not load an image. But also doesnt run results (Don't run failed or success). But when I use it in Fragment and recyclerview It works.
My code:
Glide.with(CommentActivity.this).load(imageurl).dontAnimate().listener(new RequestListener<Drawable>() {
#Override
public boolean onLoadFailed(#Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
imageurl="";
alertDialog.dismiss();
GenelUtil.ToastLong(getApplicationContext(),getString(R.string.failedtoloadimage));
return false;
}
#Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
imageType="url";
imagelayout.setVisibility(View.VISIBLE);
alertDialog.dismiss();
return false;
}
}).into(commentimage);
How to fix this?

WF 4 OnUnhandledException not hit

I've created a custom activity which contains as a Body another Activity.
[Browsable(false)]
public Activity Body { get; set; }
protected override void Execute(NativeActivityContext context)
{
ActivityInstance res = context.ScheduleActivity(Body, new CompletionCallback(OnExecuteComplete), OnFaulted);
}
private void OnFaulted(NativeActivityFaultContext faultContext, Exception propagatedException, ActivityInstance propagatedFrom)
{
throw new Exception(propagatedException.Message);
}
When an exception is thrown during the execution of the Body, ma handler for the OnFaulted is hit.
My execution starts with a call to static method Run of the WorkflowApplication class. My WorkflowApplication instance has a handler associated for the OnUnhandledException event.
instance.OnUnhandledException +=
delegate(WorkflowApplicationUnhandledExceptionEventArgs args)
{
Console.WriteLine(args.ExceptionSource);
waitEvent.Set();
return UnhandledExceptionAction.Cancel;
};
But regardless of what happens when the Activity hosted in the Body is executed, i never reach the handler defined above. I thought that if i throw an exception from the OnFaulted, i will be able to redirect the flow to the OnUnhandledException but i was wrong. Any ideas ?
I need this in order to centralize my errors, check them and display messages accordingly. Also i need a way to stop the execution and so on and i don't want to define handlers all over the application. Is there any way to accomplish this ?
As Will suggested, i will post what i did to handle my scenario.
Basically, in my custom activity i have hosted an Assign :
[Browsable(false)]
public Activity Body { get; set; }
Activity System.Activities.Presentation.IActivityTemplateFactory.Create(System.Windows.DependencyObject target)
{
return new Assignment()
{
Body = new Assign() { DisplayName = "" }
};
}
I've added this code to my Execute method :
ActivityInstance res = context.ScheduleActivity(Body, new CompletionCallback(OnExecuteComplete), OnFaulted);
I was trying to run this Assignment by giving an array a negative value as index and and an exception was thrown. This, somehow ended my execution but no handler for the events of my WorkflowApplication instance were hit.
Here is the method given as a callback when executing the body ( in our case the Assign activity ) :
private void OnFaulted(NativeActivityFaultContext faultContext, Exception propagatedException, ActivityInstance propagatedFrom)
{
faultContext.HandleFault();
CommunicationExtension ce = faultContext.GetExtension<CommunicationExtension>();
ITextExpression toTextExpression = (propagatedFrom.Activity as Assign).To.Expression as ITextExpression;
string valueTextExpression = string.Empty;
if ((propagatedFrom.Activity as Assign).Value != null)
{
if ((propagatedFrom.Activity as Assign).Value.Expression != null)
valueTextExpression = (propagatedFrom.Activity as Assign).Value.Expression.ToString();
}
if (ce != null)
{
ce.AddData(string.Format("{0} found on Assignment definition [{1} = {2}]", propagatedException.Message, toTextExpression.ExpressionText, valueTextExpression));
}
}
The trick was to call :
faultContext.HandleFault();
and use CommunicationExtension to allow me to to display the erros in the GUI.
The code for this class is trivial :
public class CommunicationExtension
{
public List<string> Messages { get; set; }
public CommunicationExtension()
{
Messages = new List<string>();
}
public void AddData(string message)
{
if (string.IsNullOrEmpty(message))
return;
Messages.Add(message);
}
}
Use this to add the extension:
CommunicationExtension ce = new CommunicationExtension();
instance.Extensions.Add(ce);
where instance is my WorkflowApplication instance.
I understood that for each instance of the workflow application we have one instance of its extension class. So i can send messages like this from all my custom activities in order to display their status.
I hope this scenario can help other people too.

.NET Fault tolerant StateServer

we use a StateServer for handling Session for the known benefits (web farm, IIS recycling).
However I am trying to figure out how to make this fault tolerant. Nothing we store in the Session is critical, it is just used for performance. So if the StateServer is not available we are happy to reload from disk.
However there appears to be no way of detecting if the StateServer is online or not, so the following code all runs fine even if the StateServer is down
try
{
//It is not NULL as it has been configured
if (HttpContext.Current.Session != null)
Session["Test"] = "value";
}
// No exception is thrown
catch (Exception)
{
throw new Exception();
}
Now it makes sense to me that no exception is thrown. The Session handling would not be very performant if it had to check the status on every write. So I am guessing what happens is that it writes all the Session vaiables when the Response is written.
There lies the problem, when it tries to write the Session it fails with a 500 error and I do not know anyway to intercept this error and handle it.
Unable to make the session state request to the session state server.
Please ensure that the ASP.NET State service is started and that the
client and server ports are the same.
What I would like to happen is that the write just fails silently (or logs an error) and clients are not impacted. As it is write now the entire site goes down due to this single point of failure.
Any ideas - am I missing something obvious?
well, it can be hard. Asp.net uses session tightly, so if session storage fails, it asp.net will also fails during initialization of session module. You can write own session state provider, that will wrap existing one, and in case of fail it will return empty session items, but it can be hard to use it, because session behavior can be unpredictable.
You can look into built in SQL session state provider, that has failover in case if your SQL server has replication.
UPDATE1
Here is example of wrapper for default session providers
public class SessionProviderWrapper : SessionStateStoreProviderBase
{
private readonly SessionStateStoreProviderBase _provider;
private static Func<SessionStateStoreProviderBase> _createProvider;
static SessionProvider()
{
_createProvider = InitializerProvider();
}
private static Func<SessionStateStoreProviderBase> InitializerProvider()
{
if (_createProvider != null)
return _createProvider;
var sessionType = "stateserver"; // you can switch to another session provider
Type type;
switch (sessionType)
{
case "inproc":
type = Type.GetType("System.Web.SessionState.InProcSessionStateStore, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
break;
case "sql":
type = Type.GetType("System.Web.SessionState.SqlSessionStateStore, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
break;
case "stateserver":
type = Type.GetType("System.Web.SessionState.OutOfProcSessionStateStore, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
break;
default:
throw new ConfigurationErrorsException("Unknow session type: " + sessionType);
}
if (type == null)
{
throw new InvalidOperationException("Failed to find session provider for " + sessionType);
}
_createProvider = GenerateConstructorCall(type);
return _createProvider;
}
private static Func<SessionStateStoreProviderBase> GenerateConstructorCall(Type type)
{
// we are searching for public constructor
var constructor = type.GetConstructors().FirstOrDefault(c => c.GetParameters().Length == 0);
if (constructor == null)
{
// otherwise for internal. SQL session provider has internal constructor, but we don't care
constructor = type.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).FirstOrDefault(c => c.GetParameters().Length == 0);
}
var node = Expression.New(constructor);
var lambda = Expression.Lambda<Func<SessionStateStoreProviderBase>>(node, null);
var func = lambda.Compile();
return func;
}
public SessionProvider()
{
var createProvider = InitializerProvider();
_provider = createProvider();
}
public override void Initialize(string name, NameValueCollection config)
{
_provider.Initialize(name, config);
}
public override string Name
{
get { return _provider.Name; }
}
public override string Description
{
get { return _provider.Description; }
}
public override void Dispose()
{
_provider.Dispose();
}
public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback)
{
return _provider.SetItemExpireCallback(expireCallback);
}
public override void InitializeRequest(HttpContext context)
{
_provider.InitializeRequest(context);
}
public override SessionStateStoreData GetItem(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId,
out SessionStateActions actions)
{
try
{
return _provider.GetItem(context, id, out locked, out lockAge, out lockId, out actions);
}
catch (Exception ex)
{
locked = false;
lockAge = TimeSpan.Zero;
lockId = null;
actions = SessionStateActions.None;
// log ex
return new SessionStateStoreData(new SessionStateItemCollection(), new HttpStaticObjectsCollection(), 10);
}
}
public override SessionStateStoreData GetItemExclusive(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId,
out SessionStateActions actions)
{
return _provider.GetItemExclusive(context, id, out locked, out lockAge, out lockId, out actions);
}
public override void ReleaseItemExclusive(HttpContext context, string id, object lockId)
{
_provider.ReleaseItemExclusive(context, id, lockId);
}
public override void SetAndReleaseItemExclusive(HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem)
{
_provider.SetAndReleaseItemExclusive(context, id, item, lockId, newItem);
}
public override void RemoveItem(HttpContext context, string id, object lockId, SessionStateStoreData item)
{
_provider.RemoveItem(context, id, lockId, item);
}
public override void ResetItemTimeout(HttpContext context, string id)
{
_provider.ResetItemTimeout(context, id);
}
public override SessionStateStoreData CreateNewStoreData(HttpContext context, int timeout)
{
return _provider.CreateNewStoreData(context, timeout);
}
public override void CreateUninitializedItem(HttpContext context, string id, int timeout)
{
_provider.CreateUninitializedItem(context, id, timeout);
}
public override void EndRequest(HttpContext context)
{
_provider.EndRequest(context);
}
}
Basically you can make try\catch on each method like in GetItem method, and in case of error, you can return empty session object. If it fails in try\catch application still will be alive. But performance will be decreased as for each request it will throw a couple of exceptions on Get\Release, that will be handled in catch section. But anyway these exceptions will decrease performance a bit
I would like to accept tgolisch answer as a solution that works for me.
In Global.asax we will look for the missing StateServer error in the Application_Error event
If we find it we will use Server.ClearError() and log the error
We will also use this to log the error and possibly send out an alert
Thanks all!

Resources