Monday, February 8, 2010

Developing data analysis objects with the help of IO module

After creating PivotingChart Module I was able to really control the fluent DevExpress Pivot grid options at runtime and design more complex analysis pivoting UI writing no code and save all that “configuration” at the same database record as the analysis object.

But I was still developing inside my VS and since my model was not stable yet I continuous drop the database using the DxCore addin to drop database at design time which by the way have been updated to support multiple datastores

image

and damn I lose the designed analysis UI cause it was stored in the database

Time for some IO module use

I could export my analysis objects

image

and use the following import to load the configured objects at application start up

from an embedded resource

public class Updater : ModuleUpdater

{

    public Updater(Session session, Version currentDBVersion) : base(session, currentDBVersion) { }

    public override void UpdateDatabaseAfterUpdateSchema()

    {

        base.UpdateDatabaseAfterUpdateSchema();

        var unitOfWork = new UnitOfWork(Session.DataLayer);

        new ImportEngine().ImportObjects(unitOfWork,GetType(), "Resources.Analysis.xml");

        unitOfWork.CommitChanges();

    }

}

or from a file on your disk

public class Updater : ModuleUpdater

{

    public Updater(Session session, Version currentDBVersion) : base(session, currentDBVersion) { }

    public override void UpdateDatabaseAfterUpdateSchema()

    {

        base.UpdateDatabaseAfterUpdateSchema();

        var unitOfWork = new UnitOfWork(Session.DataLayer);

        new ImportEngine().ImportObjects(unitOfWork, @"c:\Analysis.xml");

        unitOfWork.CommitChanges();

    }

}

DiggIt!

Wednesday, February 3, 2010

Multiple datastores support

 

THE PROBLEM
WorldCreator creates dynamic types for used within Xaf. It is doing that by compiling code templates at WorldCreator module setup method. To find those templates it has to query a persistent datastore using XPO. Now when you create a new XPO session it will check if all object types that XPObjectType table contains if are valid. So if you have used customizedtypesinfo to create runtime associations since it is called after module setup it will throw an exception complaining for invalid tables.

Saying the above you understand that there is no way to open a connection to an XPO database that has records for objects with associations that have not fully defined.

THE SOLUTION

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

public class DataStoreAttribute:Attribute

{

    readonly Type _nameSpaceType;

    readonly string _dataStoreNameSuffix;

 

    public DataStoreAttribute(Type nameSpaceType, string dataStoreNameSuffix) {

        _nameSpaceType = nameSpaceType;

        _dataStoreNameSuffix = dataStoreNameSuffix;

    }

 

    public string NameSpace {

        get { return _nameSpaceType.Namespace; }

    }

 

    public string DataStoreNameSuffix {

        get { return _dataStoreNameSuffix; }

    }

}

You can add the above attribute to your AssemblyInfo.cs file to decouple all classes inside a namespace. I have already decouple WorldCreator objects using the following line in eXpand.BaseImpl

[assembly: DataStore(typeof(PersistentAssemblyInfo),"WorldCreator")]

The first parameter is the type that will provide the namespace to decouple and the secode the datastore name suffix.

If DataStoreAttribute is applied it will create a database in the same server as your default connectionstring. But if you want you can provide your own custom connectionstring like

<connectionStrings>

    <add name="ConnectionString" connectionString="Integrated Security=SSPI;Pooling=false;Data Source=SERVER;Initial Catalog=Solution1;"/>

    <add name="WorldCreatorConnectionString" connectionString="Integrated Security=SSPI;Pooling=false;Data Source=OTHERSERVER;Initial Catalog=WorldCreator;"/>

  </connectionStrings>

Ps: Sharing objects is not supported , so you have to be sure that all classes are defined in the namespace that you are decoupling

DiggIt!

Monday, February 1, 2010

New Pivoting module

eXpand says hi to its new Pivoting module.

Show In Analysis action similar to show in reports (see also Devexpress example)
image

All Pivot control settings can be controled at runtime using the Pivot Settings action

image

see for example the Pivot Options View settings view

image

ModelArtifacteState module has been used to create a Show In Analysis , Pivot Settings Permissions that can be applied to the Roles you want .

[NonPersistent]

public class ShowInAnalysisPermission : ControllerStateRulePermission {

    public override string ControllerType {

        get { return typeof (ShowInAnalysisViewController).FullName; }

        set { base.ControllerType = value; }

    }

 

    public override string ToString() {

        return string.Format("{1}: {0}", ID, GetType().Name);

    }

}

[NonPersistent]

public class PivotSettingsPermission : ControllerStateRulePermission {

    public override string ControllerType {

        get { return typeof (PivotOptionsController).FullName; }

        set { base.ControllerType = value; }

    }

 

    public override string ToString() {

        return string.Format("{1}: {0}", ID, GetType().Name);

    }

}

image

In place pivot editing by using the AllowEdit model attribute

image

AnalysisControlVisibility for controlling the visibility of Pivot or Chart control

image

PivotedPropertyAttribute

You can make at runtime complex views like the above by applying it.

image

Say you have an object with an associated collection property like

[Association("OwnerShellSite-CompetitorLinks")]

[Aggregated]

[DevExpress.Xpo.DisplayName("Competitors")]

public XPCollection<CompetitorLink> OwnerCompetitorLinks {

    get { return GetCollection<CompetitorLink>("OwnerCompetitorLinks"); }

}

if you like instead of the listview that will be shown by default to display a pivot upon OwnerCompetitorLinks collection then you just create another property like

[PivotedProperty("Prices", "Name='Site price analysis'")]

public Analysis PriceAnalysis {

    get { return _priceAnalysis; }

    set { SetPropertyValue("PriceAnalysis", ref _priceAnalysis, value); }

}

and eXpand will do the rest for you!!!

You may also want to pivot on an orphan collection

[Browsable(false)]

public XPCollection<Price> CompetitorPrices {

    get {

        return new XPCollection<Price>(Session);

    }

}

then you should use a different constructor like

[PivotedProperty("CompetitorPrices", "Name='Competitor site price analysis'","PropertyWithSameTypeAsCurrentObjectInPrice")]

public Analysis CompetitorPriceAnalysis {

    get { return _competitorPriceAnalysis; }

    set { SetPropertyValue("CompetitorPriceAnalysis", ref _competitorPriceAnalysis, value); }

}

In the following video you can see how you render any collection of your object with the pivot control in the same detailview as the object using eXpand’s PivotedPropertyAttribute at RUNTIME

The modules you have to register for Pivoting with eXpand would be eXpand.ExpressApp.PivotChart.dll ,eXpand.ExpressApp.PivotChart.Win.dll

DiggIt!

Monday, January 25, 2010

.NET hacking made easy

I am in a mood this year so I decided to spend some time with a problem that I have left in the past.

The problem

I really wanted to use Runtime member for existent Types and also enable validation for those members. But for the reason i have describe in this post it was not possible, unless I change DevExpress source code and recompile (bad choice). DevExpress and any vendor could, for their own reasons not support your suggestion. Maybe for good or for bad I really not care, what I care is how to use Runtime member for existent Types with validation enable.

So I will try a different approach I will use CThru which is an AOP open source interception framework based on the Typemock Open-AOP API to “For any (past or future) object of type X in the system, make property Y of said object already return a fake value” and in my case that will be

For any (past or future) object of type RulePropertyValueProperties, make property TargetPropertyName return my version of code

Lets say for a moment that you know nothing on CThru, and even the idea of learning a “strange AOP” frameworks frightens you cause of the luck of time. I ll explore the proccess of doing the above like I know nothing about it also

Previous post of mine about AOP can be found here

1st Step

Go to their site at codeplex http://cthru.codeplex.com/ and read all stuff under Learn section. There are not many info there but very informative as you have already notice if you follow the above links I posted.

2nd Step

Download the source code and… here it is—> a CThru.Tests project. That will do all the job!!! There should be tests explaining how the framework works. After exploring the solution I came across TraceAspect class, which was mention to me at CThru site. That class/aspect can enable logging to any class within .Net framework except for classes within mscorlib. Just take a look how is is to implement it

    public class TraceAspect : Aspect {

        private readonly Predicate<InterceptInfo> _shouldIntercept;

        private readonly string _logPath;

 

        public TraceAspect(Predicate<InterceptInfo> shouldIntercept, string logPath) {

            _shouldIntercept = shouldIntercept;

            _logPath = logPath;

        }

 

        public TraceAspect (Predicate<InterceptInfo> shouldIntercept) {

            _shouldIntercept = shouldIntercept;

        }

 

        public override bool ShouldIntercept (InterceptInfo info) {

            return _shouldIntercept(info);

        }

 

        public override void ConstructorBehavior (DuringCallbackEventArgs e) {

            DoTrace(e);

        }

 

        public override void MethodBehavior (DuringCallbackEventArgs e) {

            DoTrace(e);

        }

 

        protected virtual void DoTrace (DuringCallbackEventArgs e) {

            string message = GetMessage(e);

            DoTrace(message);

        }

 

        protected virtual void DoTrace(string message) {

            if (_logPath != null) System.IO.File.AppendAllText(_logPath, message + Environment.NewLine);

            Console.WriteLine(message);

        }

 

        protected virtual string GetMessage(DuringCallbackEventArgs e) {

            string message;

            try {

                string parameters = GetParameters(e);

                message = string.Concat(e.TypeName, ".", e.MethodName, "(", parameters, ")");

            }

            catch (Exception ex) {

                message = ex.ToString() + Environment.NewLine;

            }

            return message;

        }

 

        protected virtual string GetParameters (DuringCallbackEventArgs e) {

            var list = new List<string>();

            if (e.ParameterValues != null) {

                foreach (var param in e.ParameterValues) {

                    var value = param != null ? param.ToString() : "null";

                    list.Add(value);

                }

            }

            return string.Join(", ", list.ToArray());

        }

    }

Just inheriting from CThru.Aspect abstract class and implement ShouldIntercept abstract method to return a Predicate<InterceptInfo> delegate you are able to log any type you want with a very simple call like

var aspect = new TraceAspect(info => info.TargetInstance is IHttpHandler, @"C:\log.txt");

Very very powerfull and easy!!! many thnks for that wonderful API to Roy Osherove and TypeMock people.

So back to our case our aspect will look like

    public class ExistentMembersEnableValidationAspect : Aspect {

        static FieldInfo backingField;

 

 

        public ExistentMembersEnableValidationAspect() {

            backingField =

                typeof (RulePropertyValueProperties).GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Where(

                    info => info.Name == "propertyName").Single();

        }

 

        public override bool ShouldIntercept(InterceptInfo info) {

            return info.TargetInstance is RulePropertyValueProperties;

        }

 

        public override void MethodBehavior(DuringCallbackEventArgs e) {

            base.MethodBehavior(e);

            if (e.MethodName == "set_TargetPropertyName") {

                e.MethodBehavior = MethodBehaviors.SkipActualMethod;

                backingField.SetValue(e.TargetInstance, e.ParameterValues[0]);

            }

        }

    }

and the spec I wrote using MSpec is like

image

I am sure you can see why “hacking” is on my post title by now :) the above approach could be used to bypass a licensing system as well

To finalize this long post, I understand that some of you may not like that approach again for your own reasons that I would be happy to learn. So I am going to create a new platform suffix for eXpand modules the CThru platform suffix.

In order to use the above solution you have to register the eXpand.ExpressApp.WorldCreator.CThru assembly found in eXpand.DLL folder

But to those of you that like and want to use the above approach I need to remind you that eXpand has an open source lisence for CThru and TypeMock so please feel free to contact me so you can get your lisence to be used with eXpand

You may also wondering about speed implications. The following controller will fix that for you

public partial class RuleSetInitializationController : DevExpress.ExpressApp.Validation.RuleSetInitializationController

{

    public RuleSetInitializationController()

    {

        InitializeComponent();

        RegisterActions(components);

    }

    protected override void OnActivated()

    {

        if (Application != null) {

            var module = (ValidationModule) Application.Modules.FindModule(typeof (ValidationModule));

            if (module != null) {

                CThruEngine.AddAspect(new ExistentMembersEnableValidationAspect());

                CThruEngine.StartListening();

                InternalMockManager.Locked = false;

                module.RuleSetInitialized += (sender, args) => {

                    CThruEngine.StopListeningAndReset();

                    InternalMockManager.Locked = true;

                };

                module.InitializeRuleSet();

            }

            else {

                Tracing.Tracer.LogWarning("Cannot find Validation module in Module list: {0}",typeof (ValidationModule).AssemblyQualifiedName);

            }

        }

    }

 

}

since it will create the aspect only when its needed. And to prove my saying watch the next video

DiggIt!

Monday, January 18, 2010

Collaborating with Xaf and IO module

.NET provides a lot of ways to collaborate between systems. All of them are based on data serialization. XPO is missing that, and have a client project that could not live without some generic type of serialization. So I create a simple but powerful IO engine

  • It can serialize any object that inherits DevExpress.Xpo.XPBaseObject.
  • It will also serialize any object that is related to the root object of serialization.
  • To control the export engine A serialization graph can be provided .
  • Object's properties can be serialized according to Serialization Strategy enumeration 

    public enum SerializationStrategy

    {

        SerializeAsValue = 0,

        SerializeAsObject,

        DoNotSerialize

    }

  • Friendly keys support. For importing data from other RDBMS systems that do not have a GUID primary key

Scenario

  1. From a non xaf application I need to import customers based on some filtering taken from a xaf application.
  2. The design of Customer object differs between applications. In the Xaf application Customer inherits user but in the non Xaf does not. Property names also differ

The above problems can be solved with IO module with easy

2 apps communicating
Lets try to build a WCF service to enable communication. We are going to host it on IIS so create a new WCF Service Application

 image
reference the following assemblies take a not that I also reference Solution3.Web which is my client front end

 image

add an HttpModule to setup an application instance at HttpApplication init. We need to setup an application instance to be sure that the XPDictionary modifications through controllers take place

image

    public class InitXafAppModule:IHttpModule

    {

        public void Init(HttpApplication context) {

            WebApplication.SetInstance(context.Session, new Solution3AspNetApplication());

 

            if (ConfigurationManager.ConnectionStrings["ConnectionString"] != null) {

                WebApplication.Instance.ConnectionString =

                    ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;

            }

 

            WebApplication.Instance.Setup();

            WebApplication.Instance.Start();

 

        }

 

        public void Dispose() {

 

        }

    }


Our service is going to have the following contract

    [ServiceContract]

    public interface IIOService {

        [OperationContract]

        string Export(string typeName, string criteria);

 

        [OperationContract]

        void Import(string xml);

    }

and implemented as

    public class IOService : IIOService

    {

        public string Export(string typeName, string criteria)

        {

            var session = WebApplication.Instance.ObjectSpaceProvider.CreateUpdatingSession();

            var xpBaseObjects = new XPCollection(session, ReflectionHelper.GetType(typeName), criteria).OfType<XPBaseObject>();

            XDocument xDocument = new ExportEngine().Export(xpBaseObjects);

            var stringWriter = new StringWriter();

            xDocument.Save(stringWriter);

            return stringWriter.GetStringBuilder().ToString();

        }

 

        public void Import(string xml)

        {

            var unitOfWork = new UnitOfWork(WebApplication.Instance.ObjectSpaceProvider.CreateUpdatingSession().DataLayer);

            var importEngine = new ImportEngine();

            importEngine.ImportObjects(XDocument.Parse(xml), unitOfWork);

            unitOfWork.CommitChanges();

        }

    }

Now we are able to call the WCF service to get the xml of Customers of the Xaf application and transform it using extension methods defined in IO module like

var xElement = XDocument.Parse(xml).Root;


IEnumerable<NonXafCustomer> customers =xElement.SerializedObjects("Customer").Select(element => new NonXafCustomer {Name = element.Property("UserName").Value});



ps:Import/Export action within a xaf application are inside export predefined category and they are available for all objects



image

DiggIt!

Monday, January 11, 2010

WorldCreator2 source code is out and stable

 

I have never really release a stable version through this blog of the module that allows you to create dynamic types through templating and scripting, so I am doing it now that the code is stable enough.

To get the code read http://apobekiaris.blogspot.com/2009/10/how-to-get-expand-latest-version.html

New Features

eXpand Application Solution project item template

John Pouliezos created a better design experience for all eXpand users by adding a New Project Item template.

10-1-2010 8-28-35 μμ

Using the above template you do not have to worry any more about setting up assembly references or registering modules/ persistent classes

To install the template run the vs_setup.cmd batch file located at the root of eXpand folder after running buildall.cmd. You may want to uncomment the x86 lines if your system is not x64

10-1-2010 8-48-30 μμ

or change your VS path if its not installed at the default location.

Runtime assembly validation

Your dynamic assemblies may not compile any more if you mess your scripts, up to now compilation happen every application startup, so to save that startup time I have added a new validate action that can validate your scripts and display any errors at persistent assembly compile errors property without restart

10-1-2010 8-57-11 μμ

Auto generation of associated collection

Again to speed things up and since xpo requires to add a collection property to the other part of association, when u create a new referenced object association you can automatically create the other part as well.

image

take a note that the “Auto Generate Other Part Member” now works only on reference properties and not the other way around, also the generation takes place at persistent reference memberInfo saving only if member info has a persistent association attribute

ps:if you do not use the eXpand new project item template I suggest you add the following code at your module.designer.cs file that is responsible for loading all persistent classes

image image
DiggIt!

Monday, December 21, 2009

eXpand presentation at XERP

XERP is an open source movement in order to create a .Net profitable enviroment. eXpand is serving the same goal and did a presentation of current state eXpand at 1st XERP meeting.

I have demo the creation of a simple domain without writing any code. The modules used in the session

WorldCreator for runtime Domain objects modelling + any custom scripting required to achieve the goal

AdditionalViewsControlProvider for disaplying controls and bound them to domain objects

ModelDifference module to configure the application model .

ModelArtifact to make conditional a behaviour expressed by a controller

 

DiggIt!