Inside Architecture

Notes on Enterprise Architecture, Business Alignment, Interesting Trends, and anything else that interests me this week...

March, 2005

Posts
  • Inside Architecture

    How to get rid of circular references in C#

    • 4 Comments

    A refers to B, B refers to A, Why can't we all just get along?

    Every now and again, I see a posting on the newsgroups where someone has created a circular reference in their code structure, and they can't figure out how to get out from under it.  I'm writing this article for those folks (and so I have some place to send them when I run across this problem repeatedly).

    Let's start by describing a ciruclar reference.  Let's say that I have a logging layer that is useful for recording events to a log file or a database.  Let's say that is relies on my config settings to decide where to log things.  Let's also say that I have a config settings library that allows me to write back to my config file...


    //calling app:
    Logging myLogObject = new Logging();
    myLogObject.WriteToLog("We are here!");
    MyConfig cnf = new MyConfig();
    cnf.SetSetting("/MyName","mud", myLogObject);

    The class may look like this:

    public class Logging {
     public Logging()
     {
       MyConfig cnf = new MyConfig();

       LoggingLocation = cnf.GetSetting("//Log/Location");
       if (LoggingLocation == "File")
       {
          // save logs to a file
       } 
       else
       {
            // save logs to a database
       }
     }

     public void WriteToLog(String LogMessage, int Severity)
     {
       // write the log message
     }

    }

    If you notice, my little logging app refers to my config file library in the constructor of the logging object.  So now the logging object refers to the config object in code.

    Let's say, however, that we want to write a log entry each time a value is changed in the config file. 

    public class MyConfig
    {
       public MyConfig() { }
       public string GetSetting(string SettingXPath)
       {
          // go get the setting
       }
       public void SetSetting(string SettingXPath, string newValue, Logging myLog)
       {
          // set the string and...
          myLog.WriteToLog("Updated " + SettingXPath + " : " + newValue);
       }
    }

    OK, so I removed most of the interesting code.  I left in the reference, though.  Now the config object refers to the logging object.  Note that I am passing in actual objects, and not using static methods.  You can get here just as easily if you use static methods.  However, digging yourself out requires real objects, as you will see.

    Now, compile them both.  One class will require the other.  If they are in the same assembly, it won't matter.  However, if they are in seperate DLLs, as I want to use them, we have a problem, because neither wants to be the one to compile first.

    The solution is to decide who wins: the config object or the logging object.  The winner will be the first to compile.  It will contain a definition of an interface that BOTH will use.  (Note: you can put the interface in a third DLL that both will refer to... a little more complicated to describe, but the same effect.  I'll let you decide what you like better :-).

    For this example, I will pick the config object as the winner. In this case, the logging object will continue to refer to the config object, but we will break the bond that requires the config object to refer to the logging object.

    Let's add the Interface to the Config object assembly:

    public interface IMyLogging
    {
       void WriteToLog(String LogMessage, int Severity);
    }

    Let's change the code in the call to SetSetting:

       public void SetSetting(string SettingXPath, string newValue, IMyLogging myLog)
       {
          // set the string and...
          myLog.WriteToLog("Updated " + SettingXPath + " : " + newValue);
       }

    You will notice that the only think I changed was the declaration.  The rest of the code is unchanged.

    Now, in the Logging object:

    public class Logging : IMyLogging {
    // the rest is unchanged
    }

    Now, the Logging assembly continues to rely on the config assembly, but instead of just relying on it for the definition of our config class, we also rely on it for the definition of the IMyLogging interface.

    On the other hand, the config class is self sufficient.  It doesn't need any other class to define anything.

    Now, both assemblies will compile just fine.

  • Inside Architecture

    On Security in Workflow

    • 2 Comments

    It's been ages sinces I've blogged on workflow.  I've been wildly busy implementing a workflow engine in C# that will ride under any .Net app while providing a truly light and easy to understand modeling language for the business user.

    One business modeler is now able to go from inception to full document workflow implementation in about 20 hours, including creating the forms, e-mails, model, staging, debugging, and deployment.  The only tools that need to be installed on the modeler's PC are Infopath (for forms, e-mail, and model development) and our custom workflow management tool that allows management, packaging of a workflow and remote installation to the server.

    One problem that we've been solving has to do with security.  Just how do you secure a workflow.

    For those of you who live on Mars, Microsoft is very heavily focussed on driving security into every application, even ones developed internally.  Plus, workflow apps need security too.

    Thankfully, the first "big" refactoring we've done to the design of the workflow engine was in the area of security.  I'd hate to have added workflow security later, after we had a long list of models in production.  As it stands, we only have a handful of models to update.

    So what does security in a workflow look like?  Like security in most apps, (common sense) plus some interesting twists. Here are some of the most salient security rules.

    a) We have to control who can submit a new item to the workflow. In our models, all new items are added to a specific stage, so you cannot start "just anywhere" but we also have to be cognizant that not all workflows may be accessed by all people.  There are two parts to this: who can open the initial (empty) form and how do we secure submission to the workflow?  We solved both with web services that use information cached from the active directory (so that membership in an AD security group can drive permission to use a form).

    b) Once an item is in a workflow, we need to allow the person assigned to it to work on it.   There are two possibilities here.  Possibility 1 states: There is no reason to set permission on each stage, because the system only works if the person who is assigned to the item can work on it. Possibility 2 states: a bug in the model shouldn't defeat security.  We went with the second one.  This means that the model can assign a work item to a person only if that person will have permission to work on the item (in the current stage for entry actions or in the next stage for exit link actions).

    c) Each stage needs seperate permission settings.  A person can have read-only permission in one stage, read-write in a second, and no permission at all in the third. 

    d) It is rational to reuse the same groups for permission as we do for assignment, since they are likely to coincide.  Therefore, if we assign an item to a group of people (where any one of them can "take the assignment", then it makes sense that the same group of people will have permission to modify the work item in that stage.  Two purposes, one group.

    If you have opinions about the proper rules for managing access to workflow stages and the document they contain, post a response to this message.  I'd love to hear about it.

Page 1 of 1 (2 items)