Can I control if an activity of a workflow is a singleton or not? I discovered the same activity class instance within a workflow is (re)used every time the workflow is executed.
Or simply said, in Execute() method of the activity method I get a different context.WorkflowInstanceId, but the same context.ActivityInstanceId.
Is this by design? By default?
Can I control activity instancing? Can I have a new instance of activity every time the workflow is executed?
Yes it is the default behavior. An activity instance can be the same instance in a miltithreaded enviroment (web context) which can bite you. So to be safe you should always have all your activity variables as Argument. Arguments are passed via ActivityContext which is different for each activity instance.
public class CustomActivity : Activity
{
public int Age { get; set; }
protected override void Execute(CodeActivityContext context)
{
//do some work with Age
}
}
Since different threads can set/get that same instance variable, instead of the code above you should do this:
public class CustomActivity : Activity
{
public InOutArgument<int> Age { get; set; }
protected override void Execute(CodeActivityContext context)
{
//do some work with Age within CodeActivityContext
}
}
Related
Im using asp.net core. Here is the basic way to use model with controller.
public class BookController : Controller
{
private readonly ApplicationDbContext _context { get; set; }
public BookController(ApplicationDbContext context)
{
_context = context;
}
public IActionResult Create(Book model)
{
// adding new model
}
public IActionResult Edit(Book model)
{
// modifying the model
}
public IActionResult Delete(Book model)
{
// removing the model
}
}
My question: when shall/should I implement the code inside the controller? When shall/should I implement it in another class?
Something like this:
public interface IBook
{
int Add(Book book);
int Update(Book book);
int Remove(Book book);
}
public class BookData : IBook
{
private readonly ApplicationDbContext _context { get; set; }
BookData(ApplicationDbContext context)
{
_context = context
}
public int Add(Book model)
{
// ...
return _context.SaveChanges();
}
// other implements...
}
Then, calling it inside controller:
public IActionResult Create(Book model)
{
var bookData = new BookData(_context);
int result = bookData.Add(model);
// ...
}
For the interface, I think it may be useful for the case: I have many controllers that require same action/method names.
Example: MessageController requires 3 actions/methods at least (Create/Add, Edit/Update, Delete/Remove). It's same to NotificationController class, CommentController class...
So, the interface can be improved to:
public interface IMyService<T> where T : class
{
int Add(T model);
int Update(T model);
int Remove(T model);
}
public class MyService<T> : IMyService<T> where T : class
{
private readonly ApplicationDbContext _context { get; set; }
public MyService(ApplicationDbContext context)
{
_context = context;
}
public int Add(T model)
{
Type type = typeof(model);
if (type == typeof(Book))
{
// adding new book model
}
else if (type == typeof(Comment))
{
// adding new comment model
}
// ...
return -1;
}
// other implements...
}
Do I misunderstand something?
If I read it correctly with data classes you actually means repository (which is an abstraction over the persistence layer). You should always encapsulate persistence logic behind a class (be it via repository pattern, command/query pattern or request handler) and use it instead of directly using the context in your service classes.
That being said, you can directly inject your BookData to your controller instead of the ApplicationDbContext. One thing you should consider you lose in your current implementation is the Unit of Work pattern. Right now, every add will instantly persist the data.
This may not be what you want, so you should move the _context.SaveChanges(); outside of the Add/Remove/Update methods and call it explicitly. This allows you to insert i.e. 10 records and if one of them fails, nothing will be persisted to the database.
But if you call _context.SaveChanges(); after each insert and you get an error in the 8th (of 10) records, then 7 get persisted and 3 will be missing and you get inconsistent data.
Controller shouldn't contain any logic at all, only do short validation of the input model (ModelState.IsValid check) and if its okay, call the services which do all the logic and report the result back to the user. Only in very simple tutorials and guides logic is put into the controller action for reasons of simplicity. In real world applications you should never do that. Controllers are much harder to unit test than service classes.
I build a simple custom native activity that return a string value.
public sealed class MyActivity : NativeActivity<string>
{
public InArgument<string> Id { get; set; }
protected override void Execute(NativeActivityContext context)
{
var returnString = QuerySomthing();
context.SetValue<string>(base.Result, returnString);
}
}
How can I get this value in the workflow's variables?
You can access the 'Result' property of your activity. All you need to do is create a variable on the workflow (of type String) and bind this to the 'Result' property. Then you can access the variable later on in the workflow to analyse its value. HTH
I am using a class named:
public class ProcessFlowPersistenceIOParticipant : PersistenceIOParticipant
It inherits from System.Activities.Persistence.PersistenceIOParticipant in the WF4 framework.
I would like to override the BeginOnLoad(..) method.
In this override I would like to intercept the deserialization of the workflow instance and inject the business entity from the entity database into the entity workflow variable.
BeginOnLoad is fired when the workflow instance is loaded from the instance store.
via: workflowApplication.Load(workflowInstanceGuid);
I can see the workflow guid inside the readwritevalues dictionary.
Find the key in readWriteValues.Keys matching namespace
"urn:schemas-microsoft-com:System.Activities/4.0/properties"
Then the guid is inside:
value = readWriteValues[xName];
_workflowInstanceId = ((System.Activities.Runtime.ActivityExecutor)value).WorkflowInstanceId;
It is accessible via a debugger but not in code as ActivityExecutor is an internal class.
So is there a way to determine what workflow instance is being loaded inside BeginOnLoad?
Any tips much appreciated.
Mike
This question is similar to Access workflow id from inside BeginOnSave.
However in the case of BeginOnLoad there is no activity execution context available to get the workflow instance guid.
If you also implement the IWorkflowInstanceExtension interface in the ProcessFlowPersistenceIOParticipant you should be able to get at the workflow ID through the WorkflowInstanceProxy in the SetInstance() function.
public class TaskActivity : NativeActivity
{
protected override void Execute(NativeActivityContext context)
{
context.GetExtension<RelevantDataExtensionIO>().WorkflowInstanceId = context.WorkflowInstanceId;
}
}
public class RelevantDataExtensionIO : PersistenceIOParticipant
{
public const string NamespaceWorkflowInstanceId = "WorkflowInstanceId";
public Guid WorkflowInstanceId { get; set; }
public static XNamespace Namespace
{
get { return XNamespace.Get("http://sample.com/RelevantDataIO"); }
}
public RelevantDataExtensionIO()
: base(false, false)
{
}
protected override void CollectValues(out IDictionary<XName, object> readWriteValues, out IDictionary<XName, object> writeOnlyValues)
{
readWriteValues = new Dictionary<XName, object>();
readWriteValues.Add(Namespace.GetName(NamespaceWorkflowInstanceId), this.WorkflowInstanceId);
writeOnlyValues = null;
}
protected override IAsyncResult BeginOnLoad(IDictionary<XName, object> readWriteValues, TimeSpan timeout, AsyncCallback callback, object state)
{
Guid id = this.WorkflowInstanceId;
return base.BeginOnLoad(readWriteValues, timeout, callback, state);
}
}
I am going though the Apress ASP.NET MVC 3 book and trying to ensure I create Unit Tests for everything possible but after spending a good part of a day trying to work out why edit's wouldn't save (see this SO question) I wanted to create a unit test for this.
I have worked out that I need to create a unit test for the following class:
public class EFProductRepository : IProductRepository {
private EFDbContext context = new EFDbContext();
public IQueryable<Product> Products {
get { return context.Products; }
}
public void SaveProduct(Product product) {
if (product.ProductID == 0) {
context.Products.Add(product);
}
context.SaveChanges();
}
public void DeleteProduct(Product product) {
context.Products.Remove(product);
context.SaveChanges();
}
}
public class EFDbContext : DbContext {
public DbSet<Product> Products { get; set; }
}
I am using Ninject.MVC3 and Moq and have created several unit tests before (while working though the previously mentioned book) so am slowly getting my head around it. I have already (hopefully correctly) created a constructor method to enable me to pass in _context:
public class EFProductRepository : IProductRepository {
private EFDbContext _context;
// constructor
public EFProductRepository(EFDbContext context) {
_context = context;
}
public IQueryable<Product> Products {
get { return _context.Products; }
}
public void SaveProduct(Product product) {
if (product.ProductID == 0) {
_context.Products.Add(product);
} else {
_context.Entry(product).State = EntityState.Modified;
}
_context.SaveChanges();
}
public void DeleteProduct(Product product) {
_context.Products.Remove(product);
_context.SaveChanges();
}
}
BUT this is where I start to have trouble... I believe I need to create an Interface for EFDbContext (see below) so I can replace it with a mock repo for the tests BUT it is built on the class DbContext:
public class EFDbContext : DbContext {
public DbSet<Product> Products { get; set; }
}
from System.Data.Entity and I can't for the life of me work out how to create an interface for it... If I create the following interface I get errors due to lack of the method .SaveChanges() which is from the DbContext class and I can't build the interface using "DbContext" like the `EFDbContext is as it's a class not an interface...
using System;
using System.Data.Entity;
using SportsStore.Domain.Entities;
namespace SportsStore.Domain.Concrete {
interface IEFDbContext {
DbSet<Product> Products { get; set; }
}
}
The original Source can be got from the "Source Code/Downloads" on this page encase I have missed something in the above code fragments (or just ask and I will add it).
I have hit the limit of what I understand and no mater what I search for or read I can't seem to work out how I get past this. Please help!
The problem here is that you have not abstracted enough. The point of abstractions/interfaces is to define a contract that exposes behavior in a technology-agnostic way.
In other words, it is a good first step that you created an interface for the EFDbContext, but that interface is still tied to the concrete implementation - DbSet (DbSet).
The quick fix for this is to expose this property as IDbSet instead of DbSet. Ideally you expose something even more abstract like IQueryable (though this doesn't give you the Add() methods, etc.). The more abstract, the easier it is to mock.
Then, you're left with fulfilling the rest of the "contract" that you rely on - namely the SaveChanges() method.
Your updated code would look like this:
public class EFProductRepository : IProductRepository {
private IEFDbContext context;
public EFProductRepository(IEFDbContext context) {
this.context = context;
}
...
}
public interface IEFDbContext {
IDbSet<Product> Products { get; set; }
void SaveChanges();
}
BUT... the main question you have to ask is: what are you trying to test (conversely, what are you trying to mock out/avoid testing)? In other words: are you trying to validate how your application works when something is saved, or are you testing the actual saving.
If you're just testing how your application works and don't care about actually saving to the database, I'd consider mocking at a higher level - the IProductRepository. Then you're not hitting the database at all.
If you want to make sure that your objects actually get persisted to the database, then you should be hitting the DbContext and don't want to mock that part after all.
Personally, I consider both of those scenarios to be different - and equally important - and I write separate tests for each of them: one to test that my application does what it's supposed to do, and another to test that the database interaction works.
I guess your current code looks something like this (I put in the interface):
public class EFProductRepository : IProductRepository {
private IEFDbContext _context;
// constructor
public EFProductRepository(IEFDbContext context) {
_context = context;
}
public IQueryable<Product> Products {
get { return _context.Products; }
}
public void SaveProduct(Product product) {
if (product.ProductID == 0) {
_context.Products.Add(product);
} else {
_context.Entry(product).State = EntityState.Modified;
}
**_context.SaveChanges();**
}
public void DeleteProduct(Product product) {
_context.Products.Remove(product);
**_context.SaveChanges();**
}
}
public class EFDbContext : DbContext, IEFDbContext {
public DbSet<Product> Products { get; set; }
}
public interface IEFDbContext {
DbSet<Product> Products { get; set; }
}
The problem is EFProductRepository now expects an object implementing the IEFDbContext interface, but this interface does not define the SaveChanges method used at the lines I put between the asteriskes so the compiler starts complaining.
Defining the SaveChanges method on the IEFDbContext interface solves your problem:
public interface IEFDbContext {
DbSet<Product> Products { get; set; }
void SaveChanges();
}
Having almost no architectural experience I'm trying to design a DRY KISS solution for the .NET 4 platform taking an MVP approach that will eventually be implemented as a Desktop (WinForms) and Web (ASP.NET or Silverlight) product. I did some MVC, MVVM work in the past but for some reason I'm having difficulties trying to wrap my head around this particular one so in an effort to get a grip of the pattern I've decided to start with the simplest sample and to ask you guys for some help.
So assuming a quite simple Model as follows (in practice it'd most definitely be a WCF call):
internal class Person
{
internal string FirstName { get; set; }
internal string LastName { get; set; }
internal DateTime Born { get; set; }
}
public class People
{
private readonly List<Person> _people = new List<Person>();
public List<Person> People { get { return _people; } }
}
I was wondering:
What would be the most generic way to implement its corresponding View/Presenter triad (and helpers) for say, a Console and a Forms UI?
Which of them should be declared as interfaces and which as abstract classes?
Are commands always the recommended way of communication between layers?
And finally: by any chance is there a well-docummented, testeable, light framework to achieve just that?
I've written a number of apps that require a GUI and a winforms UI, the approach I have typically taken to implementing MVP is to create a generic view interface (you can subclass this for more specific views) and a controllerbase class which is given a view. You can then create different view implementations which inherit from the IView (or more specific view) interface
interface IView
{
event EventHandler Shown;
event EventHandler Closed;
void ShowView(IView parentView);
void CloseView();
}
class ControllerBase<T> where T: IView
{
private T _view;
public ControllerBase(T view)
{
_view = view;
}
public T View
{
get { return _view; }
}
public void ShowView(IView owner)
{
_view.ShowView(owner);
}
public void ShowView()
{
ShowView(null);
}
public void CloseView()
{
_view.CloseView();
}
}
Heres an example of how it would work in a specific case
interface IPersonView: IView
{
event EventHandler OnChangeName;
string Name { get; set; }
}
class PersonController: ControllerBase<IPersonView>
{
public PersonController(string name,IPersonView view) : base(view)
{
View.Name = name;
View.OnChangeName += HandlerFunction;
}
private void HandlerFunction(object sender, EventArgs e)
{
//logic to deal with changing name here
}
}
To implement this view in winforms, just make sure your form inherits from IPersonView and implements all the required properties/events and you're good to go. To instantiate the view/controller you'd do something like the following
PersonForm form = new PersonForm();
PersonController controller = new PersonController("jim",form);
controller.ShowView();