eXpress App Framework Team

This Blog

News

You are welcome to test the new XAF features prior to the 17.2 release: one, two, three, four, five, five

June 2011 - Posts

  • XAF–Ask the team webinar today

    Tolis and a bit of the XAF team

    Hello everyone, this was a hard week for me. After the big DX party we had on Wednesday, I am finally sober enough to run this webinar. What is different with this webinar is that I am in the same room with some of our gurus. They brought me here for release planning. However since they used a helicopter it is really hard to understand the location of this place.

    Anyway bring your beers and come to join us in our monthly ask the team discussion.

  • Working with CRUD activities – Short Transactions

    In this post we are going to examine a workflow model that involves long operations. Our example will be based on the following concept which should be familiar from previous posts.

    When working with workflows and persistent objects it is better to keep transactions short. For example, when reading data from a database, checking values, modifying, creating, deleting, committing changes and completing transactions. It is better to avoid continuous operations in the ObjectSpaceTransactionScope, because we are inside an XPO transaction. Since this is an atomic operation, workflow can not be persisted while workflow is inside the ObjectSpaceTransactionScope. If there is a need to use delays, especially within loops, consider placing them outside XAF’s container activities (NoPersistScope, ObjectSpaceTransactionScope).

    Take this example, an issue is active after 4 hours and we need to notify the manager about it. We can use the WorkFlow MainDemo as a starting point for providing a solution to this scenario.

    First we need to modify our issue class to provide creation time information. Adding a new DateTime property and initializing it after object construction fulfills this requirement.

    image

    Secondly we are going to create a new workflow definition at runtime and set the Target Object Type to Issue. At the same time we are going to check the Object Is Created without providing any criteria. These adjustments are enough for the workflow server services to start the workflow definition.

    image

    We are going to initiate the workflow model by retrieving the creation time from the Issue and storing it in a variable. There will be additional stages in this workflow, thus it is better to start with a Sequence activity that will function as a container and will help share variables between child activities.

    image

    The name of the Sequence activity has been changed to SequenceRoot. The reason is that it is not clear how many Sequence activities will be used and we want Scope to differentiate between them. Of course this is a matter of design preference and more confident developers may skip this step. issueCreateOn holds the creation time letting us move to the next step. The result is that we are able to use a Delay activity inside a DoWhile to periodically check if the 4hr time interval has passed. Alternatively we could follow similar approaches to model this. Using a small delay duration we could again calculate if the time interval has passed allowing us to inject behavior just after the Issue is closed. An example would be to sent an email that the Issue is not active any more.

    image

    In the above design the DoWhile activity cannot act as a container. Moreover since we haven’t implemented the workflow yet we have used a Sequence activity to fill this role. We have also parameterized the duration of the Delay activity with the maxCloseIssue variable. Finally we have used this variable to calculate when the time interval passed.

    The design is not yet complete due to the fact that the DoWhile condition should include a check for whether a current issue is active. There will be a problem with the Delay activity at this point because the workflow will unload and persist to the database. In order to prevent this we need to query the issue again, after the Delay duration, to obtain its active property as in the first stage.

    image

     

    Finally we need to update the DoWhile condition with the isIssueActive constrain.

     

    image

    The following diagrams show the final stages of the workflow. All that remains is to create a task to notify the manager. We can use an If activity to check if the Issue is active then query the Issue again and create a new Task in order to achieve this.

    image

    There are cases however with complex conditions (see DoWhile condition above) or times when we want to get the values of variables or even see whether objects returned from activities like GetObjectsByCriteria are valid. In such cases we can use the debugger and initialize the targetObjectId argument with a valid value. We are then able to set the breakpoints we want and just hit run to see if our workflow execution is valid. The next video demonstrates the above and more

    We would appreciate your feedback on this post. Has it been useful to you? Feel free to contact us  with any further questions.

    Related Links
    Videos in our TV channel
    Online documentation
    Blog posts

  • EasyTest in the real world

    As developers we are constantly finding new real world uses for DX products. Take this example from DX-Squad member Martin Praxmarer;

       “I want to distribute the testexecutor to either an outsourced testing team or even to resellers of my application. Resellers (or even big customers with a specific functionality) want/can run their own functional tests to be sure an update doesn't break their environment.”

    This is the perfect example of a programmer using XAF to take their development to another level.

    Problems could have occurred with the EULA as TestExecutor is included in XAF and ships with DXperience Universal license. However DX has provided an easy solution by removing this restriction from our EULA and offering the tool for free. Now we are permitted to use TestExecutor for a wider range of applications in addition to our development environment and build server.

     Related Links

    Happy EasyTesting!

  • XAF – The State of Domain Components Technology in v2011 Vol 1

    This post may be outdated. For the latest Domain Components concepts and examples refer to the current online documentation.

    We are happy to announce that in v2011 vol1 the Domain Components (DC) technology leaves CTP and reaches the Beta stage. During this release, XAF and XPO teams  invested significant resources in fixing known issues and covering more scenarios. While doing this, we have rewritten the old mechanism of persistent interface entities generation.

    Registering entities As Alias

    One of the key features of this rewrite is a new entities registration mode - so-called AsAlias mode. It is important for this blog to remind you what  an “entity” is in terms of DC. Here and in the future, by “entity” we mean a persistent interface or domain component, representing a final business entity (business model if you want). Although, domain components are often composed of several components (sorry for the tautology), not every domain component can be called an “entity”. This is again only the registered domain component used in your final application. I hope that now, we are done with the terms and can continue.clip_image002

    Registering an entity as alias means that during the code generation, a single implementation class will be physically generated for it. Hence, all queries to XPO from this class will be served as for a regular XPO class. Furthermore, only one table will be created in the database for such entity! Let’s demonstrate this with the help of a concrete example.

    I think that is enough theory for now. I will take a test case from one of my Code Central examples (E2829 - How to generate and assign a sequential number for a business object within a database transaction, while being a part of a successful saving process) and describe it more easily:

      1: using DevExpress.ExpressApp.DC;
    
      2: using DevExpress.Persistent.Base;
    
      3: using DevExpress.Persistent.Validation;
    
      4: 
    
      5: namespace GenerateUserFriendlyId.Module.BO {
    
      6:     public interface ISupportSequentialNumber {
    
      7:         long SequentialNumber { get; set; }
    
      8:     }
    
      9:     [DomainComponent]
    
     10:     public interface IBaseDomainComponent : ISupportSequentialNumber  { }
    
     11: 
    
     12:     [DefaultClassOptions]
    
     13:     [DomainComponent]
    
     14:     [XafDefaultProperty("Title")]
    
     15:     [ImageName("BO_Note")]
    
     16:     public interface IDocument : IBaseDomainComponent {
    
     17:         [Calculated("concat('D', ToStr(SequentialNumber))")]
    
     18:         string DocumentId { get; }
    
     19:         [RuleRequiredField("IDocument.Title.RuleRequiredField", DefaultContexts.Save)]
    
     20:         [FieldSize(255)]
    
     21:         string Title { get; set; }
    
     22:         [FieldSize(8192)]
    
     23:         string Text { get; set; }
    
     24:     }
    
     25: }

    As you see, here I have one base domain component – IBaseDomainComponent, and another one – IDocument, descending from it (ISupportSequentialNumber is not domain component and just a pure interface, which we will not discuss here).

    Previously, if I had registered my IDocument component:

      1: ...
    
      2: public override void Setup(XafApplication application) {
    
      3:     base.Setup(application);
    
      4:     if (!XafTypesInfo.IsInitialized) {
    
      5:         XafTypesInfo.Instance.AddEntityToGenerate("Document", typeof(IDocument), typeof(BasePersistentObject));
    
      6:     }
    
      7: }
    
      8: ...
    
      9: [NonPersistent]
    
     10: public abstract class BasePersistentObject : BaseObject, ISupportSequentialNumber { ... }
    
     11: ...

    I would have received the following database structure:

    clip_image004

    Take special note that 5 tables would have been generated in this situation:

    • a single table for a registered entity (dbo.Document);
    • two separate tables to hold data of each domain component (dbo.IBaseDomainComponentClass & dbo.IDocumentClass);
    • two link tables used to establish relations between domain component data and entities (these are the expanded dbo.IBaseDomainComponentClassDocument and dbo.IDocumentClassDocument).

    At first glance, this may look like overkill for such a trivial case, but it is inevitable if you want to support multiple inheritance and other DC features. However, in reality, multiple inheritance (some people out there consider it to be bad practice) is not needed in many cases. Or, it can be easily avoided by designing your business entities more carefully. We think that the majority of real cases are exactly those, and so we have made it possible to utilize a simpler database structure for them + other benefits that could not be used previously.

    Below is the NEW way of registering the business entity I was talking about above:

      1: ...
    
      2: public override void Setup(XafApplication application) {
    
      3:     base.Setup(application);
    
      4:     if (!XafTypesInfo.IsInitialized) {
    
      5:         XafTypesInfo.Instance.RegisterEntity("Document", typeof(IDocument), typeof(BasePersistentObject));
    
      6:     }
    
      7: }
    
      8: ...
    
      9: [NonPersistent]
    
     10: public abstract class BasePersistentObject : BaseObject, ISupportSequentialNumber { ... }
    
     11: ...

    Using this new mode helps me get the following database structure for my domain components definitions above:

    clip_image006

    If we dig more and see the auto-generated code for this entity (you can do this either by setting a breakpoint into the DevExpress.ExpressApp.DC.Xpo.TypeGenerator.GetCode method or by inspecting the generated cache DcAssembly.dll via Reflector), we will see what it looks like:

      1: ...
    
      2: public class Document : BasePersistentObject, IBaseDomainComponent, IDocument, ISupportSequentialNumber, ... { 
    
      3: ...

    I intentionally omitted other XPO service stuff in the Document class declaration for the sake of simplicity. My main goal was to demonstrate that if an entity is registered AsAlias, a true class will be created behind the scenes, and this class will support all interfaces from the original domain component and its inheritance chain. Since it is a true class, an inevitable constraint comes from it - multiple inheritance is not available for “aliased” interfaces.

    Before you are completely scared off and disappointed by this fact, I would provide quick clarification on it. Below, the allowed and illegal inheritance chains are demonstrated (take into account that A, B, C – are domain components registered AsAlias in your application):

    A : B
    B : C

    or

    A : B
    C : B
    – Both are allowed, because after generating entities there will be always a single base entity or a single inheritance chain.

    A : B, C – Illegal.

    Starting from 11.1, AsAlias mode is used by default, and you will receive a warning message from the deprecated AddAntityToGenerate method. You will have to either use the new RegisterEntity method and AsAlias mode or explicitly tell XAF that you want to use the old registration mode and its peculiarities.

    There are still some known issues and suggestions…

    Although the new AsAlias mode has greatly helped us in resolving old known issues (such as lack of server mode support, incorrect work on the Web, etc.), there are still some known issues, which we need to sort out before releasing the Domain Components technology. I separated the remaining problems into two categories, for convenience.

    The first category consists of items that cause problems under certain scenarios. Those will certainly be resolved in the next minor releases, and it is sometimes even possible to workaround them in the current version. Take special note that some of these items are already NOT problems in AsAlias mode (marked in italic).

    In the second category there are suggestions, based on the feedback we received from our customers. Implementing them can make the work with DC better, more convenient, but without these improvements DC can still be used normally by developers in all scenarios. Some suggestions are unique and even not present for pure persistent objects.

    So, here we go:

    Issues:

    • Improve support of domain components in built-in modules: System Windows Forms (support the ICategorizedItem interface), Audit Trail (make it possible to customize audit trail settings), Validation (support Rule Unique validation rule), Clone Object, Scheduler (support recurring events), etc.;
    • Support filtering by criteria, containing a key value (e.g. @CurrentUserId);
    • Support selection in the Web List Editors for unregistered base domain components* (already works in the AsAlias mode);
    • Cannot filter by the ObjectType and other XPO service fields (already works in the AsAlias mode).

    Suggestions

    • Make it possible to supply a custom domain logic before deleting an object (OnDeleting);
    • Make it possible to supply a custom domain logic after an associated collection is changed (AfterListChanged);
    • Make it possible to supply a custom domain logic before a property getter or setter is executed (BeforeXXX);
    • Make it possible to mark a property as index (analog of the XPO’s IndexedAttribute);
    • Support multiple inheritance for base interfaces, containing a property with the same name;
    • Support medium trust environments.

    * By unregistered base domain components we mean domain components that are parts of an entity, but are not registered as an entity. In our case, this is the IBaseDomainComponent interface.

    Please note that I took only most popular customers suggestions and core issues, which are causing other side-effects or malfunctioning. So, if you are are aware of an issue that is not in this list, it is possible that it is caused by one of the core issues listed above. Feel free to verify this with Support to be sure. We will be glad to give you updates on this.

    And finally, I want to announce one important thing, which I presume many of you want to hear: we hope to fix all the issues above in the next minor updates. Please stay tuned.

    As always, we look forward to hearing your thoughts. Please do not hesitate to contact our Support Team if you encounter problems with certain scenarios using Domain Components or wish to propose an improvement.

    Related help links:

    Happy XAFingclip_image002

  • Working with XAF CRUD activities–Introduction

    In this post we are going to explore the built in XAF CRUD activities beginning with how a workflow execution takes place.

    The workflow server acts as a host for WorkflowServiceHost objects and a number of services. Services will perform every action needed in a very decoupled way. For example, there is a service that will read WorkFlowDefinitions, another that creates and starts a WorkflowServiceHost for each definition, another that will search for objects that match the WorkflowDefintions’ criteria and so on. Every 15 seconds the later service runs and if objects found it calls the service that can start the corresponding workflow. Note that only one workflow instance can be started for each found object. The following image is an Issue workflow definition taken from our Workflow demo. It will run for all Issues whose Active property is true.

    image

    However in the above image we see that Object Fits Criteria is not checked meaning that  this WorkFlowDefintion doesn’t provide StartWorkFlowConditions therefore this workflow will not start. In addition we can check Object Is Created and force the workflow to run instantly when a new Issue is created rather than after 15 sec. Moreover if a WorkFlowDefintion is not active will not start. You can activate a WorkFlowDefintion by executing the Activate action (next to refresh).

    When working with workflows and persistent objects it is better to keep transactions short. For example, when reading data from a database, checking values, modifying, creating, deleting, committing changes and completing transactions. It is better to avoid continuous operations in the ObjectSpaceTransactionScope, because we are inside an XPO transaction. Since this is an atomic operation, workflow can not be persisted while workflow is inside the ObjectSpaceTransactionScope. If there is a need to use delays, especially within loops, consider placing them outside XAF’s container activities (NoPersistScope,ObjectSpaceTransactionScope).

    Next we are going to examine how to create a workflow from scratch using the demo . The scenario is, creating a new Task when an active Issue is found and setting its subject by concatenating a fixed string with the issue subject.

    image

    Since we are going to create a new persistent object (Task) we have to use an ObjectSpaceTransactionScope as a container for our activities. After we create a new WorkflowDefinition a new 'targetObjectId' argument will automatically be created for it. We need to manage arguments only when we are creating a reused workflow definition and planning to call it manually. We have to leave the 'targetObjectId' argument unchanged if WorkflowDefinition instances will be started by the WorkflowServer.

    image

    The next step is to find the active Issue using the targetObjectId value and assign it as  Key to a GetObjectByKey activity.

    image

    However the Issue is being queried because we need to assign its subject to a Task object that will be create later. For this reason we need to define a variable that can hold it.

    image

    Variables in workflows are very much like the variables we are used to in imperative languages. They describe a named location for data to be stored and they follow certain scoping rules. Since we need the issue variable to be accessible from all activities inside the ObjectSpaceTransactionScope, we use this value in the Scope column.

    The next step is to create the new Task object. Later the resultant Task will be used by other activities so we also need to create a variable to hold it.

    image

    In the final step we are going to use both ObjectSpaceTransactionScope variables - issue and task as defined in previous steps. A native WF Assign activity is dropped into the designer and uses to set the Task’s subject to an expression.

    image

    There is no need to commit the XPO transaction because by default, the ObjectSpaceTransactionScope activity commits all the changes at the end. However it is possible to control this behaviour by setting the AutoCommit attribute to false.

    image

     

    In the next post we are going to talk about “short transactions” inside a long running workflow and how to debug it.

    Please free to ask any questions you might have and as always happy XAFing!

LIVE CHAT

Chat is one of the many ways you can contact members of the DevExpress Team.
We are available Monday-Friday between 7:30am and 4:30pm Pacific Time.

If you need additional product information, write to us at info@devexpress.com or call us at +1 (818) 844-3383

FOLLOW US

DevExpress engineers feature-complete Presentation Controls, IDE Productivity Tools, Business Application Frameworks, and Reporting Systems for Visual Studio, along with high-performance HTML JS Mobile Frameworks for developers targeting iOS, Android and Windows Phone. Whether using WPF, ASP.NET, WinForms, HTML5 or Windows 10, DevExpress tools help you build and deliver your best in the shortest time possible.

Copyright © 1998-2017 Developer Express Inc.
All trademarks or registered trademarks are property of their respective owners