|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionGreetings reader, this article sets out to make the task of defining properties a little less typing intensive. It should provide a convenient location to track changes to entities or whatever you can think of. In short, you'll be able to write properties that look like this: public DateTime DateCreated{
get{ return (DateTime)propertyValue; }
set{ propertyValue = value; }
}
The above code is a very simple example, it doesn't do much more than save you defining the underlying variable (i.e. Let's look at what's needed to get this going. The base class[Serializable]
public abstract class Persistable {
public Persistable(){
properties = (PropertyValue[])
GetType().GetCustomAttributes(typeof(PropertyValue), true);
for (int i = 0; i < properties.Length; i++)
properties[i].parent = this;
}
PropertyValue[] properties;
//The main point of entry/exit for our entities data
protected object propertyValue{
set{
PropertyValue property = PropertyValue;
if (property == null)
throw new Exception("Property not found");
property.SetValue(value);
}
get{
PropertyValue property = PropertyValue;
return property == null ? null : property.Value;
}
}
//To only be used by the propertyValue property
//Finds the PropertyValue attribute for the currently executing property
PropertyValue PropertyValue{
get{
System.Diagnostics.StackTrace st =
new System.Diagnostics.StackTrace();
if (st.FrameCount > 0){
string propertyName =
st.GetFrame(2).GetMethod().Name;//Jump TWO steps back
propertyName = propertyName.Substring(4);
return FindProperty(propertyName);
}
return null;
}
}
//Scans through the PropertyValue array
//till it finds the requested PropertyValue.
PropertyValue FindProperty(string name){
for (int i = 0; i < properties.Length; i++){
if (properties[i].Name.Equals(name)){
return properties[i];
}
}
return null;
}
[Serializable]
[AttributeUsage(AttributeTargets.Class, AllowMultiple=true)]
public class PropertyValue : Attribute{
public PropertyValue(string name){
this.name = name;
}
protected object value;
string name;
internal Persistable parent;
public string Name{
get{ return name; }
}
public virtual object Value{
get { return value; }
}
internal virtual void SetValue(object value){
this.value = value;
}
}
}
Using the codeHere's a simple example: [Serializable]
[Persistable.PropertyValue("ApplicationNumber")]
public class ApplicationMessage : Persistable {
#region ApplicationMessage Properties
public string ApplicationNumber{
get{ return (string)propertyValue; }
set{ propertyValue = value; }
}
#endregion
}
Important: Note that the first argument to the Now in order to make Suppose we need an audit log of changes made to our " ///Persistable
public virtual Persist(){
...
//Custom persistence in override OR
//I like to pass "this" to the Data Layer
//ie. id = MyObjPersister.Persist(this);
}
Next add supporting objects for logging. //Persistable
StringBuilder changeLog;
long id;//Standardise Persistable ids.
//Depending on how you run things you can
//get away with no having a Set'er on the ID
public long ID{
get{ return id; }
set{ id = value; }
}
//Appends the supplied string to the log
void LogChange(string detail){
if (changeLog == null){
changeLog = new StringBuilder();
if (id == 0)
changeLog.AppendFormat("{0}: Instance" +
" of {1} was created.\n",
DateTime.Now, GetType());
else
changeLog.AppendFormat("{0}: Log started" +
" for instance of {1} with ID : {2}.\n",
DateTime.Now, GetType(), id);
}
changeLog.AppendFormat("{0}: {1}\n", DateTime.Now, detail);
}
//Returns the body of the changelog
string ChangeLog{
get{ return changeLog == null ? string.Empty : changeLog.ToString(); }
}
Now we change the implementation of //PropertyValue
internal virtual void SetValue(object value){
parent.LogChange(string.Format("Property {0} " +
"was changed from {1} to {2}.", this.value, value));
this.value = value;
}
Now we're logging our changes to a //Persistable
public virtual Persist(){
...//persist the object
Log.LogAudit(ChangeLog);
}
//
//IN ORDER FOR AN APPLICATION TO AUTOMATICALLY
//CREATE AN EVENT LOG CERTAIN (i dunno) PRIVILEGES ARE NEEDED.
//The alternative is to create it manually and just let the app add to it.
public sealed class Log {
static readonly string applicationName =
ConfigurationSettings.AppSettings["ApplicationName"];
static readonly string logSourceName =
ConfigurationSettings.AppSettings["LogName"];
static Log(){
if (!EventLog.Exists(applicationName))
EventLog.CreateEventSource(logSourceName, applicationName);
}
public static void LogAudit(string info) {
string output = string.Format("{0}\n", info);
EventLog.WriteEntry(logSourceName,
output, EventLogEntryType.Information, 1);
}
}
So now every time you Points of InterestIn the future (post Whidbey), it'd be sweet to change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||