Eric Evans: Domain-Driven Design

January 29, 2010 Book Reviews No comments

Domain Driven Design by Eric Evans is one of the books that every architect must read if he wants to develop really extensible enterprise level application, which absorbs knowledge of the problematic domain.

Book talks about Ubiquitous Language which is the language between Domain Experts and Developers and helps them build model of the application.

Once you have this language you could easily start build your model with Entities and Value Objects, making Associations between them and other elements of the system. Then you use Services to apply operations on your domain. To interact with Infrastructure you need Repositories and Factories, this makes Persistace Ignorance Layer to hide and isolate your model from technical impacts of your infrastructure.

Refactoring Toward Deeper Insight plus Distilling of model takes your system to the breakthrough. If you have clear model, future Developers could easily work with it addin new functionality and speaking with Customer on common language they will know it, because code raises it to them.

This is one of most valuable book I’ve ever read!



No comments


Session.Merge(object obj) to RESCUE

January 29, 2010 Errors, NHibernate No comments

Error:

“a different object with the same identifier value was already associated with the session: 14, of entity: Developer.RoadMap.To.Success.Entities.Customer”

I had something like this in the SaveCustomer method:

if ( customer.CustomerID > 0 )
{
    Session.Update( customer);
}
else
{
    Session.SaveOrUpdate( customer);
}
transaction.Commit();

And this don’t work correctly. Simple change to

if ( customer.CustomerID > 0 )
{
    customer = Session.Merge( customer );
}
else
{
    Session.SaveOrUpdate( customer);
}
transaction.Commit();

resolved my issue.


No comments


Event Name: CLR20r3

January 27, 2010 Deployment, Errors 2 comments

I got error which says “MyApplicationName has stopped working” once deployed simple tool application to the deployment machine which is MS 2008 Server.

But application works just fine on my Dev Machine.
I took a look on event viewer and it says:

Fault bucket 952814299, type 5
Event Name: CLR20r3
Response: None
Cab Id: 0

Problem signature:
P1: myapplicationname.exe
P2: 1.0.0.0
P3: 4b607991
P4: MyApplicationName
P5: 1.0.0.0
P6: 4b607991
P7: 83
P8: f
P9: System.IO.FileNotFoundException
P10:


It looks like something I was referencing is something in the framework that wasn’t installed on the server.
But what?

I remembered that when worked with UI I inadvertently took some thing from ToolBox. I immediately removed that thing, but REFERENCE were left in projects references.
It was Microsoft.VisualBasic and Microsoft.VisualBasic.PowerPacks.Vs.

Moral:
Once you get errors on deployment machine check carefully if you haven’t referenced something that is not needed. And remember about Event Viewer.


2 comments


Managed Extensibility Framework

January 27, 2010 .NET, Frameworks, MEF 4 comments

MEF is the Framework which allows you to load extensions to you application easily. It does discovery and composition of parts you need to be included in your application at run-time. You could extend your behavior simply with adding new Plugin. Managed Extensibility Framework will do everything for you.

Hello MEF World!

Assume we have really simple application and we want it to say “Hello MEF World!“:

    class Program
    {
        static void Main(string[] args)
        {
            var program = new Program();
            program.Run();
        }
        private void Run()
        {
            ProgrammGreeter.SayHello();
        }
        protected IGreeter ProgrammGreeter{ get; set;}
    }
    public interface IGreeter
    {
        void SayHello();
    }
    public class Greeter:IGreeter
    {
        public void SayHello()
        {
            Console.WriteLine(“Hello MEF World!”);
        }
    }

That is absolutely how this look and we want to make this work. The main issue is to have instance in property ProgrammGreeter to be real instance of Greeter.

Lets accomplish this with MEF

In order to do this we need to include reference to System.ComponentModel.Composition.

Accordingly to MSDN: “MEF is an integral part of the .NET Framework 4 Beta 1, and is available wherever the .NET Framework is used. You can use MEF in your client applications, whether they use Windows Forms, WPF, or any other technology, or in server applications that use ASP.NET. In addition, there are plans to add MEF support for Silverlight applications.

Most likely MEF will be included into .NET Framework 4.0, but for now we could download it from codeplex site here.

Once we added reference we could add Import and Export attributes.
Export stands for exposing some capabilities and Import stands for dependency on some other capability.

Our Greeter provides some capabilities so we add Export there:

    [Export(typeof(IGreeter))]
    public class Greeter : IGreeter

We want to use that capability in our Programm class, we depend on that functionality. Add Import:

        [Import]
        protected IGreeter ProgrammGreeter { get; set; }

Usually our capabilities lives in other asseblies, but also they could live in called assembly. Anyway we need to say how to compose all our dependencies to MEF.
This could be done with method Compose which we be calling before we are using capabilities, usually at the start of app:

        private void Run()
        {
            Compose();
            ProgrammGreeter.SayHello();
        }
        private void Compose()
        {
            var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
            var compositionContainer = new CompositionContainer(assemblyCatalog);
            compositionContainer.ComposeParts(this);
        }

I ran my application and got:

How does Managed Extensibility Framework work?

I think that you are bit concerned/confused regarding that Compose method. Just read comments in code of Compose, which I made more detailed:

        //We need guide MEF how to Compose all we need
        private void Compose()
        {
            //Catalog says where to search for capabilities (Where do exports live)
            var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
            //CompositionContainer holds defined dependencies and coordinates creation
            var compositionContainer = new CompositionContainer(assemblyCatalog);
            //CompositionBatch object holds references to all objects that need to be composed
            var compositionBatch = new CompositionBatch();
            //one of such objects is Programm instance (this), it needs to be composed
            compositionBatch.AddPart(this);
            //And finally Container has method called Compose to do actuall Composing
            compositionContainer.Compose(compositionBatch);
        }

In Managed Extensibility Framework there are primitives called ComposablePart which holds extensions to your application grabbed from Catalog. But also it might be that they have Imports which also needed to be composed.

Take a look on this picture from Managed Extensibility Framework wiki page.

More complex Example

In this example we will have application which parses XML file (contains information about some developer). Then when we want to deploy our application to Clients we want that XML to pass some rules, but they could differ from Client to Client. To accomplish this we put rules into separate dll and will work with it as with plugin.

We have two assemblies:

  • MEF.DEMO which declares ISecurityRule and IDataRule.
  • MEF.Rules has implementation of those interfaces.

Like on picture below. I simply don’t want to bore you with explaining of Rules logic. If you want sources just ping me.

Our Programm class wants to load rules from other assembly so we put Imports.

        [Import]
        public ISecurityRule SecurityRule { get; set; }
        [ImportMany]
        public IDataRule[] DataRules { get; set; }
        public void Run()
        {
            Console.WriteLine(“Programm run.”);
            Compose();
            Console.WriteLine(“Composition completed.”);
            var document = XDocument.Load(“developer.xml”);
            Console.WriteLine(document.ToString());
            var passesValidation = SecurityRule.PassesValidation(document);
            Console.WriteLine(string.Format(“Rule {0}: {1}”, SecurityRule.GetType(), passesValidation));
            foreach (var d in DataRules)
            {
                var valid = d.IsValid(document);
                Console.WriteLine(string.Format(“Rule {0}: {1}”, d.GetType(), valid));
            }          
        }

As you noticed we are using ImportMany, name says for itself.

We need to change our Compose method to search for Exports in Directory where execution assembly is located. For that we use DirectoryCatalog.

        private void Compose()
        {
            var catalog = new DirectoryCatalog(Environment.CurrentDirectory);
            var container = new CompositionContainer(catalog);
            container.ComposeParts(this);
        }

Put those dlls in one folder, and run MEF.DEMO. You will get:

The goal of MEF is to seamlessly glue together classes which import services from other parts of the application, and some classes which export those services. You could say that MEF is like DI container. Yes it has a lot of it, but Managed Extensibility Framework is concentrated on composition. And that composition could be done at run time at any point of time you want that to happen. Also you could do re-composition whenever you want to do that. You could load capabilities with Lazy technical or add some metadata to your exports. Discovering of dependencies in Catalog could be done with Filtering.

Managed Extensibility Framework is great feature, that Microsoft added to .NET 4.0 Framework.


4 comments


Button in pressed/unpressed state in System.Windows.Forms

January 26, 2010 QuickTip, UI, WindowsForms No comments

Do you want to see your button to be in pressed or unpressed state when you hit it once?

Did you catch that this behavior is not really button’s behavior – it is more checkBox’s behavior.

So to accomplish your goal you need move checkBox to your form and set appearance from “Normal” to “Button”. Like here:

System.Windows.Forms.CheckBox checkBox1 = new System.Windows.Forms.CheckBox();
checkBox1.Appearance = System.Windows.Forms.Appearance.Button;

Kick me if you don’t want to see such posts on my blog. :)


No comments


I Increased posting frequency

January 26, 2010 Opinion, RandomThoughts, Success No comments

I have 18th post this month that is more than in past three months. This means that I increased frequency of posting and I think that did not lost quality of its content. What do you think?

I think I’m good on this. I also increased amount of blogs I read (near 30).

Why do I think that blogging helps me?

  • I’m learning how to express my thoughts.
  • I grab only consistent knowledge on themas of my posts. This means that I do good research over internet before posting something.
  • After I posted something I leave a good knowledge portion left in my mind.
  • My blog will grow and I will get more readers so will be more famous. People needs this sometimes.
  • This blog also could be a good visiting card for my further career.

To get more readers I need to have some certification that my blog is good to read and this could be reached only if I will continue learn something.

I also found one interested post where guy explains why Why Blog Post Frequency Does Not Matter Anymore. Yes, but my blog has defined content boundary and my posts are not something like posts on twitter, so I believe that it will lead me to Success.

BTW: If you are one of the guys who think that I’m too small fish to read my blog I would say: “Follow me and see if you will be so fast all the distance as I will be.”

Honestly I think we should see people in light of theirs attitude to something, but not in light of theirs knowledge of something.

Leave your comment with link to your blog. I will follow you immediately. ;)


No comments


Specification

January 25, 2010 Design Patterns 3 comments

SPECIFICATION

Generally saying Specification is a predicate that determines if an object does or does not satisfy some criteria. By using Specifications you could easily recombine business logic together using boolean logic.

Have you ever thought that bool TryParse(string s, out int result) could be seen as some pattern? Yes we could talk about this method like about specification of integer represented in string, and this is validation usage. This pattern also could be used not only for Validation, but also for Queuring and Building purposes.

Let us imagine that we need to validate if some Patient is eligible for drugs procedures at home provided by nurse.

So this we will need two specifications. If they are both satisfied we could say that this patient is eligible for drugs procedures at home.
 
First specification

    public class EligibleForDrugs : ISpecification
    {
        public bool IsSatisfiedBy(Patient patient)
        {
            return patient.IsActive && patient.HasPayer;
        }

    }
 
Second specification

    public class EligibleForNurseVisit : ISpecification
    {
        public bool IsSatisfiedBy(Patient patient)
        {
            return patient.IsActive && patient.IsAtHome;
        }
    }

As you guess ISpecification interface looks like:

    internal interface ISpecification
    {
        bool IsSatisfiedBy(Patient patient);
    }

Usage could look like:

        public List<Patient> FetchPatientsForVisitWithDrugs(List<Patient> patients)
        {
            var eligiblePatients = new List<Patient>();
            ISpecification drugsSpec = new ElegibleForDrugs();
            ISpecification nurseVisit = new ElegibleForNurseVisit();
            foreach (var patient in patients)
            {
                if(drugsSpec.IsSatisfiedBy(patient) && nurseVisit.IsSatisfiedBy(patient))
                {
                    eligiblePatients.Add(patient);
                }
            }
            return eligiblePatients;
        }

You could say that we can put all verification in our method FetchPatientsForVisitWithDrugs. Yes, but this is not right way, because your specifications could be used in different locations and also if see this from DDD perspective you always need to bring concept things into the light.

Another question: Don’t you see this systax
if(drugsSpec.IsSatisfiedBy(patient) && nurseVisit.IsSatisfiedBy(patient))
to be boring systax? Yes, especially if you have many specifications.

Let us improve our design.

First we will add some methods to our interface like here:

    public interface ISpecification
    {
        bool IsSatisfiedBy(Patient patient);
        ISpecification And(ISpecification secondSpec);
        ISpecification Or(ISpecification secondSpec);
        ISpecification Not(ISpecification secondSpec);

    }

And also will add CompositeSpecification which will be abstract  base class for our two existing.

    public abstract class CompositeSpecification : ISpecification
    {
        public abstract bool IsSatisfiedBy(Patient patient);
        public ISpecification And(ISpecification secondSpec)
        {
            return new AndSpecification(this, secondSpec);
        }
        public ISpecification Or(ISpecification secondSpec)
        {
            return new OrSpecification(this, secondSpec);
        }
        public ISpecification Not(ISpecification secondSpec)
        {
            return new NotSpecification(secondSpec);
        }
    }
Classes returned by different method of this new CompositeSpecification are used to combine few specifications in order to build new complicated one. They could look simple like this AndSpecification class:
    public class AndSpecification : CompositeSpecification
    {
        private ISpecification firstOne;
        private ISpecification secondOne;
        public AndSpecification(ISpecification firstSpec, ISpecification secondSpec)
        {
            firstOne = firstSpec;
            secondOne = secondSpec;
        }
        public override bool IsSatisfiedBy(Patient patient)
        {
            return firstOne.IsSatisfiedBy(patient) && secondOne.IsSatisfiedBy(patient);
        }
    }

Let’s move to our existing specifications and how they changed with our new design:

    public class EligibleForDrugs : CompositeSpecification
    {
        public override bool IsSatisfiedBy(Patient patient)
        {
            return patient.IsActive && patient.HasPayer;
        }

    }

This all gives us ability to have build specifications quering in more sweet way.
New Usage

            ISpecification specification = new EligibleForDrugs()
                                           .And(new EligibleForNurseVisit());

Now we work with this new specification as with simple single one: if(specification.IsSatisfiedBy(patient))
With other specifications like OrSpecification and NotSpecification we could build more complicated queries.

For example I will show some possible usage of this in Nhibernate:

        public DetachedCriteria PatietQuery(DetachedCriteria criteria)
        {
            criteria.Add(criteria.EqualTo(“patient.IsActive”, true));
            criteria.Add(
                    Expression.Not(
                        Expression.Or(
                            Expression.Eq(“patient.Type”, PatientStatus.Discharge),
                            Expression.Eq(“patient.Type”, PatientStatus.Death)
                        )
                    )
                );
            return criteria;
        }

Advantages of the Specification:

  • Specification declares requirements to the output but do not expose how those results are reached.
  • Rules are defined explicitely. This means that developer could know what to expect from the specification even without knowledge how that is realized.
  • You get flexible interface, which could be easily enhanced. You also could build your composite specifications for queuring.
  • Another good advantage is possitility to test everything easily. You just define fail, non-fail states of the object and verify by checking boolean result.


3 comments


Template Method

January 23, 2010 Design Patterns 2 comments

Consider you need to develop some searching engine. Engine will look for different messages that has been sent. Searching process consists with few operations which make sense for each of message, BUT could have some characteristic which differs.
You want to write Searcher, which will allow you encapsulate algorithm of searching, but you also want to leave ability override behavior of some operations for specific messages. How could you accomplish this easily?

TEMPLATE METHOD

This pattern is intuitive as well as realization of it. You will need base class which holds primitive operations and some Template method (Search) which operates with those operations. Each operation could be overridden in derived classes.

I wrote naive implementation of this pattern, because I call primitive operations one by one in my template method. In real world you could hold complex algorithm built on your primitive operations. And you will just need to override parts which differs from standard implemented in base class. Please note that you could make primitive operations abstract. This will require implementation in each derived class.

My example implementation

//base class
public class MessagesSearcher {

    protected Date DateSent;
    protected String PersonName;
    protected int ImportanceLevel;

    public MessagesSearcher(Date dateSent, String personName, int importanceLevel){
        DateSent = dateSent;
        PersonName = personName;
        ImportanceLevel = importanceLevel;
    }
   
    //primitive operations
    protected void createDateCriteria(){
        System.out.println(“Standard date criteria has been applied.”);
    }
    protected void createSentPersonCriteria(){
        System.out.println(“Standard person criteria has been applied.”);
    }  
    protected void createImportanceCriteria(){
        System.out.println(“Standard importance criteria has been applied.”);
    }
   
    //TEMPLATE METHOD
    public String Search(){
        createDateCriteria();
        createSentPersonCriteria();
        System.out.println(“Template method does some verification accordingly to search algo.”);
        createImportanceCriteria();
        System.out.println(“Template method verifies if message could be so important or useless from person provided in criteria.”);
        System.out.println();
        return “Some list of messages…”;
    }
}

public class ImportantMessagesSearcher extends MessagesSearcher{

    public ImportantMessagesSearcher(Date dateSent, String personName) {
        super(dateSent, personName, 3); // 3 means important message
    }
   
    //primitive operation overriden
    protected void createImportanceCriteria(){
        System.out.println(“Special importance criteria has been formed: IMPORTANT”);
    }
}

public class UselessMessagesSearcher extends MessagesSearcher {

    public UselessMessagesSearcher(Date dateSent, String personName) {
        super(dateSent, personName, 1); // 1 means useless message
    }
   
    //primitive operation overriden
    protected void createImportanceCriteria(){
        System.out.println(“Special importance criteria has been formed: USELESS”);
    }
}

Following usage:

MessagesSearcher searcher = new UselessMessagesSearcher(null, “Sally”);
searcher.Search();
searcher = new ImportantMessagesSearcher(null, “Killer”);
searcher.Search();

Produces output:
   

Standard date criteria has been applied.
Standard person criteria has been applied.
Template method does some verification accordingly to search algo.
Special importance criteria has been formed: USELESS
Template method verifies if message could be so important or useless from person provided in criteria.

Standard date criteria has been applied.
Standard person criteria has been applied.
Template method does some verification accordingly to search algo.
Special importance criteria has been formed: IMPORTANT
Template method verifies if message could be so important or useless from person provided in criteria.

Hope my example was not painful to understand. Honestly I do not see it to be 100% clear example on this pattern, but I think I did a great job on this. Of course you could find dozens of examples of it over internet. But this one is mine and it have put something in my mind.


2 comments


Generics performance vs. non-generics performance

January 22, 2010 .NET, Opinion 7 comments

Today I was reading some book on the .net development and found there interesting thing.

Guy explains “Why to use Generics?
He wrote that Frameworks 1.0 and 1.1 did not support Generics, so developers were using Object.
He says, that generics offers two significant advantages over using the Object class:
1) Reduced run-time errors
That is because type-safety.
2) Improved perfomance
Casting requires boxing and unboxing, which slows performance. Using of Generics doesn’t require casting or boxing, which improves run-time performance.

And then funny thing…
He put a box which looks like:

Real Word
(his name)
I haven’t been able to reproduce the performance benefits of generics;
however, according to Microsoft, generics are faster than using
casting. In practice, casting proved to be several times faster than
using a generic. However, you probably won’t notice performance
differences in your applications. (My tests over 100,000 iterations took only a few seconds.) So you should still use generics because they are type-safe.

OMG! I could not believe in his words. As per me this should be BULLSHIT, unless I 100% missed something there.

Test

I wrote a really quick verification like:

namespace TestGenericsPerfomance
{
    class Program
    {
        internal static void Main(string[] args)
        {
            Stopwatch stopWatch = new Stopwatch();
            //Working with value objects
            //Generic wins 100%
            stopWatch.Start();
            ArrayList nonGenericArrayList = new ArrayList();
            for (int i = 0; i < 10000000; i++)
            {
                nonGenericArrayList.Add(i);//takes Object so boxing is performed here…
            }
            stopWatch.Stop();
            Console.WriteLine(string.Format(“Int32: ArrayList (boxing): {0:0}”, stopWatch.Elapsed.TotalMilliseconds));
            stopWatch.Restart();
            List<Int32> someCustomersIds = new List<Int32>();
            for (int i = 0; i < 10000000; i++)
            {
                someCustomersIds.Add(i);
            }
            stopWatch.Stop();
            Console.WriteLine(string.Format(“Int32: List<Int32> (generic): {0:0}”, stopWatch.Elapsed.TotalMilliseconds));
 
            //Working with reference objects
            //Generic still wins, but not so sure..
            Customer sharedCustomer = new Customer();
            stopWatch.Restart();
            ArrayList nonGenericArrayListCustomers = new ArrayList();
            for (int i = 0; i < 10000000; i++)
            {
                nonGenericArrayListCustomers.Add(sharedCustomer);//no boxing.. jut putting the same reference
            }
            stopWatch.Stop();
            Console.WriteLine(string.Format(“Customer: ArrayList (no boxing): {0:0}”, stopWatch.Elapsed.TotalMilliseconds));
            stopWatch.Restart();
            List<Customer> genericBasedOnInterface = new List<Customer>();
            for (int i = 0; i < 10000000; i++)
            {
                genericBasedOnInterface.Add(sharedCustomer);//just put the same reference in generic list
            }
            stopWatch.Stop();
            Console.WriteLine(string.Format(“Customer: List<Customer> (no boxing): {0:0}”, stopWatch.Elapsed.TotalMilliseconds));
        }
        private class Customer
        {
            public string Name = “Andriy Buday”;
            public string Buy(string what)
            {
                return “I’m glad I bought that.”;
            }
        }
    }
}

And the result is:

Int32: ArrayList (boxing): 2443
Int32: List<Int32> (generic): 294
Customer: ArrayList (no boxing): 586
Customer: List<Customer> (no boxing): 315
Press any key to continue . . .

As you see generics are much faster. Also I searched over internet and found a lot of different stuff that says that generics provide better performance.

My Opinion

You would said what kind of book do I read. Is it “C# for Complete Dummy“?
No, that is Microsoft’s training Kit for exam 70-536.
Even if this was a book “C# for Dummy” it should not contain mistakes. And even if this is a book for kids it should not contain wrong thing. Yea.. it could be very simple, but not wrong!

I thought to write e-mail to that guy, but then decided that there is no need in this.

Just be careful when you read books and others thoughts, even mine :)


7 comments


Complex Custom Configuration

January 19, 2010 .NET 1 comment

Have you ever faced with need to have your custom configuration?

Probably yes, on MSDN you can find a good example on custom configuration here.
That example was not 100% what I need, since I needed few included one in others collections. Like below:

<?xml version=1.0 encoding=utf-8 ?>
<configuration>
  <configSections>
      <section name=ServicesSettings type=RoadMap.CustomConfiguration.ServicesSection, RoadMap.CustomConfiguration/>
  </configSections>
  <ServicesSettings>
    <Services>
      <add serviceName=Greeter isEnabled=true interval=7>
        <Messages>
          <add messageName=Hello/>
          <add messageName=World/>
        </Messages>
      </add>

      <add serviceName=BadBoy isEnabled=false interval=“10”>
        <Messages>
          <add messageName=Go to/>
          <add messageName=Hell/>
        </Messages>
      </add>

    </Services>
  </ServicesSettings>
</configuration>

As you see I want to get list of services which of them could be enabled or disabled also it could have interval to send one or many messages, which are also configured.

As you see I already added RoadMap.CustomConfiguration.ServicesSection to map ServiceSettings section to my appropriate class:

ServicesSection

using System.Configuration;
namespace RoadMap.CustomConfiguration
{
    public class ServicesSection : ConfigurationSection
    {
        [ConfigurationProperty(“Services”)]
        public ServicesCollection Services
        {
            get { return ((ServicesCollection)(base[“Services”])); }
        }
    }
}

Next you will probably will want to take a look is ServicesCollection:

ServicesCollection

using System.Configuration;
namespace RoadMap.CustomConfiguration
{
    [ConfigurationCollection(typeof(ServiceElement))]
    public class ServicesCollection : ConfigurationElementCollection
    {
        protected override ConfigurationElement CreateNewElement()
        {
            return new ServiceElement();
        }
        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((ServiceElement)(element)).Name;
        }
        public bool ContainsKey(string key)
        {
            var element = BaseGet(key);
            return element != null ? true : false;
        }
        public ServiceElement this[int idx]
        {
            get
            {
                return (ServiceElement)BaseGet(idx);
            }
        }
        public ServiceElement this[object key]
        {
            get
            {
                return (ServiceElement)BaseGet(key);
            }
        }
        public void Add(ServiceElement element)
        {
            base.BaseAdd(element);
        }
    }
}

ServiceElement

using System;
using System.Configuration;
namespace RoadMap.CustomConfiguration
{
    public class ServiceElement : ConfigurationElement
    {
        [ConfigurationProperty(“serviceName”, DefaultValue = “Greeter”, IsRequired = true)]
        [StringValidator(InvalidCharacters = “~!@#$%^&*()[]{}/;'”|\”, MinLength = 1, MaxLength = 60)]
        public String Name
        {
            get
            { return (String)this[“serviceName”]; }
            set
            { this[“serviceName”] = value; }
        }
        [ConfigurationProperty(“isEnabled”, DefaultValue = true, IsRequired = false)]
        public bool IsEnabled
        {
            get
            { return (bool)this[“isEnabled”]; }
            set
            { this[“isEnabled”] = value; }
        }
        [ConfigurationProperty(“interval”, DefaultValue = “10”, IsRequired = false)]
        [IntegerValidator(ExcludeRange = false, MaxValue = 100, MinValue = 1)]
        public int Interval
        {
            get
            { return (int)this[“interval”]; }
            set
            { this[“interval”] = value; }
        }
        [ConfigurationProperty(“Messages”)]
        public MessagesCollection Messages
        {
            get { return ((MessagesCollection)(base[“Messages”])); }
        }
    }
}

As you see it has Messages property which is again collection (similar to ServicesCollection) of MessageElements:

MessageElement

using System;
using System.Configuration;
namespace RoadMap.CustomConfiguration
{
    public class MessageElement : ConfigurationElement
    {
        [ConfigurationProperty(“messageName”, DefaultValue = “hi”, IsRequired = true)]
        [StringValidator(InvalidCharacters = “~!@#$%^&*()[]{}/;'”|\”, MinLength = 1, MaxLength = 60)]
        public String Name
        {
            get
            { return (String)this[“messageName”]; }
            set
            { this[“messageName”] = value; }
        }
    }
}

To ensure you that this works as expected just take a look on following screenshots:

We have one Greeter service:

It has two messages and second one is “World”:

Hope you could just copy-paste my code and also add MessagesCollection and you are done, just change naming to your needs.


1 comment