A Google Map module for XAF web applications
25 Σεπτεμβρίου 13 07:43 πμ | tolisss | 0 σχόλια   

XAF it’s a great platform simply because everything is pluggable and reusable! In this post I will demonstrate one more pluggable and reusable contribution – the MapView module from Sergej Derjabkin!

Scenario: We have a business object which has an Address property and we want to display them in Google maps. However we have no time to research or develop anything by ourselves.

Step1: Install the MapView module by drag & drop from the toolbox.

image

Step2: Open Application Model editor to configure from where the module will take its data. This requires that we locate the Customer in the BOModel node and simply change the attributes as illustrated below.

image

Step3: To display the Customer Addresses, the MapView module provides the MapListEditor. Simply install the MapViewWebModule and assign the list editor to the Customer_ListView.

image

Step4: Run the XAF web app and see the results in the map!

image

Bonus scenario: Display a detail view of the mapped address.

Sergej Derjabkin also contributed webmaster detail functionality which is available with XpandSystemAspNetModule so install it as in Step1 and set the MasterDetailMode attribute to ListViewAndDetailView. Youi ‘ll need to override the SupportMasterDetailMode of your WebApplication descendant and return true.

image

Simple and fast – the XAF way!

Sergej Derjabkin released his MapView module as a preview in eXpand v13.1.7.2 and asked me to get your feedback in order to develop further, so feel free to thank him personally and ask your questions or even contribute your code or ideas in eXpand forums. To see MapView module in action use the Demos/Modules/MapView/MapViewTester.sln found in eXpandFramework sources.

Subscribe to XAF feed
Subscribe to community feed

Δημοσίευση στην κατηγορία: ,
Web shortcuts supported!
22 Σεπτεμβρίου 13 05:10 μμ | tolisss | 0 σχόλια   

Using the next version 13.1.7.3 of eXpandFramework consider designing your shortcuts in a platform agnostic module because it will be possible to be used in your web apps as is!

To enable the web shortcuts you need to install the XpandSystemAspNetModule. If you want to disable them you can use the model setting you see below.

image

 

For this implementation I used the jwerty javascript library, however this library cannot detect successfully a few shortcuts used by the browser such as the Ctrl+N and the Ctrl+T. Therefore I added the CtrlNReplacement, CtrlTReplacement attributes you see in the image above. If you know a better library than jwerty that works better I can replace it at once.

Let me know your feedback in eXpand forums please

Happy XAF’ing to all!

Δημοσίευση στην κατηγορία:
How to manage users (register a new user, restore a password, etc.) from the logon form
19 Σεπτεμβρίου 13 06:45 πμ | tolisss | 0 σχόλια   

The excellent E4037 example from DevExpress Code Central is integrated with our community project (eXpandFramwork) in version 13.1.7.1.

Installation

This functionality is embedded in the XpandSecurityWinModule/XpandSecurityWebModule depending on the platform you use. All eXpand modules are in the toolbox for fast Drag & Drop installation.

image

Configuration

The configuration for this feature as excepted can be found in the XAF Application Model options node under the Registration sub node as illustrated below.

image

Attribute Enabled : Setting it to true two extra action Register and ForgotPassword will be activated in the Logon form as shown

image

image

UserModelClass: Here we can configure the type of user that will be created

EmailMember: This is a lookup of all members of UserModelClass and is only to save the email. 

RoleModelClass && RoleCriteria: Using those two attributes we can configure which roles will be assigned to the new registered user.

Hope you find it useful and you have a lot of feedback for it in eXpand forums.

p.s. : This implementation does not send registration or pass forgotten emails. I will release a new EmailModule following the workflow presented in Declarative data auditing. Do not forget that we are talking about highly extensible modules as all XAF modules are so, In the meantime it is really easy to write a controller and send the mail you like.

Forgot to mention that there is also Password Score model member attribute you can use to validate the new password against common limits like Very Weak, Weak, Strong etc.

Happy XAF’ing to all!

Δημοσίευση στην κατηγορία:
XAF community forums are OPEN!
16 Σεπτεμβρίου 13 06:25 πμ | tolisss | 0 σχόλια   

Although XAF has many communication channels like the official support center, the XAF facebook site, the eXpand forums etc. apparently there is a need for a forum dedicated only to XAF where people can discuss anything XAF related without either the XAF or the eXpand team will interfere unless explicitly requested of course.

So feel free to use this new forums I opened.

XAF Only Forums

Model View inheritance in next eXpandFramework version
30 Αυγούστου 13 02:35 μμ | tolisss | 0 σχόλια   

Right now in XAF it is possible to Clone an Application Model node by simply right click on it and choose Clone from the context menu. What will happen is that an identical node will be created. However by design, further modifications are not synchronized between mother-child nodes. I am going to demonstrate a different approach that does synchronize child nodes and you can find it in eXpandFramework 13.1.6.9 or later when using any module.

In the next image we see two Application Model views, first the MDO_DetailView -the base node- and then the RDO_DetailView which its ModelClass.Type descents from the MDO_DetailView ModelClass.Type.

image

In any Object View it is now possible to add MergeDifference items like the “Everything MDO” we see in the above picture. The Lookup datasource of the View attribute enumerates all views of the hierarchy chain of the current View.ModelClass.Type. For now, there are two Strategies (Everything and Only Layout). The merging algorithm will create a model node out of the differences of all loaded modules. For example the RDO_DetailView will have the modified/bold Layout of the MDO_DetailView layout as startup layout.

For any questions, feel free to use the eXpandFramework forums.

Happy XAF’ing to all!

Δημοσίευση στην κατηγορία: , ,
Declarative data auditing
20 Αυγούστου 13 02:09 μμ | tolisss | 0 σχόλια   

In this post I will provide a discussion on how to apply auditing configurations to your XAF applications, I will use the build-in XAF Audit Trail module and the eXpand Logic module for extending the XAF Application Model.

Goal

Our goal is to be able to declaratively configure auditing for different scenarios. For example apply an auditing configuration to a group of objects that fit in a criterion on a predefined group of views  only when these views are shown in the main window.

Background -The logic module

The logic module provides the API we will use to extend the Application Model. In eXpand there are a few modules which use this API. For example three of them live in the ModeArtifactState module. In the next image we can see the structure of two of them the ConditionalAction and  the ConditionalController.

image

Bellow there is the third child of the ModelArtifactState module ObjectView structure. I want to draw your attention to the common attributes we see in both images. All they come from the Logic Module which has the engine to evaluate them. Moreover the Logic module allows us to define permissions and class attributes using the same common attributes.

image

(AdditionalViewControls, MasterDetail and ModelAdaptor also attach them selves to the Logic Module)

Building a new Audit Trail Module

Using the Logic module is quite easy and the benefits too many. We will go through all the steps for creating an new AuditTrail module. Make a note that we discuss a workflow that can be applied to almost any scenario.

1) The startup interface

First off we need an interface that will be the AuditTrail Rule needed from the Logic Module. Let’s go to XAF Audit Trail documentation to read what we can use to design that interface. In order to attach to the Logic Module this interface needs to derive from ILogicRule interface. Bellow we see the IAuditTrailRule interface with one property the which we can use later to configure the AuditMode from the model or by using Role permissions.

public interface IAuditTrailRule:ILogicRule {

    ObjectAuditingMode? AuditingMode { get; set; }

}

2) The Rule context interface

public interface IContextAuditTrailRule : IAuditTrailRule, IContextLogicRule { 

}

The IContextAuditTrailRule provides information about contexts such as Execution, Action, View, Frame. In the top most images of this post you see that our model already has this information. However I mentioned before that the Logic Module supports permissions and class attributes. So the IContextAuditTrailRule will be implemented by the AuditTrailAttribute, and the permission classes which they need to know about context but not about model.

3) The model interfaces

[ModelInterfaceImplementor(typeof(IContextAuditTrailRule), "Attribute")]

public interface IModelAuditTrailRule : IContextAuditTrailRule, IModelConditionalLogicRule<IAuditTrailRule> {

}

The Logic module will extend the Application Model with the IModelAuditTrailRule and will give a structure similar to the one you saw in the top most images of this post. The IModelConditionalLogicRule comes from the Logic module so we only need to use here.

In addition to IModelAuditTrailRule interface we need to feed the Logic module with a list of IModelAuditTrailRules, so let’s design them.

[ModelNodesGenerator(typeof(LogicRulesNodesGenerator))]

public interface IModelAuditTrailLogicRules : IModelNode, IModelList<IModelAuditTrailRule> {

}

The LogicRulesGenerator is a class already implemented in the Logic Module and is needed only in the case we design a LogicRuleAttribute (see step 5)

Next, we need a container interface for the IModelAudiTrailLogicRules like the next one.

public interface IModelLogicAuditTrail : IModelLogicContexts {

    IModelAuditTrailLogicRules Rules { get; }

}

The IModelLogicContexts interface comes from the Logic module and it will provide all the context information that the IModelAuditTrail needs.

Finally, we need the root interface to extend the application model, as below.

public interface IModelApplicationAudiTrail:IModelNode {

    IModelLogicAuditTrail AudiTrail { get; }

}

public sealed class XpandAuditTrailModule :XpandModuleBase {

        public override void ExtendModelInterfaces(ModelInterfaceExtenders extenders) {

            base.ExtendModelInterfaces(extenders);

            extenders.Add<IModelApplication, IModelApplicationAudiTrail>();

        }

4) The Rule Object class

All rules from all sources (model, attributes, permissions) ultimately are converted to LogicRule object instances. The LogicRule abstract class lives in the Logic module. So, we need to design a concrete LogicRule class for the Audit Trail module like the one bellow.

public class AuditTrailRule:LogicRule,IAuditTrailRule {

        public AuditTrailRule(IContextAuditTrailRule auditTrailRule)

            : base(auditTrailRule) {

            AuditingMode=auditTrailRule.AuditingMode;

        }

 

        public ObjectAuditingMode? AuditingMode { get; set; }

The AuditTrailRule class must also implement the common IAuditTrailRule interface as the rest of the classes. Note that we also have to initialize any Audit Trail specific properties in the constrictor.

5) The class attribute (Optional)

Below is the AuditTrailRuleAttribute which must derive from the LogicRuleAttribute. The LogicRuleAttribute comes from the Logic module so we do not need to implement anything.

public sealed class AuditTrailRuleAttribute:LogicRuleAttribute,IContextAuditTrailRule {

    public AuditTrailRuleAttribute(string id) : base(id) {

    }

 

    public ObjectAuditingMode? AuditingMode { get; set; }

To map the AuditTrailRuleAttribute to the Application Model we need to derive from the LogicRuleNodeUpdater as below. The LogicRuleNodeUpdater is implemented in the Logic Module.

public class AuditTrailRulesNodeUpdater : LogicRulesNodeUpdater<IAuditTrailRule, IModelAuditTrailRule> {

    protected override void SetAttribute(IModelAuditTrailRule rule, IAuditTrailRule attribute) {

        rule.Attribute = attribute;

    }

 

}

6) The permission classes (Optional)

The design of the permission classes is equally simple. For example the permission must derive from LogicRulePermission and implement the IContextRule interface. Here the same as step 4 there is an extra step we need to initialize the properties in the ctor as you see below.

public class AuditTrailRulePermission:LogicRulePermission,IContextAuditTrailRule {

    public const string OperationName = "AuditTrail";

 

    public AuditTrailRulePermission(AuditTrailOperationPermissionData contextLogicRule)

        : base(OperationName, contextLogicRule) {

        AuditingMode=contextLogicRule.AuditingMode;

    }

 

    public override IList<string> GetSupportedOperations() {

        return new[] { OperationName };

    }

 

    public ObjectAuditingMode? AuditingMode { get; set; }

To finish the permission support, we need a concrete implementation of the LogicRuleOperationPermissionData which comes from the Logic module.

public class AuditTrailOperationPermissionData : LogicRuleOperationPermissionData,IContextAuditTrailRule {

    public AuditTrailOperationPermissionData(Session session) : base(session) {

    }

 

    public override IList<IOperationPermission> GetPermissions() {

        return new IOperationPermission[] { new AuditTrailRulePermission(this) };

    }

 

    public ObjectAuditingMode? AuditingMode { get; set; }

7) The Logic Installer

To finish with the structure of our custom Audit Trail module we need a concrete implementation of the LogicInstaller class like the next one.

public class AuditTrailLogicInstaller : LogicInstaller<IAuditTrailRule, IModelAuditTrailRule> {

    public AuditTrailLogicInstaller(IXpandModuleBase xpandModuleBase)

        : base(xpandModuleBase) {

    }

 

    public override List<ExecutionContext> ExecutionContexts {

        get { return new List<ExecutionContext> {ExecutionContext.ViewChanging}; }

    }

 

    public override LogicRulesNodeUpdater<IAuditTrailRule, IModelAuditTrailRule> LogicRulesNodeUpdater {

        get { return new AuditTrailRulesNodeUpdater(); }

    }

 

    protected override IModelLogicWrapper GetModelLogicCore(IModelApplication applicationModel) {

        var auditTrail = ((IModelApplicationAudiTrail)applicationModel).AudiTrail;

        return new ModelLogicWrapper(auditTrail.Rules, auditTrail);

    }

}

ExecutionContexts:

There I used an ExecutionContext.ViewChanging as my default context. You free to use any context its appropriate for your task. The logic engine will evaluate the IAuditTrailLogicRule only when ViewChaning.

LogicRulesNodeUpdater:

If you implement the optional AuditTrailLogicRuleAttribute you need to pass its model updater at this point.

GetModelLogicCore:

There we need to return a ModelLogicWrapper class with the IModelAuditTrailRules and the rest of the context. It is possible to share rules and contexts from any model path using a different contructor overload. For example we may design the IModelLogicAuditTrail interface like below.

public interface IModelLogicAuditTrail : IModelNode {

    IModelAuditTrailLogicRules Rules { get; }

    IModelExecutionContextsGroup ExecutionContextsGroup { get; }

}

So now the IModelLogicAuditTrail knows only about ExecutionContexts (no FrameTemplateContext, no Actions, no Views). For this configuration the appropriate ModelLogicWrapper instantiation is shown below.

protected override IModelLogicWrapper GetModelLogicCore(IModelApplication applicationModel) {

    var auditTrail = ((IModelApplicationAudiTrail)applicationModel).AudiTrail;

    return new ModelLogicWrapper(auditTrail.Rules, auditTrail.ExecutionContextsGroup);

}

Finally we need to register the installer in the contructor of our new module as shown below.

public sealed class XpandAuditTrailModule :XpandModuleBase {

    public XpandAuditTrailModule() {

        LogicInstallerManager.RegisterInstaller(new AuditTrailLogicInstaller(this));

    }

The Audit Trail structure is ready! Bellow we see the model  for an AuditTrailRule similar to the one of the top most images of this post.

 image

The Logic module knows what to do with all the attributes except the AuditingMode. Next we discuss how to write logic for this attribute.

The Audit Trail Logic

To write logic for the AuditTrailRule, we have to subscribe to LogicRuleViewController RuleExecture event. The LogicRuleViewController lives of course in the Logic module and we do not need to implement it.

public class AuditTrailRuleViewController:ViewController {

    LogicRuleViewController _logicRuleViewController;

    ObjectAuditingMode _oldObjectAuditingMode;

 

    protected override void OnFrameAssigned() {

        base.OnFrameAssigned();

        Frame.Disposing+=FrameOnDisposing;

        _logicRuleViewController = Frame.GetController<LogicRuleViewController>();

        _logicRuleViewController.LogicRuleExecutor.LogicRuleExecute+=LogicRuleExecutorOnLogicRuleExecute;

    }

 

    void FrameOnDisposing(object sender, EventArgs eventArgs) {

        Frame.Disposing-=FrameOnDisposing;

        _logicRuleViewController.LogicRuleExecutor.LogicRuleExecute -= LogicRuleExecutorOnLogicRuleExecute;

    }

 

    void LogicRuleExecutorOnLogicRuleExecute(object sender, LogicRuleExecuteEventArgs logicRuleExecuteEventArgs) {

        var logicRuleInfo = logicRuleExecuteEventArgs.LogicRuleInfo;

        var auditTrailRule = logicRuleInfo.Rule as IAuditTrailRule;

        if (auditTrailRule != null) {

            if (!logicRuleInfo.InvertCustomization) {

                ApplyCustomization(auditTrailRule);

            } else {

                InvertCustomization(auditTrailRule);

            }

        }

    }

 

    void InvertCustomization(IAuditTrailRule auditTrailRule) {

        var auditTrailService = AuditTrailService.Instance;

        if (auditTrailRule.AuditingMode.HasValue)

            auditTrailService.ObjectAuditingMode = _oldObjectAuditingMode;

 

    }

 

    void ApplyCustomization(IAuditTrailRule auditTrailRule) {

        var auditTrailService = AuditTrailService.Instance;

        if (auditTrailRule.AuditingMode.HasValue) {

            _oldObjectAuditingMode = auditTrailService.ObjectAuditingMode;

            auditTrailService.ObjectAuditingMode = auditTrailRule.AuditingMode.Value;

        }

    }

LogicRuleExecutorOnLogicRuleExecute method:

This method will be called for all ILogicRule interfaces, for example the new IAuditTrailRule and if you use the MasterDetail module the IMasterDetailRule. So first thing is to cast the returned Rule to IAuditTrailRule and if not it’s the right place to write our logic. In step 7 in the AuditTrailInstaller we used only ExecutionContext.ViewChaning so this method will be called only when ViewChanging and rule is IAuditTrailRule. In addition the LogicRuleInfo provides information about inverting any customization. 

Audit Trail Rules in Action

In next eXpandFramework version 13.1.6.3 the Audit Trail is fully functional. More attributes are included and also an IModelMemberAuditTrail to allow creation of the collection needed to monitor auditing from the UI.

In the next image we see a rule that will force the Auditing service to use LightWeght mode for all objects.

image

Next is a rule applied directly to the Customer class that will audit the members included in the Customer_LastName_Age_Group in all Customer DetailViews

[AuditTrailRule("Audit_Customer", AuditTrailMembersContext = "Customer_LastName_Age_Group",ViewType = ViewType.DetailView)]

public class Customer : Person {

here is the rule that the Logic module will generate for the above AuditTrailAttribute.

image

and finally using permissions a rule that will audit Employee members under the “Emplyee_Members” context.

var permissionData = ObjectSpace.CreateObject<AuditTrailOperationPermissionData>();

permissionData.ObjectTypeData = typeof (Employee);

permissionData.ID = "audit_emplyee";

permissionData.AuditTrailMembersContext = "Employee_Members";

((XpandRole) userRole).Permissions.Add(permissionData);

You can explore how this module works in Demos/Modules/AuditTrail/AuditTrailTester.sln

Until next time,

Happy XAF’ing!

Δημοσίευση στην κατηγορία: ,
Conditional assemblies merged in ModelArtifact in 13.1.6
14 Αυγούστου 13 07:01 μμ | tolisss | 0 σχόλια   

Hello all,

The following modules do not exist anymore in 13.1.6.1

ConditionalActionState, ConditionalControllerState, ConditionalObjectView now are under the ModelArtifact omprella.

Also Logic.Win merged with Logic module. So you need to remove all code and change the usings in case you have them install in your projects.

There are a few breaking changes in 13.1.6.1, so please post in the forums in case you get lost with the new super fast and flexible logic ruling engine.

In short everything that has to do with Logic Rules is now handled by the logic modules and there are a few classes like LogicRuleManager, LogicInstallerManager, LogicRuleCollector, LogicRuleEvaluator etc that do all the hard job. The design now is very clean and easy to follow and I am sure it will reduce many strange issues we had and will help to build new modules based on the Logic engine!

Δημοσίευση στην κατηγορία:
Flexible-fast layouts with CSS styles in the XAF application model
06 Αυγούστου 13 05:20 μμ | tolisss | 0 σχόλια   

XAF has a build-in mechanism for customizing the layout’s. However nothing can be compared with the power of native CSS styles. In this post I will discuss eXpand’s implementation of CSS styles in the XAF application model.

How XAF renders a layout

To render a web layout XAF uses the WebLayoutManager class. This class queries all the IModelViewLayoutElements of a DetailView.Model.Layout and renders WebControls accordingly. For example for an IModelLayoutViewItem which is an interface that links the layout element with a property editor, the WebLayoutManager will render two controls. The first one will hold the caption/label and the second one will be the actual control depending on the type of the property editor. Take a look how an looks IModelLayoutViewItem in the Model Editor.

image

As you can see XAF supports a lot of attributes by default! Due to the large number of attributes WebLayoutManager introduces a table to hold and position our controls and a div above it to allow more flexibility in configuration.

It is also possible to use more more interfaces to design a layout. In the next image we see what is supported by default. However WebLayoutManager behavior is the same.

image

 

What we need to style?

Of course everything fast-flexible and without introducing complexities and XAF application model is the perfect tool for this. To summurize the previous paragraph we may wish to style

  1. The actual WebControl
  2. The label of the WebControl
  3. The container table
  4. The container div
  5. The whole view

How we get control instances

All XAF controls are rendered by property editors. For the web there is an abstract WebPropertyEditor (see a simplistic inheritance view).
image
It is enough to create a Controller then query all WebPropertyEditor ViewItems and subscribe to ControlCreated event. When the event raised we can do webPropertyEditor.Control and get the instance we need. Let’s see this a pseudo code snippet.

public class LayoutStyleController:ViewController<DetailView>,IModelExtender {

 

    protected override void OnActivated() {

        base.OnActivated();

        foreach (var item in View.GetItems<WebPropertyEditor>()) {

            item.ControlCreated+=ItemOnControlCreated;

        }

    }

 

    void ItemOnControlCreated(object sender, EventArgs eventArgs) {

        var webPropertyEditor = ((WebPropertyEditor) sender);

        webPropertyEditor.ControlCreated-=ItemOnControlCreated;

     //here we have our webcontrol  instance

        var control = webPropertyEditor.Control;

    }

How to get the layout container

WebLayoutManager is designed with the highest standards, so it is as easy as subscribing to its LayoutCreated event and getting the value of the Container property

protected override void OnActivated() {

    base.OnActivated();

    View.LayoutManager.LayoutCreated += LayoutManager_LayoutCreated;

}

 

void LayoutManager_LayoutCreated(object sender, EventArgs e) {

    View.LayoutManager.LayoutCreated-=LayoutManager_LayoutCreated;

     //here we have our webcontrol  instance

    WebControl container = (WebControl) View.LayoutManager.Container;

}

How to get the rest of the objects we need to style

All the rest are only known from the WebLayoutManager which renders them using an advanced template mechanism. It is of course possible to override it however I want to continue working with pluggable controllers. So I will create an interface to help me parse those templates from a Controller.

public interface IWebLayoutManager {

    event EventHandler<TemplateInstantiatedEventArgs> Instantiated;

}

 

public class XpandLayoutManager : WebLayoutManagerIWebLayoutManager {

    ViewItemsCollection _detailViewItems;

 

    public event EventHandler<TemplateInstantiatedEventArgs> Instantiated;

 

    protected virtual void OnInstantiated(TemplateInstantiatedEventArgs e) {

        var handler = Instantiated;

        if (handler != null) handler(this, e);

    }

    protected override LayoutBaseTemplate CreateLayoutItemTemplate() {

        var layoutBaseTemplate = base.CreateLayoutItemTemplate();

        layoutBaseTemplate.Instantiated += LayoutBaseTemplateOnInstantiated;

        return layoutBaseTemplate;

    }

 

    protected override LayoutBaseTemplate CreateLayoutGroupTemplate() {

        var layoutBaseTemplate = base.CreateLayoutGroupTemplate();

        layoutBaseTemplate.Instantiated += LayoutBaseTemplateOnInstantiated;

        return layoutBaseTemplate;

    }

    void LayoutBaseTemplateOnInstantiated(object sender, TemplateInstantiatedEventArgs templateInstantiatedEventArgs) {

        OnInstantiated(templateInstantiatedEventArgs);

    }

Also I need to plug this custom XpandLayoutManager to my WebApplication descendant as below.

public class XpandWebApplication : WebApplication {

    protected override LayoutManager CreateLayoutManagerCore(bool simple) {

        return new XpandLayoutManager();

    }

Now it is possible to subscribe to to XpandLayoutManager Instanciated event from a controller and parse the templates to discover the label, the container table and the container div.

Extending the model

Having all the WebControls instances we want to style it is time to extend the model with a few interfaces so to control the styling from there. Bellow is the interface we need

public interface IModelLayoutStyle : IModelNode {

    FontStyle FontStyle { get; set; }

    Color FontColor { get; set; }

    Color BackColor { get; set; }

    string CssClass { get; set; }

    string Style { get; set; }

}

This interface can be used to extend IModelDetailView and IModelLayoutGroup to control the style of the whole view and of a grouped layout element as illustrated below.

public class LayoutStyleController:ViewController<DetailView>,IModelExtender {

     public void ExtendModelInterfaces(ModelInterfaceExtenders extenders) {

         extenders.Add<IModelDetailView, IModelLayoutStyle>();

         extenders.Add<IModelLayoutGroup, IModelLayoutStyle>();

     }

Now for the IModelLayoutViewItem as we discussed in the beginning there are three controls we need to style (actual, label and container). So we need to introduce another interface and to extend the IModelLayoutViewItem like the next one.

public interface IModelLayoutViewItemStyle {

    ILayoutStyle LayoutStyle { get; }

}

 

public interface ILayoutStyle:IModelNode {

    IModelLayoutStyle Container { get;  }

    IModelLayoutStyle Control { get;  }

    IModelLayoutStyle Caption { get; }

}

After extending the IModelLayoutViewItem the Model Editor now will display the next structure.

image

Finally it’s time to write the StyleProvider class and put them all in a reusable controller. However I will skip adding so much code in a post and I will redirect you to eXpandFramework GitHub repository (just grab the LayoutStyleController.cs  and extend the WebLayoutManager as  discussed above).

Demo

Bellow you can see a cool view a designed with the CSS in Application Model and as always with zero code lines.

image

Those of you that come often to eXpand forums will recognize for sure that this is a replicate of the Kunena forums (see for your self Smile)!

image

This functionality is available with eXpandFramework 13.1.5.19.

Until next time,

Happy XAF’ing to all!

Δημοσίευση στην κατηγορία:
Creating object relationships using the application model
28 Ιουλίου 13 06:46 μμ | tolisss | 0 σχόλια   

In next version of eXpandFramework 13.1.5.13 it will be possible to create associations between business objects. Let’s see in details how this will work.

1. Installation – Prerequisites

The runtime members can be found in the eXpand.ExpressApp assembly, therefore you need to install the XpandSystemModule. However because this assembly has platform specific versions you will not find it in the toolbox and you have to go for its win or web version which is XpandSystemWindowsFormsModule or XpandSystemAspNetModule. To see how easy it is to install the XpandSystemWindowsFormsModule watch the next video. Note that it is also possible to create object relationship for the web.

2. Simple association

In the next video you can see how we can create a relationship between two entities at runtime. To be more specific I will create a relationship between the TopicIcon and The Category business objects. I already have a sample application and logged in as the Admin user so the relationship I will create it will be stored in Admin’s user model. 

3. Creating the many part of the relation

In the next video instead of working with XAF’s default model editor, we will use the ModelDifference module. XAF’s Application Model is by design multi layered and the ModelDifference module exposes this functionality in a more business oriented approach. It is also faster to work with it because as you can watch in the video I only execute the save action without even reloading the model! Even if the ModeDifference module introduces the concept of application models, I am going to use again Admin’s model and I will create an Icons collection for the Category object and I will link the reference TopicIcon Category property I created in previous video. Note to install the ModelDifference module you need to go through the exact steps of step one but this time for the ModelDifferenceWindowsFormsModule.

4. Creating an Orphaned Collection

An orphaned collection does not participate in a relationship however it is possible to be filters. In step three I linked a TopicIcon with a Category and also added a TopicIcon to the same Category instance. Both TopicIcons were of Type Idea. Now I will create an Orphaned collection of all TopicIcons with Type Idea and I will add it to the Category_DetailView.

5. Distributing the Application Model

We already created our relationships in the Admin’s model. However, this means that they can be used only for the Admin user. To confirm this in the next video I will give Edit Model permissions to a normal user and I will login to explore his model. Then I will switch back to the Admin which has permissions to modify ModelDifference module objects. Next I will create a Role model by cloning one of the existing models. Finally I will associate the Role model with the users Role, I will merge it with the Admin’s model and switch back to the User to confirm that he also can see the same as the admin.

Forgot to mention that runtime member creation is now very fast thanks to Sandrowelter (see this thread in eXpand forums).

Happy XAF’ing to all!

Δημοσίευση στην κατηγορία:
Runtime views created from business users
16 Ιουλίου 13 10:23 πμ | tolisss | 0 σχόλια   

You all know the powerful Application Model Editor with the embedded layout control that allows view creation without any technical knowledge. However the Model Editor is so powerful that may be dangerous to allow access to everybody. A few years now in eXpand we have the XpandViewVariants module that allowed end users to build views without the model editor. This modules is based in XAF’s built-in ViewVariants module and the XAF team is constantly improving it. However eXpand resources are not so huge so our module was a bit outdated.

Today things changed, because I spend some hours to refactor the ModifyVariantsController and now can do magic. if you using eXpand you only need to install XpandViewVariants module, if not and thanks to XAF’s MVC architecture just grab the controller for eXpand’s online repository http://goo.gl/mnFR7 or even follow its history http://goo.gl/CPx5A.

Now simply watch the next video to see that this controller can do for you.http://screencast.com/t/nrELagRJBhY

P.S.: We really appreciate your input in our latest surveys we run for both XAF and eXpand. If you haven’t participate yet please see this post

http://apobekiaris.blogspot.ru/2013/07/poll-which-of-following-expand.html.

Comments as always in eXpand forums Smile, here a related thread http://goo.gl/cQ05p.

Δημοσίευση στην κατηγορία:
Anonymous authentication for XAF aps.net applications
14 Ιουλίου 13 05:21 μμ | tolisss | 0 σχόλια   

As promised  in eXpand’s forums with next version of eXpand (13.1.5.8) you can enjoy anonymous authentication for your web applications!

The anonymous authentication functionality is embedded in Xpand.ExpressApp.Security.Web module. After installing this module you need to enable it and setup the anonymous username using XAF’s Application Model Editor.

image

It is possible and recommended to combine anonymous authentication with auto-authentication discussed in http://apobekiaris.blogspot.gr/2013/07/auto-authentication-rememberme-for-your.html. Note that the model of the previous post is refactored to allow each feature to work independently.

image

Next you need to configure XAF’s security system by setting up the Authentication and the LogonParameters as illustrated in the image bellow.

image

 

And finally you need to create the anonymous user and role in your ModuleUpdater.cs. For this and if your use XpandRole class I provided the next extensions methods (GetAnonymousRole, GetAnonymousUser).

void CreateAnonymousSecurityObjects() {

    var anonymousRole = ObjectSpace.GetAnonymousRole("Anonymous");

    anonymousRole.GetAnonymousUser();

 

    //add project specific permissions

    anonymousRole.SetTypePermissions<Category>(SecurityOperations.ReadOnlyAccess, SecuritySystemModifier.Allow);

    anonymousRole.SetTypePermissions<Topic>(SecurityOperations.Read, SecuritySystemModifier.Allow);

The GetAnonymousRole method will create a new XpandRole (if not exists) and will add two custom permissions the MyDetailsPermission that will hide MyDetails from anonymous role and the AnonymousLoginPermission. It is also possible to do the same using XAF’s UI as in the next image.

image

Moreover I want to mention that using XpandRole is not mandatory, I used it because of the built-in support for custom permissions. You may have your own implementation following for example How to: Implement Custom Permission, Role and User Objects so feel free to use them.

Together with the MyDetailsPermission I mentioned the AnonymousLoginPermission. This one is responsible for hiding the default XAF’s Logoff action and for providing a new LoginAnonymous action. So when someone visits your site and you use Xpand.ExpressApp.Security.Web with enabled anonymous access, by default XAF will authenticate the anonymous user you created in the ModuleUpdater, and with the LoginAnonymous action will allow authentication as provided by XAF.

image

That was it my friends! I hope you find this implementation easy to use and useful. For questions, feedback etc feel free to use eXpand forums.

 

Happy XAF’ing to all!

Δημοσίευση στην κατηγορία: ,
Auto authentication + rememberme for your XAF web apps coming
10 Ιουλίου 13 03:24 μμ | tolisss | 0 σχόλια   

In next version 13.1.5.2 of eXpandframework there is a new Security module for web (Xpand.ExpressApp.Security.Web.dll) that can automatically logon using forms authentication. It is based on the CanAutomaticallyLogonWithStoredLogonParameters functionality of XAF web apps.

Installation

To use it simply install the Xpand.ExpressApp.Security and use the XpandLogonParameters object in your authentication type

image

To enable this functionality as usual we need to use XAF’s Application Model editor.

image

As you can see in the image above it is possible to control the ticket expiration as well.

By default XpandLogonParameters will render a RememberMe checkbox

image

However again using Model Editor we can simply remove the RememberMe PropertyEditor and the auto authentication will work for any user logged in last!

image 

Happy XAFing to everyone! and do not forget your input in our forums http://www.expandframework.com/forum/11-news/3452-auto-authenticate-and-remember-me.html#4007

P.S.: Here is the related code in our github repo http://goo.gl/XfIPC

Δημοσίευση στην κατηγορία: , , ,
Poll - Which of the following eXpand modules/feautres do you use most?
09 Ιουλίου 13 05:39 πμ | tolisss | 0 σχόλια   

Our community project (www.eXpandframework.com) is growing fast and thanks everybody for the contribution and trust! However in order to use our limited resources better and make some plans for the future I would to ask your participation in the following survey.

I would like to ask your input one more time in the following survey: Click here to take survey

Δημοσίευση στην κατηγορία:
Which eXpand module/feature do you use most?
09 Ιουλίου 13 05:14 πμ | tolisss | 0 σχόλια   

Our community project (www.eXpandframework.com) is growing fast and thanks everybody for the contribution and trust! However in order to use our limited resources better and make some plans for the future I would to ask your participation in the following survey.

I would like to ask your input one more time in the following survey: Click here to take survey

Δημοσίευση στην κατηγορία:
DetailView as a PreView in GridView
09 Ιουλίου 13 04:30 πμ | tolisss | 0 σχόλια   

Recently I had the need to display a complex layout as a preview row in my AspxGridView. Instead of adding a nonpersistent property where I will construct the html I though it would be easier to simply use XAF’s ModelEditor to design a DetailView and then assign that in my preview row.

After one hour or less I ended up with this controller.

    [ModelAbstractClass]

    public interface IModelListViewPreviewRowDetailView : IModelListView {

        [DataSourceProperty(ModelViewsDomainLogic.DataSourcePropertyPath)]

        [DataSourceCriteria(ModelObjectViewDomainLogic.ModelViewsByClassCriteria)]

        [Category("eXpand")]

        IModelDetailView PreviewRowDetailView { get; set; }

    }

 

    public class PreviewRowDetailViewController:ViewController<ListView>,IModelExtender {

 

        protected override void OnViewControlsCreated() {

            base.OnViewControlsCreated();

            var previewRowDetailView = ((IModelListViewPreviewRowDetailView) View.Model).PreviewRowDetailView;

            if (previewRowDetailView!=null) {

                var gridView = ((ASPxGridListEditor) View.Editor).Grid;

                gridView.Templates.PreviewRow = new PreviewRowTemplate(Application,ObjectSpace,previewRowDetailView.Id);

                gridView.Settings.ShowPreview = true;

            }

        }

 

        class PreviewRowTemplateITemplate {

            readonly XafApplication _xafApplication;

            readonly IObjectSpace _objectSpace;

            readonly string _viewId;

 

            public PreviewRowTemplate(XafApplication xafApplication, IObjectSpace objectSpace, string viewId) {

                _xafApplication = xafApplication;

                _objectSpace = objectSpace;

                _viewId = viewId;

            }

 

            void ITemplate.InstantiateIn(Control container) {

                var templateContainer = (GridViewPreviewRowTemplateContainer) container;

                object obj = templateContainer.Grid.GetRow(templateContainer.VisibleIndex);

                var detailView = ViewFactory.CreateDetailView(_xafApplication, _viewId, _objectSpace, obj, false);

                detailView.CreateControls();

                templateContainer.Controls.Add((Control) detailView.Control);

            }

 

        }

 

        public void ExtendModelInterfaces(ModelInterfaceExtenders extenders) {

            extenders.Add<IModelListView, IModelListViewPreviewRowDetailView>();

        }

    }

In the image bellow you can see a ListView of DetailViews Smile

image

In next image you can see how simple is to configure this all thanks to XAF Application Model.

image

The controller of course now lives in www.expandframework.com and you can follow its history in our online repository.

http://goo.gl/oCJ1J

This is not a perfect solution, however it does its job. I also posted in eXpand forums where we can all discuss further improvements

http://www.expandframework.com/forum/11-news/3443-detailview-as-previewrow.html#3988

Δημοσίευση στην κατηγορία:
Security in On-line shop? Easily!
24 Μαΐου 13 06:26 πμ | tolisss | 0 σχόλια   

I can think many reason why Security is necessary when developing even the simplest online shop backend. I will not elaborate them but I will concentrate on how to empower the application prototype we created for our DXSK8 e-shop with a flexible Security System. Note that after this we really close to first paycheck Winking smile

I remind you that in previous post we applied a XAF layer(rich application) over an EF model located in an external lib (DSK8.Service). Now we will extend the same EF model to support XAF’s Security System.

1) Design Entity Framework Model for the Security System objects.

XAF’s Security system uses Users, Roles and Permissions to configure both the data access and the UI generation for both platforms! This is done with the help of a few system interfaces such as :
User: ISecurityUser, IAuthenticationStandardUser, IOperationPermissionProvider
Role:, IOperationPermissionProvider.

Our EF model from the DXSK8.Service project already contains an Employee entity which is perfect to take the role of XAF’s system user. Therefore, first we need to add all public properties of the user depended interfaces to our Employee entity. Do not worry XAF interfaces are well designed and its just 3 properties as you see below. The UserName in the black frame already existed in our Login entity that's why is not in the Employee entity with the rest of the new fields. However XAF has no problem to understand it as is!

image

Next step is to design the Roles and Permissions objects. I will go only for a Type Permission system although XAF supports member level and criteria based as well. So I only need the bellow Roles, TypePermissionObject entities.

image

The database migration should be done as suggested from EF and I will not elaborate but I followed a standard technic as the one described in Code First Migrations. 

Note: We also need to use partial classes to implement the consumed interfaces however their implementation is rather easy and reusable for example let’s see how easy it is to implement the Employee interfaces. For Role, TypePermissionObject implementation please check post’s sample (See also How to: Implement Custom Security Objects (Users, Roles, Operation Permissions))).

[ImageName("BO_User"), DefaultProperty("UserName")]

public partial class Employee : ISecurityUserIAuthenticationStandardUser,

                                IOperationPermissionProvider {

 

    #region IOperationPermissionProvider

    IEnumerable<IOperationPermissionProvider> IOperationPermissionProvider.GetChildren() {

        if (!Roles.IsLoaded) {

            Roles.Load();

        }

        return new EnumerableConverter<IOperationPermissionProvider, Role>(Roles);

    }

 

    IEnumerable<IOperationPermission> IOperationPermissionProvider.GetPermissions() {

        return new IOperationPermission[0];

    }

    #endregion

    #region ISecurityUser

    Boolean ISecurityUser.IsActive {

        get { return IsActive.HasValue && IsActive.Value; }

    }

 

    String ISecurityUser.UserName {

        get { return UserName; }

    }

    #endregion

 

    #region IAuthenticationStandardUser

    Boolean IAuthenticationStandardUser.ComparePassword(String password) {

        var passwordCryptographer = new PasswordCryptographer();

        return passwordCryptographer.AreEqual(StoredPassword, password);

    }

 

    public void SetPassword(String password) {

        var passwordCryptographer = new PasswordCryptographer();

        StoredPassword = passwordCryptographer.GenerateSaltedPassword(password);

    }

 

    Boolean IAuthenticationStandardUser.ChangePasswordOnFirstLogon {

        get { return ChangePasswordOnFirstLogon.HasValue && ChangePasswordOnFirstLogon.Value; }

        set { ChangePasswordOnFirstLogon = value; }

    }

 

    String IAuthenticationStandardUser.UserName {

        get { return UserName; }

    }

    #endregion

 

}

2)  Install XAF Security System

Although XAF has strong design time support I will go through this step using one line of code in both Program.cs and Global.asax.cs just before application.Setup() call.

application.Security = new SecurityStrategyComplex(typeof(DXSK8.Service.Employee), typeof(DXSK8.Service.Role), new AuthenticationStandard());

application.Setup();

The above snippet will apply a security strategy using the Entity Framework entities located in the external DXSk8.Service lib . For this type of security strategy XAF spares our time as usual and will automatically display a customizable credentials window for both platforms,

 

image

image

 

In addition XAF will detect the custom Security EF Entities we designed in step 1 and will auto populate the navigation menu.

 

Win
image
Web
image
   

 

3) Supply initial data

Always when installing a security system make sure that some one knows the password Smile. We forgot to add at least a user with admin privileges. For this job an appropriate event to use is XafApplication’s CustomCheckCompatibility event inside our platform agnostic module.

 

public override void Setup(XafApplication application) {

    base.Setup(application);

    application.CustomCheckCompatibility+=ApplicationOnCustomCheckCompatibility;

    application.CreateCustomObjectSpaceProvider += ApplicationOnCreateCustomObjectSpaceProvider;

}

 

void ApplicationOnCustomCheckCompatibility(object sender, CustomCheckCompatibilityEventArgs e) {

    var objectSpace = e.ObjectSpaceProvider.CreateUpdatingObjectSpace(true);

    var updater = new Updater(objectSpace, Version.Parse("1.0.0.0"));

    updater.UpdateDatabaseAfterUpdateSchema();

}

and the UpdateDatabaseAfterUpdateSchema where we created:
a) A Content Manager role with CRUD on Product but ReadOnly on Orders/Employees

b) A Sales Manager role wirh CRUD on Order but ReadOnly on Product/Employees

public override void UpdateDatabaseAfterUpdateSchema() {

    base.UpdateDatabaseAfterUpdateSchema();

    if (ObjectSpace.FindObject<Employee>(CriteriaOperator.Parse("UserName=?","Admin")) == null) {

        var roleAndUser = CreateRoleAndUser("Admin");

        roleAndUser.IsAdministrative = true;

        CreateRole("Content Manager", new[]{

            CRUDPermission(typeof(Product)),

            ReadOnlyPermission(typeof(Order)),

            ReadOnlyPermission(typeof(Employee))

        });

 

        CreateRole("Sales Manager", new[]{

            CRUDPermission(typeof(Order)),

            ReadOnlyPermission(typeof(Product)),

            ReadOnlyPermission(typeof(Employee))

        });

 

        var employees = ObjectSpace.GetObjects<Employee>();

        foreach (var employee in employees) {

            employee.IsActive = true;

            employee.ChangePasswordOnFirstLogon = true;

        }

 

        ObjectSpace.CommitChanges();

    }

}

In post’s sample you can explore the implementation of the rest of the methods which is really simple.

 

The rest of the job needs a business user to simply associate Employees with Roles using XAF’ well thought UI. For example in the next two shots we see how to assign a Content Manager Role to a list of users.

 

image

image

Conclusion

Trying to focus in solving business problems with the help of technology is hard. Therefore tools like XAF that bridge those two worlds are like god gifts. We saw how easy was to integrate a complex and sensitive feature like security while working with EF as datalayer. Thanks to the flexible and well designed XAF our product now can be market easier since it features a complete security system.

This time I will close with a phrase I hear constantly from our customers lately:

XAF really works!

Download sample from here and attach the mdf file found in DXSK8.Service/App_Data folder to your SQL instance. Also make sure you already visit How to: Get Started with the Entity Framework Model First in XAF to be sure you know the basics.

.

Δημοσίευση στην κατηγορία: ,
UI Annotation using Business Rules
01 Μαΐου 13 11:51 μμ | tolisss | 0 σχόλια   

XAF already provides strong and flexible validation for any object that fits specified Rules with build-in the Validation Module. In this post you can find a sample XAF application which extends the Validation to provide support for Warning/Information messages.

The implementation uses any Validation Business Rule that exists in XAF’s Application Model. Below we see the default ones but its applicable to custom business rules as well.

image

The sample code extends the Application Model of IModelRuleBase and by using one more property like RuleType marks the rule as warning or information as shown:

image

When the Validation occurs this implementation will not raise exceptions for Warning and Information Rules and will change their notification icon accordingly.

Windows

image

Web

image

By default, it is also possible to create business rules that evaluated when an object is changed  by using the ObjectSpaceObjectChanged custom context (see also Contextual Validation Concepts).

To use this RuleType functionality discussed today in your XAF Applications you need to download the sample from RuleType.zip. The functionality is described by just one controller in RuleTypeController.cs which is spanned across the platform agnostic and platform depended projects.

Note: I “borrow” the code for RuleType support from our community project expandframework and for one more time we clearly see how flexible is XAF and how powerful to provide reusable solutions!

P.S.: The original eXpand implementation has code support using a RuleTypeAttribute as well as ListView support and can be found in Xpand.ExpressApp.Validation, Xpand.ExpressApp.Validation.Win and Xpand.ExpressApp.Validation.Web assemblies (See also this discussion in eXpand’s forums).

Δημοσίευση στην κατηγορία: ,
Dressing up an Entity Framework model with a rich app UI in 5 min
17 Απριλίου 13 04:36 πμ | tolisss | 0 σχόλια   

Imagine that we have already build a mobile app using DXTREME such as the DXSK8 demo and already have a ready-to-use Entity Framework data model. Now we are faced with a task to provide a rich administrative application that will be mainly used in Intranet from the desktop (Windows) or web browser. This application should have a typical CRUD UI for managing goods in an online shop, content on our main web site, etc. and of course have potential for future extensibility and customization by a customer request. Following the instructions of this post it should be easy to do it your self from scratch in less than five minutes! (Sample app at then end of this post).

1) Create a XAF Cross-platform application

Create a new XAF solution called DXSK8.Admin by using the DXperience v12.2 XAF Cross-Platform Application project template as shown below.

image

Below we see the created solution which contains two ready to run XAF applications (DXSK8.Admin.Win, DXSK8.Admin.Web) and three empty XAF modules where the DXSK8.Admin.Module is the platform agnostic one. We are going to work in the platform agnostic module because we want to minimize code duplication between our Win and Web XAF applications.

image

2) Adding Entity Framework model types to XAF

XAF auto generates rich CRUD UI for our data using our award-winning DevExpress visual components. However our Entity Framework model is located in an external library so in our platform agnostic module we need to reference the EF model container which is the DXSK8.Service assembly along with the System.Data.Entity and DevExpress.ExpressApp.EF assemblies.

image

Next its time to add the all the EF model entities in our application business model by using the following code in the constructor of this platform agnostic module.

image

public sealed partial class AdminModule : ModuleBase {

    public AdminModule() {

        InitializeComponent();

        AdditionalExportedTypes.Add(typeof(DXSK8.Service.Customer));

        AdditionalExportedTypes.Add(typeof(DXSK8.Service.Address));

        AdditionalExportedTypes.Add(typeof(DXSK8.Service.Brand));

        AdditionalExportedTypes.Add(typeof(DXSK8.Service.Employee));

        AdditionalExportedTypes.Add(typeof(DXSK8.Service.ImageSource));

        AdditionalExportedTypes.Add(typeof(DXSK8.Service.Login));

        AdditionalExportedTypes.Add(typeof(DXSK8.Service.NotificationChannel));

        AdditionalExportedTypes.Add(typeof(DXSK8.Service.Order));

        AdditionalExportedTypes.Add(typeof(DXSK8.Service.OrderItem));

        AdditionalExportedTypes.Add(typeof(DXSK8.Service.Person));

        AdditionalExportedTypes.Add(typeof(DXSK8.Service.Product));

        AdditionalExportedTypes.Add(typeof(DXSK8.Service.ProductFlavor));

        AdditionalExportedTypes.Add(typeof(DXSK8.Service.ProductType));

        AdditionalExportedTypes.Add(typeof(DXSK8.Service.Store));

    }

As a result now the XAF Application Model contains all types from the EF model and we are ready to use it we are ready to modify the auto generated Views, define the navigation structure or empower our app with built-in or open source modules.

image image

For example in the sample app in the end of the post we used the Model Editor to modify the model of the platform agnostic module and create a Navigation menu for both platforms as shown:

image

Note: Creating Navigation Items is fully described in XAF docs (Add an Item to the Navigation Control). In addition you can find a detail tutorial and a big list of How To that can help you get the most out of XAF really fast!

3) Switch the Application to Using the Entity Framework

We continue to work in the platform agnostic DXSK8.Admin.Module. To use the EFObjectSpace instances to access data we need to provide an IObjectSpaceProvider implementation designed for EF and located in DevExpress.ExpressApp.EF assembly. For this we need to modify again our Module.cs codebehind class as shown.

Note that EFObjectSpaceProvider’s first parameter is Entity Framework’s ObjectContext implementation from DXSK8.Service project.

    public override void Setup(XafApplication application) {

        base.Setup(application);

        application.CreateCustomObjectSpaceProvider += ApplicationOnCreateCustomObjectSpaceProvider;

    }

 

    void ApplicationOnCreateCustomObjectSpaceProvider(object sender, CreateCustomObjectSpaceProviderEventArgs e) {

        var typesInfo = (TypesInfo)Application.TypesInfo;

        const string metadata = "res://*/SK8Data.csdl|res://*/SK8Data.ssdl|res://*/SK8Data.msl";

        const string provider = "System.Data.SqlClient";

        var objectContextType = typeof(DXSK8.Service.SK8DataContainer);

        e.ObjectSpaceProvider = new EFObjectSpaceProvider(objectContextType, typesInfo, null, e.ConnectionString, metadata, provider);

    }

Note: XAF will not modify the schema of your existing database!

Conclusion

Microsoft recommends when accessing data to use Entity Framework, which from v5 is open sourced and has an unlimited list of add-ons and really big audience. We used this amazing technology to create the DXSK8 data service and in this post we demoed how to use XAF with three simple steps to manage its content by creating rich CRUD UI views as below on the spot. Therefore it should be clear that we can deliver app prototypes for our EF models really fast and our end users can enjoy access to their data with modern UI look & feel from day one! Note that XAF has a lot of build-in and open sourced modules that can be install with a simple drag and drop and can save you months of work.

In the next images we see two of the default auto generated XAF CRUD Views one for each platform (Win and Web).

image

image

For those of you that you have Entity Framework models and you want to try these instructions on them you may download an XAF trial from here.

Sample Download (Contains DXSK8.Service project as well).

In next post we will continue with a discussion over reusable EF models in XAF stay tuned!

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

Until next time,

Happy XAF’ing!

Subscribe to XAF feed
Subscribe to community feed

Δημοσίευση στην κατηγορία: ,
Migrating a legacy real world application
15 Απριλίου 13 02:56 πμ | tolisss | 0 σχόλια   

Recently we made the decision to clone our Winforms VideoRent real world application and create a new XAF application – the XVideoRental. Wearing my LEGO designer hat Smile I will go through all migration steps as if I were in your shoes.

XVideoRental uses only a small part of XAF tooling –>Native modules + Code Central examples + open sourced project and community resources. All the time invested was for gathering ready to use implementations and putting them in a reusable project agnostic library. In addition since all these ready to use implementations exist already in our community project (eXpand) we created a second open source version of XVideoRental where this project agnostic library does not exist so we consumed even less resources for building it!

As you can read in the overview post the XVideoRental contains almost zero designed time code and everything is described declaratively in XAF’s Application Model xafml file, allowing full customization after distribution.

Real world applications are really demanding. We spend huge times for first release and in most cases is very poor compared to the next ones. The reason is simple, we do not have enough time to prepare a domain-specific language (DSL) that will bridge business requirements with our existing technical tooling/knowledge. Therefore we try to re-invent the wheel in many areas whereas XAF exists as the most comprehensive tooling available. Using application model and the Security System, XAF fully describes and configures the behavior of platform agnostic applications. Both Application Model and Security System are the technology abstraction or in other words the DSL language we need to minimize the time to market cost of a real world application.

We recommend:

1.  Watch the BUILDING A PROJECT MANAGER APPPLICATION IN 5 MIN video where we used the same LEGO designer approach as in XVideoRental in a simpler application as our MainDemo.



2.  Go for a quick overview of XVideoRental by reading XVideoRental real world application (RWA) – The overview.
3.  Go through the next table where from these simple statistics it should be clear the tremendous gain we get when developing with the XAF way.

  Number of projects Classes Lines of code
Legacy VideoRent
Location:
Four non reusable projects  256 27965
XAF XVideoRental • 1 project agnostic library
• 1 non reusable module
• 1 front end application almost unmodified as  created from VS templates
-
77
5
-
806
126
Open Sourced XVideoRental • References open sourced libs (project agnostic lib not exist)
• 1 non reusable module
• 1 front end application almost unmodified as  created from VS templates
-
36
5
-
807
126

In short the legacy app is using 256 classes. The XVideoRental much less 77 and 90% or them are simply concrete implementations from the referenced project agnostic library. However in the 3rd row where this project agnostic library is replaced from a reference to our open source project that number of classes goes further down to only 36!

Legacy app location:               %Public%\Documents\DXperience 12.2 Demos\Common\DevExpress.VideoRent.Win\CS\
XAF app location:                   %Public%\Documents\DXperience 12.2 Demos\eXpressApp Framework\XVideoRental\CS\
Open source XAF app location:
http://www.expandframework.com/downloads/download.html –>Demos\XVideoRental\

4.  Finally go through the list bellow where we compare the legacy and XAF application side by side.

Legacy VideoRent

XAF XVideoRental

Data Access  

• Legacy app uses ORM technology and our XPO to describe the video rent business. However special skills needed and extra efforts to create a clear separation from  other layers, so many helper classes exists even for very common tasks such as database connectivity.

• XAF has built-in support for both XPO and MS Entity Framework. We can simply utilize the legacy domain model by simply copy- paste the classes. Helper classes are of no use because XAF can handle all common tasks transparently for us!

• A real world application requires an importing mechanism for initial data. The legacy app imports data from xml files with structure that fits exactly to the structure of the business objects. Therefore even for a small  change in the BO design we need to modify and retest this mechanism.

• XVideoRental plugs-in an abstract domain agnostic importing engine from Fast prototyping requires an initial data import mechanism, allowing us to modify the structure of BO in the minimum time possible. In addition how to Supply Initial Data is well documented sparing our time for making architectural decisions.

• In a real world application sequential number integration is essential. However special design and knowledge is needed to be able to build something reliable.

• XVideoRental operates under a business application framework therefore a rich click and run SDK provides solutions to such common problems E2829. So  the developer only needs to integrate and not to think about the technical difficulties or guess the showstoppers.

Architecture  

Legacy app has a design time modularization based on Forms/UserControls/(Bussiness Concept). However it is not possible to extended it without adding new Forms and recompiling the whole application inside VS. In addition because of the lack in documentation determining the best place to write code for a specific behavior can still cause big headaches.

Application life cycle is component centric and was invented on demand for the current application.

XVideoRental demo is using XAF’s well-documented and simple to use MVC architecture. Also, while the discussed application is a simple fat client app, demanding users looking for something more advanced may also find a ready to use client-server solutions in XAF.

• VS templates to fast create modules. which by design are reusable and independent from main application.
• Well documented Application life cycle guide us where we to write code (e.g. Setup, Login, View Activation etc.)
• Simple to follow tutorial on how to Extend Functionality.
• Detailed guide of all the main concepts for building business applications.

Data Validation  

A real world application without strong validation support is unstable and has huge support times.
Building a validation engine is not trivial at all and requires third party components which will raise the cost even further. 
Therefore the legacy application time frame and budget wouldn’t allow any investment here and there is no validation support.

Creating validation rules does not require you to be a developer, even end-users can create them because it is quite easy and intuitive, not more difficult than creating a filtering rule in your Outlook. We only need to install the build-in Validation module!

Data Representation  

The legacy application a large number of components. Therefore the developer requires A huge amount of mundane, repetitive work was invested to:

XAF has native support for a large number of DX components. Automatic UI generation (CRUD detail and list forms, navigation and menu systems - all based on data models).  This is a huge time saver because almost every typical business application contains a good percentage of list and detail forms, navigation and menu systems - all linked together without any effort from your side.

• Create a large number of data entry forms, drag & drop numerous controls on it, arrange their positions and configure data bindings
• Providing a consistent look and feel is not an easy job and requires deep knowledge of a large number of components as well as a special design
• Interact with the database through XPO, create CRUD operations and support transactions needs careful considerations and a lot of time, so it was done as basic as possible by simply pushing non mandatory tasks such as undo operations and transaction for the next application release Smile.
• In an agile real world the navigation menu system should be controlled as declaratively as possible. However legacy app does not conform this requirement resulting in huge update times for every customer request.
• Extend XtraReports for every Business object we want to create reports.
• Design reports inside VS making their support  impossible in real world.
• Design analysis views inside VS making their support impossible in real world.

• We plugged-in a mechanism that allows to control any component at runtime from Dressing up our classes – Date with a model tonight!.
• A business rule driven Pivot editor borrowed from How to rule the Pivot we showed how to marry business requirements with a complex component like Pivot.
• Legacy code was converted on the spot to declarative as in Tooltips to the max - expressive UI.
• From Visiting dashboards we add a ready to use extension that provides collaboration for our views.
• We went over expectations by simply installing a community module from Dashboards in the real world – A Scotland strike.

Application Configuration  

Although most of the components can persist their state there is no application level integration by default. In addition their serialization is not designed to be human friendly and its hard to edit and support. The legacy developer had to create an integration mechanism deep in application’s infrastructure. This costly. wrap-up was as basic as possible and target only a few major forms producing a non consistent feeling.

XVideoRental is a XAF application which by design is described declaratively in XAF’s Application Model. Using Model Editor at runtime an end user can modify any part of the app.

However we didn’t spend the 10 min required to plugin the ModelDifference community module and consume the application from a persistence storage such as a database cause we were  building a clone and not demo the endless features of XAF!

Zero migration resources for this one!

Application Security  

The legacy developer tried to create a basic security implementation. However he soon realized that the efforts needed for something useful and reliable will probably exist the efforts for building the whole application. So, unfortunately due to app budget there is no investment in implementing a security system.

Our time frame here was really loosed since we already have a mature plug n’ play Security module. This flexibility allows us to plugin more goodies such as User Friendly permissions and  metadata based permission policies

Reporting  

The major goal of business applications is to be able to create and print reports.

Therefore the legacy app has a dedicated project for reporting. In which the developer had to use Visual Studio for report design. As a result he loosed any chance to update them on demand after project distribution which is a really common case.

At the same time the reports were extended and bound to VideoRent business objects making the whole implementation not reusable from any other project.

XVideoRental uses the built-in Reports Module which natively integrates our award winning XtraReports suite and provides a runtime designer.

The module saves the reports in the database so our job was to copy paste the Reports layout from the legacy app and distribute them as discussed in Distribute the Created Reports with the Application.

Moreover we provided collaboration/filtering with other views using as usual a no code approach as discussed in Visiting dashboards.

Data Printing and Export  

The legacy developer had to write special code for each control on your forms that he wished to print or export. Although this functionality is very useful in real world again the time frame wouldn’t allow such an investment.

XVideoRental can export data from the grid, pivot, chart, tree view, layout and others to a wide number of formats (PDF, RTF, TXT, CSV, HTML, MNT, XLS, XJSX, PNG, GIF, JPG, BMP, TIFF, WMF, EMF) without spending not even 1 minute to install or configure the system!

You probably can guess why eh? As usual XAF has a built-in generic mechanism for all controls out of the box!

Data Analysis  

Legacy app has a whole structure to support only a few data analysis views for the 4 major BO which are Customer, Movie, Receipt and Rent. Huge amount of code is located in dedicated forms for each analysis views making the solution not able to survive in real world. The reason of course is  that for each new customer request the developer has to change the code inside VS recompile and redistribute the app. A common example is a calculated value where it needs a UI to define these members, special algorithms to create them

XVideoRental uses the build-in Pivot Chart Module which as usual shifts development to the runtime allowing business users to modify the analysis display at any time. Uses the extended Pivot from How to rule the Pivot. Empowering the app with the dashboard suite as in Dashboards in the real world – A Scotland strike! was as simple as drag & drop the module from VS toolbox!. Essential for data analysis runtime calculated members as in Domain Components+ Calculated properties + Application Model was in the menu as well.

Localization  

There are technics for localizing .NET application via satellite assemblies however they do not localize application specific data and they are very time consuming, so the legacy app does not support any kind of localization

XAF supports all standard localization approaches and also addresses the problems that occur with them. With XAF, it is always possible to localize any part of your application at runtime (e.g., correct certain values from satellite assemblies). A convenient wizard provides the capability to use online translation services from MS, Google, etc. So, it is possible to leave the localization job to non-programmers who can easily import/export data without leaving the application.

Customizing Controls Appearance  

Even for the simplest operation like making bold a grid column or hiding a control from a view developer time is needed as long as recompilation and redistribution of the application

XVideoRental addresses this declaratively using the Conditional appearance module and the technic described in Dressing up our classes – Date with a model tonight! where any component can be serialized and controlled declaratively from XAF’s application model using the runtime Model editor.

This is control-agnostic and we spared our time digging into the specifics of each control – XAF did everything for us!

Implementing Custom Business Requirements  

Lets talk a concrete example here. The legacy app uses tooltips to create a more expressive UI. However even if the developer wrote a decoupled class at the end he has to attach it to various controls and forms. This makes the whole design not flexible since changes require developer presence.

XVideoRental can use the same decoupled class from the legacy application. However it simply attaches the behavior to application model instead of attaching it to controls and forms. This solution is project agnostic and allows later changes from a non programmer at runtime! This process is discussed in details in Tooltips to the max - expressive UI.

Getting Help and Support  

Application and developer are simply married. If for any reason they divorced then everything becomes very unstable and tricky. It is really hard to find another developer to continue support a legacy app. Even if we manage to do so the cost will be extremely high since there are no docs, support etc.

XVideoRental uses bricks/samples from XAF’s code central and community project. Thus by design there is a large number of developers that can support its code base. Not to forget the unmatched documentation and support we can get from the XAF team.

   

Conclusion

Even thought XAF does not contain solutions to each and every business problem in the world,  the framework is very strong in providing its own extensibility ( "preventing the lock-in effect").  It is fast and easy to plugin solutions to common business problems, at the end XAF is a Domain Specific Language that  that can bridge business requirements with our existing technical tooling/knowledge!

Until next time,

Happy XAF’ing!

Subscribe to XAF feed
Subscribe to community feed

Δημοσίευση στην κατηγορία: ,
Socialized XAF
07 Μαρτίου 13 01:30 μμ | tolisss | 0 σχόλια   

XAF community is really active, there are many places where you can participate in XAF related conversations, ask for dedicated help from other devs etc. Depending on your choice, to follow anything new comes along you can subscribe to your favorite RSS or site for the following list.

XAF official RSS Posts from our blog.
XAF Facebook page Official XAF Facebook page (includes blog posts).
XAF Facebook group Join other XAF users there and discuss anything XAF related with them.
XAF LinkedIn group A XAF dedicated group on Linked.
XAF twitter Tweets new posts. releases etc. (Follow us to get notified).
Other XAF bloggers RSS A list of several personal XAF related posts. (Apostolis Bekiaris, Dennis Garavsky, Manuel Grundner, Mike Calvert:, Nathanial Wools, Robert Anderson, Martynas Dauciunas and more.

Let me know at [email protected] if you want to ride this feed as well.
   
eXpand Twitter or Tweeterfeed Tweets everything in this list plus new eXpand releases plus new Git commits.
eXpand’s main RSS The most complete XAF info source currently available. Contains everything is XAF/eXpand related from official XAF and community sites.
Samples’s forum A forum dedicated to community samples/ideas. Feel free to post anything interesting there. We will review it and add it to eXpand’s code base.

In addition if you or your company are doing XAF consultancy or trainings, feel free to contact us to get you listed in our XAF consultancy page.

Δημοσίευση στην κατηγορία:
Dashboards in the real world – A Scotland strike!
22 Φεβρουαρίου 13 09:47 πμ | tolisss | 0 σχόλια   

The DevExpress Universal Subscription now includes an interactive data visualization Dashboard for Windows, the Web and Mobile devices. DevExpress Dashboard helps you deliver solutions that allow any enterprise to visually explore business trends using stunning and easily understood performance indicators.

If you are an XAF user, you already know that a framework such as XAF provides reusable building blocks to quickly build feature-rich business applications for Windows or the Web. In this post, I’ll discuss how Stephen Manderson, an XAF user from Scotland merged the capabilities of XAF and DevExpress Dashboard to create a new reusable XAF Dashboard module.

To best demo this Dashboard integration, we’ll use our XVideoRental RWA demo. The sample is available for your review at the bottom of this post. 

XAF users already know that dashboard support is part of the shipping product.  A few days ago I posted Visiting Dashboards where I discussed possible use case scenarios and extensions of the native implementation in order to deliver dashboard solutions to address real problems without writing any code!

Stephen Manderson was recently asked by a customer if it was possible for end users to create dashboards without going through IT to request changes and modifications to their system. The solution as you can imagine was the migration of the Dashboard Suite to his XAF application.

Stephen’s goals were simple.

  1. Create dashboards like any other BO at runtime.
  2. Pass any number of Target Persistent Object as data sources.
  3. Restrict access to dashboards based on Roles.

The DashboardDesigner

 

This step is really easy, we only need to drag this DashboardDesigner component into a simple empty windows form:

 

image

 

Displaying custom forms in XAF requires no special skills and is well documented: How do I show a custom window?

 

Create dashboards like any other BO at runtime

Working with XAF is straight forward. We have a DX component (DashboardDesigner) and we want to integrate it. Almost all our components are serializable and the DashboardDesigner is no exception. This means that we need a Persistent object to host the Xml for the layout and a collection of XAF BO Types that will be assigned as data sources.

To start we can use the following interface:

public interface IDashboardDefinition {

    int Index { get; set; }

    string Name { get; set; }

    Image Icon { get; set; }

    bool Active { get; set; }

    string Xml { get; set; }

    IList<ITypeWrapper> DashboardTypes { get; }

}

For the sake of simplicity I wont post the full implementation however you can grab it and follow its history in eXpand’s github repo or in the sample at the end of this post.

 

The Xml property along with the Designer’s LoadFromXml method can be used to load the Designer’s layout. So we need:

  1. To create a SimpleAction in a ViewController. We choose a ViewController instead of any other Controller simply because targeting a certain view and not the whole app.
  2. Then we configure the controller a bit further, to activate it only for BO that implements IDashboardDefinition.
  3. Finally we subscribe to SimpleAction’s Execute event, and we load the Windows form with the Dashboard designer component.

public class DashboardDesignerController : ViewController {

    readonly SimpleAction _dashboardEdit;

 

    public DashboardDesignerController() {

        _dashboardEdit = new SimpleAction(this, "DashboardEdit", PredefinedCategory.Edit);

        TargetObjectType = typeof(IDashboardDefinition);

        _dashboardEdit.Execute += dashboardEdit_Execute;

    }

 

    public SimpleAction DashboardEditAction {

        get { return _dashboardEdit; }

    }

 

    void dashboardEdit_Execute(object sender, SimpleActionExecuteEventArgs e) {

        using (var form = new DashboardDesignerForm()) {

            new XPObjectSpaceAwareControlInitializer(form, Application);

            form.LoadTemplate(View.CurrentObject as IDashboardDefinition);

            form.ShowDialog();

        }

    }

 

In the above snippet we chose to implement the LoadTemplate method in the DashboardDesignerForm because the Dashboard’s XML loading is not of XAF concern. This form is simply another separate windows based layer.

Visualizing our business data in the designer

The dashboard designer allows for us to see our XAF data and shape our dashboards in real time as shown:

 

image

 

This designer is similar to our Reports designer but does not offer support for dynamic members aliases. However we covered them in depth in Dynamic member aliases from Application Model.

 

Dashboards in action

 

To visualize our dashboards we have to:

  1. Dynamically populate the navigation menu items

    We want to extend XAF’s functionality therefore we need to find the responsible built-in controller. This leads to ShowNavigationItemController where we can subscribe to its events and populate the navigation items from DashboardDefinition persistent objects. A possible implementation can be found in sample in WinDashboardNavigationController.cs or you can follow its history online.

  2. Modify XAF’s security system to restrict access to dashboards based on Roles.

    Since we really care about making it easy for the business user, the sample is using a possible implementation as discussed in depth in User friendly way to add permissions.

  3. Display the dashboard’s using built-in DashboardViewer control.

    Here we easily can follow an SDK sample: How to show custom forms and controls in XAF (Example). In short we need to create and return a new DashboardViewer control by overriding the CreateControlCore method of a PropertyEditor. In case we want to access extra system info we may use a different class than a PropertyEditor as discussed in Implement Custom Property Editors

Our active dashboards are linked in the “Dashboards” navigation group; this can be renamed and reordered so all changes are reflected within this group. The end result in post’s sample looks like:

 

image

 

image

 

image

What’s next?

Stephen is already working in a State Machine designer plus an integration with XAF’s KPI module which gives dashboard its full power according to his words! Forgot to mention that a web version of Dashboards is coming soon!

Big thanks to Stephen Manderson for sharing this cool XAF implementation with us, I am sure this post/contribution will boost his spirit/cv/carrier a bit Winking smile , We welcome any of you that wants to share it’s cool XAF stuff with the rest of us. Feel free to use our Support Center for this or our community project.

Please do  not forget your feedback about what we discussed today.

Unit next time Happy XAF’ing as always!

Download XVideoRental sample here. The sample contains the following modification

  1. User friendly way to add permission migrated in Common.Win.General namespace.
  2. XVideorental references DynamicMemberAliases.Module from Domain Components+ Calculated properties + Application Model.
  3. XVideorental references ProvidedAssociation.Module from Modifying Business Objects using Attributes.
  4. XVideorental references eXpand’s/Stephen's Dashboard module.
Δημοσίευση στην κατηγορία: ,
Domain Components+ Calculated properties + Application Model
05 Φεβρουαρίου 13 12:32 μμ | tolisss | 0 σχόλια   

There is no official support for this scenario, however this does not mean that XAF is not designed with the highest standards. It means that we do not have docs and tests that can cover all possible combinations. However XAF is a flexible beast and we will go for supporting this case as short as possible.

Domain Components

With XAF it is possible to design business objects from interfaces! Given those interface DC with smart algorithms create concrete persistent class at runtime. It is possible to explore the DC dynamic assembly by overriding the in solution’s WinApplication descendant as shown:

public partial class DynamicMemberAliases2WindowsFormsApplication : WinApplication {

    protected override string GetDcAssemblyFilePath() {

        return Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, DcAssemblyFileName);

    }

Exploring the DC assembly for the following DomainComponent1

[DomainComponent]

public interface DomainComponent1 {

    string Email { get; set; }

    string Twitter { get; set; }

}

public override void Setup(XafApplication application) {

    base.Setup(application);

    XafTypesInfo.Instance.RegisterEntity("Manager", typeof(DomainComponent1));

 

We find out that XAF creates on the fly the next Manager class which is a simple XPO persistent object and is specific to our DomainComponent1 (see RegisterEntity method above).

 

 

image

This is really great! We already know how to Dynamic member aliases from Application Model and we can apply the same technic to the Manager class which very conveniently is related only with DomainComponent1. However there is a small problem, although the Dynamic member aliases from Application Model will successfully create the members in the Manager class, XAF does not know their existence. In next section we will discuss how to workaround this.

The TypesInfo system

  1. XAF works with object types, so the XAF team introduced the TypesInfo, a wrapper around .NET Reflection. For UI creation and for all metadata operations XAF uses the TypesInfo system. In addition the TypesInfo system allows metadata modification with code as easy as it can be! The power is there my friends, because the UI is automatically generated by querying types and members from TypesInfo.
  2. XAF supports by default XPO and Entity Framework but is possible to support a custom ORM as well. To make this possible XAF team architecture a separate interface the ITypeInfoSource, which holds all Type metadata (e.g. for XPO-> XpoTypeInfoSource).

UI + business logic <— TypesInfo –> XpoTypeInfoSource OR EFTypeInfoSource OR any ITypeInfoSource.

In short the above theory leads to the conclusion that the XpoTypeInfoSource will be asked from XAF to provide the Type members for any class. Therefore, we only need to override the EnumsMembers method of XpoTypeInfoSource to provide our own implementation! Bellow you see a part of this implementation, you can find the rest in the sample at the end of the post.

public class XpandXpoTypeInfoSource : DevExpress.ExpressApp.DC.Xpo.XpoTypeInfoSource, ITypeInfoSource {

    void ITypeInfoSource.EnumMembers(TypeInfo info, EnumMembersHandler handler) {

        EnumMembers(info, handler);

        Type type = info.Type;

        if (TypeIsKnown(type)) {

            if (type.IsInterface) {

                EnumDCInterfaceMembers(info, handler);

            }

        }

    }

Wasn’t this amazingly fast and simple? I always emphasize that XAF has 2 advantages

  1. It is well architectured –> overridable.
  2. It is well architectured –> reusable.

Based on the above 2 assumptions you can download and use the DynamicMemberAliasesForDC.zip Winking smile.

We are happy to read your feedback about this!. Remember that your questions are the best candidates for future posts.

P.S. : eXpandFramework users only need to register the Core modules (see How to use an eXpand module with an existing XAF application)

Until next time, happy XAF’ing!

Δημοσίευση στην κατηγορία: , ,
Dynamic member aliases from Application Model
29 Ιανουαρίου 13 06:34 πμ | tolisss | 0 σχόλια   

Although I promised to talk about Stephen Manderson’s Dashboard module I will skip and I will provide a discussion on dynamic member aliases. The reason is that cross data source filtering provided by the Dashboard Suite does not permit aliases for our aggregated members. I already touched dynamic members subject at calculated members creation—Pros and Cons. However today we will go in details through all steps involved in creating member aliases through XAF’s Application Model and as usual at the end of the post a sample will be available.

In the following image you can see existing implementations from our community project eXpand as discussed in calculated members creation—Pros and Cons.

image_thumb[14]

In this post we are only interested in the RuntimeCalculatedMember entry.,

Extending the model

Following our documentation to the letter (How to: Extend the Application Model) first we need to define and interface that will persist all parameters to the model.

public interface IModelRuntimeCalculatedMember : IModelMember {

    [Required]

    string AliasExpression { get; set; }

}

 

The context popup menu

You probably noticed in IModelRuntimeCalculatedMember instead of deriving from IModelNode interface as suggested in our docs we used the IModelMember. This is an already registered interface that describes the model members. So do not need to re extend our Application Model with the IModelRuntimeCalculatedMember. XAF knows how to create the popup menu with the correct entry:

 

image

 

Changing Model Editor’s behavior

 

AliasExpression

 

In IModelRuntimeCalculatedMember we marked the AliasExpression property with the RequiredAttribute because an empty alias is not valid. XAF Model Editor will notify that this is a mandatory property with an asterisk icon as shown:

 

image

Editable Type at Runtime

Since our IModelRuntimeCalculatedMember derives from IModelMember and not from IModelNode it inherits all its properties. This however, raises a conflict with XAF’s native support for design time custom members. The conflict refers to IModelMember Type property which is by design editable only in design time. As we see in the next image is marked with a ModelReadOnlyAttribute which tells Model Editor what to do.

image

In XAF everything is overridable! So to change Type property we need to create a new Type property in our IModelRuntimeCalculatedMember and mark it with the new keyword. In addition we need to create and use an AlwaysEditableCalculator  instead of the DesignerOnlyCalculator:


image

Remember the IsCustom functionality

As I already mentioned XAF has native support for runtime members only if Model Editor is at design time. This is done adding a new IModelMember and setting IsCustom to true as shown:

image

image

IModelRuntimeCalculatedMember inherits from IModelMember. This means when we create a new IModelRuntimeCalculatedMember XAF will set IsCustom to true as it does for simple IModelMember. ModuleUpdaters that can change Application Model’s values are designed to work only in the “zero” layer and here we need to change the differences made from the Model Editor designer. However XAF is designed to be extensible and our docs to solve the problems Convert Application Model Differences. The solution to this problem is to implement Implement a Node Updater following our docs to the letter:

image

NodeUpdaters are one more powerful tool provided to us by XAF an is designed to take us out of trouble. As you can see in above image it does it fairly simple.

  1. We make our module or any class a NodeUpdater by implementing the IModelNodeUpdater<T> interface.
  2. We register the new NodeUpdater by overriding the AddModelNodeUpdaters or our module.
  3. Implement our logic inside the the UpdateNode method

The Dessert

The AliasExpression property will hold basic criteria + complex criteria as well as aggregated function. Right now there is no editor associated with the property. However we can easily associate a CriteriaModelEditorControl editor as shown:

image

As we see the CriteriaModelEditorControl offers great features:

image

The Coding part 

Up to now we modeled a new Application Model member type the IModelRuntimeCalculatedMember. What remains is to write the algorithm to create that member in our TestBO object. Unfortunately we cannot use the standard place for extending our business objects as suggested by our knowledgebase. This is because the Application Model is not fully constructed at that point. However we can use any other place, as far as our algorithm is smart enough to execute just one time without consuming many resources. 

private static IEnumerable<IModelRuntimeCalculatedMember> GetCustomFields(IModelApplication model) {

    return model.BOModel.SelectMany(modelClass => modelClass.AllMembers).OfType<IModelRuntimeCalculatedMember>();

}

 

static void AddRuntimeMembers(IModelApplication model) {

    foreach (IModelRuntimeCalculatedMember modelRuntimeMember in GetCustomFields(model))

        try {

            Type classType = modelRuntimeMember.ModelClass.TypeInfo.Type;

            XPClassInfo typeInfo = _dictionary.GetClassInfo(classType);

            lock (typeInfo) {

                if (typeInfo.FindMember(modelRuntimeMember.Name) == null) {

                    new XpandCalcMemberInfo(typeInfo, modelRuntimeMember.Name, modelRuntimeMember.Type, modelRuntimeMember.AliasExpression);

                    XafTypesInfo.Instance.RefreshInfo(classType);

                }

            }

 

In fact forget about the many resources when using our frameworks, Please search our Support Center, there are answers to almost all common problems you will face! If not shoot the guys they are happy to die for you Winking smile!

Now let’s touch the unknown XpandCalcMemberInfo class:

  1. XPO allows non persistent calculated properties with the use of PersistentAliasAttribute.
  2. To create a dynamic member we simply need to instantiate an XPCustomMemberInfo derivative like the  XpandCalcMemberInfo.

public class XpandCalcMemberInfo : XPCustomMemberInfo {

    public XpandCalcMemberInfo(XPClassInfo owner, string propertyName, Type propertyType, string aliasExpression)

        : base(owner, propertyName, propertyType, null, true, false) {

        AddAttribute(new PersistentAliasAttribute(aliasBLOCKED EXPRESSION;

    }

 

    public override object GetValue(object theObject) {

        var xpBaseObject = ((XPBaseObject)theObject);

        return !xpBaseObject.Session.IsObjectsLoading && !xpBaseObject.Session.IsObjectsSaving

                   ? xpBaseObject.EvaluateAlias(Name)

                   : base.GetValue(theObject);

    }

 

    protected override bool CanPersist {

        get { return false; }

    }

}

 

Therefore in the constructor we added a PersistentAliasAttribute using the AddAttribute method of the XPCustomMemberInfo. In addition we had to modify the returned value of the member by overriding the GetValue method and using an approach similar with the EvaluateAlias docs,

Best place to create the dynamic members

In my opinion there is no such place and everything depends on our requirements. However I can suggest a solution we used in eXpand for many years without problems. You can do it just after login where the the user model is fully merged.

public sealed partial class DynamicMemberAliasesModule : ModuleBase {

    public override void Setup(XafApplication application) {

        base.Setup(application);

        application.LoggedOn += (sender, args) => RuntimeMemberBuilder.AddFields(application.Model);

    }

The check please!

We discussed in detail all the steps needed for dynamic member aliases. In DynamicMemberAliases.zip is a XAF solution to see everything in action.

To implement the rest of the dynamic members (RuntmeNonPersistent, RuntimeOrphanedCollection, RuntimeMember) you either

  1. Need to use core or ModelDifference module of eXpandFramework (see .
  2. Copy RuntimeMemberBuilder, all interfaces from IModelRuntimeMember.cs and extend the Application Model with the included IModelMemberEx interface.

That’s all you need, to have a few productive and happy hours with XAF Smile. I really enjoy working with such a flexible framework and I am sure the XAF team will continue to surprise us in the future!

Remember next post will talk the integration of XAF + Dashboard suite so stay tuned.

We are happy to read your feedback about anything you heard today!. Remember that your questions are the best candidates for future posts .

Until next time, happy XAF’ing!

Δημοσίευση στην κατηγορία: ,
User friendly way to add permissions
25 Ιανουαρίου 13 06:03 πμ | tolisss | 0 σχόλια   

XAFsecurity system is really flexible and can easily address complex scenarios. Depending on the nature of our application (e.g. geek level of business users Smile) we may want to modify the default design to make it more user friendly! This will be a detailed discussion on all the steps involved in doing so. In addition a sample application is available for download at the end of the post.

The goal is to create a user Role that will be able to Read and Navigate to predefined DashboardDefinition instances (SecurityOperation.ReadOnly). The DashboardDefinition is a simple business object.

If we had to use code we use a ModuleUpdater and the following snippet:

public class Updater : ModuleUpdater {

    public Updater(IObjectSpace objectSpace, Version currentDBVersion) : base(objectSpace, currentDBVersion) { }

    public override void UpdateDatabaseAfterUpdateSchema() {

        base.UpdateDatabaseAfterUpdateSchema();

 

        var role= ObjectSpace.FindObject<SecuritySystemRole>("Name='User'");

        var criteria = CriteriaOperator.Parse("Oid=?", "TOO hard to know the key value").ToString();

        const string operations = SecurityOperations.ReadOnlyAccess;

        role.AddObjectAccessPermission<DashboardDefinition>(criteria,operations);

 

    }

}

 

The handy AddObjectAccessPermission Role extension method hides the internals which are:

  1. Searches if a SecuritySystemTypePermissionObject exists for the DashboardDefinition type and creates it accordingly. The SecuritySystemTypePermissionObject is a persistent object with a Type property which is used to relate the permission with business objects. Moreover SecuritySystemTypePermissionObject has a set of properties (AllowRead, AllowNavigate etc.) used by the Security System to determine if permissions are granted for a business object.
  2. Creates a new SecuritySystemObjectPermissionsObject which holds the Criteria and Operation action and relates it with the SecuritySystemTypePermissionObject from step 1.

Although the AddObjectAccessPermission allows us to write user friendly code there are a few problems:

  1. This post is about a friendly (non code) way to add permissions and our goal is to modify the default XAF UI.
  2. It is difficult to construct the Criteria parameter of the AddObjectAccessPermission method (the developer should be aware of the name and value of the key property).

Let’s first see how the above code snippet is translated to a XAF UI and what steps needed from the end user.

image

The most difficult step as with the code approach is the Criteria construction. This time is even harder since we are not a developer any more but a business user. This means that even simple stuff like identifying the key property may look like a mountain.  In addition the end user needs a huge amount of time for creating permissions for a lot of objects.

The solution to this problem is to modify the default XAF UI and allow the business user to associate a Role with a DashboardDefinition object instance as shown bellow:

image

The above UI represents a many collection between Roles and DashboardDefintion. We can tell that is an M-M relation because only the link action is available (see left arrow)., The New DashboardDefinition action is hidden and the creation of the intermediate objects is done magically from XAF!

To create the DashboardDefinition collection shown in the above UI, we can use the ProvidedAssociationAttribute as discussed in Modifying Business Objects using Attributes post.

image

In this step using a simple attribute we guided XAF to create a totally different UI for associating a Role with a DashboardDefintion. What remains is to write code that will automatically create the required permissions by extending the SecuritySystemRole class.

Creating a custom Security Module

Extending the SecuritySystemRole class means that we need to create a custom Role class deriving from the SecuritySystemRole. The process is well documented How to: Implement Custom Security Objects (Users, Roles, Operation Permissions). However since we want a reusable functionality we recommend to create a module to host the custom Role class. XAF follows this recommendation with the Security module, our community project eXpandFrameWork with the XpandSecurityModule.

public class XRole:SecuritySystemRole {

    public XRole(Session session) : base(session) {

    }

 

}

 

Next step is to create an attribute with two parameters:

  1. OperationProviderProperty: Is the name of the property that will provide the SecurityOperation which will be applied to the collection of DashboardDefinition of our XRole.
  2. CollectionName: Is the name of the dynamically created DashboardDefinition collection member in our XRole.

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]

public class SecurityOperationsAttribute : Attribute {

    readonly string _collectionName;

    readonly string _operationProviderProperty;

 

    public SecurityOperationsAttribute(string collectionName, string operationProviderProperty) {

        _collectionName = collectionName;

        _operationProviderProperty = operationProviderProperty;

    }

 

    public string CollectionName {

        get { return _collectionName; }

    }

 

    public string OperationProviderProperty {

        get { return _operationProviderProperty; }

    }

}

 

Now its time to use this SecurityOperationsAttribute in our DashboardDefintion class which does not live in our custom Security module:

 

image

 

The collectionName parameter (DashboardDefinitions) is the name of the collection created from the ProvidedAssociationAttribute as discussed in the start of the post. The operationProviderProerty (DashboardOperation) does not yet exist in our XRole class and we need to create it in an abstract way since our Security modules has no knowledge of the DashboardDefinition existence. Writing abstract code with XAF is really a piece of cake! Our goal is to enumerate through all PersistentTypes (this includes DashboardDefintion) marked with the SecurityOperationAttribute. Then for each Persistent type we need to create a dynamic member in our XRole class to hold the SecurityOperation. Again note that our module is not even aware of what is the Role type.

public sealed partial class MySecurityModule : ModuleBase {

    public override void CustomizeTypesInfo(ITypesInfo typesInfo) {

        base.CustomizeTypesInfo(typesInfo);

        var roleTypeProvider = Application.Security as IRoleTypeProvider;

        if (roleTypeProvider != null) {

            foreach (var attribute in SecurityOperationsAttributes(typesInfo)) {

                CreateMember(typesInfo, roleTypeProvider, attribute);

            }

        }

    }

 

    void CreateMember(ITypesInfo typesInfo, IRoleTypeProvider roleTypeProvider, SecurityOperationsAttribute attribute) {

        var roleTypeInfo = typesInfo.FindTypeInfo(roleTypeProvider.RoleType);

        if (roleTypeInfo.FindMember(attribute.OperationProviderProperty) == null) {

            var memberInfo = roleTypeInfo.CreateMember(attribute.OperationProviderProperty, typeof (SecurityOperationsEnum));

            memberInfo.AddAttribute(new RuleRequiredFieldAttribute());

        }

    }

 

    IEnumerable<SecurityOperationsAttribute> SecurityOperationsAttributes(ITypesInfo typesInfo) {

        var typeInfos = typesInfo.PersistentTypes.Where(info => info.FindAttribute<SecurityOperationsAttribute>() != null);

        return typeInfos.SelectMany(info => info.FindAttributes<SecurityOperationsAttribute>());

    }

 

With the above code a new property will be added to the previously XRole UI.

 

image

 

 

Now we need a method to get the SecurityOperations given an XRole instance and the dynamic collection of DashboardDefinition objects. Note that the name property that provides these values exist in the SecurityOperationsAttribute marking our DashboardDefinition object:

 

static string GetSecurityOperation(ISecurityRole securityRole, XPMemberInfo memberInfo) {

    var typeInfo = XafTypesInfo.Instance.FindTypeInfo(memberInfo.CollectionElementType.ClassType);

    var roleTypeInfo = XafTypesInfo.Instance.FindTypeInfo(securityRole.GetType());

    var operationsAttribute = typeInfo.FindAttributes<SecurityOperationsAttribute>().FirstOrDefault(attribute => attribute.CollectionName == memberInfo.Name);

    return operationsAttribute != null ? Convert(securityRole, roleTypeInfo, operationsAttribute) : null;

}

 

static string Convert(ISecurityRole securityRole, ITypeInfo roleTypeInfo, SecurityOperationsAttribute operationsAttribute) {

    var value = roleTypeInfo.FindMember(operationsAttribute.OperationProviderProperty).GetValue(securityRole);

    if (value == null || ReferenceEquals(value, ""))

        return null;

    var securityOperations = (SecurityOperationsEnum)value;

    var fieldInfo = typeof(SecurityOperations).GetField(securityOperations.ToString(), BindingFlags.Public | BindingFlags.Static);

    if (fieldInfo != null)

        return fieldInfo.GetValue(null).ToString();

    throw new NotImplementedException(value.ToString());

}

 

Having a list of SecurityOperations from the GetSecurityOperation method we can use XAF’s metadata API to create the ObjectOperationPermissions as simple as:

 

public static IEnumerable<ObjectOperationPermission> ObjectOperationPermissions(this ISecurityRole securityRole, XPMemberInfo member) {

    var collection = ((XPBaseCollection)member.GetValue(securityRole)).OfType<object>();

    var securityOperation = GetSecurityOperation(securityRole, member);

    if (!string.IsNullOrEmpty(securityOperation)) {

        foreach (var operation in securityOperation.Split(ServerPermissionRequestProcessor.Delimiters, StringSplitOptions.RemoveEmptyEntries)) {

            foreach (var obj in collection) {

                yield return ObjectOperationPermissions(member, obj, operation);

            }

        }

    }

}

 

static ObjectOperationPermission ObjectOperationPermissions(XPMemberInfo member, object obj, string securityOperation) {

    return new ObjectOperationPermission(member.CollectionElementType.ClassType, Criteria(obj, member.CollectionElementType), securityOperation);

}

 

static string Criteria(object obj, XPClassInfo classInfo) {

    var keyProperty = classInfo.KeyProperty;

    var keyValue = keyProperty.GetValue(obj);

    return CriteriaOperator.Parse(keyProperty.Name + "=?", keyValue).ToString();

}

Finally we put all these methods to a class SecuritySystemRoleExtensions  and override our custom XRole GetPermissionsCore method as discussed in  How to: Implement Custom Security Objects (Users, Roles, Operation Permissions). So, in simple English this can b said: For each collection member in our XRole that his collection element type is marked with a SecurityOperationsAttribute call the above ObjectOperationPermissions extension method to get the permissions and add them to the list of XRole’s permission. XAF’s language does not differ much from English Smile, so this  will be:

public class XRole : SecuritySystemRole {

    public XRole(Session session)

        : base(session) {

    }

 

    protected override IEnumerable<IOperationPermission> GetPermissionsCore() {

        var operationPermissions = base.GetPermissionsCore();

        return OperationPermissionCollectionMembers().Aggregate(operationPermissions, (current, xpMemberInfo) => current.Union(this.ObjectOperationPermissions(xpMemberInfo).Cast<IOperationPermission>()));

    }

 

    IEnumerable<XPMemberInfo> OperationPermissionCollectionMembers() {

        return ClassInfo.OwnMembers.Where(info => info.IsAssociationList && info.CollectionElementType.HasAttribute(typeof(SecurityOperationsAttribute)));

    }

Today, we discussed how to mix BO’s metadata with instance data using a simple attribute in order to avoid tedious and repetitive work. To summarize when we want to create user friendly ObjectAccessPermissions  we can simply mark our BO as shown:

 

image

 

Note that even if DashboardDefintion class may live in a module we do not have source code, XAF will not sweat at all! It is really easy to dynamically replace attributes adjusting to your own preferences (see also How to customize a Business Model at runtime (Example)):

 

public override void CustomizeTypesInfo(ITypesInfo typesInfo) {

    base.CustomizeTypesInfo(typesInfo);

    var typeInfo = (TypeInfo) typesInfo.FindTypeInfo(typeof (DashboardDefinition));

    var memberInfo = typeInfo.FindMember("Roles");

 

    //replace ProvidedAssociationAttribute in Roles collection

    memberInfo.RemoveAttributes<ProvidedAssociationAttribute>();

    memberInfo.AddAttribute(new ProvidedAssociationAttribute("DashboardDefinition-Roles","MyDashboardDefintions",RelationType.ManyToMany, null));

 

    //replace SecurityOperationsAttribute

    typeInfo.RemoveAttributes<SecurityOperationsAttribute>();

    typeInfo.AddAttribute(new SecurityOperationsAttribute("MyDashboardDefintions", "MyDashboardOperation"));

}

 

The credits for this post go first to XAF with its unbelievable flexible API, second to a great XAFer named Stephen Manderson and third to me that wrote this post Smile. Moreover Stephen shared with us his Dashboard module which is the most wanted integration of XAF and our new Dashboard tool!

 

Next post we be all about Stephen’s Dashboard module, in the meantime let us know your thoughts in everything you heard today.

 

The sample with today’s discussion can be downloaded from here and is build against XAF v12.2.5.

 

Until next time, Happy XAFing!

Δημοσίευση στην κατηγορία: ,
Modifying Business Objects using Attributes
21 Ιανουαρίου 13 06:34 πμ | tolisss | 0 σχόλια   

Very often there is a need to add new members to existing Business objects that live in assemblies that we do not own.

Take the following example: We have a persistent object DashboardDefinition:

public class DashboardDefinition : BaseObject {

    public DashboardDefinition(Session session)

        : base(session) {

    }

    [Association("Role-Dashboards")]

    public XPCollection<DevExpress.ExpressApp.Security.Strategy.SecuritySystemRole> Roles {

        get {

            return GetCollection<DevExpress.ExpressApp.Security.Strategy.SecuritySystemRole>("Roles");

        }

    }

}

 

We want to create a many to many relation between DashboardDefinition and SecuritySystemRole objects. We already wrote the one part of the association in the DashboardDefinition –>Roles property. However we need to add a new collection of DashboardDefinition to the SecuritySystemRole, so we have 3 alternatives:

  1. Change in the source project, add the new property. then recompile then use the new assembly in your project —> Very tedious and hard to support approach.
  2. Create a custom class that derives from SecuritySystemRole, add the new property there and use the new class instead of SecuritySystemRole —> This design suffers from flexibility, at some point we will end with a lot of SecuritySystemRoles descendants.
  3. Create an ProvidedAssociationAttribute that when decorates a member will result in runtime creation of the other part.

In simple English the problem goes as following:

  1. Design a ProvidedAssociationAttribute that can hold the association name:

    [AttributeUsage(AttributeTargets.Property)]

    public class ProvidedAssociationAttribute : Attribute {

        readonly string _associationName;

     

        public ProvidedAssociationAttribute(string associationName) {

            _associationName = associationName;

        }

     

        public string AssociationName {

            get { return _associationName; }

        }

    }

     
  2. We want to write code to access and customize Types information (add new member). So, we need to override the CustomizeTypesInfo method in a module or implement IModelExtender interface in a controller (see also How to: Access Business Class Metadata).


    public
    sealed partial class ProvidedAssociationModule : ModuleBase {

        public override void CustomizeTypesInfo(ITypesInfo typesInfo) {

            base.CustomizeTypesInfo(typesInfo);

        }

     
  3. For all persistent objects with members decorated with the ProvidedAssociationAttribute:

    public override void CustomizeTypesInfo(ITypesInfo typesInfo) {

        base.CustomizeTypesInfo(typesInfo);

        var memberInfos = MemberInfos(typesInfo);

        foreach (var memberInfo in memberInfos) {

     

        }

    }

     

    IEnumerable<IMemberInfo> MemberInfos(ITypesInfo typesInfo) {

        Func<IMemberInfo, bool> hasAttribute = info => info.FindAttribute<ProvidedAssociationAttribute>() != null;

        return typesInfo.PersistentTypes.SelectMany(info => info.Members).Where(hasAttribute);

    }

     
  4. Create the dynamic collection using metadata taken from the decorated member

        foreach (var memberInfo in memberInfos) {

            CreateMember(memberInfo);

        }

    }

     

    void CreateMember(IMemberInfo memberInfo) {

        var dictionary = XpoTypesInfoHelper.GetXpoTypeInfoSource().XPDictionary;

        var providedAssociationAttribute = memberInfo.FindAttribute<ProvidedAssociationAttribute>();

        var customMemberInfo = dictionary.GetClassInfo(memberInfo.ListElementType).CreateMember(memberInfo.Owner.Name + "s", typeof (XPCollection), true);

        var associationAttribute = new AssociationAttribute(providedAssociationAttribute.AssociationName,memberInfo.Owner.Type);

        customMemberInfo.AddAttribute(associationAttribute);

        memberInfo.AddAttribute(new AssociationAttribute(providedAssociationAttribute.AssociationName));

    }

  5. Decorate Roles of the DashboardDefinition object to dynamically create a DashboardDefinitions collection in the SecuritySystemRole object

    image

     

 

The ProvidedAssociationAttribute idea exist in our community project (www.expandframework.com) a few years now and it happens to be a favorite one among eXpand users. Through the years of course we created a real world implementation of it. I decouple all related files in this XAF Solution for everybody to give a quick try or even copy paste it in your solutions!

PS: Although the current implementation is XAF depended is rather easy to replace all XAF related code with XPO and use it to non XAF projects as well.

We are happy to read your feedback about this!. Remember that your questions are the best candidates for future posts

Δημοσίευση στην κατηγορία: , ,
Περισσότερες Δημοσιεύσεις « Προηγούμενη - Επόμενη »

Search

Go

Το Ιστολόγιο

Ιστορικό Δημοσιεύσεων

Συνδρομές