Working with BrokenRules in a WCF environment

Working with BrokenRules in a WCF environment

Old forum URL: forums.lhotka.net/forums/t/3021.aspx


SultanOfSuede posted on Monday, June 11, 2007

I have to use an architecture in which all business validation is performed in a server side business layer run under WCF.  Via the data portal methods, I can send and receive data contracts that are used to hydrate my CSLA business base classes.  However, I run into a problem if I just count on the WCF layer to run validation by itself.  I don't want to write duplicate validation code in the business base classes, I just want to take the response message of the service and use it to populate the broken rules collection.

So, for instance, I have a Dog object.  I send the Dog to the WCF layer and the layer finds that the dog is named Fido.  There is a rule that says no dog may be named Fido and generates an object message to this effect when it builds the response message.  Back in the data portal method, I inspect the response and see the message, but I cannot add any BrokenRule item directly even though I know which property failed the validation.   I know that if dog.Name == "Fido", then I need the object to update its collection to reflect this without me having to write an additional delegate on the client.  As I understand, CSLA expects the ValidationRules collection and the RuleMethods to decide how and when BrokenRules get populated.   

Obviously, I'd rather go with a pure CSLA solution end to end, but my company is convinced that every application must be written to match their flawed conception of SOA.  The idea of remoting an object and getting location transparency is beyond their technical level.  I want to leverage CSLA for its rich client features, such as bindable collections, sorting, validation, undo, etc.  Hence, I need to use server-side validation but keep it integrated with the error provisioning features of CSLA. 

What am I missing?  Has anyone else designed a server-side validation solution using CSLA?

Thx in advance,

Ian

RockfordLhotka replied on Monday, June 11, 2007

So you are writing a client app that calls a set of WCF services. Those services implement all the business logic (including validation), and you want to create a set of "thin" business objects on the client. Did I get that right?

In your objects, you'll still have DataPortal_XYZ methods, they'll just call the WCF services instead of talking to the database. That part is actually pretty easy, because (conceptually) you have "WCF Service==Stored Procedure" from an architectural perspective.

But then the issue is that the service has validated your data and found it to be wrong. How do you get the "wrongness" into your object so it can in turn be expressed to the UI via data binding?

First, your WCF service obviously must have some contract by which it can return a list of what's wrong. Without that list you are done at step one. That list must detail what is wrong on a per-data-field basis or it isn't useful to you either. It should be quite possible to come up with a general validation-error-result contract that can be used by all service implementations (perhaps via a fault).

Second, your DataPortal_XYZ method must be prepared to accept this contract (in lieu of the normal success result). Upon accepting this validation-error-result from the service, you now have all the info you need to create a set of broken rules.

Third, you need a rule method that understands how to pull a specific property's errors out of the validation-error-result message. This rule method must be attached to every property on your object.

Fourth, your DataPortal_XYZ can call ValidationRules.CheckRules(), thus running the rules for each property, which of coruse means that each property will get the broken rules from the validation-error-result message.

Of course I haven't TRIED any of this, so there may be (probably are) hidden bits of complexity. But at a high level this certainly seems like a good solution Smile [:)]

SultanOfSuede replied on Monday, June 11, 2007

Yup, this was the path I've gone down.  #3 is were I get a little hung up though.  My response message has an array called ValidationResultExceptionInfo.  These are very simple objects with properties like PropertyName, Description, Severity & ResultCode.  PropertyName and Description tell me which property flunked validation and why and they are of the most interest to me from a CSLA point of view. 

I need to figure out how to implement what you describe.  It's a little fuzzy in my head but I'm certain it will work. 

Thanks for the response Rocky.  Your suggestion has given me something to focus.  I'll post whatever I come up with. 

Igor replied on Monday, June 11, 2007

 

    [ServiceContract]

    public interface IService1

    {

 

        [OperationContract]

        [FaultContractAttribute(

      typeof(GreetingFault),

      Action = "http://www.contoso.com/GreetingFault",

      ProtectionLevel = ProtectionLevel.None)]

        string MyMethod(string Name);

    }

 

 

    #region Validation

 

    [DataContractAttribute]

    public class GreetingFault

    {

        private string _msg;

 

        private BrokenRules _brokenRulesList;

 

        [DataMemberAttribute]

        public BrokenRules BrokenRulesList

        {

            get { return _brokenRulesList; }

            set { _brokenRulesList = value; }

        }

 

        [DataMemberAttribute]

        public string Msg

        {

            get { return this._msg; }

            set { this._msg = value; }

        }

 

        public GreetingFault(string message)

        {

            this._msg = message;

            _brokenRulesList = new BrokenRules();

            _brokenRulesList.Add(new BrokenRule("Rule1", "S1", "Descr1"));

            _brokenRulesList.Add(new BrokenRule("Rule2", "S2", "Descr2"));

            _brokenRulesList.Add(new BrokenRule("Rule3", "S3", "Descr3"));

        }

 

    }

 

    [DataContract]

    public class BrokenRule

    {

        string _ruleName;

        string _ruleSeverity;

        string _ruleDescription;

 

        [DataMember]

        public string RuleName

        {

            get { return _ruleName; }

            set { _ruleName = value; }

        }

 

        [DataMember]

        public string RuleSeverity

        {

            get { return _ruleSeverity; }

            set { _ruleSeverity = value; }

        }

 

        [DataMember]

        public string RuleDescription

        {

            get { return _ruleDescription; }

            set { _ruleDescription = value; }

        }

 

        public BrokenRule(string ruleName, string ruleSeverity, string ruleDescription)

        {

            _ruleName = ruleName;

            _ruleSeverity = ruleSeverity;

            _ruleDescription = ruleDescription;

        }

    }

 

    [CollectionDataContract]

    public class BrokenRules : List<BrokenRule> { }

 

    #endregion

 

 

    public class Service1 : IService1

    {

 

      

        public string MyMethod (string Name)

        {

            throw new FaultException<GreetingFault>(new GreetingFault("A Greeting error occurred." ));

        }

 

 

        static void Main(string[] args)

        {

...

        }

 

   }

 

Client code:

 

                  try

                  {

                        localhost.Service1 ws = new localhost.Service1();

                        MessageBox.Show(ws.MyMethod(“Name”));

                  }

                  catch (System.Web.Services.Protocols.SoapException ex)

                  {

                        Console.WriteLine(ex.Detail.InnerXml);

                  }

 

SultanOfSuede replied on Wednesday, June 13, 2007

After playing with this some more, I think I've hit a limitation.

Here's the scenario:

A Dog : BusinessBase instance is saved.  A WCF message is sent to the service and the service runs a validation process.  A list of broken rules is returned to the DataPortal_XYZ method as part of a response message.  These broken rules contain property/description sufficient to work within the CSLA validation design.

In the DataPortal_XYZ method of the client Dog (a CSLA BusinessBase object), a ProcessBrokenRules method is run that takes the server-side generated list of broken rules and attaches each one to its respective property.  So, to use my earlier example, no dog may be named Fido.  The property name is "Name" and can be attached via the ValidationRules' AddRule() method AFTER the DataPortal_XYZ method is called.  At this point, everything works.  Errors are correctly populated and I can read the descriptions and use them with an error provider.

The problem though is that the BrokenRules collection is pretty much untouchable.  If the user makes corrections to the instance of Dog he's working with and wants to save again, he can't because from the busines object's perspective, it's still invalid.  No new WCF message can be sent to the server through the data portal because a CSLA exception is thrown stating that the object is in an invalid condition.  Even were this possible, there's no way to reset the broken rules in order to accommodate a new set of broken rules from the server. 

Neither the Remove() nor Clear() methods work on the BrokenRulesCollection work in the context of a business class.  They are not designed to be used directly, otherwise I could call them just prior to sending my WCF message to the services (validation) layer.  I think at this point, I would need to branch away from CSLA and come up with a different method of doing business validation. 

Here's some pseudo-code of what I'd like to be able to do:

function DataPortal_Update()
begin
   ResetBrokenRules()
   msg = CreateWCFMessage()
   SendMessage(msg)
   ProcessBrokenRules(msg.BrokenRules)
end

 

Igor replied on Wednesday, June 13, 2007

"You have "WCF Service==Stored Procedure" from an architectural perspective", right? If the "Stored Procedure" fails the reasons are reported back to your DataPortal_XYZ method. You could analyse this response and set accordingly some private flags in your object, then check your business rules; the rules should take into account values of the flags.

I might be wrong, but I suspect that you are trying to pass back in your WCF Service/Stored Procedure a "properly typed" collection of broken rules. I would think that either your communications support type fidelity or not. If yes (“a pure CSLA solution end to end”), there is no need to move the collection of broken rules back and forth because you move your BO itself. If no ("WCF Service==Stored Procedure"), you should not move either the broken rules collection or BO: you are moving just data. You might be able to make a hybrid work, but I do not think that it would be a good solution.

SultanOfSuede replied on Thursday, June 14, 2007

You might be able to make a hybrid work, but I do not think that it would be a good solution.
Yup, I agree. I'm constrained by certain decisions made by other people, but I've a real need to leverage binding, validation, sorting and filtering within a rich client application. For these reasons, I was going for a thin client implementation of CSLA, but I don't want to have to hack the validation stuff because I prefer to stay on the primary branch.

ajj3085 replied on Thursday, June 14, 2007

SultanOfSuede:
Yup, I agree. I'm constrained by certain decisions made by other people, but I've a real need to leverage binding, validation, sorting and filtering within a rich client application. For these reasons, I was going for a thin client implementation of CSLA, but I don't want to have to hack the validation stuff because I prefer to stay on the primary branch.


Unfortunately service oriented is the opposite of rich client in many respects.  What exactly are the people making decisions trying to acomplish?  To get the 'richness' you need, you'll end up in a similar situation as web development; you'll need to duplicate much of the logic to provide the rich experience, and there's a huge cost in that, and a huge chance for the logic to start to get out of sync.

SultanOfSuede replied on Thursday, June 14, 2007

What exactly are the people making decisions trying to acomplish?
As explained to me, my company wants every application to use a service for data retrieval so that if someone in another department needs data, there's less work to do. Flick a switch and voila. They can just get pointed to the app's service. Unfortunately, this is not SOA, but once certain memes get started, they never go away. As a result, enormous amounts of time and money are spent writing "SOA" apps when all available metrics indicate that there is little history of departments pinging each other for data. Suppose I have an app with 500 public methods. Of these, maybe 2% are used externally and over the course of the app's lifetime, maybe another 2% will be used by external consumers still within our company. Why then do we spend so much time writing hundreds of methods as services when they really aren't? The assumption made by my company's architects is that the application data will have an interface that always matches what Bob in accounting needs. It also presupposes that everyone is agreed on security, validation, error-handling, etc. This of course is all hogwash, but hey, it's what I've to work with.

RockfordLhotka replied on Thursday, June 14, 2007

If you are trying to _really_ be SOA, then you must view this as two separate applications, each with their own reponsibilties.

 

The result of that view, is that your client app is responsible for providing the user with the best possible experience – almost certainly including implementing its own validation logic.

 

The fact that the same (or similar) validation logic will be in some of the services you call doesn’t matter – that’s their responsibility.

 

SOA is NOT A WAY TO REUSE CODE. Rather the reverse: it is a great way to duplicate code all over the place. Sad but true.

 

Rocky

 

 

From: SultanOfSuede [mailto:cslanet@lhotka.net]
Sent: Thursday, June 14, 2007 9:35 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Working with BrokenRules in a WCF environment

 

You might be able to make a hybrid work, but I do not think that it would be a good solution.

Yup, I agree. I'm constrained by certain decisions made by other people, but I've a real need to leverage binding, validation, sorting and filtering within a rich client application. For these reasons, I was going for a thin client implementation of CSLA, but I don't want to have to hack the validation stuff because I prefer to stay on the primary branch.

Copyright (c) Marimer LLC