[Update: Thanks to Mark Miller's comments below, I have changed the templates and added a link to the new ones below marked as version 2. The new templates fix some bugs and add some additional functionality. You can now use nullables and generics in your type definition without issue. I changed the shortcuts as well as added additional shortcuts. I have outlined these below:
- krp -> [Rocky Lhotka Register Property] Registers a CSLA property
- kdp -> [Rocky Lhotka Declare Property] Declares a CSLA property
- krdp -> [Rocky Lhotka Register and Declare Property] Declare and Register a CSLA property
- krp<Type> -> Registers a CSLA property with a specified type where you only have to fill in the property name. For example krpi will create a registered property of type int. There are a lot of type shortcuts that ship with CodeRush.
- kdp<Type> -> Declares a CSLA property with a specified type. Works similar to#4 above except it declares the property.
]
Version 3.0 of CSLA.NET brought a new way of declaring fields and properties within business objects. This was done in order to reduce the amount of code that needed to be written and to reduce the possibility of creating runtime exceptions.
Before version 3.0 of CSLA.NET, the business object developer would have to ensure that certain lines of code were present in order for state tracking and validation to work correctly. The following lines of code are an example of how business object properties were written previous to version 3.0.
1: [Serializable()]2: public class Customer : Csla.BusinessBase<Customer>
3: {4: private string _firstName;
5: 6: public string FirstName
7: { 8: get 9: {10: CanReadProperty(true);
11: return _firstName;
12: } 13: set 14: {15: CanWriteProperty(true);
16: if (_firstName != value)
17: {18: _firstName = value;
19: PropertyHasChanged(); 20: } 21: } 22: } 23: 24: private Customer()
25: { 26: } 27: }You can see this is pretty standard property/field declaration that you would see in any object (before Auto-Implemented properties). Let me explain what the various CSLA.NET specific calls do.
In line 10, there is a call to a base class method CanReadProperty. This method checks the current roles that are assigned to the user that is logged and makes sure that the current user has the rights to read this specific property. Property level authorization is another feature of CSLA.NET which I will explain at a later date. The parameter of true that is passed to the call specifies that the application should throw an exception at this point if the user is not authorized to read the property.
Similar functionality for authorizing a property setter is found in line 15 with a call to the base method of CanWriteProperty.
The last bit of functionality that this code sample demonstrates is the ability for CSLA to perform state tracking and validation. Business objects in CSLA have the ability to let the client of the business layer to determine if an object is dirty, new, or saved to the data store. A key piece of this functionality is implemented with a call to the PropertyHasChanged method as shown in line 19 above. This call does 2 things. First it marks the object as being dirty. Therefore, when the client application calls Save, the business object knows that it needs to perform an update or an insert into the data store. Second, the business object performs validation for all the validation rules based on that property. For example, if the Customer object contained a business rule stating that the FirstName property needed to have a non null or empty value and the client application assigned a string.Empty, the object would then be marked as invalid. If the user then tried to save the object, a ValidationException would be thrown by the business object.
As you can see, these steps of simply retrieving and setting property values have a large impact on how the CSLA business object operates. Skipping one of these steps or performing one of these steps at the wrong time can easily lead to logical errors. Because of this, Rocky Lhotka introduced the concept of registering properties in CSLA version 3, a la Windows Workflow properties.
Here is an example of the how a business object developer would write the same functionality in CSLA version 3.0 and above:
1: [Serializable()]2: public class Customer : Csla.BusinessBase<Customer>
3: {4: private static PropertyInfo<string> FirstNameProperty = RegisterProperty<string>(typeof(Customer), new PropertyInfo<string>("FirstName"));
5: 6: public string FirstName
7: { 8: get 9: {10: return GetProperty<string>(FirstNameProperty);
11: } 12: set 13: {14: SetProperty<string>(FirstNameProperty, value);
15: } 16: } 17: 18: private Customer()
19: { 20: } 21: }As you can see, this is a lot less code and it performs the same amount of functionality as the code listed above. The code at line 10 makes a call to a base class GetProperty method. This method internally makes a call to CanReadProperty just as above. The code at line 14 makes a call to SetProperty. This methon internally makes a call to CanWriteProperty and PropertyHasChanged respectively.
Although the latter implementation requires less code and is less error prone, it is still very verbose and it requires a lot of typing. Since declaring properties is what a business object developer does a lot of, I decided that a code template would be great to implement. I am a huge fan of CodeRush and Refactor as I have been using those productivity tools for a while now. I decided to write a custom CodeRush template for declaring properties in CSLA.
Creating a field, or in this case, registering a property on a class, only requires a user to type RP (Register Property), followed by the type and name of the property. Creating a property only requires a user to type DRP (Declare Registered Property), followed by the type and name of the property.
I demonstrate their use in the video below. [NOTE: In the video, I make reference to generics when I really meant nullable types. I was obviously on something.].
If you use CodeRush and you would like to install these templates, I outlined the steps below.
- Download the attached xml file
- Open Visual Studio
- Browse to DevExpress -> Options
- On the left hand, find Editor -> Templates
- Create a folder called Custom Templates if it is not already created
-
- Right-click on the folder structure and click New Root Category...
- Name the folder Custom Templates
- Right click on Custom Templates and click Import Templates...
You will now be able to use the RP and DRP custom templates as shown above. You may need to restart Visual Studio for these templates to take effect.
There are also Codesmith templates available if you would rather use Codesmith templates as there are a lot of these available for CSLA. You can check the templates out here.
Download CodeRush Template (XML file)
Download CodeRush Template Version 2 (see update above) (XML file)
Jamie,
A few suggestions:
1. Try using the "TypeLink" TextCommand instead of the "Link" TextCommand to support the "?" character in links.
2. You can be even more efficient if you combine the field generation with the property generation into a single template. You can chain from one template to another by right-clicking the template editor and selecting "Insert Alias...". You can use this to call your field creation template from your property template.
3. The "rp" name conflicts with the "r?Type?" templates used to create read-only properties (e.g., rp creates a read-only property returning a point by default). This suggestion might be considered a bit crazy, but you might rename this template to k?Type? ("k" isn't used as a template verb yet, and the "k" appears in both Rocky's first and last name, so there is some mnemonic value there). Then inside your template when you need the type specified by the template, you can use "«?Get(Type)»". Then "ki" would give you a CSLA property of type int, "ks" would give you a CSLA property of type string, etc. Super efficient, and all you're left with is typing in the name of the property.
4. When you need to remove a setter or a getter, the most efficient way is to place the caret on the "set" or "get" keyword and press the Cut key (e.g., Ctrl+X or Shift+Delete). This will cut the setter or getter to the clipboard, so if you don't want to lose what's on the clipboard the second most efficent way is to place the caret on the "set" or "get" keyword and press the Selection Increase key (Ctrl+W or Num+), followed by the Delete key.
Posted by: Mark Miller | December 01, 2009 at 04:23 PM