WF4: Bookmark with NonBlocking option - workflow-foundation-4

Has anyone used CreateBookmark() with BookmarkOptions.NonBlocking?
I'm trying to use it with MultipleResume option but seems I cannot even resume.
Bookmark activity:
public InArgument<string> BookmarkName { get; set; }
public InArgument<BookmarkOptions> BookmarkOptions { get; set; }
protected override void Execute(NativeActivityContext context)
{
var options = BookmarkOptions.Get(context);
context.CreateBookmark(BookmarkName.Get(context),
ReadCompleteCallback,options);
}
Test Code:
[TestMethod]
public void TestMethod1()
{
InitWorkflow();
wfat = WorkflowApplicationTest.Create(sm);
wfat.TestActivity();
Assert.IsTrue(wfat.WaitForIdleEvent());
var res = wfat.TestWorkflowApplication.ResumeBookmark("First", "data");
Assert.IsTrue(res == BookmarkResumptionResult.Success, "Resumption fail with result:" + res);
Assert.IsTrue(wfat.Bookmarks.Contains("First"), "No first bkmk");
}
private void InitWorkflow()
{
sm = new StateMachine()
{
States =
{ //First state with non blocking bookmark
new State(){
DisplayName = "First",Entry = new BookmarkActivity(){BookmarkName = "First",BookmarkOptions =
BookmarkOptions.NonBlocking | BookmarkOptions.MultipleResume},
Transitions =
{
new Transition(){ }
}
}, //Second state with blocking bookmark
new State(){
DisplayName = "Second",Entry = new BookmarkActivity(){BookmarkName = "Second",BookmarkOptions =
BookmarkOptions.None},
Transitions =
{
new Transition(){ }
}
},
new State(){
DisplayName = "End",
IsFinal = true
}
}
};
sm.InitialState = sm.States[0];
sm.InitialState.Transitions[0].To = sm.States[1];
sm.States[1].Transitions[0].To = sm.States[2];
}
Result of ResumeBookmark in above test code is 'NotFound'
I would appreciate any working code that demonstrates NonBlocking option.

Even NonBlocking bookmarks are removed when the activity that created it is completed. They allow the activity to continue execution but that's it.
Bottom line you've to maintain an activity in a not completed state (usually the outside activity) and everything inside it will execute even when a NonBlocking bookmark is found.
That's why you're getting a NotFound error. The activity that created the bookmark has ended and the bookmark no longer exists.
P.S.: A somehow usual use case for NonBlocing bookmarks is, for example, when you've a long running activity, that might throw exceptions while executing, and that way you've the possibility to resume the workflow at a previous state.

Related

Prism Forms doesn't have OnNavigatingTo anymore. How to run some code before Views's constructor?

Look at the code below. There's two DelegateCommand that are set in Views's constructor:
public DelegateCommand DeletePromotionCommand { get; set; }
public DelegateCommand EditPromotionCommand { get; set; }
public PromotionDetailViewModel(INavigationService navigationService, IPageDialogService pageDialogService)
: base(navigationService, pageDialogService)
{
Title = "Promoção";
DeletePromotionCommand = new DelegateCommand(DeletePromotion, CanDeletePromotion);
EditPromotionCommand = new DelegateCommand(EditPromotion, CanEditPromotion);
}
The CanEditPromotion is called when the EditPromotionCommand is set in the constructor. CanEditPromotion method is shown below:
private bool CanEditPromotion()
{
var userString = Preferences.Get("user", string.Empty);
if (userString == string.Empty)
return false;
var userId = (Guid)JObject.Parse(userString)["id"];
if (userId == Promotion.CreatedBy)
return true;
else
return false;
}
Note that on the 4th sentence I need the Promotion property. This property need to be set before the Views's constructor, so it will be null and, at exactly line, it will break the app.
Before I should use the code below to set Promotion property, but Prism doesn't have OnNavigatingTo method anymore. Promotion info comes from the Page before and is passed as a parameter navigation:
public override async void OnNavigatingTo(INavigationParameters parameters)
{
base.OnNavigatedTo(parameters);
try
{
IsBusy = true;
Promotion = parameters["promotion"] as Promotion;
var marketService = new Service<Market>();
Market = await marketService.GetAsync(Promotion.MarketId);
IsBusy = false;
}
catch (Exception)
{
IsBusy = false;
}
}
When I try to use INavigatingTo at my BaseViewModel, it is show to me a message saying to use IInitialize instead. I tried but the Initialize method is still fired after the View's constructor.
As is indicated in the official release notes for Prism 7.2 OnNavigatingTo was deprecated due after a lot of consideration and feedback from the Prism community. This was in part due to the fact that OnNavigatingTo was expected to run to Initialize your ViewModel prior to the View being pushed onto the Navigation Stack. The issue is that over time its intent was getting lost and people were trying to misuse the API. The only way for us to move forward was to remove the reference to INavigatingAware from INavigationAware which unfortunately creates a soft break in which OnNavigatingTo simply isn't called. In the case where you have a direct reference to INavigatingAware you will get a hard compilation error.
To migrate your code you should use the new initialization API with either IInitialize, IInitializeAsync or IAutoInitialize. Assuming that you simply use IInitialize you'll update your legacy code from:
public void OnNavigatingTo(INavigationParameters parameters)
{
// your code here
}
to the new IInitialize version
public void Initialize(INavigationParameters parameters)
{
// your code here
}
Keep in mind that if you use the Async version of this the long running task will have to complete before the page is pushed thus causing a noticeable delay in navigation. It may often be more desirable therefore to simply use async void to avoid blocking the Navigation.
You can read more in the Prism 7.2 Release Notes here
I resolved this way:
At CanEditPromotion I put a null verification for Promotion property:
private bool CanEditPromotion()
{
var userString = Preferences.Get("user", string.Empty);
if (userString == string.Empty)
return false;
var userId = (Guid)JObject.Parse(userString)["id"];
if (Promotion != null && userId == Promotion.CreatedBy)
return true;
else
return false;
}
And I observe the Promotion property when the EditPromotionCommand is set:
public DelegateCommand DeletePromotionCommand { get; set; }
public DelegateCommand EditPromotionCommand { get; set; }
public PromotionDetailViewModel(INavigationService navigationService, IPageDialogService pageDialogService)
: base(navigationService, pageDialogService)
{
Title = "Promoção";
DeletePromotionCommand = new DelegateCommand(DeletePromotion, CanDeletePromotion)
.ObservesProperty(() => Promotion);
EditPromotionCommand = new DelegateCommand(EditPromotion, CanEditPromotion)
.ObservesProperty(() => Promotion);
}
And I used the OnNavigatedTo method to set Promotion property:
public override async void OnNavigatedTo(INavigationParameters parameters)
{
try
{
IsBusy = true;
Promotion = parameters["promotion"] as Promotion;
var marketService = new Service<Market>();
Market = await marketService.GetAsync(Promotion.MarketId);
IsBusy = false;
}
catch (Exception)
{
IsBusy = false;
}
}

Set a job to failed using Hangfire with ASP.NET?

I have an ASP.NET app which sends emails whenever the user signs up in the web site. I'm using hangfire in order to manage the jobs and postal in order to send emails.
It all works great, but here's the thing:
I want the superuser to change how many times the APP can send the email before deleting the job.
Here's my code
public static void WelcomeUser(DBContexts.Notifications not)
{
try{
var viewsPath = Path.GetFullPath(HostingEnvironment.MapPath(#"~/Views/Emails"));
var engines = new ViewEngineCollection();
engines.Add(new FileSystemRazorViewEngine(viewsPath));
Postal.EmailService service = new Postal.EmailService(engines);
WelcomeUserMail welcomeUserMail = new WelcomeUserMail();
welcomeUserMail.To = not.ReceiverEmail;
welcomeUserMail.UserEmail = not.ReceiverEmail;
welcomeUserMail.From = BaseNotification.GetEmailFrom();
service.Send(welcomeUserMail);
}
catch(Exception e)
{
DBContexts.DBModel dbModel = new DBModel();
DBContexts.Notifications notificacionBD = dbModel.Notifications.Find(not.NotificationID);
notificacionBD.Status = false;
notificacionBD.Timestamp = DateTime.Now;
notificacionBD.Error = e.Message;
int numberOfRetriesAllowed = ParameterHelper.getNumberOfRetriesAllowed();
if (notificacionBD.Retries > numberOfRetriesAllowed)
{
//In this case Hangfire won't put this job in the failed section but rather in the processed section.
dbModel.SaveChanges();
}
else
{
notificacionBD.Retries++;
dbModel.SaveChanges();
throw new Exception(e.Message);
}
}
}
Why not just add attributes to handle it automatically?
[AutomaticRetry(Attempts = 10, LogEvents = true, OnAttemptsExceeded = AttemptsExceededAction.Delete)]
public void MyTask(){
//doing stuff
}
Or you could just make your own attribute that mimics the AutommaticRetryAttribute class but you handle it how you want?
https://github.com/HangfireIO/Hangfire/blob/a5761072f18ff4caa80910cda4652970cf52e693/src/Hangfire.Core/AutomaticRetryAttribute.cs

Accessing OutArgument value of Receive implementation child activity within custom WF4 activity

Using VS2012/.NET 4.5 I am creating a custom activity which implements a Receive child activity (as an implementation child). The parameters are in the example below fixed to just one: OutValue of type Guid.
I really would love to access the value of incoming parameter value in ReceiveDone, because I need to work with it and transform it before returning it from the activity. Please ignore that I am currently using a Guid, it still fails to access the value with and InvalidOperationException:
An Activity can only get the location of arguments which it owns. Activity 'TestActivity' is trying to get the location of argument 'OutValue' which is owned by activity 'Wait for
workflow start request [Internal for TestActivity]'
I have tried everything I could think of, but am stupefied. There must be a way to do this very simple thing?
public class TestActivity : NativeActivity<Guid>
{
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
var content = ReceiveParametersContent.Create(new Dictionary<string, OutArgument>()
{
// How to access the runtime value of this inside TestActivity?
{"OutValue", new OutArgument<Guid>()}
});
startReceiver = new Receive()
{
DisplayName = string.Format("Wait for workflow start request [Internal for {0}]", this.DisplayName),
CanCreateInstance = true,
ServiceContractName = XName.Get("IStartService", Namespace),
OperationName = "Start",
Content = content
};
foreach (KeyValuePair<string, OutArgument> keyValuePair in content.Parameters)
{
metadata.AddImportedChild(keyValuePair.Value.Expression);
}
metadata.AddImplementationChild(startReceiver);
}
protected override void Execute(NativeActivityContext context)
{
context.ScheduleActivity(startReceiver, ReceiveDone);
}
private void ReceiveDone(NativeActivityContext context, ActivityInstance completedInstance)
{
var receive = completedInstance.Activity as Receive;
ReceiveParametersContent content = receive.Content as ReceiveParametersContent;
try
{
// This causes InvalidOperationException.
// An Activity can only get the location of arguments which it owns.
// Activity 'TestActivity' is trying to get the location of argument 'OutValue'
// which is owned by activity 'Wait for workflow start request [Internal for TestActivity]'
var parmValue = content.Parameters["OutValue"].Get(context);
}
catch (Exception)
{ }
}
private Receive startReceiver;
private const string Namespace = "http://company.namespace";
}
Use internal variables to pass values between internal activities.
Although not directly related to your code, see the example below which should give you the idea:
public sealed class CustomNativeActivity : NativeActivity<int>
{
private Variable<int> internalVar;
private Assign<int> internalAssign;
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
base.CacheMetadata(metadata);
internalVar = new Variable<int>("intInternalVar", 10);
metadata.AddImplementationVariable(internalVar);
internalAssign = new Assign<int>
{
To = internalVar,
Value = 12345
};
metadata.AddImplementationChild(internalAssign);
}
protected override void Execute(NativeActivityContext context)
{
context.ScheduleActivity(internalAssign, (activityContext, instance) =>
{
// Use internalVar value, which was seted by previous activity
var value = internalVar.Get(activityContext);
Result.Set(activityContext, value);
});
}
}
Calling the above activity:
WorkflowInvoker.Invoke<int>(new CustomNativeActivity());
Will output:
12345
Edit:
In your case your OutArgument will be the internalVar
new OutArgument<int>(internalVar);
You need to use OutArgument and them to variables. See the code example with the documentation.
I may have tried everything I thought of, but I am stubborn and refuse to give up, so I kept on thinking ;)
I here have changed my example to use a Data class as a parameter instead (it does not change anything in itself, but I needed that in my real world example).
This code below is now a working example on how to access the incoming data. The use of an implementation Variable is the key:
runtimeVariable = new Variable<Data>();
metadata.AddImplementationVariable(runtimeVariable);
And the OutArgument:
new OutArgument<Data>(runtimeVariable)
I can then access the value with:
// Here dataValue will get the incoming value.
var dataValue = runtimeVariable.Get(context);
I haven't seen an example elsewhere, which does exactly this. Hope it will be of use to any one but me.
The code:
[DataContract]
public class Data
{
[DataMember]
Guid Property1 { get; set; }
[DataMember]
int Property2 { get; set; }
}
public class TestActivity : NativeActivity<Guid>
{
public ReceiveContent Content { get; set; }
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
runtimeVariable = new Variable<Data>();
metadata.AddImplementationVariable(runtimeVariable);
Content = ReceiveParametersContent.Create(new Dictionary<string, OutArgument>()
{
{"OutValue", new OutArgument<Data> (runtimeVariable)}
});
startReceiver = new Receive()
{
DisplayName = string.Format("Wait for workflow start request [Internal for {0}]", this.DisplayName),
CanCreateInstance = true,
ServiceContractName = XName.Get("IStartService", Namespace),
OperationName = "Start",
Content = Content
};
metadata.AddImplementationChild(startReceiver);
}
protected override void Execute(NativeActivityContext context)
{
context.ScheduleActivity(startReceiver, ReceiveDone);
}
private void ReceiveDone(NativeActivityContext context, ActivityInstance completedInstance)
{
// Here dataValue will get the incoming value.
var dataValue = runtimeVariable.Get(context);
}
private Receive startReceiver;
private Variable<Data> runtimeVariable;
private const string Namespace = "http://company.namespace";
}

fubumvc - simple forms validation using IFailureValidationPolicy

I've been trying to implement form validation correctly and a discussion on fubu mailing list has been the most helpful (http://groups.google.com/group/fubumvc-devel/browse_thread/thread/d54b135fe0254653/12180cd86e9dc50b).
I'm still not entirely clear on certain points, I'm a newbie so I'm going through some yak shaving.
It seems like the example given in the discussion performed the validation within the controller itself using IsValid(model).
I'm trying to avoid this by decorating my input model with validation attributes such as Required and then use the validation configuration to Transfer on failure (via a policy).
this.Validation(x => {
x.Actions
.Include(call => call.HasInput && call.InputType().Name.EndsWith("Input"));
x.Failures
.ApplyPolicy<AccountValidationFailedPolicy>();
});
And here's the class that implments the policy:
public class AccountValidationFailedPolicy : IValidationFailurePolicy {
public bool Matches(ValidationFailure context) {
return (context.InputType() == typeof (RegisterAccountInput));
}
public void Handle(ValidationFailure context) {
var incomingRequest = (RegisterAccountInput) context.InputModel;
var failedValidation = new RegisterationFailedNotification {
CVV = incomingRequest.CVV,
AcceptTerms = incomingRequest.AcceptTerms,
Countries = incomingRequest.Countries,
PhoneNumber = incomingRequest.PhoneNumber,
PIN = incomingRequest.PIN
};
FubuContinuation.TransferTo(failedValidation);
}
}
Handle simply tries to Transfer to another action via a new model, copying the values into the new model so that I can redisplay them again on the form.
I must be doing something wrong here, because it's not transferring anywhere.
I have a class with this method which I was hoping would handle it.
public AccountViewModel New(RegisterationFailedNotification notification) {
....
}
Am I on track here, or is there something fundamental that I'm not getting? Perhaps a policy is not the thing to do here?
#stantona
The policy mechanism will work here. I'll spare you the details about how I plan to make this simpler (very soon), and note that your use of FubuContinuation.TransferTo simply creates a FubuContinuation -- it doesn't execute it.
Here's what you need:
public class AccountValidationFailedPolicy : IValidationFailurePolicy {
private readonly IFubuRequest _request;
private readonly IValidationContinuationHandler _handler;
public AccountValidationFailedPolicy(IFubuRequest request, IValidationContinuationHandler handler) {
_request = request;
_handler = handler;
}
public bool Matches(ValidationFailure context) {
return (context.InputType() == typeof (RegisterAccountInput));
}
public void Handle(ValidationFailure context) {
var incomingRequest = (RegisterAccountInput) context.InputModel;
var failedValidation = new RegisterationFailedNotification {
CVV = incomingRequest.CVV,
AcceptTerms = incomingRequest.AcceptTerms,
Countries = incomingRequest.Countries,
PhoneNumber = incomingRequest.PhoneNumber,
PIN = incomingRequest.PIN
};
var continuation = FubuContinuation.TransferTo(failedValidation);
_request.Set(continuation);
_handler.Handle();
}
}

Can I get a series of good results and a thrown exception from Moq

I am mocking a wrapper to an MSMQ. The wrapper simply allows an object instance to be created that directly calls static methods of the MessageQueue class.
I want to test reading the queue to exhaustion. To do this I would like the mocked wrapper to return some good results and throw an exception on the fourth call to the same method. The method accepts no parameters and returns a standard message object.
Can I set up this series of expectations on the method in Moq?
Yup, this is possible if you don't mind jumping through a few minor hoops. I've done this for one of my projects before. Alright here is the basic technique. I just tested it out in Visual Studio 2008, and this works:
var mockMessage1 = new Mock<IMessage>();
var mockMessage2 = new Mock<IMessage>();
var mockMessage3 = new Mock<IMessage>();
var messageQueue = new Queue<IMessage>(new [] { mockMessage1.Object, mockMessage2.Object, mockMessage3.Object });
var mockMsmqWrapper = new Mock<IMsmqWrapper>();
mockMsmqWrapper.Setup(x => x.GetMessage()).Returns(() => messageQueue.Dequeue()).Callback(() =>
{
if (messageQueue.Count == 0)
mockMsmqWrapper.Setup(x => x.GetMessage()).Throws<MyCustomException>();
});
A few notes:
You don't have to return mocked messages, but it's useful if you want to verify expectations on each message as well to see if certain methods were called or properties were set.
The queue idea is not my own, just a tip I got from a blog post.
The reason why I am throwing an exception of MyCustomException is because the Queue class automatically throws a InvalidOperationException. I wanted to make sure that the mocked MsmqWrapper object throws an exception because of Moq and not because of the queue running out of items.
Here's the complete code that works. Keep in mind that this code is ugly in some places, but I just wanted to show you how this could be tested:
public interface IMsmqWrapper
{
IMessage GetMessage();
}
public class MsmqWrapper : IMsmqWrapper
{
public IMessage GetMessage()
{
throw new NotImplementedException();
}
}
public class Processor
{
private IMsmqWrapper _wrapper;
public int MessagesProcessed { get; set; }
public bool ExceptionThrown { get; set; }
public Processor(IMsmqWrapper msmqWrapper)
{
_wrapper = msmqWrapper;
}
public virtual void ProcessMessages()
{
_wrapper.GetMessage();
MessagesProcessed++;
_wrapper.GetMessage();
MessagesProcessed++;
_wrapper.GetMessage();
MessagesProcessed++;
try
{
_wrapper.GetMessage();
}
catch (MyCustomException)
{
ExceptionThrown = true;
}
}
}
[Test]
public void TestMessageQueueGetsExhausted()
{
var mockMessage1 = new Mock<IMessage>();
var mockMessage2 = new Mock<IMessage>();
var mockMessage3 = new Mock<IMessage>();
var messageQueue = new Queue<IMessage>(new [] { mockMessage1.Object, mockMessage2.Object, mockMessage3.Object });
var mockMsmqWrapper = new Mock<IMsmqWrapper>();
mockMsmqWrapper.Setup(x => x.GetMessage()).Returns(() => messageQueue.Dequeue()).Callback(() =>
{
if (messageQueue.Count == 0)
mockMsmqWrapper.Setup(x => x.GetMessage()).Throws<InvalidProgramException>();
});
var processor = new Processor(mockMsmqWrapper.Object);
processor.ProcessMessages();
Assert.That(processor.MessagesProcessed, Is.EqualTo(3));
Assert.That(processor.ExceptionThrown, Is.EqualTo(true));
}

Resources