Vibrant discussion about CSLA .NET and using the framework to build great business applications.
I am trying to use BrokenRulesCollection as a property of a Command Object, but I am unable to create a new instance of a BrokenRule and Add it to the collection.
In summary, inside the Command Object, I am calling other CSLA Objects to carry out some Database Updates for several Objects inside a Loop.
I want to capture all possible errors including Validation Errors, and return them in a collection object which can be accessed via the UI code.
I am thinking to use the BrokenRulesCollection, is this a good idea?
Or should I use List of String (Arrays) to capture the errors ...etc and return the resutls as a simple array ?
Why I cannot create BrokenRules objects ?
Tarek.
In general terms - I would not use BrokenRule / BrokenRuleCollection for this purpose. These classes exist for a specific responsibility on BusinessRules.
1. Your other CSLA objects may have structure/tree of BrokenRules (not just on the root object).
2. All possible errors (Exceptions) may not map directly to a BrokenRules, f.ex Inner exceptions may hold essential data. Or how about DataPortalException that may or may not have a BusinessException (as inner exception).
I believe you should create your own structure for this purpose and send back to your client application.
Jonny Bekkum, Norway CslaContrib Coordinator
Hi Jonny,
Yes, I agree with you. This is what I have done to report errors back to the UI:
Public Shared Function RefreshDBFields(ByVal theUserCtrlInfoPack As UserCtrlInfoPack, ByVal DoGetCountOnly As Boolean) As RefreshDBFieldsCommand Dim result As RefreshDBFieldsCommand If Not AppSecurity.GetSingleton.IsUserAuthorized(AppSecurity.CodesApp.eHRMD, AppSecurity.CodesActions.RefreshDBFlds, AppSecurity.CodesDataTypes.SPMSForm, theUserCtrlInfoPack) Then Throw New System.Security.SecurityException( _ String.Format( _ My.Resources.NotAuthErrorPrm2, _ theUserCtrlInfoPack.AuthUserID, _ AppSecurity.CodesActions.RefreshDBFlds.ToString, _ SPMSForm.GetSPMSFormInits.GetObjectName, "<all>")) End If result = DataPortal.Execute(Of RefreshDBFieldsCommand)(New RefreshDBFieldsCommand(theUserCtrlInfoPack, DoGetCountOnly)) Return result End Function Public Class RefreshDBFieldsCommand Inherits CommandBase Private mRecordsToBeRefreshedCnt As Integer Private mRecordsRefreshedCnt As Integer Private mDoGetCountOnly As Boolean Private mRecordVersion As Integer Private mUserCtrlInfoPack As UserCtrlInfoPack Private mMessages As New List(Of String) Private mSuccess As Boolean Public ReadOnly Property RecordsToBeRefreshedCnt() As Integer Get Return mRecordsToBeRefreshedCnt End Get End Property Public ReadOnly Property RecordsRefreshedCnt() As Integer Get Return mRecordsRefreshedCnt End Get End Property Public ReadOnly Property Messages() As String() Get Return mMessages.ToArray() End Get End Property Public ReadOnly Property Success() As Boolean Get Return mSuccess End Get End Property Public Sub New(ByVal theUserCtrlInfoPack As UserCtrlInfoPack, ByVal DoGetCountOnly As Boolean) mUserCtrlInfoPack = theUserCtrlInfoPack mDoGetCountOnly = DoGetCountOnly mSuccess = True End Sub Protected Overrides Sub DataPortal_Execute() Dim theSPMSForm As SPMSForm = Nothing Dim theStaffID As String Dim theReviewFrom As String Dim theMsg As String Using cn As New SqlConnection(Database.SPMSFormDB) cn.Open() Using cm As SqlCommand = cn.CreateCommand cm.CommandType = CommandType.StoredProcedure cm.CommandText = "uspSPMSFormListGetRecVer" cm.Parameters.AddWithValue("@RecVer", SPMSForm.GetSPMSFormInits.RecordVersion) mRecordsToBeRefreshedCnt = 0 mRecordsRefreshedCnt = 0 Using da As New SqlDataAdapter(cm) Using ds As New DataSet da.Fill(ds) mRecordsToBeRefreshedCnt = ds.Tables(0).Rows.Count If Not mDoGetCountOnly Then For Each theRow As DataRow In ds.Tables(0).Rows theStaffID = theRow.Item("StaffID") theReviewFrom = theRow.Item("ReviewFrom") mUserCtrlInfoPack.SetQueryUser(theStaffID) Try theSPMSForm = SPMSForm.GetSPMSForm(cn, mUserCtrlInfoPack, theReviewFrom) theSPMSForm.SetSubmitActionRefreshDBFlds() theSPMSForm.SaveForm() Catch ex As Csla.Validation.ValidationException mSuccess = False mMessages.AddRange(theSPMSForm.BrokenRulesCollection.ToArray()) Catch ex As Exception mSuccess = False theMsg = _ String.Format(My.Resources.ErrRefreshDBFlds, _ ex.Message, theSPMSForm.GetObjectName(), theSPMSForm.IDStr, _ mUserCtrlInfoPack.AuthUserID) mMessages.Add(theMsg) End Try mRecordsRefreshedCnt += 1 theSPMSForm = Nothing Next If mSuccess Then theMsg = _ String.Format( _ My.Resources.RefreshDBFldsConf, _ SPMSForm.GetSPMSFormInits.GetObjectName(), mRecordsRefreshedCnt.ToString, _ mRecordsToBeRefreshedCnt.ToString) mMessages.Add(theMsg) End If End If End Using End Using End Using End Using End Sub End Class
Public Shared Function RefreshDBFields(ByVal theUserCtrlInfoPack As UserCtrlInfoPack, ByVal DoGetCountOnly As Boolean) As RefreshDBFieldsCommand Dim result As RefreshDBFieldsCommand If Not AppSecurity.GetSingleton.IsUserAuthorized(AppSecurity.CodesApp.eHRMD, AppSecurity.CodesActions.RefreshDBFlds, AppSecurity.CodesDataTypes.SPMSForm, theUserCtrlInfoPack) Then Throw New System.Security.SecurityException( _ String.Format( _ My.Resources.NotAuthErrorPrm2, _ theUserCtrlInfoPack.AuthUserID, _ AppSecurity.CodesActions.RefreshDBFlds.ToString, _ SPMSForm.GetSPMSFormInits.GetObjectName, "<all>")) End If result = DataPortal.Execute(Of RefreshDBFieldsCommand)(New RefreshDBFieldsCommand(theUserCtrlInfoPack, DoGetCountOnly)) Return result End Function
Public Class RefreshDBFieldsCommand Inherits CommandBase
Private mRecordsToBeRefreshedCnt As Integer Private mRecordsRefreshedCnt As Integer Private mDoGetCountOnly As Boolean Private mRecordVersion As Integer Private mUserCtrlInfoPack As UserCtrlInfoPack Private mMessages As New List(Of String) Private mSuccess As Boolean
Public ReadOnly Property RecordsToBeRefreshedCnt() As Integer Get Return mRecordsToBeRefreshedCnt End Get End Property
Public ReadOnly Property RecordsRefreshedCnt() As Integer Get Return mRecordsRefreshedCnt End Get End Property
Public ReadOnly Property Messages() As String() Get Return mMessages.ToArray() End Get End Property
Public ReadOnly Property Success() As Boolean Get Return mSuccess End Get End Property
Public Sub New(ByVal theUserCtrlInfoPack As UserCtrlInfoPack, ByVal DoGetCountOnly As Boolean) mUserCtrlInfoPack = theUserCtrlInfoPack mDoGetCountOnly = DoGetCountOnly mSuccess = True End Sub
Protected Overrides Sub DataPortal_Execute() Dim theSPMSForm As SPMSForm = Nothing Dim theStaffID As String Dim theReviewFrom As String Dim theMsg As String Using cn As New SqlConnection(Database.SPMSFormDB) cn.Open() Using cm As SqlCommand = cn.CreateCommand cm.CommandType = CommandType.StoredProcedure cm.CommandText = "uspSPMSFormListGetRecVer" cm.Parameters.AddWithValue("@RecVer", SPMSForm.GetSPMSFormInits.RecordVersion) mRecordsToBeRefreshedCnt = 0 mRecordsRefreshedCnt = 0 Using da As New SqlDataAdapter(cm) Using ds As New DataSet da.Fill(ds) mRecordsToBeRefreshedCnt = ds.Tables(0).Rows.Count If Not mDoGetCountOnly Then For Each theRow As DataRow In ds.Tables(0).Rows theStaffID = theRow.Item("StaffID") theReviewFrom = theRow.Item("ReviewFrom") mUserCtrlInfoPack.SetQueryUser(theStaffID) Try theSPMSForm = SPMSForm.GetSPMSForm(cn, mUserCtrlInfoPack, theReviewFrom) theSPMSForm.SetSubmitActionRefreshDBFlds() theSPMSForm.SaveForm() Catch ex As Csla.Validation.ValidationException mSuccess = False mMessages.AddRange(theSPMSForm.BrokenRulesCollection.ToArray()) Catch ex As Exception mSuccess = False theMsg = _ String.Format(My.Resources.ErrRefreshDBFlds, _ ex.Message, theSPMSForm.GetObjectName(), theSPMSForm.IDStr, _ mUserCtrlInfoPack.AuthUserID) mMessages.Add(theMsg) End Try mRecordsRefreshedCnt += 1 theSPMSForm = Nothing Next If mSuccess Then theMsg = _ String.Format( _ My.Resources.RefreshDBFldsConf, _ SPMSForm.GetSPMSFormInits.GetObjectName(), mRecordsRefreshedCnt.ToString, _ mRecordsToBeRefreshedCnt.ToString) mMessages.Add(theMsg) End If End If End Using End Using End Using End Using
End Sub End Class
I have yet to test the code above. By the way, this is related to the same post I did before (Progress Bar Implementation with Command Object):
http://forums.lhotka.net/forums/t/11176.aspx
Do you have any comment on this matter?
Side Questions: Is there an easy way to insert VB or C# code in this forum ?
Not knowing how your business object structure is, ther may be some issues with:
mMessages.AddRange(theSPMSForm.BrokenRulesCollection.ToArray()) If theSPMSForm has child objects/lists with broken rules you need to use BusinessRules.GetAllBrokenRules (static method) to get the broken rules from all nodes - the entire tree - and eventually merge into a list of broken rules. The ProgressBar implementation is very similar (same programming model) to the BackgroundWorker. This would not necessarily fit so well with a programming model for command object. Do you use n-tier (an own application server)? I haven't used this component myself, but the "simple" solution would be to run the code in "DataPortal_Execute" inside the DoWork method. Paste code: I use Productivity Power Tools addin for VS2010 - this allows me to do "HTML Copy" of code. And IE will paste this into the forum as HTML (Firefox used to allow this but not the latest versions).
Thanks Jonny,
It seems that "BusinessRules.GetAllBrokenRules" is not available in CSLA for .NET 2.0 the one I am using.
Anyway, I don't think I need it, since it is a single level object (but very complex).
I am only concerned about the design of my approach. So seems my appraoch is correct.
Regarding Productivity Power Tools addin, is there one for VS 2005? I am not using VS2010 yet.
Use this one for VS2005 and VS2008. http://copysourceashtml.codeplex.com/
I would prefer to move up to VS2008 or VS2010 anyway (if possible) and use CSLA N2 http://wwws.lhotka.net/cslanet/N2.aspx
This will give you access to nearly all of C# 3.0 syntax - including lambdas and linq2objects when your project targets .NET 2.0 SP1.
Read more about LinqBridge here: http://www.albahari.com/nutshell/linqbridge.aspx
I'll try to move to VS2008 or VS2010 ASAP.
I installed CopyCourseAsHTML (after closing VS2005) from here:
http://copysourceashtml.codeplex.com/releases/view/31130
When I started VS2005 (under Windows 7), I did not see "Copy as HTML". Also, the Add-in Manager box is empty (nothing was installed).
I know this is off-topic, but I appreciate if some one can help me here.
Oh, many thanks Jonny, now I am able to use CopySourceAsHTML with VS2055.
Here is the latest result (to verify):
1 2 Public Shared Function RefreshDBFields(ByVal theUserCtrlInfoPack As UserCtrlInfoPack, ByVal DoGetCountOnly As Boolean) As RefreshDBFieldsCommand 3 Dim result As RefreshDBFieldsCommand 4 If Not AppSecurity.GetSingleton.IsUserAuthorized(AppSecurity.CodesApp.eHRMD, AppSecurity.CodesActions.RefreshDBFlds, AppSecurity.CodesDataTypes.SPMSForm, theUserCtrlInfoPack) Then 5 Throw New System.Security.SecurityException( _ 6 String.Format( _ 7 My.Resources.NotAuthErrorPrm2, _ 8 theUserCtrlInfoPack.AuthUserID, _ 9 AppSecurity.CodesActions.RefreshDBFlds.ToString, _ 10 SPMSForm.GetSPMSFormInits.GetObjectName, "<all>")) 11 End If 12 result = DataPortal.Execute(Of RefreshDBFieldsCommand)(New RefreshDBFieldsCommand(theUserCtrlInfoPack, DoGetCountOnly)) 13 Return result 14 End Function 15 16 <Serializable()> _ 17 Public Class RefreshDBFieldsCommand 18 Inherits CommandBase 19 20 Private mRecordsToBeRefreshedCnt As Integer 21 Private mRecordsRefreshedCnt As Integer 22 Private mDoGetCountOnly As Boolean 23 Private mRecordVersion As Integer 24 Private mUserCtrlInfoPack As UserCtrlInfoPack 25 Private mMessages As New List(Of String) 26 Private mSuccess As Boolean 27 28 Public ReadOnly Property RecordsToBeRefreshedCnt() As Integer 29 Get 30 Return mRecordsToBeRefreshedCnt 31 End Get 32 End Property 33 34 Public ReadOnly Property RecordsRefreshedCnt() As Integer 35 Get 36 Return mRecordsRefreshedCnt 37 End Get 38 End Property 39 40 Public ReadOnly Property Messages() As String() 41 Get 42 Return mMessages.ToArray() 43 End Get 44 End Property 45 46 Public ReadOnly Property Success() As Boolean 47 Get 48 Return mSuccess 49 End Get 50 End Property 51 52 Public Sub New(ByVal theUserCtrlInfoPack As UserCtrlInfoPack, ByVal DoGetCountOnly As Boolean) 53 mUserCtrlInfoPack = theUserCtrlInfoPack 54 mDoGetCountOnly = DoGetCountOnly 55 mSuccess = True 56 End Sub 57 58 Protected Overrides Sub DataPortal_Execute() 59 Dim theSPMSForm As SPMSForm = Nothing 60 Dim theStaffID As String 61 Dim theReviewFrom As String 62 Dim theMsg As String 63 Using cn As New SqlConnection(Database.SPMSFormDB) 64 cn.Open() 65 Using cm As SqlCommand = cn.CreateCommand 66 cm.CommandType = CommandType.StoredProcedure 67 cm.CommandText = "uspSPMSFormListGetRecVer" 68 cm.Parameters.AddWithValue("@RecVer", SPMSForm.GetSPMSFormInits.RecordVersion) 69 mRecordsToBeRefreshedCnt = 0 70 mRecordsRefreshedCnt = 0 71 Using da As New SqlDataAdapter(cm) 72 Using ds As New DataSet 73 da.Fill(ds) 74 mRecordsToBeRefreshedCnt = ds.Tables(0).Rows.Count 75 If Not mDoGetCountOnly Then 76 For Each theRow As DataRow In ds.Tables(0).Rows 77 theStaffID = theRow.Item("StaffID") 78 theReviewFrom = theRow.Item("ReviewFrom") 79 mUserCtrlInfoPack.SetQueryUser(theStaffID) 80 Try 81 theSPMSForm = SPMSForm.GetSPMSForm(cn, mUserCtrlInfoPack, theReviewFrom) 82 theSPMSForm.SetSubmitActionRefreshDBFlds() 83 theSPMSForm.SaveForm() 84 Catch ex As Csla.Validation.ValidationException 85 mSuccess = False 86 mMessages.AddRange(theSPMSForm.BrokenRulesCollection.ToArray()) 87 Catch ex As Exception 88 mSuccess = False 89 theMsg = _ 90 String.Format(My.Resources.ErrRefreshDBFlds, _ 91 ex.Message, theSPMSForm.GetObjectName(), theSPMSForm.IDStr, _ 92 mUserCtrlInfoPack.AuthUserID) 93 mMessages.Add(theMsg) 94 End Try 95 mRecordsRefreshedCnt += 1 96 theSPMSForm = Nothing 97 Next 98 If mSuccess Then 99 theMsg = _ 100 String.Format( _ 101 My.Resources.RefreshDBFldsConf, _ 102 SPMSForm.GetSPMSFormInits.GetObjectName(), mRecordsRefreshedCnt.ToString, _ 103 mRecordsToBeRefreshedCnt.ToString) 104 mMessages.Add(theMsg) 105 End If 106 End If 107 End Using 108 End Using 109 End Using 110 End Using 111 112 End Sub 113 End Class
Much better !