New Posts New Posts RSS Feed: [CANCELLED] Exception Handling
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

[CANCELLED] Exception Handling

 Post Reply Post Reply
Author
Linguinut View Drop Down
Senior Member
Senior Member
Avatar

Joined: 14-Jun-2007
Location: United States
Posts: 394
Post Options Post Options   Quote Linguinut Quote  Post ReplyReply Direct Link To This Post Topic: [CANCELLED] Exception Handling
    Posted: 03-Dec-2007 at 3:47pm
Originally posted by Bill Jensen

Do you really want an exception in this case?  If the user isn't in Sales, wouldn't you want execution to just continue without New, Delete and Save buttons?
 
This is not my choice when using declarative security attributes.  A security exception is thrown when the condition is not met.  It needs to be handled.
 
Originally posted by Bill Jensen

You could also use:
 
IPrincipal myPrincipal = Thread.CurrentPrincipal;
PageToolBar.AddNewItemEnabled = myPrincipal.IsInRole("Sales");
etc.
 
Certainly.  I am just looking for the cleanest, most efficient way of doing this.  Is this it?
 
 
Originally posted by Bill Jensen

 
Re your last question,
 
If you're removed disabled the ability to change data, why would there be any changes to prompt for saving in the application save handler?
 
If all I do to the viewcontrol is remove the ability to click a button based on role, the user would still have the ability to change a combo box, or the string in a text box, or some other data-bound control on the form.  I suppose, I could set the form to read-only based on user role.  Is that even possible? 
 
Originally posted by Bill Jensen

Even if there were some by mistake, you could check the user role in the application close handler and skip both the prompt and the save.
 
Bill J.
 
Yup.  Sure.  Can you imagine the code in that close event, though?  After ten business modules and 60-70 workitems running around.  Whew!  Again, I am just trying to determine the best way to do this.
 
For years, I have done the IF INROLE OR USERNAME=? THEN DO SOMETHING route.  It is littered all throughout my code.  Messy.  Really messy.  One little change can start a debugging avalanche.  The Enterprise Library seems to have an answer for this, but it does not seem like anyone had really put this stuff together.  Can anyone tell me what the best practice is?  Do I stick with the imperative logic in all my code?  Is there a clean way to handle the declarative methods and their exceptions?  Do I scrap it all and come up with my own scheme?
 
If this is not the proper forum for this question, then please point me in the right direction.  Since the business object is directly involved, I was hoping someone familiar with DevForce may have run into this security issue before.
Back to Top
Bill Jensen View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Jul-2007
Location: United States
Posts: 229
Post Options Post Options   Quote Bill Jensen Quote  Post ReplyReply Direct Link To This Post Posted: 03-Dec-2007 at 2:41pm
Do you really want an exception in this case?  If the user isn't in Sales, wouldn't you want execution to just continue without New, Delete and Save buttons?
 
You could also use:
 
IPrincipal myPrincipal = Thread.CurrentPrincipal;
PageToolBar.AddNewItemEnabled = myPrincipal.IsInRole("Sales");
etc.
 
Re your last question,
 
If you're removed disabled the ability to change data, why would there be any changes to prompt for saving in the application save handler?
 
Even if there were some by mistake, you could check the user role in the application close handler and skip both the prompt and the save.
 
Bill J.
Back to Top
Linguinut View Drop Down
Senior Member
Senior Member
Avatar

Joined: 14-Jun-2007
Location: United States
Posts: 394
Post Options Post Options   Quote Linguinut Quote  Post ReplyReply Direct Link To This Post Posted: 30-Nov-2007 at 4:37pm
So, since getting declarative security checks to work in the model is not feasible, then I am doing this in my CustomerPageController:
 
protected override void ConfigureAddNewItemButton()
{
    base.ConfigureAddNewItemButton();
    PageToolBar.AddNewItemEnabled = false;
    PageToolBar.DeleteItemEnabled = false;
    PageToolBar.SaveEnabled = false;
    try
    {
        SetButtonAccessibility();
    }
    catch (System.Exception ex)
    {
        ExceptionPolicy.HandleException(ex, "default Policy");
    }
}
 
[PrincipalPermission(SecurityAction.Demand, Role = @"Sales")]
private void SetButtonAccessibility()
{
    PageToolBar.AddNewItemEnabled = true;
    PageToolBar.DeleteItemEnabled = true;
    PageToolBar.SaveEnabled = true;
}
 
Perhaps, this is a cleaner way, since the user who is not allowed to alter customer records will not even be able to click these buttons.
 
HOWEVER (and there seems to always be one of these!!), if I create logic on the application close event that detects changes to cached entities (like a customer) and asks the user if they want to save changes before leaving...well, I think you can see the dilemma that I now have.  Sure, the button functionality was taken away (a good start, for now), but the actual save event was not!  That is why I want this declarative security action to happen at the model level.  There are too many areas where I have to do the same security coding over and over again. 
 
Oh, well.
Back to Top
Linguinut View Drop Down
Senior Member
Senior Member
Avatar

Joined: 14-Jun-2007
Location: United States
Posts: 394
Post Options Post Options   Quote Linguinut Quote  Post ReplyReply Direct Link To This Post Posted: 30-Nov-2007 at 11:29am
If I place the try-catch outside of the model, then whereever I add the ability to create a customer, I would need to employ that structure.  Not sure if I like that prospect.  If it is in the model, then I only need to work out the details one time.   However, here's the next problem that is driving me nuts...
 
If I put a try-catch block in the model to handle the exceptions on the create method, what do I do with the return value?  In my scenario, a CustomerMaster object needs to be returned.  I would rather that the code just not run; however, because of the try-catch, an object must be returned.  This gets a bit sticky.  Do you have any other tips for this approach?
Back to Top
Bill Jensen View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Jul-2007
Location: United States
Posts: 229
Post Options Post Options   Quote Bill Jensen Quote  Post ReplyReply Direct Link To This Post Posted: 29-Nov-2007 at 5:37pm

Sorry to take some time to respond.  The forum has been quiet lately and I've become very busy with other activities.

First, thanks for finding and posting the answer to the earlier question.  The only comment I would make (and this is a general .Net practice, not specific to DevForce or Cabana) is that catching of the Exception type is generally discouraged (particularly if it might be handled silently) because it can mask other problems in the application (or at least make them very hard to debug).  It might be necessary sometimes, but probably not here.
 
So I'd suggest that you catch only the exception(s) thrown by the call that indicate the condition to be handled, letting others bubble up to higher level handlers.
 
Second, the entity constructor is executed (ultimately) by the Create method, so putting the try-catch there is too late.  You need to put it around the call to the CustomerMaster.Create() method or some outer method.
 
Finally, yes, we have tried to keep our Cabana Model assembly CAB-free, but there's nothing that says your Model couldn't depend on the Enterprise Library.    You might find that the best place for the try-catch is in your code outside of the model.
 
Thanks,
Bill J.
Back to Top
Linguinut View Drop Down
Senior Member
Senior Member
Avatar

Joined: 14-Jun-2007
Location: United States
Posts: 394
Post Options Post Options   Quote Linguinut Quote  Post ReplyReply Direct Link To This Post Posted: 29-Nov-2007 at 12:38pm
What is the best way to handle an exception within the Model project?  Let's say that I want to allow the create method on an object to a specific group, like this:
 
[PrincipalPermission(SecurityAction.Demand, Role = "Sales")]
public static CustomerMaster Create(PersistenceManager pPersMgr, string pCustname, int pStatus){...}
 
How do I handle that?  Where would the try-catch block be to handle such an exception?  Object constructor?  If I do this, wouldn't I need to add the references to the Enterprise Library assemblies into the Model project?  Would I then be violating some kind of CAB rule?
 
I know...a lot of questions.
Back to Top
Linguinut View Drop Down
Senior Member
Senior Member
Avatar

Joined: 14-Jun-2007
Location: United States
Posts: 394
Post Options Post Options   Quote Linguinut Quote  Post ReplyReply Direct Link To This Post Posted: 29-Nov-2007 at 11:08am

This is actually quite simple to resolve.

In the Exception Handling Application Block and within the "default Policy", I added an entry for SecurityException.  I set the PostHandlingAction to "None" but added a logging handler so that an email would be generated and an entry would be made into the local Application event log.

Next, I added a try-catch block in the AddPageLinks method, like this:
 
private void AddPageLinks(NavViewContext context)
{
    try
    {
        context.AddNavTaskLink("Customers", ShowCustomersPageHandler, ResourceNames.CustomersImage);
        context.AddNavTaskLink("Sales Orders", ShowSalesOrdersPagePageHandler, ResourceNames.UserImage);   
        // Add NavBar Links Here <<*** Wizard Marker - Do not edit, move or delete ***>>
        AddPageLinksForMarketing(context);
    }
    catch (Exception ex)
    {
        if (ExceptionPolicy.HandleException(ex, "default Policy"))
            throw;
    }
}
 
What happens now is that the Exception Handling is done at the module level rather than the application level.  If the exception is actually a SecurityException, it will be trapped, logged and an email sent (since no other process occurs, the program continues--user is totally unaware); however, if it is something else, then the catch block throws the exception so that the next level in the application can then handle it.
 
This is quite a powerful tool.  I am glad that I am beginning to understand it.
 
Bill


Edited by Linguinut - 29-Nov-2007 at 11:10am
Back to Top
Linguinut View Drop Down
Senior Member
Senior Member
Avatar

Joined: 14-Jun-2007
Location: United States
Posts: 394
Post Options Post Options   Quote Linguinut Quote  Post ReplyReply Direct Link To This Post Posted: 28-Nov-2007 at 2:24pm

When I employ the PrincipalPermission attribute for a method in a class, and the user is not in the role specified, the application throws an exception.  Example code from SalesModuleController.cs file:

private void AddPageLinks(NavViewContext context)
{
    context.AddNavTaskLink("Customers", ShowCustomersPageHandler, ResourceNames.CustomersImage);
    context.AddNavTaskLink("Sales Orders", ShowSalesOrdersPagePageHandler, ResourceNames.UserImage);
    AddPageLinksForMarketing(context);
 
    // Add NavBar Links Here <<*** Wizard Marker - Do not edit, move or delete ***>>
}
 
[PrincipalPermission(SecurityAction.Demand, Role="Marketing")]
private void AddPageLinksForMarketing(NavViewContext context)
{
    context.AddNavTaskLink("Leads", ShowLeadMasterPagePageHandler, ResourceNames.UserImage);
    context.AddNavTaskLink("Markets", ShowMarketMasterPagePageHandler, ResourceNames.SalesOrdersImage);
}

Now, what is happening should happen...a SecurityException is thrown because a user does not belong to the Marketing group.  The problem is that I am having trouble handling that exception in CAB/DF.  The code bombs at this point in the ShellApplication.cs file (marked in red):

private static void HandleException(Exception ex)
{
    if (ex == null)
        return;
 
    // ToDo: Intercept LoginCancelException and terminate the app
    ExceptionPolicy.HandleException(ex, "default Policy");
 
    // ToDo: Do a better job of unfolding the exception and dump it into the debug log as well.
    MessageBox.Show("An unhandled exception occurred, and the application is terminating. For more information, see your Application event log.");
    Application.Exit();
}
 
The initial exception listed is a ModuleLoadException, not a SecurityException, as expected.  The SecurityException is baked into the InnerException information.
 
So, how do I properly capture this SecurityException?  I have tried several variations in the app.config file, but I cannot seem to get to the right combination.  I hope you can provide some direction on this.
 
Bill


Edited by Linguinut - 06-Dec-2007 at 4:39pm
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down