eXpress App Framework Team

This Blog

News

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

November 2012 - Posts

  • Let’s create metadata based permission policies

    XAF has a great security system which can be used to protect our data either at client or server side. There is also great support for modifying the Security behavior at runtime using a permission matrix. However we need to provide initial permissions before distributing our application. In this post we are going to discuss a way to connect methods that describe permission policies with our domain objects, of course using metadata (Attributes).

    For supplying initial data XAF provides a well documented approach through ModuleUpdaters. We can use them and write methods that create initial permissions. There are also many extension methods that can help us write faster code,

    image

    Full permission policy

    This policy can be applied to any role and give full permission for the related objects. To connect a domain object with a method we need to do the following:

    1. Define a FullPermissionAttribute as,

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

      public class FullPermissionAttribute : Attribute {

      }

       

    2. Decorate all related objects

      [FullPermission]

      public class MovieArtist : VideoRentalBaseObject {

      [FullPermission]

      public class Artist : VideoPerson {

    3. With the use of XAF’s sub types info metadata API write an abstract algorithm that will enumerate all domain objects and assign full permission to them for a certain role

      public static void CreateFullPermissionAttributes(this SecuritySystemRole systemRole,  bool defaultAllowValues = true) {

          var persistentTypes = XafTypesInfo.Instance.PersistentTypes.Where(info => info.FindAttribute<FullPermissionAttribute>() != null);

          foreach (var typeInfo in persistentTypes) {

              systemRole.CreateTypePermission(typeInfo.Type,  defaultAllowValues);

          }

      }

      public static SecuritySystemTypePermissionObject CreateTypePermission(this SecuritySystemRole systemRole, Type targetType, bool defaultAllowValues = true) {

          var permission = systemRole.CreateTypePermission(targetType);

          permission.TargetType = targetType;

          permission.AllowDelete = defaultAllowValues;

          permission.AllowNavigate = defaultAllowValues;

          permission.AllowRead = defaultAllowValues;

          permission.AllowWrite = defaultAllowValues;

          permission.AllowCreate = defaultAllowValues;

          return permission;

      }

    4. Invoke the CreateFullPermissionAttributes form the roles you want to apply inside the ModuleUpdater’s

      public override void UpdateDatabaseAfterUpdateSchema() {

          base.UpdateDatabaseAfterUpdateSchema();

          var employersRole = ObjectSpace.GetRole<SecuritySystemRole>("Employers");

          employersRole.CreateFullPermissionAttributes();

    Permission Behavior policy

    A common policy for an application is a “settings” policy. Which really means that for certain roles like the employee role there should be limited access to objects that store “settings” data. To implement this we can follow the follow steps

    1. Define an attribute to decorate our objects as in previous step. This time we do not know the policy name (settings) so we design this as an Enum parameter in the ctor.

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

      public class PermissionBehaviorAttribute : Attribute {

          readonly string _name;

       

          public PermissionBehaviorAttribute(object @enum) {

              if (!@enum.GetType().IsEnum)

                  throw new NotImplementedException();

              _name = Enum.GetName(@enum.GetType(), @enum);

          }

       

          public PermissionBehaviorAttribute(string name) {

              _name = name;

          }

       

          public string Name {

              get { return _name; }

          }

      }

       

    2. Design an enumeration to hold all possible security policies

      public enum PermissionBehavior {

          Admin,

          Settings,

          ReadOnlyAccess

      }

       

    3. Decorate related objects

      [PermissionBehavior(PermissionBehavior.ReadOnlyAccess)]

      public class Language : VideoRentalBaseObject {

    4. Create a method to describe the ReadOnlyAccess permission policy inside ModuleUpdater.

      public class Updater : ModuleUpdater {

          void ReadOnlyAccesPermissionBehaviour(SecuritySystemRole securitySystemRole, ITypeInfo typeInfo) {

              securitySystemRole.SetTypePermissions(typeInfo.Type, SecurityOperations.ReadOnlyAccess, SecuritySystemModifier.Allow);

          }

    5. With the use of XAF’s sub types info API write an abstract algorithm that will enumerate all domain objects and invoke a delegate with same parameters as the method in step 4

      public static void CreatePermissionBehaviour(this SecuritySystemRole systemRole, Enum behaviourEnum, Action<SecuritySystemRole, ITypeInfo> action) {

          var typeInfos = XafTypesInfo.Instance.PersistentTypes.Where(info => {

              var permissionBehaviorAttribute = info.FindAttribute<PermissionBehaviorAttribute>();

              return permissionBehaviorAttribute != null && permissionBehaviorAttribute.Name.Equals(Enum.GetName(behaviourEnum.GetType(), behaviourEnum));

          });

          foreach (var typeInfo in typeInfos) {

              action.Invoke(systemRole, typeInfo);

          }

      }

       

    6. Invoke the CreatePermissionBehaviour inside the ModulerUpdater feeding it with the ReadOnlyAccesPermissionBehaviour method of step 4

      employersRole.CreatePermissionBehaviour(PermissionBehavior.ReadOnlyAccess, ReadOnlyAccesPermissionBehaviour);

    In this post we created reusable algorithms from any XAF projects to help us speeding up the configuration of the initial permissions. When of course talking about code reusability we talk about money saving!

    P.S. In a real world application the above coding will be converted to a permission matrix UI representation, making super easy further configurations!

     
    image

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

    Next post will be about what else? its model time!

    Happy XAFing as always.

    Updated: The code and screen shots are taken from the XVideoRental application. This demo can be found along with the other XAF demos in v12.2 

  • Visiting dashboards

    DashboardView is a type of XAF View that is used to display several Views side-by-side. However XAF by default does not provide any connection between these Views. In this post, with the help of XAF model, we will discuss a few abstract connection mechanisms and possible uses of dashboards.

    Cascading ListViews

    In a dashboard, in order to connect the ListViews we need first to connect their models. This can be done using the following interfaces,

    public interface IModelDashboardViewFilter : IModelNode {

     

        [DataSourceProperty("FilteredColumns")]

        IModelColumn FilteredColumn { get; set; }

     

        [DataSourceProperty("DataSourceViews")]

        IModelListView DataSourceView { get; set; }

    }

    [ModelAbstractClass]

    public interface IModelDashboardViewItemEx : IModelDashboardViewItem {

        IModelDashboardViewFilter Filter { get; }

    } 

    and then extend XAF’s model, see also our documentation on extending the model

    public void ExtendModelInterfaces(ModelInterfaceExtenders extenders) {

        extenders.Add<IModelDashboardViewItem, IModelDashboardViewItemEx>();

    }

    This design allows us to use Model Editor to connect our views. In the following image we see that the selected objects of the Customer_ListView_Calendar are going to filter the Calendar list view on the Receipt.Customer field.

    image

    Next we see this dashboard view in action, a SchedulerListEditor on the right is filtered by a GridListEditor,

    image

    Following we see this technic applied to 3 ListViews. The selected pie section of the left View filters the pivot which in its turn filters a LayoutListEditor!

    image

    Cascading views are as well useful for filtering reports, so by selecting objects on the left View we create a report on the right view and everything is inside a Tabbed MDI environment!

    image

    Of course we haven’ wrote the code yet but this is the easy part. XAF’s API is so rich and so well designed that is like we speak our native language! The great thing when XAFing is that our code is fully reusable from any project since it has no knowledge of our domain objects.

    Let try to form our requirement in English first:
    For each ListView in a Dashboard we need to filter another View when the selection is changed

    And now in XAF language Smile:

    protected override void OnViewControlsCreated() {

        base.OnViewControlsCreated();

        foreach (var result in View.Items.OfType<DashboardViewItem>()) {

            var frame1 = result.Frame;

            if (frame1 != null && frame1.View is ListView) {

                var listView = ((ListView)frame1.View);

                DashboardViewItem result1 = result;

                listView.SelectionChanged += (sender, args) => OnSelectionChanged(new SelectionChangedArgs(listView, result1));

            }

        }

    void OnSelectionChanged(SelectionChangedArgs selectionChangedArgs) {

        var dataSourceListView = DataSourceListView((IModelListView)selectionChangedArgs.DashboardViewItemModel.View);

        if (dataSourceListView != null) {

            var dashboardViewItems = View.Items.OfType<DashboardViewItem>();

            foreach (var dashboardViewItem in dashboardViewItems) {

                var modelDashboardViewItemEx = (IModelDashboardViewItemEx)dashboardViewItem.GetModel(View);

                FilteredListView(dataSourceListView, dashboardViewItem, modelDashboardViewItemEx);

            }

        }

    Controlling DashboardViewItem visibility

    Cascading views are really powerful and soon we will have the need to hide an intermediate view in the chain but being able to filter other views upon it. Therefore we need to add a Visibility property in our model and handle it from our code.

    public interface IModelDashboardViewItemEx : IModelDashboardViewItem {

        [DefaultValue(ViewItemVisibility.Show)]

        ViewItemVisibility Visibility { get; set; }

    and in a reusable from all projects controller implement the required logic.

    protected override void OnActivated() {

        base.OnActivated();

        ((ISupportAppearanceCustomization)View.LayoutManager).CustomizeAppearance += LayoutManagerOnCustomizeAppearance;

     

    }

    void LayoutManagerOnCustomizeAppearance(object sender, CustomizeAppearanceEventArgs customizeAppearanceEventArgs) {

        var modelDashboardViewItem = View.Model.Items.OfType<IModelDashboardViewItemEx>().FirstOrDefault(item => item.Id == customizeAppearanceEventArgs.Name);

        if (modelDashboardViewItem != null)

            ((IAppearanceVisibility)customizeAppearanceEventArgs.Item).Visibility = modelDashboardViewItem.Visibility;

    }

    Displaying HTML Messages

    A DashboardView does not have direct dependency with our domain objects. Therefore we can easily use it, even at runtime, to display static text view items and other controls (ControlDetailItem) or images (StaticImage).

    image

    XAF has great support for HTML Formatting so a Static Text like “<u><b>Hello</b></u>” will render the following:

    image

    Simulating View inheritance

    XAF does not support View inheritance however we can extend our model and support it. Lets take the case that we have a very complex listview and we want to display it in both in MasterDetail and ListViewOnly modes without the need to support two View versions. For this we have to extend again the model, this time by a MasterDetailMode property and implement the logic in a ViewController.

    [ModelAbstractClass]

    public interface IModelDashboardViewItemEx : IModelDashboardViewItem {

        MasterDetailMode? MasterDetailMode { get; set; }

    public class DashboardInteractionController : ViewController<DashboardView>, IModelExtender {

        protected override void OnViewControlsCreated() {

            base.OnViewControlsCreated();

            ResetMasterDetailModes();

        }

        void ResetMasterDetailModes() {

            foreach (var masterDetailMode in _masterDetailModes) {

                masterDetailMode.Key.MasterDetailMode = masterDetailMode.Value;

            }

            _masterDetailModes.Clear();

        }

     

        protected override void OnActivated() {

            base.OnActivated();

            foreach (var item in View.GetItems<DashboardViewItem>().Select(item => item.GetModel(View)).OfType<IModelDashboardViewItemEx>()) {

                AssignMasterDetailModes(item);

            }

        }

     

        void AssignMasterDetailModes(IModelDashboardViewItemEx modelDashboardViewItem) {

            if (modelDashboardViewItem.MasterDetailMode.HasValue) {

                var modelListView = modelDashboardViewItem.View as IModelListView;

                if (modelListView != null) {

                    _masterDetailModes.Add(modelListView, modelListView.MasterDetailMode);

                    modelListView.MasterDetailMode = modelDashboardViewItem.MasterDetailMode.Value;

                }

            }

        }

    Since XAF has a great modularization system the core classes/implementations of the above ideas are included in this zip file. However we will not update the contents of the zip file. For locating up to date versions each file in the zip has an OnlineRepoLocation attribute that points to eXpandFramework’s Github repository.

    This post adds a few more tools in our development library that can leverage the XAF power using the Model. When we “model” there are three basic advantages:

    1. We can use these model tools at runtime. For this XAF already provides a runtime time Model Editor.
    2. We create robust unbreakable code and since we model instead of developing we mostly have no bugs only wrong configuration!
    3. Implementations are reusable from all our projects!

    Next post we will boost our R&D times even further and discuss a bit about Security system policies.

    P.S.: We are preparing detailed samples demonstrating all the above ideas Smile, stay tuned!

    If some of you have invented similar ways to connect your dashboards. You can use our support center and share them with the rest of the community.

    Happy XAFing!

    Updated: The code and screen shots are taken from the XVideoRental application. This demo can be found along with the other XAF demos in v12.2 

  • Fast prototyping requires an initial data import mechanism

    To improve development time and achieve better results we need to use frameworks like XAF. Moreover with XAF it’s really easy to create applications that are maintainable at runtime! After designing a domain model in VS we are almost ready to go. At this point, however we need a smart and flexible importing mechanism for feeding our domain models with initial data. Customers are impressed when they see real world data! So lets build together this mechanism proving once more the XAF power.

    Requirements

    1. Domain model agnostic.

      This really means that our importing algorithms should depend only on object types. Therefore we can implement this as an attribute and decorate our domain objects. 
       
    2. Database agnostic

      XPO that supports all common database engines with its rich metadata API is our answer here.
       
    3. Flexible mapping configuration

      For this we are going to create the an XPO dictionary on the fly. Querying our domain object attributes we can map this dictionary correctly.
       
    4. Inheritance mapping configuration

      Take as example an Artist, Customer both inheriting a Person object. The attribute should allow to map different the properties of Person when Artist and when Customer.

    Examples

    1. The following example imports all members that belong to MovieArtist from a table with same name columns (AllOwnMembers=true). In addition it maps the oid column in the table of the importing data store to the Oid property of VideoRentalBaseObject (BaseNMembers=”oid|Oid”). Finally it does lookup data in a data store in a table named vMovieArtist (Name=”vMovieArtist”).

      [InitialData(BaseMembers = "oid|Oid", AllOwnMembers = true,Name = "vMovieArtist")]

      public class MovieArtist : VideoRentalBaseObject {

          Artist artist;

          Movie movie;

    2. The next one imports from a table named CompanyType only the column named Name (AllOwnMembers=false, BaseMembers=null, only Name property is decorated)

      [InitialData()]

      public class CompanyType : VideoRentalBaseObject {

          [InitialData]

          public string Name {

              get { return _name; }

              set { SetPropertyValue("Name", ref _name, value); }

          }


    3. By default all object relations are auto imported unless the related object is not included in the configuration. Then only the key value is imported. It is also possible to control the mapping in many to many relations as

      public class Movie : VideoRentalBaseObject {

       

          [InitialData(DataProviderTableName = "CountryMovies", DataProviderQueryColumnName = "Movies", DataProviderResultColumnName = "Countries")]

          [Association("Movies-Countries")]

          public XPCollection<Country> Countries {

              get { return GetCollection<Country>("Countries"); }

          }

    The algorithm

    1. This is an initial data import mechanism. For such operations XAF provides the ModuleUpdater. We need the XafApplication’s IObjectSpace and one UnitOfWork that connects to an external data source so we can simply design an extension method like,

      public static void Import(this IObjectSpace objectSpace, UnitOfWork unitOfWork) {

      }

      and invoke it inside UpdateDatabaseAfterUpdateSchema as,

       

      public class Updater : ModuleUpdater {

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

          public override void UpdateDatabaseAfterUpdateSchema() {

              base.UpdateDatabaseAfterUpdateSchema();

              var connectionString = ConfigurationManager.ConnectionStrings["initialdata"].ConnectionString;

              ObjectSpace.Import(new UnitOfWork{ConnectionString = connectionString});

       

    2. Using XAF’s rich reflection API we can enumerate all our domain objects, search for the InitialData attribute and create an XPO dictionary on the fly! This is rather easy as XPO follows a similar to .NET structure, so we have to create XPClassInfo for Classses and XPMemberInfo for members. A great sample exists in our code central so we can get a fast start with this API (E269). Following are the 2 main methods that implement the import mapping.

      public static void ImportCore(this IObjectSpace objectSpace, UnitOfWork unitOfWork) {

          var builder = new InitDataDictionaryBuilder(objectSpace);

          builder.InitDictionary(unitOfWork);

          foreach (var persistentTypeInfo in builder.GetPersistentTypes()) {

              Import(objectSpace, builder, unitOfWork, persistentTypeInfo);

          }

          unitOfWork.CommitChanges();

      }


      internal class InitDataDictionaryBuilder {

          public void InitDictionary(UnitOfWork unitOfWork) {

              var persistentTypes = GetPersistentTypes();

              CreateMemberInfos(unitOfWork.Dictionary, persistentTypes);

          }

       
      A complete and up to date version can be found in expandframework’s github repository.


    In this post we improved the already rapid XAF development, by creating the import mechanism from almost any type of data into our domain model. In the next one we will visit another great tool offered by XAF the dashboard views.

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

    Happing XAFing as always! 

     Updated: The code and screen shots are taken from the XVideoRental application. This demo can be found along with the other XAF demos in v12.2  

LIVE CHAT

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

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

FOLLOW US

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

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