Create and Populate Date Dimension for Data Warehouse - CodeProject
Layers Pattern in Practice - CodeProject
-
Upload
quan-nguyen -
Category
Documents
-
view
227 -
download
0
Transcript of Layers Pattern in Practice - CodeProject
-
7/30/2019 Layers Pattern in Practice - CodeProject
1/17
ers Pattern in Practice - CodeProject
2/5/2013 2:09//www.codeproject.com/Articles/75082/Layers-Pattern-in-Practice?display=Print
Articles Platforms, Frameworks & Libraries Windows Presentation Foundation Applications
Layers Pattern in PracticeBy Ciumac Sergiu, 23 Apr 2010
Download executable - 916 KB
Download setup executable - 1.25 MB
Download sources - 0.99 MB
Download additional libraries - 514 KB
IntroductionBackground
Technology used
Conceptual integrity
Objectives
Data Access Layer
Entity Objects
Business Logic layer
Presentation Layer
Datagrid
Disconnected Data Environment
4.94 (52 votes)
-
7/30/2019 Layers Pattern in Practice - CodeProject
2/17
ers Pattern in Practice - CodeProject
2/5/2013 2:09//www.codeproject.com/Articles/75082/Layers-Pattern-in-Practice?display=Print
Styling the grid
Chart
Post release debugging
Testing
Source code
Conclusion
The main task of this article is to present a generic application's lifecycle, with problems and solutions to common issues which programmers face on a
daily basis. Once you start building an application, you ought to take into consideration lots of things, mainly from different theoretical areas of
programming. Of course, as an architect of a software product, you might bump into different problems, mainly related to understanding of the entire
omplexity of the project, at the very beginning of the specification design. The aim of the text written below is to highlight key points which one nee
ake into account at the start of the application conception. Herein, a simple WPF software product will be presented as an example, starting from its
pecification design, going through the development of a 3-tiered class hierarchy (User interface design - GUI; Business Logic - further noted as BL; an
Data Access Layer - DAL), and ending up with a setup project and post-release debugging. One can argue that "programming is an art" and there is n
need to define generic rules beforehand, constraining the architect's mind. Indeed it is so, and the article will actually try to show solutions to common
problems in Windows application design, leaving the choice of the lifecycle methodology to the architect.
Where architecture tells what happens, implementer tells how it is made to happen" Blaauw
The tutorial written below will try to encompass both the architect's and the implementer's mind by showing what and how problems are solved togetThe software example which is going to be presented is a BillsManager. The application's ultimate goal is to allow a client to manage his bills (simple
traightforward).
Technology used
decided to build BillsManager as a Windows application based upon the rising in popularity Windows Presentation Foundation technology. I find it v
prominent and really a step forward in Windows based development. The Data Access Layer will be constructed around XML files which will store the
ser's bills. So, as it can be inferred, the minimal requirement is .NET 3.5 SP.1.
Conceptual integrity
Conceptual integrity is the most important consideration in system design" Frederick Brooks
ndeed, as practice shows, in order to successfully build any software, one should clearly define written specifications (a necessary tool, although not a
ufficient one). From theory to practice - below is a list of the main objectives which BillsManager is going to meet.
Objectives
Show how much money a person needs to spend this month
Archive the payments
Show the nearest deadline
Chart the expenditures
Chart the expenditures by an interval of time
Show information about every bill
Give the possibility to export the archive in a file for backup
Assume that the target audience is not English-speaking
BillsManager will try to accomplish these fairly straightforward objectives. Although one can argue that these specifications are not enough to build a
uccessful application, I will leave them as they are in order, not to increase the complexity of the example on which all the explanatory part is built up
ier applicationSoftware architecture encompasses the set of significant decisions about the organization of a software system, including the selection of the structural
lements and their interfaces by which the system is composed; behavior as specified in the collaboration among those elements; composition of these
tructural and behavioral elements into larger subsystems; and an architectural style that guides this organization. Software architecture also involves
unctionality, usability, resilience, performance, reuse, comprehensibility, economic and technology constraints, tradeoffs, and aesthetic concerns" P.Kruchte
ooch, K. Bittner, R.Reitman
-
7/30/2019 Layers Pattern in Practice - CodeProject
3/17
ers Pattern in Practice - CodeProject
2/5/2013 2:09//www.codeproject.com/Articles/75082/Layers-Pattern-in-Practice?display=Print
As it is stated in the above self-descriptive paragraph, while designing the application, the software architecture team should have in mind a strong vie
bout how the requirements will be projected into the real environment, and how this environment can be as generic as it is possible. Separation of
nterfaces, business logic, and data access layer is a very important and also common need in software development. Essentially, nowadays, reusability
plays a crucial role within the Object Oriented paradigm. The BillsManager application will implement the 3-layered structure using the Layers Pattern
guidelines. Figure 1 below shows a general view of the systematization which is going to be used.
A 3-layered pattern is used in order to build better organized software parts. It provides a mechanism of defining reusable business components,
longside with deployment flexibility and smart resource connection management. All the components which are responsible for data visualization (e
DataGrid) will be placed in the Presentation Layer. All business logic rules will be encapsulated in business components within the BL layer. Finally, al
data related code needs to be defined within the Data Access Layer. Frequently, the DAL layer is responsible for database access. In the example prov
n this article, the database will be an XML file (but that does not make a difference as long as the GUI and the BL are not aware of the underlying data
ource). A more advanced explanation of this pattern can be found in Enterprise Solution Patterns using Microsoft .NET.
ta Access Layern order to have a flexible architectural component, I will start with the contract (interface) which each DAL connection manager should implement in
order to meet the requirements of the Domain Layer. Following is the code for the IDalBillsManager interface.
////// Interface for Bills' data source manager///publicinterface IDalBillsManager{ /// /// Read bills ///
Bills Read(DateTime fromDate, DateTime toDate); ///
/// Read a bill from datasource by its ID
///
Bill ReadById(Guid id); /// /// Insert bills into the datasource /// void Insert(Bills bill);
/// /// Delete a bill from datasource /// int Delete(Guid guid); ///
/// Delete a enumeration of bills from the datasource
///
int Delete(IEnumerable guids); /// /// Update the bill from database /// int Update(Guid billId, Bill newBill); /// /// Set settings for DAL Provider /// object[] Settings
{ get; set;
-
7/30/2019 Layers Pattern in Practice - CodeProject
4/17
ers Pattern in Practice - CodeProject
2/5/2013 2:09//www.codeproject.com/Articles/75082/Layers-Pattern-in-Practice?display=Print
}}
As it can be seen from the methods which need to be implemented, they define a very general contract which can be summarized in the following
esponsibilities:
Read bills from the data source (can be any data source: XML, Excel, SQL Server, network resource, etc).
Delete bills from the data source.
Update bills in the data source.
Insert bills in the data source.
Get or set the settings for the data source (e.g., connection string, path to archive file, etc.).
t is important to point out that the contract should relinquish the following rule within [IN] and [OUT] parameters. It should have:
Most general parameters at the input [IN] (E.g., IEnumerable interface)
Most specific return types [OUT] (E.g., Bills)
ubsequent to the interface definition, it is valuable to mention that the Business Logic programmer will access methods of the DAL Manager only
hrough an interface instance.
private IDalBillsManager _dalManager = XmlDalBillsManager.GetInstance();
f in a future development cycle, you choose to switch the DAL Manager to another version or to an entirely new library, you will need to change only
ne of code, which is the assignment operation written above. After doing this, the entire business logic library will work as it is supposed to, without
equiring any other changes in the code. The responsibilities, defined in the IDalBillsManager interface will be held by the Data Access Manager. I
our case, it will be an XML-based DAL Manager, meaning that all the bills information will be stored in an XML archive file. Below, you can see the XMLchema on which our archive will relinquish (this schema is located in BillSchema.xsd under the BillEntityLib project folder). It is very important to note
our XML will use strongly established rules of composition.
The XSD file describes the content that is allowed in an XML document in order for the last one to be considered valid (i.e., within the defined constraif you are not comfortable with XML schemas and their rules, please consult any available material on this topic. Our XML schema is formed from the
ollowing elements:
Bills (Root element)
Bill (Will represent every bill)
Name (Name of the bill)
DueDate (Bill's due date)
Amount (Bill's amount)
AddedOn (When was the bill added on)
Status (Bill's status)
-
7/30/2019 Layers Pattern in Practice - CodeProject
5/17
ers Pattern in Practice - CodeProject
2/5/2013 2:09//www.codeproject.com/Articles/75082/Layers-Pattern-in-Practice?display=Print
Our XML-based Data Access Manager will be a singleton object (meaning that where will be only one instance of the object in the entire application
fecycle). If you are not familiar with singletons, please consult the Singleton pattern article for a better explanation. The following figure presents the
diagram for the XmlDalBillsManager class. (Please notice that it implements the IDalBillsManager interface.)
Consequently, our XML based manager should support thread-safe operations (so that the archive does not get corrupt if multiple threads attempt to
write to the database at the same time - which could result in data loss or unpredictable behavior). Thus, the user is allowed to call the operations
Insert, Read, Update, and Delete without a clue of how the archive is protected from corruption. As it is not difficult to observe, here we can
mplement the Readers/Writers thread algorithm in order to solve the above mentioned problem. Herein, the manager will implement the following po
If somebody reads the data from the archive, other readers are allowed to perform the same operation (access for writers is prohibited).
If somebody writes the data into archive, no other thread (read or write) can perform any operation with the above mentioned data source.
or a more detailed review, please consult any available material related to the Readers/Writers threading algorithm.
tity ObjectsHaving the XML schema defined, we can now generate entity classes. These are the classes which do not hold any responsibility (do not have any
methods). They are just binary representations of the data from the XML. The Bills and Bill classes will perform only the storage function within t
Business Logic Domain (they will not have any additional methods except getters/setters for their properties). There are different approaches within th
ayers pattern regardless of the entity and business logic elements. You can define the business logic methods (Insert, Read, Delete, Update) in t
ame classes in the entity library (we'll see later what methods will actually be implemented in the business domain). The others can be separated in tw
different classes. I've used the following separation of business components:
Entity classes
Manager class
Don't worry if you do not understand the entire concept; you'll get it once you take a look at the actual implementation. I've decided to perform the
eparation, because it is more natural to have exactly the same copy of a Bill item in the computer memory as it is in the data source (no matter wh
data source: XML, text, Excel, relational database, etc.). At the same time, these entity objects will actually be serializable. This feature will allow any .NE
programmer to extend the program functionality by adding a new layer within the Business Logic and the Data Layer and pass objects from the Busine
Domain to the Data Domain in serialized state. Serialization allows to save an object's state (Bills and Bill) into any stream (memory, network, file,
and pass it within the Application Domain or Remoting services.
rom BillSchema.xsd, we can see that there will be only two entity classes: Bills and Bill. .NET provides an easy mechanism for generating .cs files
xsdschemas. This mechanism is achieved through the XML Schema Definition tool. One can access xsd.exe through Visual Studio's command prompt
by opening the command line and navigating to c:\Program Files\Microsoft Visual Studio 9.0\VC>. The command which needs to be applied is xsd [na
of xml schema].xsd /c. By applying this command, the XSD tool will generate partial classes which correspond to the schema definition.
//------------------------------------------------------------------------------
//
// This code was generated by a tool.
// Runtime Version:2.0.50727.4926
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
//------------------------------------------------------------------------------
using System.Xml.Serialization;
//
// This source code was auto-generated by xsd, Version=2.0.50727.3038.
//
-
7/30/2019 Layers Pattern in Practice - CodeProject
6/17
ers Pattern in Practice - CodeProject
2/5/2013 2:09//www.codeproject.com/Articles/75082/Layers-Pattern-in-Practice?display=Print
///[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.303")][System.SerializableAttribute()][System.Diagnostics.DebuggerStepThroughAttribute()][System.ComponentModel.DesignerCategoryAttribute("code")][System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true,
Namespace="http://tempuri.org/billschema.xsd")][System.Xml.Serialization.XmlRootAttribute(
Namespace="http://tempuri.org/billschema.xsd",IsNullable=false)]
publicpartialclass Bills {/*Bills collection from the datasource*/
private Bill[] itemsField;
///[System.Xml.Serialization.XmlElementAttribute("Bill")]
public Bill[] Items { get { returnthis.itemsField;
} set { this.itemsField = value;
}}
}
///[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")][System.SerializableAttribute()][System.Diagnostics.DebuggerStepThroughAttribute()][System.ComponentModel.DesignerCategoryAttribute("code")][System.Xml.Serialization.XmlTypeAttribute(Namespace="http://tempuri.org/billschema.xsd")]
publicpartialclass Bill {/*Each bill from the datasource, has exactly the same properties*/
privatestring nameField;
private System.DateTime dueDateField;
privatedecimal amountField;
private System.DateTime addedOnField;
privatestring statusField;
privatestring idField;
///
publicstring Name {
get { returnthis.nameField;
} set { this.nameField = value;
}}
///
public System.DateTime DueDate { get { returnthis.dueDateField;
} set { this.dueDateField = value;
}}
/// publicdecimal Amount { get { returnthis.amountField;
} set { this.amountField = value;
}}
///
public System.DateTime AddedOn { get { returnthis.addedOnField;
} set { this.addedOnField = value;
}
-
7/30/2019 Layers Pattern in Practice - CodeProject
7/17
ers Pattern in Practice - CodeProject
2/5/2013 2:09//www.codeproject.com/Articles/75082/Layers-Pattern-in-Practice?display=Print
}
/// publicstring Status { get { returnthis.statusField;
} set { this.statusField = value;
}}
///[System.Xml.Serialization.XmlAttributeAttribute()]
publicstring ID { get { returnthis.idField;
} set { this.idField = value;
}}
}
ollowing is the class diagram for the Entity objects. Please note that I've added some additional class members to those which were generated. (I wil
xplain later why there was a need to implement the INotifyPropertyChanged interface by the Bill class).
siness Logic Layerwill now discuss the Business Logic responsibilities and how they were materialized in the actual code. As in the case of the Data Domain, I've decided
define an interface IBillsManager which is going to deliver the contract to all the classes which will implement that interface. Here is the definition
he IBillsManager interface:
////// Interface for Bill manager business logic///publicinterface IBillsManager{ /// /// Read from data source ///
Bills Read(DateTime fromDate, DateTime toDate);
/// /// Reads a bill by its ID
-
7/30/2019 Layers Pattern in Practice - CodeProject
8/17
ers Pattern in Practice - CodeProject
2/5/2013 2:09//www.codeproject.com/Articles/75082/Layers-Pattern-in-Practice?display=Print
///Bill ReadById(Guid id);
/// /// Insert a bill into the database
///
void Insert(Bills bill);
/// /// Delete a bill from database /// int Delete(Guid bill);
///
/// Delete a list of bills with the specified guids ///
int Delete(IEnumerable guids);
/// /// Update a bill in the database /// int Update(Guid billId, Bill newBill);
/// /// Settings /// object[] Settings
{ get; set;
}}
You can see that the aforementioned interface defines exactly the same methods as the Data Layer interface IDalBillsManager. Yes, indeed the
methods are the same because the actual responsibilities are also the same. The only difference is that every manager (either from the Business Doma
rom the Data Layer) is responsible for different logical operations on the data which passes through. As an example, see the following figure:
As can be seen, even though the method signature for both the Business and Data Domain is the same, internally, they are responsible for different
ogical interactions within the objects. In the above example, the Business Domain insertion operation is responsible for:
Validation
Sending the request to the Data Layer
Checking whether the Insert operation occurred or not
Throwing an exception if appropriate
At the same time, the Data Layer is responsible for:
The actual insert operation into the data source
One can argue that there was no need to define two different interfaces with the same signature for the Business and Data Domains; instead, I should
have used the same interface for both. I definitely consider this argument a mistake, because the client programmer would be able to cast Business an
-
7/30/2019 Layers Pattern in Practice - CodeProject
9/17
ers Pattern in Practice - CodeProject
2/5/2013 2:09//www.codeproject.com/Articles/75082/Layers-Pattern-in-Practice?display=Print
Data Logic objects into the same interface, without a clue of whether he accesses methods from one or the other domain. This approach breaks the en
philosophy of layer separation and should never be used.
sentation LayerThe last but not the least layer in the pattern is the Presentation Layer. It is actually responsible for the interaction between the user and the machine.
There are plenty of topics which one might find useful while developing a GUI (Graphical User Interface). If you are building a WPF application, you mi
nd it useful to check Sacha Barber's articles here at CodeProject. Anyway, I will cover several of them which I think are the most generic ones. We'll st
with the DataGrid, a component which is responsible for presenting the data to the end user. Then we'll move to a more specific problem as charting
data and localizing string resources.
Datagrid
By default, .NET 3.5 does not ship a WPF datagrid component. There are different viewpoints whether it is good or not. I will just point out that I decid
ike many other developers) to use the WPFToolkit which can be freely downloaded from the CodePlex site (click here), in order to have a built-in
DataGrid with all the bells and whistles. Personally, I find those components really useful, so I really encourage everybody to explore them.
A core action one needs to define in a data grid is its binding to a data source. Binding is the concept of establishing a connection between a UI (use
nterface) component and the business logic. There is a very nice article on the MSDN site which explains how binding works in WPF components (clic
here). Typically, each binding has these four components:
a binding target object
a target property
a binding source
a path to the value in the binding source to use
or example, if you want to bind the content of a TextBox to the Name property of an Employee object, your target object is the TextBox, the targ
property is the Text property, the value to use is Name, and the source object is the Employee object. Here is the XAML code which declares and de
he DataGrid for BillsManager with the necessary binding.
As can be seen, each DataGrid column is bind to a specific property from our Entity's library Bill class.
Name - Binding="{Binding Name}"
DueDate - Binding DueDate, Converter={StaticResource DateConverter}Amount - Binding="{Binding Amount}"
AddedOn - Binding="{Binding AddedOn, Converter={StaticResource DateConverter}}"
Status - SelectedItemBinding="{Binding BillStatus}" ItemsSource="{Binding Source={StaticResource myEnum}}"
t is worth mentioning that the Converter item from the DataGrid column definition will perform the formatting operation ofDataTime values (it
how the date in short format DD.MM.YY). Shown below is the actual code for the converter item:
[ValueConversion(typeof(DateTime), typeof(String))]publicclass DateConverter : IValueConverter{ /*
* Convert each data item from the data grid into short format DD/MM/YY
*/
publicobject Convert(object value, Type targetType,object parameter, CultureInfo culture)
-
7/30/2019 Layers Pattern in Practice - CodeProject
10/17
ers Pattern in Practice - CodeProject
2/5/2013 2:09//www.codeproject.com/Articles/75082/Layers-Pattern-in-Practice?display=Print
{DateTime date = (DateTime)value;
return date.ToShortDateString(); /*Show the date in the datagrid in Short format*/
} /*Convert back*/
publicobject ConvertBack(object value, Type targetType,object parameter, CultureInfo culture)
{ string strValue = value asstring;
DateTime resultDateTime; if (DateTime.TryParse(strValue, out resultDateTime))
{ return resultDateTime;
} return DependencyProperty.UnsetValue;}
}
The code above binds the data to Bills, following this logic:
To bind the datagrid to data, set the ItemsSource property to an IEnumerable implementation. Each row in the datagrid is bound to an object in th
data source, and each column in the datagrid is bound to a property of the data object. In order for the DataGrid user interface to update automatically
when items are added to or removed from the source data, the DataGrid must be bound to a collection that implements INotifyCollectionChange
uch as an ObservableCollection. In order to automatically reflect property changes, the objects in the source collection must implement the
INotifyPropertyChanged interface". Click here for more details.
Bills from the data source are represented in the computer memory via the Bills class. Afterwards, these items are embedded in the
ObservableCollection collection. In this way, we can add, remove, edit elements of underlying list of bills without actually taking care of
pdating the user interface to reflect the changes (.NET will perform this automatically). Click here for more details.
As written above, we'll bind the data grid item source property to ObservableCollection.
_collection = new ObservableCollection(bills.Items);//define the ObservableCollection class
this._datagrid.ItemsSource = _collection;//bind the data to the datasource
Disconnected Data Environment
will now discuss the disconnected data environment approach which was implemented in our BillsManager application. This environment gives us an
nswer to how updates, deletes, and inserts of bills objects to the data grid control are reflected in the actual data source. Generally, there are two bas
mechanisms:
Connected Data Environment - once an entity (Bill) is modified in the Business Domain, the actual modification is also performed in the Data
Domain, meaning that a strong bidirectional relationship is defined within both layers.
Disconnected Data Environment - entities (Bills) which are modified in the Business Domain are marked as updated, but no modifications are
performed in the Data Domain. Once a crucial action is performed within the application (e.g., the application is closed), all the fields which are
marked as updatedare modified in the Data Domain according to their new values.
This second approach has a lot more advantages in its use. Mostly, these advantages relate to a lot more flexibility. Imagine a user changing a bill's sta
rom Unpaid to Paid. Also, he might want to modify the Amount field of the same bill. In the connected data environment, these operations will resu
he following method calls:
Change bill's status property from Unpaid to Paid
Change bill's amount property
n a disconnected data environment, the aforementioned operation will result in the following:
Mark the bill as Updated (please note, this operation will not call any method from the Data Domain).
Once the Commit operation is called, update both bills' properties at once.
The above mentioned mechanism was possible through the usage of the Publish/Subscribe event model. Every bill entity allows any client to subscrib
ts PropertyChangedEventHandler PropertyChanged event. Once you've subscribed to this event, you'll receive a notification whether a bill's
property was changed.
Styling the grid
The style of the grid is located in the resource dictionary (DataGrid.Generic.xaml). The interesting thing about the style of the grid is conditional
ormatting. Once a bill's due date is overdue and a bill's status is Unpaid, the data row changes its color from transparent to yellow. This is done thro
-
7/30/2019 Layers Pattern in Practice - CodeProject
11/17
ers Pattern in Practice - CodeProject
2/5/2013 2:09//www.codeproject.com/Articles/75082/Layers-Pattern-in-Practice?display=Print
onditional formatting. A developer can set the ItemContainerStyle property of the grid to an element which will dynamically change the
background of the data row according to some logics defined in the code behind. So we'll define a new resource dictionary element and call it
ItemContStyle:
The DataRowBackgroundConverter class's Convert method will be invoked. According to the data which is set in the data row, it will return Yel
or no color.
[ValueConversion(typeof(object), typeof(int))]publicclass DataRowBackgroundConverter : IMultiValueConverter{ #region IMultiValueConverter Members /*
* Check each element for the corresponding background color
*/ publicobject Convert(object[] values, Type targetType,
object parameter, CultureInfo culture){
if (values[0] is DateTime){
DateTime dueDate = (DateTime)values[0]; string status = values[1] asstring; if (dueDate < DateTime.Now &&
BillHelper.Convert(status) == BillStatus.Unpaid){
returnnew SolidColorBrush(Colors.Yellow); /*Return Yellow if DueDate is overdue and BillStatus is unpaid*/
}}
returnnull;}
publicobject[] ConvertBack(object value, Type[] targetTypes,object parameter, CultureInfo culture){
thrownew NotImplementedException();}
#endregion}
As you can see, WPF offers great flexibility in terms of data binding and data formatting.
Chart
Charting is a topic which is definitely very often discussed on programming forums. Many people find it challenging, because lots of things need to be
aken into consideration. I decided to use a third party charting tool rather than the one defined in the WPFToolkit. It can be freely downloaded from
Visifire site. It is a framework which provides Open Source data visualization components. I find it very nice and easy to use. The things which I would lo point out are, that the chart itself draws the data according to a set of different parameters, which can be set in many ways ( DataSeries - series o
data points which actually represent the pair X, Y, where F(x) = Y; Axis - pie, line, bar, 2D, 3D, etc., Title - the actual title text). In order to have an
xtensible mechanism of drawing the chart using different Axis, I decided to use the Strategy pattern. The strategy is actually the way how axis will b
epresented (this is done in order to have three different types of chart: Line, Bar, Pie). The following figure presents the class diagram for these items:
-
7/30/2019 Layers Pattern in Practice - CodeProject
12/17
ers Pattern in Practice - CodeProject
2/5/2013 2:09//www.codeproject.com/Articles/75082/Layers-Pattern-in-Practice?display=Print
Consequently, chart properties are set according to one of the methods of drawing it:
//chartType object of type IChartingpublicstaticvoid SetChartValuesAsync(Chart chart, IEnumerable list,
ICharting chartType, IntervalTypes interval,ChartValueTypes chartValueType, bool scrollingEnabled, bool erasePrevious)
{ if (chart != null)
{chart.Dispatcher.BeginInvoke(new Action(delegate(){
if (erasePrevious){
chart.AxesX.Clear();chart.AxesY.Clear();chart.Titles.Clear();chart.Series.Clear();
}
// Add title to Titles collection
chart.Titles.Add(chartType.GetTitle(list.First().Name)); /*Set Axis via interface instance*/
chart.AxesX.Add(chartType.GetAxis(interval, list));chart.ScrollingEnabled = scrollingEnabled;chart.Series.Add(chartType.GetDataSeries(list, chartValueType));
}), null);}
}
As we can see, the mechanism is maintainable and extensible, because even if we add new types of charts in the following versions of the application,
only need to implement the corresponding ICharting interface and pass an object of its type to the SetChartValuesAsync method. In the figur
below, we can see an example of the aforementioned settings adjustment:
-
7/30/2019 Layers Pattern in Practice - CodeProject
13/17
ers Pattern in Practice - CodeProject
2/5/2013 2:09//www.codeproject.com/Articles/75082/Layers-Pattern-in-Practice?display=Print
Localization
ocalization is the process of preparing an application to run in multiple locations. The .NET Framework provides very thorough support for localizing
ypes of client applications. Culture information and manipulation in the .NET Framework is exposed through an instance of the CultureInfo class,
which can be used to read culture settings for a given locale, as well as setting a specific locale in an application. Every thread maintains a set of cultur
nformation stored as CultureInfo settings in the CurrentCulture and CurrentUICulture properties.
WPF applications have two possibilities to set different locale statuses:
LocBaml tool
Resx approach
n my application, I'll be using the Resx resource files approach (mainly because it is a classical way of setting different locales in Windows Applications
Resx files are XML based f iles which are compiled into resource.dll libraries and can be loaded into the application via the ResourceManager class. T
ollowing snippet shows the code which performs the actual load:
CultureInfo currentCulture = Thread.CurrentThread.CurrentCulture;string culture = ConfigurationManager.AppSettings["Culture"];if (!String.IsNullOrEmpty(culture)) if(culture != "Default")
currentCulture = new CultureInfo(culture);ResourceManager resx = new ResourceManager( "BillPayManager.Properties.Resources", typeof(App).Assembly);
The currentCulture object will hold a thread's culture description. The resx object will allow us to query the .dll file with the actual cultural specifi
nformation. The default culture is read by the BillsManager application from the application configuration file (Key = "Culture"). It is important t
mention that if the App.config file doesn't explicitly set culture information, then the en-US culture will be used. Here is a query example:
this._lTotalAmount.Content = resx.GetString("TotalAmount", currentCulture);this._lNearestDeadline.Content=resx.GetString("NearestDeadline",currentCulture);
The resource files are stored within the folders with the same name as cultural info (en-US, ro-RO). Next, we can visualize how MainAssembly gets t
esources from the corresponding directories (see figure).
-
7/30/2019 Layers Pattern in Practice - CodeProject
14/17
ers Pattern in Practice - CodeProject
2/5/2013 2:09//www.codeproject.com/Articles/75082/Layers-Pattern-in-Practice?display=Print
n order to change the culture, please change the BillPayManager.exe.config file or change it via the Miscellaneous tab:
Be attentive while changing the Culture key. You can explicitly set only cultures defined in the corresponding sub folders (en-US or ro-RO).
st release debuggingThe importance of post release application debugging cannot be underestimated. Even though testing of the application can end up in a very small
number of undetected bugs, once installed on user machines, the application behavior cannot be predicted. This might happen because of several
easons: user has no admin privileges, the OS internal configuration is different of expected ones, or your application demands read/write operations t
ritical regions as the root directory of the system drive (usually C:\), the HKLM (local machine) key in the Registry, etc. Yet, developers have a mechani
which allows them to figure out problems which appear on the client-side machine, without the need to literally come to the client's office or home. Th
mechanism is called Tracing.
ven though we are unable to predict where and when the application is going to crash, we can assume that in some critical points, it might have
problems of doing some sort of operations. These critical points can be marked as traceable. Once the application reaches these points, we ought to w
he information about the current state (variables, stack trace etc.) in a file, which, if needed, can be shipped to developers in order for them to solve th
problem. Having the application's log file will allow them to recall steps which caused the application to crash. This simple mechanism can save huge
mounts of time and money. .NET Framework is shipped with the System.Diagnostics namespace, which has plenty of features that can help us t
race, debug, and monitor the performance of our application. The class in which we are interested in order to meet the post-installation debugging
purpose is the Trace class. Next, I will post a passage from here which best describes the purpose and usage of the aforementioned class.
You can use the properties and methods in the Trace class to instrument release builds. Instrumentation allows you to monitor the health of your
pplication running in real-life settings. Tracing helps you isolate problems and fix them without disturbing a running system. This class provides meth
o display an Assert dialog box, and to emit an assertion that will always fail. This class provides write methods in the following variations: Write,
WriteLine, WriteIf, and WriteLineIf. The BooleanSwitch and TraceSwitch classes provide means to dynamically control the tracing outpu
You can modify the values of these switches without recompiling your application. You can customize the tracing output's target by adding
TraceListener instances to or removing instances from the Listeners collection. The Listeners collection is shared by both the Debug and thTrace classes; adding a trace listener to either class adds the listener to both. By default, trace output is emitted using the DefaultTraceListener
lass.
The Microsoft Best Practices team advices developers to use the App.config file for the adjustments of trace listeners (this is pretty obvious, as long as
hanges in application configuration file do not require recompilation). Anyway, I've decided to adjust the diagnostics objects in the code because of
everal issues. As an example, consider you want to use DelimiterTraceListener as your main listener. Once you have specified in App.config the
path to the file that will actually store the output messages, you have no way of checking whether the user has write privileges to that location or not.
means that if the user doesn't have the required permissions, the application will throw an exception at startup once the CLR tries to instantiate the
forementioned objects. Because of this, the BillsManager application adjusts Trace objects in the method which is written below.
///
/// Initialize Delimited Trace listener
///privatevoid InitializeDelimitedTraceListener()
-
7/30/2019 Layers Pattern in Practice - CodeProject
15/17
ers Pattern in Practice - CodeProject
2/5/2013 2:09//www.codeproject.com/Articles/75082/Layers-Pattern-in-Practice?display=Print
{ bool enabled; string tracepath = ""; try
{enabled = Convert.ToBoolean(ConfigurationManager.AppSettings["BooleanSwitch"],_currentCulture);
tracepath = System.IO.Path.GetFullPath(ConfigurationManager.AppSettings["PathToTraceFile"]);
} catch (FormatException)
{enabled = false;/*Disable Boolean switch*/
} this._chbTrace.IsChecked = enabled; string path = ProbeFilePermissions(tracepath, FileIOPermissionAccess.Write); /*Check if user has enough privileges to Write in the corresponding folder */
if (path != tracepath){
try{
ModifyAppConfig("PathToTraceFile", path); /*Modify App.Config if another path is chosen*/
} catch(ConfigurationErrorsException)
{Debugger.Break();
}}
long maxSize = 1045680;/*1 MB*/ try
{maxSize = Convert.ToInt32(ConfigurationManager.AppSettings["SizeOfTrace"]);
/*Max Size of trace file*/}
catch (FormatException){
Debugger.Break();}
finally{
try{
FileInfo fileInfo = new FileInfo(path); if(fileInfo.Length > maxSize)
File.Delete(path);
} catch(Exception)
{Debugger.Break();
}}DelimitedListTraceListener listener = new DelimitedListTraceListener(path)
{Delimiter = "__",IndentSize = 4,TraceOutputOptions = TraceOptions.DateTime
};Trace.Listeners.Add(listener);/*Adding listener to the collection*/Trace.AutoFlush = true;
this._bSwitch = new BooleanSwitch("Switch", "Switch");_bSwitch.Enabled = enabled;
this.TraceSystemSettings();/*Tracing system settings*/
}
The ProbeFilePermissions() method probes the location for FileIOPermissionAccess.Write, and if the user lacks the specified permissio
eturns an alternative path to which the user has Write privileges.
Testing is one of the most unpleasant parts of developing an application. There are different approaches to the way how testing is performed (Manual
Automation testing, Unit tests). They depend mostly upon what methodology was used in software development. I prefer using Unit tests because the
s a great way of visualizing the Data Flow, Exceptions, Assertions, etc. In order to write a unit test, we needs to install the NUnit framework, freely
downloadable from their official website. Once installed, you can use features available in the NUnit.Framework namespace in order to test any pu
method. For more information about writing Unit Tests, click here.
-
7/30/2019 Layers Pattern in Practice - CodeProject
16/17
ers Pattern in Practice - CodeProject
2/5/2013 2:09//www.codeproject.com/Articles/75082/Layers-Pattern-in-Practice?display=Print
rce codeve written the application using Visual Studio 2008 TS. The source code is structured as follows:
BillManagerUninstallAction project. Custom uninstall action implemented in order to delete all the associated files (archive and trace output) on
the application is uninstalled from the user's machine.
BillPayManagerproject. This is the actual WPF application. The GUI was developed using the Expression Blend 3 IDE.
BillsBusinessLogicLib project. The library contains all the necessary classes for Business Layer management (BL). Main class - BillsManager.
BillsDalLib project. The library where all XML data access related code is located. The main class for DAL is - XmlDalBillsManager.
BillsEntityLib project. Entity library.
TestBillPayManagerproject. Several Unit Test fixtures are written in this project. I've deleted the project from the solution configuration in order
people who don't have NUnit installed on their machines to be able to compile the solution without errors. If you want to build it, please add it
the project.
TestBillPayManagerManual project. Manual tests written for GUI testing. The project is also unloaded.
SetupBillPayManagerproject. Setup for BillsManager.
n order to successfully compile the project, we need additional libraries referenced in the BillPayManagement project. These libraries are:
AvalonControlsLibrary
WPFToolkit
Visifire
During my student's life, I've always had enough books on software design. Even if each of them provides very nice analysis of software architecture, of them speaks about issues related to practical implementation. This is due to the fact that authors are most likely to speak in abstract terms, in orde
o tie themselves to a specific technology (.NET Framework in my case). This is of course great, but I've always wanted a guide which will have as an
xample a complete product, starting from the specification design and ending up with the setup project. The aim of this article is to speak about the
main issues related to .NET Windows application design, not in terms of theory, but in terms of practice. You can argue that architecture design is a to
which differs from one product to another, and it's mostly impossible to speak about every tiny problem which you will encounter during an applicati
fecycle. This is of course true, but the article's target audience is "computer science students" and not senior developers who already know all the stu
written in here. That's why I've designed a simple WPF application in order to have a generic guide for students (or uninitiated WPF developers) who
would like to build these types of applications. I've tried to keep the article's size as small as possible, but somehow it extended above initial expectatio
Thanks for reading.
Alex Railean - http://railean.net/ for helping me writing this article.Victoria - for being kind.
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)
out the AuthorCiumac SergiuSoftware Developer
Moldova (Republic Of)
Member
nterested in computer science, math, research, and everything that relates to innovation. Big fan of C# programming language, but don't mind
developing under any platform/framework if it explores interesting topics. In search of a better programming paradigm.
-
7/30/2019 Layers Pattern in Practice - CodeProject
17/17
ers Pattern in Practice - CodeProject
ermalink | Advertise | Privacy | MobileWeb04 | 2.6.130204.1 | Last Updated 23 Apr 2010
Article Copyright 2010 by Ciumac Everything else Copyright CodeProject, 1999
Terms
ments and Discussions31 messages have been posted for this article Visit http://www.codeproject.com/Articles/75082/Layers-Pattern-in-Practiceto post and view
omments on this article, or click here to get a print view with messages.