CodeFluent Entities Documentation
Writing an Aspect in Code
See Also Send comments on this topic.
CodeFluent Entities > Architect Guide > Aspect Oriented Design > Custom Aspects > Writing an Aspect in Code

Glossary Item Box

This topic illustrates how to write an aspect using C#.

Writing your aspects in Visual Studio is very interesting since you can benefit from Visual Studio's autocompletion and you can debug it at run time. However, compared to Writing an Aspect in XML, you're less impervious to change since you're not referencing a specifc version of the CodeFluent Entities API, plus the code is less accessible to other developers using your aspect.

This being said, this article will show you how to write one and then use it in a model.

 

Using the API in a class library

The same way aspects can be developed in XML, you can do it in C# in a standard class library. This way, by referencing the CodeFluent Entities API you'll benefit from autocompletion when developing it. Developing your aspect is pretty much the same, however since you're using an assembly and not a XML file anymore, using it in your model differs.

For instance, say we developed a custom aspect named Sample.Tracking which we presented at the begining of this article; well, here's how to use it in a model:

Using an aspect in an assembly Copy Code
<cf:project defaultNamespace="MyApplication"
            assemblyPaths="..\Sample.Tracking\bin\debug\Sample.Tracking.dll"
            xmlns:cf="http://www.softfluent.com/codefluent/2005/1"
            xmlns:tr="http://www.sample.com/aspects/tracking/2010/1">
  <cf:pattern typeName="Sample.Tracking.TrackingAspect, Sample.Tracking" runTemplate="true" />
...
</cf:project>

In the example above, we're using the TrackingAspect class in the Sample.Tracking assembly. To create an aspect, your aspect class needs to implement the IProjectTemplate interface available in the CodeFluent.Model namespace (you'll need to reference the CodeFluent.Model.dll assembly).

Here's the interface:

IProjectTemplate Copy Code
namespace CodeFluent.Model
{
    public interface IProjectTemplate
    {
        XmlDocument Run(IDictionary context);
    }
}

Here's a sample implementation:

TrackingAspect.cs Copy Code
namespace Sample.Tracking
{
    public class TrackingAspect: IProjectTemplate
    {
        public XmlDocument Run(IDictionary context)
        {
            if ((context != null) && (context.Contains("Project")))
            {
                // the dictionary contains at least these two entries
                Element = (XmlElement)context["Element"];
                Project = (Project)context["Project"];
                // if defined on project, do it on all entities. this is more a debug option
                bool allEntities = XmlUtilities.GetAttribute(Project.Element, "trackable", Constants.NamespaceUri, true);
                IEnumerable<XmlElement> elements;
                if (allEntities)
                {
                    elements = Project.Package.RootModelPart.SelectElements("//*");
                }
                else
                {
                    elements = Project.Package.RootModelPart.SelectElements("trackable", Constants.NamespaceUri, true);
                }
                foreach (XmlElement element in elements)
                {
                    // use a CodeFluent utility method to get entity CLR type full name
                    string entityFullName = Entity.GetClrTypeName(Project, Project.Package.RootModelPart, element);
                    if (entityFullName == null) // attribute was probably not placed on an entityproperty
                        continue;
                    Entity entity = Project.Entities[entityFullName];
                    if ((entity == null) || (entity.GetData(Constants.NamespaceUri + ":done", false)))
                        continue;
                    // TODO: implement logic
                    entity.Data[Constants.NamespaceUri + ":done"] = true;
                }
            } // else we are probably called for meta data inspection
            // we have no specific Xml to send back, but aspect description
            return Constants.Descriptor;
        }
        public Project Project { get; private set; }
        public XmlElement Element { get; private set; }
    }
}

 

In the example above we're using XPath queries and we're mostly working at the XML level (a.k.a. Mx) of the model for performance reasons.

Please note that you can also work at the M² level as well. If so, you can write code such as:

Using the API (M²) Copy Code
// Trace all entities
foreach (Entity entity in project.Entities)
{
    // Trace entity name
    Trace.WriteLine(entity.Name);
 
    // Trace all properties
    Trace.WriteLine("...Properties");
    foreach (Property property in entity.Properties)
    {
        Trace.WriteLine("......" + property.Name + ": " + property.TypeName.ToString());
    }
 
    // Trace all methods
    Trace.WriteLine("...Methods");
    foreach (Method method in entity.Methods)
    {
        Trace.WriteLine("......" + method.Name);
        // Trace stored procedures for CFQL methods
        foreach (Procedure procedure in method.Procedures)
            Trace.WriteLine("........." + procedure.Name + " = " + procedure.MethodBody.DisplayName);
    }
    Trace.WriteLine(".................................................................................");
}

 

See Also