Need .Net Design Help

J

Jack Addington

I've got a fairly simple application implementation that over time is going
to get a lot bigger. I'm really trying to implement it in a way that will
facilitate the growth. I am first writing a WinForms interface and then
need to port that to a web app. I am kinda stuck on a design issue and need
some suggestions / direction.

Basically I have a business layer that I want to use to process any
dataentry logic (row focus changes, data validation etc). I'm hoping that I
can in time just substitute a web gui for the win gui and not have much code
re-write. Anyhow my problem is how to pass message to the user back to the
GUI layer from the logic layer.

ex) GUI data object lets user change a number and it falls outside the
range.

I have subscribed to the data object's 'dataChanged' event from my logic
layer and have determined that it falls outside the acceptable range. I
basically want to display a popup message that tells the user so. Now it
seems 'wrong' to me to have a reference to system.windows.forms so I can do
a MessageDlg.Show("Bad Value ...") as obviously that won't work with the web
frontend. I don't want to raise an exception because I don't have a 'try '
clause around some sort of 'start edit' on the GUI side.

I've had thoughts that maybe I need a generic function on my frontend that
handles messages from the logic side??? Is that where an interface would
work? How do I go about making it generic so that I can re-use it for
webforms etc.

thanks so much

jack
 
B

Bob Grommes

Jack,

An ASP.NET application is a very different beast. Things like messageboxes
have to be raised by client-side JavaScript code. Also, that JavaScript
field validation has to replicate to a great extent the business logic that
resides in your business objects and/or stored procedures -- at least, it
does if you want to provide the kind of feedback users expect from a rich
client.

You can certainly swap in a different presentation layer but the code reuse
between WinForms and ASP.NET presentation layers just inherently sucks. If
you stick to Microsoft's postback-heavy model and try to keep as much logic
on the server as possible, it gets somewhat better, but it'll never just be
a matter of swapping a few things around no matter how hard you try.
Microsoft has actually backed off from a design goal like this for their
development frameworks. If they can't pull it off, you probably can't
either.

--Bob
 
J

Jack Addington

I wasn't under the impression that it would be as simple as changing a
'skin' or something but for something as simple as an update that spawns a
database error I would like a common plan to pass the information back to
the presentation.

Going back to my original question, more for the winforms since that has to
work long before I tackle the webform, would you suggest a way to
essentially push a message from a non-visual business layer to the
presentation layer?
 
N

Nicholas Paldino [.NET/C# MVP]

Jack,

You shouldn't be worried about passing messages. You should basically
consider all of your operations as atomic transactions. In this sense, you
give it input, and it spits out output, doing work in between. The output
that it spits back would be whatever errors that occur. Once you make the
call, you should not wait for a message to come from somewhere indicating
whether or not it succeeded.

Now the kinds of errors that you report back are up to you, but IMO, I
think that business errors should always be in the form of return values.
You could have a collection of warnings/business logic errors that occur,
and then return those to the user, and then they decide what to do with
them.

Exceptions are different, these are not business logic errors, and
should be allowed to propogate up the call stack, IMO.

Hope this helps.
 
J

Jack Addington

Nicholas,

Thanks for you reply, however I'm still a touch confused... Maybe a better
example would help. This is the scenario I am trying to model:

1) User makes a change to a field in a 3rd party datagrid

- this fires the dataChanged Event

2) A business object has subscribed (and this might be the wrong term) to
the Event by doing the obj.dataChange += new businessobject.method(args);

3) The business object evaluates the arguments and decides to return a
message to the user. The business object also has a non-visual set of the
data that is shared with the visual object.

How do I get the message in step 3 to display on the presentation side to
the user.

My goal is to build the presentation layer dynamically by simply adding a
tab, add the datacontrol to the tab, and setting the datasources for the
datacontrol (repeat over and over). I have used this model before in a
different language but I could do far more inheritance and could have more
visual representations of the business logic. In .Net I can't seem to just
keep inheriting the 3rd party object and still access the events/methods in
the way I want.

I don't think I want to end up with a big circular reference where the
non-visual subscribes to the visual which in turn subscribes to the
non-visual etc.

I think I am also maybe making it too complicated although I really want a
re-usable framework to build on for the client.

Thx so much,

jack

Nicholas Paldino said:
Jack,

You shouldn't be worried about passing messages. You should basically
consider all of your operations as atomic transactions. In this sense,
you give it input, and it spits out output, doing work in between. The
output that it spits back would be whatever errors that occur. Once you
make the call, you should not wait for a message to come from somewhere
indicating whether or not it succeeded.

Now the kinds of errors that you report back are up to you, but IMO, I
think that business errors should always be in the form of return values.
You could have a collection of warnings/business logic errors that occur,
and then return those to the user, and then they decide what to do with
them.

Exceptions are different, these are not business logic errors, and
should be allowed to propogate up the call stack, IMO.

Hope this helps.

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)


Jack Addington said:
I wasn't under the impression that it would be as simple as changing a
'skin' or something but for something as simple as an update that spawns a
database error I would like a common plan to pass the information back to
the presentation.

Going back to my original question, more for the winforms since that has
to work long before I tackle the webform, would you suggest a way to
essentially push a message from a non-visual business layer to the
presentation layer?
 
B

Bob Grommes

Well here's a simplified explanation what I do in my business objects. I
implement an interface, IValidator:

MessageList ValidationMessages {get;}
bool Validate(string,object)
bool ValidateAll(object)

All the above are implemented as public in the business object. I have a
business object for each DB table, but the business object that a form or
page might talk to would likely orchestrate several "table-level" business
objects and present one high-level interface to the presentation layer.

A MessageList is just a simple subclass of
System.Collections.Specialized.StringCollection with a ToString()
implementation that returns all the messages with newlines between them for
easy display. Each Validate() or ValidateAll() call clears the collection
and then adds one or more message to it if the requested validation fails.
Validate() will add zero or one messages, ValidateAll() will add zero or
more messages.

Validate(string,object) takes an attribute name and a value (which can be
either the attribute's native type, or a string representation thereof --
say, a TextBox Value) and determines whether it's valid or not. If it
returns false, it will also stuff a descriptive message in
ValidationMessages.

ValidateAll(object) does all the validations plus any entity-level integrity
checking and produces potentially multiple failure messages.

I use a passive container class to pass records around between tiers; in
"record-level" business objects, ValidateAll() gets one of those containers
to validate. ValidateAll() is normally called automatically just before
persisting the data to the back end, but the presentation layer can call it
directly to verify that all is well before even trying to persist it.

So ... a WinForms app might for example have a TextBox holding a last name
for a person. You might them make a call something like this from the
validation event:

if (this.personBO.Validate(this.Name,this.Text) == false) {
// display messagebox based on this.personBO.ValidationMessages[0]
// and take whatever other actions you wish to
}

In an ASP.NET scenario the logic for saving the page would call the
Persist() method of the business object associated with that page, which
would in turn call ValidateAll() for all tables involved. This would be a
safety net under the JavaScript code that would hopefully enforce the
business rules at the field level, but if that client side code failed, you
could display messages about all the offending fields to the user and have
them fix those fields. And then you could go plug the leak in your
JavaScript.

--Bob
 
J

Jack Addington

okay, I like that, that is a model I can use.

Now lets say that I wanted to call the xxxBO.Validate from the xxxDataGrid
in the DataChanged event but I want to create the xxxContainer on the fly so
I can't add the xxxBO.Validate method call to the actual event at design
time. BTW - my xxxDataGrid is a 3rd party data object not the generic .net
datagrid.

Now what I have started doing and have gotten stuck is basically the
following:

Form has a Tab and a Tree with nodes filled from the database with the info
I need to build the set of data tabpages. Basically I set the key/tag to
something like 'ProgramDetails'. So my operations are like:

1) Open Form ProgramModule and create programBO.
2) User clicks on Details treeNode which adds or jumps to the 'Details'
tabpg
3) The SelectedTab event fires and calls programBO.Register('Details',
tabpg.detailsDataGrid)
4) the programBO
a) sets the datasource etc for detailsDataGrid
b) registers it with the Update service (so I can update all tabpg's at
once)
c) calls programData.retrieve to populate the detailsGrid
d) subscribes (correct terminology???) to the detailsDataGrid.Data
Changed event (xxxDataGrid.DataChanged += new EventHandler(
xxxDataChanged) )
e) susbscibes to everything else

5) user changes some data
a) detailsDataGrid.DataChanged event fires
b) detailsBO.DetailsDataChanged event fires

c) stuck here... not sure how to get the message back to the form...

My current thought is that I should create an reference to the original form
and a 'show errors' method that pops a message or opens the 'Output' window
(like VS) or something.

What I would also like to do is to be able to both pop a message and pass a
return code back to the original event but it doesn't seem like adding a new
EventHandler acts a continuation of the original event but more like an
unrelated notification???

Am I out to lunch here?

Thanks so much for your time!

jack


Bob Grommes said:
Well here's a simplified explanation what I do in my business objects. I
implement an interface, IValidator:

MessageList ValidationMessages {get;}
bool Validate(string,object)
bool ValidateAll(object)

All the above are implemented as public in the business object. I have a
business object for each DB table, but the business object that a form or
page might talk to would likely orchestrate several "table-level" business
objects and present one high-level interface to the presentation layer.

A MessageList is just a simple subclass of
System.Collections.Specialized.StringCollection with a ToString()
implementation that returns all the messages with newlines between them
for
easy display. Each Validate() or ValidateAll() call clears the collection
and then adds one or more message to it if the requested validation fails.
Validate() will add zero or one messages, ValidateAll() will add zero or
more messages.

Validate(string,object) takes an attribute name and a value (which can be
either the attribute's native type, or a string representation thereof --
say, a TextBox Value) and determines whether it's valid or not. If it
returns false, it will also stuff a descriptive message in
ValidationMessages.

ValidateAll(object) does all the validations plus any entity-level
integrity
checking and produces potentially multiple failure messages.

I use a passive container class to pass records around between tiers; in
"record-level" business objects, ValidateAll() gets one of those
containers
to validate. ValidateAll() is normally called automatically just before
persisting the data to the back end, but the presentation layer can call
it
directly to verify that all is well before even trying to persist it.

So ... a WinForms app might for example have a TextBox holding a last name
for a person. You might them make a call something like this from the
validation event:

if (this.personBO.Validate(this.Name,this.Text) == false) {
// display messagebox based on this.personBO.ValidationMessages[0]
// and take whatever other actions you wish to
}

In an ASP.NET scenario the logic for saving the page would call the
Persist() method of the business object associated with that page, which
would in turn call ValidateAll() for all tables involved. This would be a
safety net under the JavaScript code that would hopefully enforce the
business rules at the field level, but if that client side code failed,
you
could display messages about all the offending fields to the user and have
them fix those fields. And then you could go plug the leak in your
JavaScript.

--Bob

Jack Addington said:
I wasn't under the impression that it would be as simple as changing a
'skin' or something but for something as simple as an update that spawns
a
database error I would like a common plan to pass the information back to
the presentation.

Going back to my original question, more for the winforms since that has to
work long before I tackle the webform, would you suggest a way to
essentially push a message from a non-visual business layer to the
presentation layer?
 
B

Bob Grommes

I think you are on the right track as far as the BO needing a reference back
to the form someplace. It'd probably need to call BeginInvoke on something
in the form that would know how to retreive error info from the BO and
present it to the user. To be honest, almost everything I've worked on so
far has been Windows Service, Console apps, .NET remoting, and ASP.NET. I
have only knocked out a couple of really small WinForms apps so far. So
I'll defer to someone who lives in the WinForms world every day to better
address your question.

Best,

--Bob
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top