This post may be outdated. For the latest Domain Components concepts and examples refer to the current online documentation.
Addresses are funny things aren’t they? If you own the the Address class, and you are writing it for your own application then they are easy things to handle. Each address object is a composition of a number of string types containing the information you require for your application. Simple and straight forward. Of course, as soon as you try to write a reusable interface library, things start to get a little more complicated, so let’s take a look at how we did it.
First, let’s start with an IBaseAddress component:
public interface IBaseAddress
{
string DisplayName { get; set; }
}
Having this base class for addresses we can now go on to define an IAddressable interface, which entities that require to have one, or more, addresses can use – things like Contacts, Orders, Shipping Notes etc. We can define our IAddressable interface like so:
[DomainComponent]
public interface IAddressable
{
[DevExpress.ExpressApp.DC.Aggregated]
[VisibleInListView(false)]
IBaseAddress PrimaryAddress { get; set; }
[CreateInstance]
IBaseAddress CreateAddress();
}
And we can use it, wherever we need to, like this:
public interface ICRMContact : IContact, IAddressable, ...
public interface ICRMAccount : IAccount, IAddressable, ...
public interface ICRMLead : ILead, IAddressable, ...
In this interface, there are two significant parts: the PrimaryAddress member, which is aggregated, and it brings in the minimum information of an addresses – the primary address.
The second significant part is the CreateAddress method that is marked with the CreateInstance attribute. This method is used as a factory method to create an entity that is registered for the IBaseAddress domain component. This method is autogenerated and will work when one entity in the application implements the IBaseAddress interface. In other cases, you need to implement it manually and you’ll have to specify which entity should be created, in this method, when it is called:
[DomainLogic(typeof(IAddressable))]
public class AddressableLogic {
public static void AfterConstruction(IAddressable addressable) {
if(addressable.PrimaryAddress == null) {
addressable.PrimaryAddress = addressable.CreateAddress();
}
}
Now our implementation is far from perfect. Using a string makes it hard to process the address by address part, to filter by a city for example. It is also impossible to guarantee any strict form of address format, which your application may need to do. Providing default lists, say of cities or of US states, is also difficult to do.
So, let’s improve things by defining a generic address component in our library, this component can be substituted with your own implementation should you need something more specific.
Our IGenericAddress component will look like this:
[DomainComponent]
public interface IGenericAddress : IBaseAddress
{
string Street1 { get; set; }
string Street2 { get; set; }
string City { get; set; }
string State { get; set; }
string Zip { get; set; }
string Country { get; set; }
}
Here you will notice that the single string DisplayName has been broken down into several string members, and is constructed from these parts when any of them is modified:
[DomainLogic(typeof(IGenericAddress))]
public class GenericAddressLogic {
private static void UpdateDisplayName(IGenericAddress address) {
address.DisplayName = string.Format("{0} {1} {2} {3} {4} {5}", address.Street2, address.Street1, address.City, address.State,
address.Zip, address.Country);
}
public static void AfterChange_Street1(IGenericAddress address) {
UpdateDisplayName(address);
}
public static void AfterChange_City(IGenericAddress address) {
UpdateDisplayName(address);
}
...
With this approach, it is possible for you to introduce any other Address implementation into any library component that contains the IBaseAddress member.
On the Order UI in our XCRM demo application, the address UI looks like this:

Well that’s all for this post, until next time, happy XAF’ing! 