N-Layered Web Applications with ASP.NET 3.5 Part 1: General Introduction


NOTE: the concepts presented in this article are now considered obsolete possibly because better alternatives are available.

Update 09/06/2013: I have written a completely new series targeting (ASP).NET 4.5 and Entity Framework Code First version 5. Check out the new series here: http://imar.spaanjaars.com/573/aspnet-n-layered-applications-introduction-part-1.

Update 02/03/2009: There is now a VB.NET version of the application available thanks to Sven Huijbrechts from ClearMedia bvba. Check it out at the Downloads section at the end of this article

Note: this is part one in a series of six. If you rather read this entire series off-line, you can buy the series as a convenient PDF document that comes with the full source. Besides the convenience, buying the PDF will also make you feel good as it shows your appreciation for the articles and helps me pay the bills for my server and hosting so I can keep running imar.spaanjaars.com and continue to provide you with great content. For more details, check out this post that shows you how you can buy the entire series right now.

In January 2007 I released the first part of a highly popular three-part article series on N-Layer design using ASP.NET. This article was followed by two more parts in February, and I updated all three articles in April to fix some minor issues in the code and in the articles. In June 2007 I added another – small – article to the series that showed you how to do custom sorting in N-Layer applications.

Now, almost two years later, it’s time for a major update on the articles and the Contact Manager Application that is discussed in the article.

Over the next six articles, I’ll show you how I improved the design of the original application, making it more powerful, secure and easier to maintain.

This is part 1 in the series. It builds on top of the earlier three part series on N-Layer design. If you haven’t already done so, be sure to check out these articles first, as a lot of code and concepts used in this new series is explained in detail in the older series.

Quick Links to All Articles

Previous Series
Building Layered Web Applications with Microsoft ASP.NET 2.0 - Part 1
Building Layered Web Applications with Microsoft ASP.NET 2.0 - Part 2
Building Layered Web Applications with Microsoft ASP.NET 2.0 - Part 3
Custom Sorting with N-Layer Design Classes and the GridView

Current Series
N-Layered Web Applications with ASP.NET 3.5 Part 1: General Introduction
N-Layered Web Applications with ASP.NET 3.5 Part 2: Introducing the Validation Framework
N-Layered Web Applications with ASP.NET 3.5 Part 3: Advanced Validation Topics
N-Layered Web Applications with ASP.NET 3.5 Part 4: Sorting, Paging and Filtering
N-Layered Web Applications with ASP.NET 3.5 Part 5: Dealing with Concurrency
N-Layered Web Applications with ASP.NET 3.5 Part 6: Security

Introduction

The original article presented a simple on-line Contact Manager Application that allows you to manage information of your contacts, including their e-mail addresses, addresses and phone numbers. While simple in its feature set, the application showed the design of a full blown multi-layered web application.

I won’t be repeating a whole lot from the first article series here, so you’re advised to read them first (if you haven’t already done so) before you proceed with this new series. In particular, I’ll skip most of the following topics:

  • Gathering requirements for your design (I’ll assume the requirements for the application haven’t changed much so the initial workshop and raw sketches still cut it).
  • Database design (as the database hasn’t changed much).
  • The Web Layer (most of the web layer has remained exactly the same since the initial release).
  • Code Organization using #regions (I am still using the same organization rules, although I made some minor changes in the variable naming scheme due to evolving programming guidelines).
  • Data Access Layer code. A lot of code in the DAL is pretty similar to that of the previous edition. The biggest changes are perhaps the extra using statement for the SqlCommand objects and the extra columns and other code added to support concurrency (explained in part 5)

To get up to speed with these topics, check out part 1, part 2, part 3 and part 4 of the original article series out now.

I’ll refer to the previous series or articles when I am using concepts that are not explained here, but that are explained in the previous series.

A Look Ahead

Before I dig into the new application in detail, I’ll give you a brief over of what to expect of the next couple of articles:

N-Layered Web Applications with ASP.NET 3.5 Part 1: General Introduction
N-Layered Web Applications with ASP.NET 3.5 Part 2: Introducing the Validation Framework 
N-Layered Web Applications with ASP.NET 3.5 Part 3: Advanced Validation Topics
N-Layered Web Applications with ASP.NET 3.5 Part 4: Sorting, Paging and Filtering
N-Layered Web Applications with ASP.NET 3.5 Part 5: Dealing with Concurrency
N-Layered Web Applications with ASP.NET 3.5 Part 6: Security

Part 1 (which you are reading right now)
In this part you’ll find a quick look back the initial design and a general overview of the new version. You’ll see how I built up the new layered structure, how I organized the project structure better now that Visual Web Developer Express Edition allows you to use Class Library projects and I’ll show the new features of the new design (some of which are discussed in full detail in later parts).

Part 2 – Introduction to Validation
Many of you have asked me to show you how to implement validation in your application. How can you make sure a user enters a valid e-mail address? How can you be sure that a date of birth falls in a valid range? How do you force a user to enter a valid name without writing a lot of code? And how do you provide feedback to your users in case they made a mistake?

These are all typical day to day programming problems that need to be solved every time you work with data and custom business entities, so it makes sense to write a common solution to this problem in the Business Layer in order to avoid writing the same logic over and over again. In part 2 I’ll show you a Validation Framework that makes all of this very easy to do.

Part 3 – Advanced Validation Topics
The Validation Framework I discussed in part 2 is only the beginning of what’s possible. This part digs deeper in the possibilities, showing how to create your own validation rules and how to localize (make available in multiple languages) the application and Validation Framework.

Part 4 – Sorting, Paging and Filtering of Data
I think the main reason why my initial articles were so popular is because they were so simple and straight forward. The code and the design were pretty easy to understand as they were only focusing on a few main areas. However, that also meant I had to leave some import topics out, like sorting, paging and filtering. I’ll make up for these omissions in part 4 of this series and show you how to implement these concepts.

Part 5 – Dealing with Concurrency
Concurrency issues can be problematic when two users try to update the same piece of data at the same time. Normally, when you don’t deal with concurrency, the last user to write to the database wins. In small web sites with only a few visitors, you may not care about concurrency issues. However, as soon as your site attracts more visitors, or you have a site where it’s likely that multiple users can access the same data at the same time, concurrency becomes a real problem. In this part I’ll show you how to handle concurrency, what your options are and how I have implemented it in the new Contact Manager application.

Part 6 – Security
Security is another topic I left out of the original article series. However, almost all web applications require some sort of security applied, be it a simple access rule to block unauthenticated visitors from accessing your management pages, to a more fine-grained control system to adapt the user interface to the currently logged on user. In this part, I’ll show you how to use declarative and imperative role based security, how to use URL authorization and how to use the ASP.NET Membership and RoleManager API’s. Note that this part does not contain a general introduction to these concepts, as many other books and articles have already been written about. I’ll refer to books and on-line articles where appropriate.

Now that you have seen what’s coming in the near future, it’s time to take a step back, and see how we got here in the first place.

A Quick Look at the Initial and at the New Design

The initial design consisted of three layers, all shown in Figure 1.

Overview of the Three Layers in the Contact Manager Application
Figure 1 – Overview of the Three Layers in the Contact Manager Application

At the top of the figure you see the Presentation or UI layer, implemented as an ASP.NET web application. In the middle you see the Business Layer which contains two separate namespaces: the BO namespace (with classes that act as relatively dumb data containers, renamed to BusinessEntities in the new design) and the Business Logic Layer (BLL) — responsible for interacting with the UI and Data Access Layers). At the bottom you see the Data Access Layer (DAL) which is responsible for accessing the database.

While this design works well from a high-level point of view, it had a few shortcomings that were pointed out by some of my readers. To be able to improve the design, it’s important to zoom in a bit on these shortcomings first.

Shortcomings of the Initial V1 Release

One of the biggest issues that people had with the design of version V1 was the lack of a validation mechanism. There was no central place to validate the state of an object and no easy way to express your validation rules. I advised some of you to implement and call a Validate method from the Save method and perform custom validation there optionally, throwing an exception when a business rule was broken. This often meant you needed to write a lot of custom code.

Another often requested feature was a common base class, or at least a common interface for the business objects. By letting classes inherit a common base class, it’s easier to define behavior that should apply to all classes in your application, make it easier to share behavior.

The V1 edition of the design was in English only. The UI wasn’t localizable and neither were any error messages or messages for broken validation rules you may have thrown from the Business Layer. Of course being able to easily translate a web site in multiple languages is almost a necessity these days in the global internet market to that’s another concern that needs to be addressed in the new version of the application.

Finally, some of you were a bit worried about the physical organization of the application. Some thought the separation of the various layers inside different folders *inside* the web application’s App_Code folder was breaking a pure multi-layered design. While I didn’t always agree with the reasoning behind these worries (and especially not with a few narrow-minded “booh booh” type of comments from people who clearly showed they didn’t understand what it’s all about and what these articles were meant to demonstrate), I do agree that good organization leads to better maintainable code and thus to better applications.

You’ll see how I address these shortcomings and more over the course of these six articles.

What’s New in v2

To give you an idea of what’s new in Design v2, I’ll list the major changes here. With the first installment of this article series, you won't be able to download the full source code yet. However, staring with part 2 which is released in December 2008, I'll supply the full code for the entire application, showing all the features and techniques I am discussing in this series. Want a copy of the full source right now and get a copy of all six articles? Check out this article to learn how you can buy the full set right now!

  • I reorganized the application’s structure by using separate Class Library projects for each layer or namespace. Previously you couldn’t do this with the free VWD Express Edition, but now with Service Pack 1 for VWD, you can easily create multi-project solutions containing web sites and class libraries.
  • I introduced a new namespace naming scheme: the BO layer has been renamed to BusinessEntities.
     
  • I introduced a new common base class for all objects in the BusinessEntities layer called BusinessBase. This class defines behavior common to all other objects, like ContactPerson and Address. This BusinessBase in turn inherits from ValidationBase which provides the services needed by the Validation Framework.
     
  • I implemented a Validation Framework to make it easy to validate your business objects before you save them in the database. Additionally, the business objects expose a collection of BrokenRules that provide information about the different rules that are broken, along with an error message that explains why these rules are broken. Although not required to implement, the framework makes it super easy to localize the error messages in different languages using standard .NET localization features. You’ll see how this works in part 3.
     
  • Both the business and the Web layer are now localizable. The download comes with all string resources translated in English and Dutch, but it’s easy to add your own language, or to modify the exiting text. The BusinessBase class defines shared behavior for localization.
     
  • The initial design featured collection classes that inherited from List<T>. FX Cop flagged this design choice, detailing it’s better to inherit from Collection<T>. You’ll see how this works and how to overcome the lack of a Sort method on this base class that is present on the List<T> class.
     
  • The entire solution is now upgraded to ASP.NET 3.5 to be able to use LINQ to Objects. This is only used in the Validation Framework and in the sorting and paging routines in the Business Layer so it’s relatively easy to downgrade the entire solution back to ASP.NET 2.0 in case you have the need.
     
  • The web project now uses a Master Page for common design elements. Additionally, all CSS and presentation related code has been moved into the main Default theme.
     
  • I implemented sorting and paging in the business and data layers making it easy for a user to see smaller chunks of data. This results in better performance and in a better user experience.
     
  • I implemented Concurrency checks in the Data Access Layer and stored procedures to deal with concurrency problems. I modified the UI pages to deal with this and inform the user of any conflicts.
     
  • I dropped support for Microsoft SQL Server 2000. The database and code that comes with these articles can be used as-is on SQL Server 2005 and 2008 though, including the free Express editions. If you really want to use this on SQL Server 2000, you’ll need to rewrite a few stored procedures, and change some of the columns in the database from nvarchar(max) to ntext. You should be able to open the database with SQL Server 2005 and 2008, but if you get an error related to a missing Microsoft.SqlServer.Management.Sdk.Sfc file, be sure to check out the file Troubleshooting.txt that comes with the download.
     
  • I wrapped the entire Default.aspx page in an AJAX UpdatePanel to smooth out page transitions.
  • I implemented security, both on the page level using URL Authorization and at the code level using declarative and imperative security checks.
     
  • Additionally, I made the following minor changes to the code or the model:
    • The NotSet items of the enumerations have been renamed to None and given a value of 0 to better align with programming guidelines. Because this default value now has the underlying value of 0 (zero) which was previously assigned to real items, the application is no longer backwards compatible with the data in the database from the previous version. However, given the limited practical use of the data in this application, I doubt that will be a problem.
    • Changed most properties to be auto-implemented properties. Not a big deal, but makes code files slightly more manageable.
    • The integer ID properties of the business entities no longer default to -1 but to 0. Again, not a big deal. It was mostly a side effect of the auto-implemented properties. Additionally, 0 looks less like a magic number than -1 does.
    • Updated variable names to match with the latest programming guidelines. Most notably: private fields have now all been prefixed with an underscore.
    • Updated the API documentation (the XML comments) so they are in line with the new model and name changes.
    • Moved some code from code behind to a separate Helpers class to make it easier to reuse it across pages.

Now that you’ve seen what’s new and coming, it’s time to look at these changes in detail. Some of them are discussed in this part while the remainder of the topics are discussed in the next six articles.

Application Setup

In the previous version of this application, the code for all layers was stored in the App_Code folder of the web application. This was necessary as Visual Web Developer Express Edition didn’t allow you to create separate class library projects and consume them in a web application. Since I wanted as many people as possible to be able to follow along, even if they were using the free Express Edition, I had to take this route which resulted in the following overview of the Web Site project in Visual Web Developer 2005:

The Solution Explorer of the Contact Manager Application Version 1.0
Figure 2 – The Solution Explorer of the Contact Manager Application Version 1.0

The application consisted of a single Web Site Project with all the code placed in the App_Code folder, separated by layer.

Fortunately, Service Pack 1 for Visual Web Developer 2008 now adds support for Class Library projects, making it easier to spread out the various layers over multiple, physically separated, class library projects. This results in the design for the Contact Manager Application shown in Figure 3:

The Solution Explorer of the Contact Manager Application Version 2.0
Figure 3 - The Solution Explorer of the Contact Manager Application Version 2.0

The Visual Studio Solution Spaanjaars.ContactManager.sln now contains 5 separate projects, each of which is discussed in the next sections. If you purchased the commerical version of this article, you have another project in the solution that contains the tests for this project.

To setup a brand new solution like this in Visual Web Developer 2008 (VWD 2008) or Visual Studio 2008 (VS 2008), (with Service Pack 1 applied), carry out the following steps:

  • Start VWD 2008 or VS 2008, choose File | New Web Site (or File | New | Web Site depending on the version of VWD 2008 you are using and the type of configuration you have chosen at start up). Choose ASP.NET Web Site and save it in a folder like C:\Projects\CompanyName\ApplicationName\CompanyName.ApplicationName.Web. In my example, I stored the site at C:\Projects\Spaanjaars\ContactManager\Spaanjaars.ContactManager.Web. This is how I usually set things up. By grouping everything under Projects, it's easy to find all your project files. Within Projects, I create a folder per customer / company, and within that folder, I create a folder per project I am doing for that customer. My source control tree is set up with an identical structure, so it's easy to find stuff when you need it. The final folder (Spaanjaars.ContactManager.Web) contains one of the Visual Studio projects that make up the entire application. In the next steps, more projects are added.

     
  • Next, choose File | Add | New project, select the Class Library template, and enter CompanyName.ApplicationName.Bll as the name of the project. In my case, I used Spaanjaars.ContactManager.Bll. Save the project in the same folder as the web project (at C:\Projects\CompanyName\ApplicationName\) so the two projects end up in the same parent folder (this is not a requirement but makes managing your projects much easier).
     
  • Repeat the previous step three more times, adding the following class libraries:
    • CompanyName.ApplicationName.BusinessEntities
    • CompanyName.ApplicationName.Dal
    • CompanyName.Validation

       
    There is a limit in the combined length for the project name and project location on disk. Visual Studio gives you a warning when you try to enter a path and name that exceed the limits.

(Note there’s no ApplicationName in the Validation project as the Validation framework can be shared by multiple applications.

  • When you’re done, your Solution Explorer should look similar to the one shown earlier in Figure 3.
  • Finally, save the solution in the root folder (at C:\Projects\CompanyName\ApplicatioName) and call it CompanyName.ApplicationName. Your application folder in a Windows Explorer should now look like Figure 4:
     

Windows Explorer Showing the Organized Folder Structure
Figure 4 – Windows Explorer Showing the Organized Folder Structure

  • The last step in the setup process is linking the various applications. To do this, right click the Web Site Project. Choose Add Reference and on the Projects tab choose the Bll and BusinessEntities projects.
  • Repeat the previous step, creating references between the following projects:
     

From

To

Spaanjaars.ContactManager.Bll

Spaanjaars.ContactManager.BusinessEntities

 

Spaanjaars.ContactManager.Dal

 

Spaanjaars.Validation

Spaanjaars.ContactManager.BusinessEntities

Spaanjaars.Validation

Spaanjaars.ContactManager.Dal

Spaanjaars.ContactManager.BusinessEntities

 

Spaanjaars.Validation


Remember you don’t have to carry out all of these steps manually if you just want to follow along with this article: the code download that I'll publish starting from part 2 of this series contains the full application, including the different projects and solution files. (If you want to get the full source now, take a look here.) However, if you want to create a similar application like this from scratch, it’s good to know how to set it up yourself.

Now that you’ve seen the general setup of the Visual Studio Solution and the various projects it contains, it’s time to look at the individual projects in more detail.

Application Design

To help you understand how all these layers work together, Figure 6 presents a graphical representation of a typical flow of data when requesting an item like a contact person or an e-mail address in the application:


Figure 5 – A Typical Flow of Data Through All Layers

Here’s a quick run-down of the process that’s carried out when a user requests the details of a contact person on the web site:

  • The Presentation layer, for example an ASPX page called ShowContactPerson.aspx gets the ID of the requested contact person from the Query String and asks the BLL for a specific ContactPerson. It does this by calling ContactPersonManager.GetItem() and passing it the ID of the contact person.
  • The BLL can optionally perform some security checks (more on that in part 6) and then forwards the request to the DAL by calling ContactManagerDB.GetItem().
  • The DAL connects to the database and asks it for a specific record. It does this by executing a stored procedure, like sprocContactPersonSelectSingleItem and passing it the ID of the contact person.
  • When the record is found, it is returned from the database to the DAL in a SqlDataReader object.
  • The DAL wraps the database data in a custom ContactPerson business entity from the BusinessEntities namespace and returns it to the BLL.
  • Finally, the BLL returns the ContactPerson object to the Presentation layer, where it can be displayed.

A similar flow is used for other data operations, for example when a Business Entity is saved or deleted, or when an entire list of entities is retrieved.

To see how each layer operates and what it is responsible for, the next couple of sections dig deeper into the various layers. Notice how I won’t discuss each and every class, feature or page in detail. A lot of it has already been explained in the first version of these articles (which you should have read by now). Additionally, future articles in this series dig deeper into some parts of the application, most notable validation in parts 2 and 3 and security (part 6), and data behaviors (paging, sorting and so on) in part 4.

The Web layer is what you primarily see when using a typical web application, so it makes sense to look at that layer first.

Spaanjaars.ContactManager.Web

This layer is implemented with a simple Visual Web Developer (VDW) 2008 Web Site Project, rather than a Web Application Project. Because it’s a Web Site Project where namespaces are not added automatically to the code behind and class files, I decided to leave them out altogether. However, if you were using a Web Application Project instead, you get namespaces for all your web pages and other code files automatically. Either way, the same principles demonstrated in these articles apply. For an excellent explanation of the differences between a Web Site Project (WSP) and a Web Application Project (WA), check out Peter Lanoie’s article on the subject: Web Site vs. Web Application Project. The Web Site Project that comes with this article is shown in Figure 6:

ax
Figure 6 – The Web Site Project of the Contact Manager Application

The Default.aspx and AddEditContactPerson.aspx pages are used to manage your contacts and their contact data like addresses and phone numbers. Part 3 of the original article series described how these pages work in detail, so you’re advised to take a look there in case you want to know how they work. The new functionality in these pages, like dealing with concurrency and validation is discussed in later parts, just as the other files, like Login.aspx and SearchContactPeople.aspx are.

The MasterPages and App_Themes folders are used for the presentational aspects of the site and are responsible for a consistent look and feel throughout the application.

The Demos folder contains a few sample pages that demo a few concepts I’ll show throughout the article series.

The Controls folder contains a simple User Control used to present validation errors. You’ll see how this works in part 2.

The App_Data folder contains the SQL Server 2005 database for this project. This database contains the various tables and stored procedures, most of which have been described in the first version of this article. For some functionality — paging for example — I added new stored procedures and modified existing ones which I’ll discuss together with the functionality that uses these procedures.

The two resources folders contain localized resources for the application. You'll see more on localization in part 3.

The Web layer has references to two other layers: the Bll and the BusinessEntities. It needs a reference to the BusinessEntities layer in order to work with specific entities like ContactPerson or Address. Additionally, it communicates with the Bll layer to get or save these entities.

Spaanjaars.ContactManager.BusinessEntities

This layer contains the main data entities for the application. Figure 7 shows the Solution Explorer for this layer:

The BusinessEntities Layer Project
Figure 7 – The Business Entities Layer Project

Besides the main entities in the root of the project, you see a folder for the collections, enumerations and for localization files. For a large part, the classes in the BusinessEntities layer are just simple data containers, or “dumb classes” as I called them in earlier articles. The use of automatically implemented properties (available in C# only, although they are coming in the next version of VB.NET) make these classes even more compact to write than ever before. Here’s a quick example of the EmailAddress class before the Validation Framework is put in place:

public class EmailAddress
{
public EmailAddress()
{
this.Type = ContactType.None;
}

/// <summary>
/// Gets or sets the unique ID of the e-mail address.
/// </summary>    
[DataObjectFieldAttribute(true, true, false)]
public int Id { get; set; }

/// <summary>
/// Gets or sets the actual e-mail address text of the e-mail address.
/// </summary>
public string Email { get; set; }

/// <summary>
/// Gets or sets the type of the e-mail address, like business or personal.
/// </summary>
public ContactType Type { get; set; }

/// <summary>
/// Gets or sets the ID of the owner (a <see cref="ContactPerson"/>)
/// of the e-mail address.
/// </summary>
public int ContactPersonId { get; set; }
}

Pretty straightforward, don’t you think? All this class does is define a data container: a bunch of public properties that make up the business entity. Other classes in other namespaces (the Bll and Dal in particular) are responsible for filling and managing these data containers.

If you look at the Class Diagram for the BusinessEntities, shown in Figure 8 you see that in reality things are slightly more complex than this. Each data entity inherits from BusinessBase which in turn inherits from ValidationBase. Both these classes and the Validation Framework are discussed in part 2 and 3, so you can ignore them for now. You'll see the full code for these and other classes in the code download that comes with part 2 and later articles in this series.

Class Diagram of the BusinessEntities Layer
Figure 8   - Class Diagram of the Business Entities Layer

Spaanjaars.ContactManager.Bll

The Bll namespace contains — just as in the original application — a number of classes that define the behavior for the entities in the application. Figure 9 shows the classes that exist in this namespace:

The Business Logic Layer Project
Figure 9 –The Business Logic Layer Project

Each of these classes is responsible for working with their counterparts from the BusinessEntities namespace. For example, there’s a ContactPersonManager class that allows you to create, retrieve, update and delete your contacts. Likewise, there’s an AddressManager class responsible for managing the Address instances of the application. To a large extent, these classes are almost identical to the ones from the v1 version, so again you’re advised to take a look at the original articles in case you have questions about these classes.

Figure 10 shows the full class diagram for this layer:

Class Diagram of the Business Logic Layer
Figure 10 - Class Diagram of the Business Logic Layer

Each of these *Manager classes exposes the following four methods:

Method Name

Input Parameters

Description

Delete

Accepts an instance of the business entity that must be deleted from the database.

Deletes the business entity from the database. When a ContactPerson entity is deleted, it also deletes its associated contact data records, like EmailAddress and PhoneNumber.

GetItem

id (int)

Gets an item from the underlying data source based on the (unique) ID of the item passed in.

GetList

Depending on the underlying type this method has a few overloads to get all records, a paged and sorted set or to get specific records for a contact person.

No matter what overload you use, this method returns a collection for the type you requested. So, ContactPerson.GetList returns ContactPersonCollection defined in the BusinessEntities namespace.

Save

Accepts an instance of the business entity that must be saved in the database.

Saves an instance of the business entity in the database. When a ContactPerson is saved, it also saves its contact data like EmailAddress and PhoneNumber.


These methods delegate the responsibility of getting and updating data to the classes in the Dal namespace. In the previous version of this article, they did literally just that, as is shown by the following piece of code that is responsible for instructing the Data Access Layer to save an EmailAddress in the database:

[DataObjectMethod(DataObjectMethodType.Update, true)]
public static int Save(EmailAddress myEmailAddress)
{
myEmailAddress.Id = EmailAddressDB.Save(myEmailAddress);
return myEmailAddress.Id;
}

This was also the place where you could implement your own validation or security code, although I left the implementation of that up to the reader.
Now, in the new version of this application design, validation is implemented at the root of the business entities. Before they call into the DAL, classes in the BLL can check the validity of the business entities using the Validation Framework. Additionally, they can make security checks to determine if the current user has sufficient permissions to carry out the operation. In short: they allow you to apply your business rules before any data gets out of or in the system. You’ll see how this works later.

Spaanjaars.ContactManager.Dal

Just as in the previous version of this application, the DAL holds a number of classes responsible for getting data in and out of the database. Figure 11 shows the complete list of available classes:

The Data Access Layer Project
Figure 11 –The Data Access Layer Project

The classes in the Data Access Layer are responsible for getting data in and out of the database. The implementation of the Contact Manager Application uses Microsoft SQL Server 2005 or 2008 so the code also targets classes in the System.Data.SqlClient namespace. However, it’s pretty easy to replace the DAL classes with another one that targets a different database like Microsoft Access or Oracle. Finally, you could rewrite these classes to use the generic counterparts of many of the main database related objects like the DbConnection, DbCommand and DbDataReader. While this greatly improves the interoperability of the application with regards to the different database it can target, it also means that you need to write a lot of “database agnostic” code. That is, you can no longer use stored procedures (as their implementation is for a large part vendor specific) but instead you’ll need to resort to inline SQL. Since the amount of code you need to rewrite to target a different database is relatively limited, I’ll opt for a database specific solution (SQL Server in my case) and leave it up to you to write in-line SQL or rewrite the code to target a different database.

Since the classes in the BLL forward their calls to the DAL, it should come as no surprise that this layer has similar classes and methods, all shown in Figure 12:

Class Diagram of the Dal

Figure 12 - Class Diagram of the Data Access Layer

The FillDataRecord method is discussed in full detail in part 2 of the original article series.

A brand new namespace in the v2 design is the Spaanjaars.Validation namespace which is discussed next.

Spaanjaars.Validation

The last class library in the solution of the Contact Manager Application is the Spaanjaars.Validation project. The code in the Spaanjaars.Validation namespace is inspired by the work by AzamSharp in his article “Creating a Domain Object Validation Framework”. I reused many of the concepts, including the attribute usage and validation code. However, I also made a lot of changes and enhancements, including the introduction of a separate ValidationBase and BusinessBase classes, localization behavior in the BusinessBase class and extended behavior on the BrokenRules collection class to quickly find specific broken rules. All of these classes are visible in Figure 13:

The Validation Project
Figure 13 – The Validation Project

I also moved the validation behavior from a separate ValidationEngine class into the ValidationBase class where my business entities ultimately inherit from. In Figure 14 you see the class hierarchy for the Validation Framework.

Class Diagram of the Validation Namespace
Figure 14 - Class Diagram of the Validation Namespace

The full details of this framework and its implementation are discussed in part 2 of this series.

Summary

I started off this article with a quick introduction and a look ahead of what you can expect from the entire series. I then looked back at the initial design of the Contact Manager Application that I released in January 2007. While the design, the application and the articles received a lot of praise from my reader base, they left a lot of room for improvement. Most notably was the lack of any easy validation mechanism, followed by the lack of a central base class or interface. Additionally, the classes in the project were not easy to localize. Finally, because all code was stored in the App_Code folder of a web application, it wasn’t as easy to maintain and reuse it across other applications.

All of these concerns — and more — have been addressed in the Contact Manager Application v2. In this first part of the article series I showed you the setup of the new application which uses separate class libraries for each of the layers. This makes the code better organized and thus easier to maintain. Additionally, it’s now easier to reuse some parts, as could be the case with the code in the Spaanjaars.Validation namespace.

I also showed you how the different layers are connected, how they work together and how the data flows from one layer to another and back. I also deliberately skipped some steps as they have been discussed in the previous edition of the article.

I closed this article with a quick overview of each of the layers and the classes they contain. This overview should help you better understand the application and its design which in turn will be helpful when I zoom in on various parts of the application in the coming articles.

In the next part and the one after that you’ll find a detailed explanation of the Validation Framework. You’ll see how to create custom attributes that you can apply to properties of your business objects to make validation super easy, requiring only a few lines of code. You also see how to write a common validation base class that your custom business entities can inherit from to incorporate the validation behavior.

Part 4 touches on advanced data topics like paging, sorting and filtering of data.

Part 5 shows you how to deal with concurrency in your applications by implementing concurrency behavior in the business entities. With this behavior, you can prevent two users from inadvertently overwriting each other’s data.

In part 6, the final part in this entire series, you’ll learn more about implementing security checks to ensure only authenticated and authorized people can access specific parts of your application and code.

I'll be publishing the later articles over the coming months and update the links to them in this and later articles.

Stay tuned!

Downloads


Where to Next?

Wonder where to go next? You can read existing comments below or you can post a comment yourself on this article .


Consider making a donation
Please consider making a donation using PayPal. Your donation helps me to pay the bills so I can keep running Imar.Spaanjaars.Com, providing fresh content as often as possible.



Feedback by Other Visitors of Imar.Spaanjaars.Com

On Wednesday, November 26, 2008 4:18:50 AM Navdeep said:
Hi Imar,

Before I start reading the article. I want to thank you for sharing. I know many of readers have been waiting for this.

Cheers,
Navdeep
On Wednesday, November 26, 2008 8:07:41 PM Jeff said:
Imar,

Thanks a ton for taking the time to write this new series! I know it will answer a lot of questions I and others have had ever since the first N-Layer series came out. You can bet I'll be pouring over the whole thing with mucho gusto and anticipation.

With separating the application out into individual Web and Class Library projects, would you say your using an MVP (Model-View-Presenter) or an MVC (Model-View-Controller) development approach for this application?
On Thursday, November 27, 2008 3:20:21 PM Imar Spaanjaars said:
Hi Jeff,

It's more like a Model View application. In a MVC application, you also have a controller that "controls" the application. That is, it can determine what data to display, where to send the user and so on.

In my case, a lot of the controller behavior is placed in Code Behind files. This makes them easier to write at first, but slightly more difficult to manage later on. For example, if you rename a page like AddEditContactPerson.aspx, you also need to look through the code, find references to this page and update the references as well.

In an MVC / MVP environment, this is a lot easier to do.

In case you're interested in this technology, be sure to check out Microsoft's MVC implementation for ASP.NET: http://www.asp.net/mvc/

Cheers,

Imar
On Sunday, November 30, 2008 6:54:11 AM Muhammad Zeeshanuddin Khan said:
Can I ask about the Cache Implementation in your project?
On Sunday, November 30, 2008 7:07:57 AM zg said:
Thanks for taking the time to write these articles!!
On Sunday, November 30, 2008 4:05:33 PM Imar Spaanjaars said:
Hi Muhammad,

Caching is not discussed in these series.

Cheers,

Imar
On Monday, December 01, 2008 1:41:32 PM Chuck said:
Imar,
I have only read through half of the article so far but it is looking good. Your original articles helped me learn more about C# and ASP.NET development. Since C# is my first programming language that I am learning they have helped me tremendously.  

During your discussion on the *Manager classes, I started to think why you designed them the way you did and maybe there is a good reason for it. Considering you know that each of the *Manager classes expose the same 4 methods, wouldn't it have been a better decision to create an interface or abstract class that each of the *Manager classes inherit from or implement? This would allow you to provide implementation specific code for each of that methods pertaining to the specific *Manager class but still implement a well designed class structure? When I used your previous articles to help me develop my first asp.net web application, I did notice that I was writing a lot of similar code, with similar functionality, which increased my development and maintenance time. My feeling is it would be better to abstract out all of the common functionality into a base class or interface and have each *Manager class override or implement it. What are your thoughts on this? Thanks!
On Monday, December 01, 2008 4:47:23 PM JD said:
Hi Imar,

Thank you for the new series.  This looks very good and I'm looking forward to reading all these articles.  I still would have liked to see some information about doing batch updates and if for that matter you would use viewstate or session to hold data between postbacks.  I learned a lot from your previous articles but saving a record into the database one at a time is not an approach that we use in our company.

Thanks
On Monday, December 01, 2008 6:08:29 PM Imar Spaanjaars said:
Hi JD,

Thanks for your feedback; I'll consider batch updates for the next series or a new part in the series.

Cheers,

Imar
On Monday, December 01, 2008 6:20:00 PM Imar Spaanjaars said:
Hi Chuck,

Yeah, you could certainly do that. However, it's not easy to come up with a single base class or interface because of the different types some of the methods are returning.

You could create a base class with simple methods like Save and Delete and have them accept a BusinessBase. Alternatively, you could create a generic class and instantiate them with a specific class that inherits from BusinessBase.

It's something I'll consider for a future update of this series.

Cheers,

Imar
On Thursday, December 11, 2008 1:28:58 AM Iker said:
I liked article. What I am not to follow is that how will i deploy the DAL layer physically on different machine?

Right now we can take reference of Dal dll and use in Bll. But if DAL is kept in seperate machine, I cannot understand how will I host it and then consume it from bll kept on diff machine. Plz help,
On Thursday, December 11, 2008 7:11:19 AM Imar Spaanjaars said:
Hi Iker,

The article series discusses N-Layer, not N-Tier, as explained in the first part of the previous series. So, this architecture isn't meant to be spread out over multiple machines. For that you'll need to look into other technologies like remoting, web services, SOA and WCF.

Cheers,

Imar
On Thursday, December 11, 2008 11:07:59 AM Iker said:
I have entire app design based on this good technique you designed..If I have now to ditribute the DAL on a different machine, can you just tell me the steps in brief or with a sample..thanks. I am clueless and am lost
On Thursday, December 11, 2008 10:32:34 PM Imar Spaanjaars said:
Hi Iker,

Like I said, this architecture isn't meant for N-Tier; it's designed for N-Layer (although it should be easy to put at least the database on a different server).

You'll need to look into other technologies. Maybe a book like Expert C# 2008 Business Objects by Rockford Lhotka would be helpful for you.

Sorry, no easy steps and no brief examples.

Cheers,

Imar
On Friday, December 12, 2008 7:21:00 AM Sharad Kapil said:
Prefect !!

( Full of knowledge )
On Friday, December 12, 2008 2:14:48 PM Chuck said:
Imar,
While these articles are definitely going to be an upgrade from your v1 series, I would definitely like to see Caching implemented in this example. There are obviously other examples of how to use caching from Scott Mitchell's ASP.NET tutorials or Marco Bellinaso's use of caching in his base classes in TheBeerHouse but I think it may be a good idea to implement some caching strategy in this design in the future. What do you think? Thanks.
On Sunday, December 14, 2008 4:56:24 AM Muhammad said:
Waiting for your next part.
On Monday, December 15, 2008 7:15:13 AM Charles O said:
Hi Imar, great article.

Since you are upgrading this v2 to .net 3.5 i was wondering if using linq to sql (or linq to entities) would help simplify things in your DAL and entities layer as well as provide direct practical guidience to those of us that have been slow to pick up on linq (or have resisted it).

Thanks again for the great articles, they have served as an invaluable learning aid for my team of young developers.

Regards.
On Monday, December 15, 2008 5:54:30 PM Imar Spaanjaars said:
Hi Charles,

You may want to check out Blogo.net. It uses my design, but Linq to Sql for data access:

http://s3maphor3.org/blogo.net/

Cheers,

Imar
On Wednesday, December 17, 2008 6:20:44 AM Subhash said:
Hi Imar,
I am new to N layer can you tell me how can I utilize this N-Layer architecture in my applications. where I want to start.

I dont have a any one to guide me proper.

I request you to please give me a start up.

Thanks
Subhash
On Wednesday, December 17, 2008 8:06:10 AM Imar Spaanjaars said:
Hi Subhash,

Where to start????????? Haven't you read the previous four articles that preceed this series? Aren't they all about getting started? What else do you need?

Imar
On Thursday, December 18, 2008 7:50:54 AM Akmal Hussain said:
Hi Imar,

First of all, thanks for sharing this excellent article.

We are looking to design a common, scalable and maintainable framework for a large complex web application such that we can quickly upgrade some existing features in asp and earlier versions of asp.net to asp.net 2.0.

The design we are figuring out is very much similar to the one presented in this article. Two things we are looking for and is not satisfied from this approach are

1. Reducing db roundtrips (For getting all details of a contact, we are making several roundtrips to the database, similarly for storing a contact in the database, several roundtrips are required.)

Is there a way to achieve this without compromising on business entities?

2. We are looking to generalize the CRUD operations such that with minimum lines of code we can achieve the results.

Can you suggest some ways / articles to achieve them?

Thanks
Akmal
On Thursday, December 18, 2008 10:19:15 PM Imar Spaanjaars said:
Hi Akmal,

For reading data, you could use stored procedures that select multiple results, and then use NextResult to get other result sets.
Same for updates: you can batch them. Google for "batch update .NET" for more info.

To minimize code, you can write a wrapper (or Google for existing ones) that enables you to execute stored procedures, get datasets, get single results with a few lines of code.

Cheers,

Imar
On Tuesday, December 23, 2008 12:50:29 AM todd said:
Great Articles! I purchased the whole series.

Question.

Have you ever used any of the ORM tools available or Entity Framework? I recently used EntitySpaces for a project and its been fabulous. The time it saves doing redundant coding is enormous. Just curious to what your thought are on this.


On Tuesday, December 23, 2008 1:31:01 AM Pablo A Castillo said:
Imar,

Thanks for sharing your knowledge and experience using ASP.NET and C#.

Pablo A Castillo
On Tuesday, December 23, 2008 10:08:26 AM Imar Spaanjaars said:
Hi todd,

Yes, I do use technologies like Linq to SQL and the ADO.NET Entities framework a lot as well.

For a real-world implementation of my design with Linq to SQL under the hood, check out Blogo.NET:

http://s3maphor3.org/blogo.net/
http://ferdychristant.com/blog/articles/DOMM-7DDFWT

Cheers,

Imar
On Tuesday, December 23, 2008 9:43:26 PM Greg Partin said:
Hi Imar,

Great article!  I agree with the others, I would like to see it implemented with a cache layer involved in your design.  

Regards,

Greg
On Wednesday, December 24, 2008 1:32:19 PM Roger Torres said:
Great article!!!. All software professional should spend more time learning how to architect applications like this using simple and well-known technologies.

I not too sure about the DAL though, it works fine for small applications, but as the development team and application grows, this approach could become a nightmare. You can check my blog at http://blogs.conatural.com to learn more about my opinion on the DAL issues ... and other shortcuts that can be taken -- like automatic generation of a stored procedure layer and batch execution.

Are you planning to post something about ASP.NET MVC in the future? I'm thinking about posting a series like this for building an online fantasy game with MVC and jQuery. What do you think?

Cheers

RT.
On Wednesday, December 24, 2008 5:10:25 PM Imar Spaanjaars said:
Hi Roger,

Yes, I agree, it requires a lot of code in the Dal. I usually use code generators like My Generation to take care of this. They can generate at least 80 to 90 percent of the model as a starting point.

Other technologies, like NHibernate, Linq to SQL or the ADO.NET Entities Framework are good replacements for the Dal code. For a real-world implementation of LINQ to SQL in my design, check out Blogo.NET:

http://s3maphor3.org/blogo.net/
http://ferdychristant.com/blog/articles/DOMM-7DDFWT

No plans yet to write on MVC, but who knows what might come. Looking forward to what you have to write about it though....

Cheers,

Imar
On Wednesday, December 24, 2008 5:12:21 PM Imar Spaanjaars said:
Hi Greg,

Thanks for your comments. I have no plans to write about caching yet, but who knows what might come in the future....

Cheers,

Imar
On Friday, December 26, 2008 8:56:13 PM Supremestar said:
Hi Imar,

You are a boon to the .NET community. Zillion thanks for your effort. But I have one request for you, in the previous article series you haven't touched on 'Exception Handling'. I would like to see your approach in handling exceptions in an enterprise application. Please consider this request.

Thanking you.

Cheers,
Supremestar
On Saturday, December 27, 2008 12:54:49 AM Imar Spaanjaars said:
Hi there,

Thanks for your suggestion; I'll add it to my list of things to consider.

Don't count on it though; a lot has already been written on exception handling, and things aren't that much different from what you'd usually use, so a discussion of exception handling in an N-Layer application wouldn't add much value or introduce new and interesting stuff.....

Cheers,

Imar
On Monday, December 29, 2008 2:34:26 PM Greg Partin said:
Is there a reason you left the caching layer out?  The reason I'm asking is because there is a constant heated debate about caching in a model like this and the amount of effort to maintain the cache (across web farms, how much data to cache, etc.) versus the performance savings it offers.  
On Monday, December 29, 2008 8:29:59 PM Imar Spaanjaars said:
Hi Greg,

Yeah, those are all important things to take into account (although I typically don't worry that much about web farms; I usually try to cache stuff at the local front end web servers, so each server has its own cache).

The reason I left it out is because - depending on how you look at it - it doesn't really belong in a Business Layer. What happens when you access this layer from a console application, a windows service or a Win Forms application? It'll be difficult or at least awkward to use web caching.

Within .NET you have a lot of other caching options available, like Page Output caching, caching with the DataSource controls, the Caching API (it would be pretty easy to cache the results of GetList or GetItem methods in the cache) or User Control / Fragment caching. If you use these techniques wisely and optionally combine them with database cache invalidation on SQL Server 2005 and later, you can handle most of the front-end performance scenarios.

If you do have the need to cache within the Bll, it's not so hard to implement it. On a number of web applications I use that technique and cache inside the GetList and GetItem methods (on these sites I don't care that much about other type of applications although we do design overloads that ignore the cache altogether). You then have a couple of options: cache the results of each individual GetList and GetItem call, or cache the entire list of objects. The latter only works when you have a limited result set (e.g. it won't work with millions of records) but might perform better, and provide better results. For example, GetItem could query the global list, rather than caching its own private copy.

Alternatively, you could write a layer on top of the Bll that sits between the Web and Bll layers. This caching layer could then contain logic that gets items either from the cache, or from the business layer. If you base this on a provider model (that is, give the Bll and Cache layer the same API and make them configurable) it's easy to swap out the Bll for the Cache layer in case your site requires it later. It may require some changes to the API but it could be well worth it if done right.

Hope this sheds some light on why I haven't discussed caching....

Cheers,

Imar
On Friday, January 02, 2009 8:18:42 PM Nice.Developer said:
hi
you are using update panels.
is it a good approach for ajax for a large site ?
i don't think ?
what do you say?
On Friday, January 02, 2009 8:25:37 PM Imar Spaanjaars said:
Hi there,

Why wouldn't they be a good approach in large sites?

Imar
On Monday, January 05, 2009 3:05:19 PM Wouter Neuteboom said:
Thanks for the great articles! You've helped me a lot with getting started!

----

Groeten uit Holland :)
On Monday, January 05, 2009 5:33:22 PM Imar Spaanjaars said:
Hi Wouter,

Graag gedaan, en de groeten terug.... ;-)

Imar
On Sunday, January 18, 2009 6:18:00 AM mohamad said:
hi
i whant show resoult of multi tables joid in a grid.
but with DDD i dont know how do this.
pls help me
On Sunday, January 18, 2009 9:39:48 AM Imar Spaanjaars said:
Hi mohamad,

It depends a bit on your design. If all you want to do is show data in a GridView, create a business entity with properties from all columns you're selecting. Then in a stored procedure, get the data with the JOIN and then fill the object.

Updating could be done in a similar fashion, but you'll need multiple INSERT / UPDATE statements to update the relevant tables.

Cheers,

Imar
On Sunday, January 18, 2009 10:24:50 AM mohamad said:
very tanks for ur answer
1-but i think i can't say my qustion , bc my inglish is bad ;)

for example i want show this contant in a datagrid:

FirstName , LastName , PersonType , Street , HouseNumber, City , Country,Email , ContactType3

but whit DDD i have problem
i think i must use datatable and dont use entity.

2- what is ur idea abou used dataset or datatable vs. dataEntity
3- tanks about ur good documnt and about validation part.
On Sunday, January 18, 2009 10:28:19 AM mohamad said:
im sorry.
i have agine a problem.
when i whnat creat a report for print what i do. i dont sea u usead creastal report or datareporter
On Sunday, January 18, 2009 10:33:13 AM Imar Spaanjaars said:
Hi mohamad,

Like I said, you could create an additional entity, like PersonWithAddress and feed it all the data you need.

Alternatively, you could use LINQ to Objects on your collections and select new, anonymous types that contain this data and bind that to the GridView. Probably cleaner than creating a new entity.

So, you don't need a DataSet. Check out my first article series to see my ideas on the DataSet.

Reporting is a bit out of scope for this article. If I am not mistaken you can bind Reporting Services reports or Crystal reports to business entities as well.

Cheers,

Imar
On Monday, January 19, 2009 9:12:26 AM mohamad said:
tansk alot. do u work with facebook toolkit? i cannot use it
On Monday, January 19, 2009 12:33:56 PM Imar Spaanjaars said:
Hi mohamad,

Never used the Facebook toolkit so you'll need to look elsewhere.

Cheers,

Imar
On Friday, January 23, 2009 4:40:37 AM Niraj D Phalke said:
I am using N-Layer architecture in my web application. I am using Oracle as Database. I want to transfer data from Business Logic Layer to the Presentation Layer in the format of XML.

I don't know which objects to use. Should I use XMLDataDocument, XMLReader or not. How should I pass the data in XML format. Which object should I use to transfer the data from BLL to Presentation Layer.

Please if any body knows how to do it please reply me.

Thanks,

Niraj D Phalke
On Friday, January 23, 2009 9:13:17 PM Robin Simmons said:
Hello Imar,
Is any part of code for your new series ported to VB yet?  I'd be happy to buy it now if it is, but the C# code is less useful to me and I have an immediate need.

Thank you,
Robin Simmons
On Friday, January 23, 2009 11:07:03 PM Imar Spaanjaars said:
Hi Robin,

Not yet, unfortunately. I'll post here as soon as it's done...

Imar
On Friday, January 23, 2009 11:19:23 PM Imar Spaanjaars said:
Hi Niraj,

That are a lot of questions, most of them too broad to fall in scope of this article.

Why do you want to transfer them as XML? In what way do you get them out of the database?

If I were you, I'd do some reading up on the System.Xml namespace, learn what the classes in this namespace can do for you, how they work best, and then make a decision...

Cheers,

Imar
On Saturday, January 31, 2009 6:00:32 AM ace said:
every thing is good but the source code given is saved in latest visual studio format. it cant be opened in vs 2005.

if you could fix that it looks good

thanks
On Saturday, January 31, 2009 8:39:29 AM Imar Spaanjaars said:
Hi there,

The title of this article is "N-Layered Web Applications with ASP.NET 3.5"; the 3.5 in the title implies Visual Studio 2008 as I am using features that only work in 3.5 / 2008. This project isn't meant to be compatible with the older 2005 / ASP.NET 2.0 release.

You could manually copy the source files from my download into new ASP.NET 2.0 web site and class library projects, and then remove the dependency on 3.5 features like LINQ. Or you could get the free VWD 2008 edition and use that with my code.

Cheers,

Imar
On Saturday, January 31, 2009 5:23:40 PM ace said:
sorry dude, actually i was in a hurry, so i couldnt read the complete heading and i just downloaded the source code.

anyways thanks for the info
On Tuesday, February 03, 2009 7:20:24 PM Imar Spaanjaars said:
Hi Robin and others interested in the VB.NET version of the application,

I just uploaded the source to my site so you can download it right now. You can read more about it here: http://imar.spaanjaars.com/QuickDocId.aspx?quickdoc=485

Cheers,

Imar
On Wednesday, February 04, 2009 11:36:31 PM Suzan said:
Hi Imar,
I like your attribute property validation approach.  However, I currently have asp.net 2.0.  Is it possible to do the same?
Thank you so much.  
On Thursday, February 05, 2009 7:21:13 PM Robin Simmons said:
Imar,  Thank you for notifying me about the VB translations.  Also, thank you again for the excellent articles.  They have been a tremendous help and learning tool for me.

Robin
On Thursday, February 05, 2009 10:34:05 PM Imar Spaanjaars said:
Hi Suzan,

Yes, you can reuse 98% of this in ASP.NET 2.0. The biggest change you need to make is inside the validation framework. It uses LINQ (which is 3.5 only) to get the properties and attributes. However, a few simple foreach loops should give you the same functionality.

Cheers,

Imar
On Thursday, February 05, 2009 10:34:57 PM Imar Spaanjaars said:
Hi Robin,

You're more than welcome. Thank you for your support.

Cheers,

Imar
On Friday, February 06, 2009 2:46:18 PM Nisar said:
here is my very first step i'm trying to setup/create the web and class library project but somehow i'm unable to have the solution file in the same folder

i have created the web site at this location
C:\Projects\Spaanjaars\ContactManager\Spaanjaars.ContactManager.Web

somehow i end-up having my solution file at this location
C:\Projects\Spaanjaars\ContactManager\Spaanjaars.ContactManager.Web.sln

what i'm missing?

second question: i assume the above project you have created is a file system?

how would you do if you select http which is IIS?

thanks.

On Friday, February 06, 2009 2:49:31 PM Nisar said:
i forgot to mention that i'm using VS2008
thanks
On Friday, February 06, 2009 7:55:24 PM Imar Spaanjaars said:
Hi Nisar,

I usually start by creating a blank solution file, and then add the projects. Then you can choose where the projects should end up.

The C# version is a Web Site Project which means it's just a folder opened in VWD. The VB version is a Web Application Project.

In both cases, you can simply create a new site in IIS, point it to the root of the Web project (the one that contains the Default.aspx file) and you';re good to go.

Cheers,

Imar
On Monday, February 09, 2009 7:29:56 PM Nisar Khan said:
Imar:

i'm getting this error when i compile the solution and i try to compile one class library at a time but still the same

Error 2 Task failed because "AL.exe" was not found, or the correct Microsoft Windows SDK is not installed. The task is looking for "AL.exe" in the "bin" subdirectory beneath the location specified in the InstallationFolder value of the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v6.0A. You may be able to solve the problem by doing one of the following:  1) Install the Microsoft Windows SDK for Windows Server 2008 and .NET Framework 3.5.  2) Install Visual Studio 2008.  3) Manually set the above registry key to the correct location.  4) Pass the correct location into the "ToolPath" parameter of the task. Spaanjaars.ContactManager.BusinessEntities

i did google and i found this solution (http://social.msdn.microsoft.com/Forums/en-US/vssetup/thread/71f6b1fc-2e22-4ced-9825-469beb4381eb/)

but still no luck even thou after i change my reg as it described in the msdn.

any help?
On Tuesday, February 10, 2009 6:10:21 PM Judith Barer said:
Thank you so much for your very helpful series of articles. I have a few questions
1. Do you recommend generating your own DAL or using something like N-Hebernate to do that. I am very much the type of person who likes to have control over all my code but I realize that if a code generator could help speed development time, maybe I should look into that.

2. I have a class called company that has as a property a field called inspection agency. - Inspection agency is also a class so I guess it should be a collection within company. However I know it there will always only be one member of this collection in the company because the company can only have one agency. What if I wanted to initialize the inspection agency to a particular agency ( the user can later change it) but the agency is really determined by the ID that is assigned to it in the SQL data base so what would be the best way to iniitalize that - Obviously I do not want to hard code the ID from the Database  and is this mixing up business objects with info from the database that should really be seperate. I hope you understand my question
Thank you
Judith
On Tuesday, February 10, 2009 7:14:50 PM Imar Spaanjaars said:
Hi Judith,

1) Yes, you can certainly use ORM mappers like N-Hibernate or LINQ to SQL or the ADO.NET entities framework. Check out this post and the Blogo.Net project; it uses my (previous) design but uses LINQ to SQL under the hood: http://imar.spaanjaars.com/QuickDocId.aspx?quickdoc=445

2) Why does it have to be a collection? You can create a property of type Company called Agency. Then in GetItem of the Company you can get the agency, populate it and then assign it to the property. Does that help?

Imar
On Tuesday, February 10, 2009 7:17:10 PM Imar Spaanjaars said:
Hi Nisar,

I haven't seen that error, but it sounds like your VS 2008 installation is not in order. What exact version do you have? Have you considered reinstalling it?

You should be able to unzip my download, double click the .sln file and things should work.

Cheers,

Imar
On Wednesday, February 11, 2009 12:14:49 AM Vladimir Kelman said:
Reading your new series with big interest.
As I understand, to use some base classes or interfaces in BL or DAL, as Chuck suggested above, one would need  to use dynamic classes and CRUD methods instead of static ones. Otherwise, how would you override / implement?
We successfully implemented an application based on a previous N-Layer design, a big thanks to Imar. For a next and bigger application (company intranet), we're hopefully leaning towards a design with [one] common static manager class which instantiates specific DAL classes as necessary (may use Singleton pattern as well). It probably would simplify plugging in our external security/validation libraries: it's hard to avoid tight coupling with static classes/methods.
On Wednesday, February 11, 2009 3:02:27 PM Judith Barer said:
>>Why does it have to be a collection? You can create a property of type Company called Agency. Then in GetItem of the Company you can get the agency, populate it and then assign it to the property. Does that help<<

That does help. Then in GetItem of Company when it gets the agency, it will have to access the database to get the correct ID from the database. or does it make sense to set up a class initially to hold the value of the ID so that every time I instantiate a new Company I do not have to access the database?
On Wednesday, February 11, 2009 10:30:21 PM Imar Spaanjaars said:
Hi Judith,

It depends on your design; you could store the ID of the "inner" company in the "outer" company. Then when you load the outer company, you take the ID and the call GetItem once more to load the inner company (the agency). Just make sure that the agency itself doesn't have an agency assigned or you'll end up in a loop..... ;-)

Cheers,

Imar
On Thursday, February 12, 2009 12:34:19 PM MG said:
Hi,

I know the FillDataRecord talked on previous article but i have a question, and i am posting here.

Which one can be usefull?
1) Getting values of every not null colums and checking the columns may be null(IsDBNull) after that getting its value. This means you have to select every not null column. If not you get indexoutofrange like exception.

2)Checking the columnNames in myDataRecord, add to List. While filling object check whether the column is in list than get the value and assign it to object's property. This means you can select what ever you want and FillDataRecord fills the ONLY necessary properties.

Here like this one: (I couldn't write it properly because it gives html error when i try to post. So i deleted greater,smaller symbols from List)
private static Restaurant FillDataRecord(IDataRecord myDataRecord)
{
ContactPerson myPerson = new ContactPerson();

List string columnNamesList = new List string ();
for (int i = 0; i < myDataRecord.FieldCount; i++)
{
      columnNamesList.Add(myDataRecord.GetName(i));
}

if (columnNamesList.Contains("FirstName"))
{
      myContactPerson.FirstName = myDataRecord.GetString(myDataRecord.GetOrdinal("FirstName"));
}
...
...
Do this for every property. Don't forget to check the nullabel columnsthey have a value or not
}

Which one do you perefer. Actually you perefered first one, but can you talk about second method. Thanks...
On Thursday, February 12, 2009 8:43:36 PM Imar Spaanjaars said:
Hi MG,

You're mixing up concepts. The check for null is not to determine whether the column exists in the result set, but to check whether the column has a value.

Cheers,

Imar
On Thursday, February 12, 2009 9:01:07 PM MG said:
I think i couldn't express my self. What i mean if we don't select the lastname in sqlstatement for example, FillDataRecord will try to get its value and throws an exception because there has no ordinal such as LastName in myDataRecord.


//This one will throw an exception if you don't select the LastName
myContactPerson.LastName = myDataRecord.GetString(myDataRecord.GetOrdinal("LastName"));

It will be more flexible first we check whether the LastName is in myDataRecord than assign it to objects property rather than try to assign value to property. Am i clear?
On Thursday, February 12, 2009 9:06:19 PM Imar Spaanjaars said:
Hi MG,

The first part is clearer, the second part isn't. If the stored procedure doesn't contain a value, it will indeed thrown an error. I don't see where "more flexible" comes in.

Anyway, your solution would work well if your goal is to have different SQL statemens for the same FillDataRecord method. Personally, I would probably create specialized versions of FillDataRecord for that purpose. Or maybe even create light-weight versions of my BO's.

Just be aware of the potential issues of not selecting all data. Your users may not be aware of the difference between an empty value, and one that simply wasn't selected.

Cheers,

Imar
On Thursday, February 12, 2009 9:46:34 PM Vladimr Kelman said:
BTW, on some occasions, the following helper method could be useful: http://pro-thoughts.blogspot.com/2008/12/suppose-you-have-c-method-which-only.html
It allows to call a method only if a supplied argument is not Null.
On Friday, February 13, 2009 1:15:29 PM kurt schroeder said:
I really owe you a lunch next time you're in Chicago
On Monday, February 16, 2009 5:38:21 AM rishad said:
u deserve a pat on ur back, by the way when are u going to give the full source code in our hands,
On Monday, February 16, 2009 3:55:02 PM Bliek said:
What made you decide to use a Web Site Project in stead of a Web Application Project? Thanks in advance.
On Monday, February 16, 2009 7:15:26 PM Big George said:
Thanks for your great article. Yet, I have a question: In your article, you put BusinessLogic, BusinessObject and DataAccess tiers as namespaces in the same solution.
In that case, you could get one big dll like:
MySolution.dll  10 MB

If you develop BusinessLogic, BusinessObject and DataAccess tiers as projects, then you could get like:
MySolution.dll   5MB
BusinessLogic.dll  2MB
BusinessObject.dll  2MB
DataAccess.dll   1MB
Which approach would be better in memory consumption? To load MySolution.dll 10MB or MySolution.dll 5MB and the other dll's?
On Monday, February 16, 2009 7:45:49 PM Imar Spaanjaars said:
Hi Vladimr,

Interesting solution. Another solution would be to create a "safe SqlDataReader" that is able to handle null values. SqlDataReader is sealed so you'll need to wrap it, but it can be worth the trouble. In the book  Expert C# 2005 Business Objects (and probably in other versions as well) Rockford Lhotka shows how this works.

Cheers,

Imar
On Monday, February 16, 2009 7:47:11 PM Imar Spaanjaars said:
Hi kurt,

Thanks for that. I'll remember that when I am there.... ;-)

Cheers,

Imar
On Monday, February 16, 2009 7:47:37 PM Imar Spaanjaars said:
Hi rishad,

Full source??

Imar
On Monday, February 16, 2009 7:48:41 PM Imar Spaanjaars said:
Hi Bliek,

For this application it doesn't really matter; both will work equally well. The C# version is a Web Site project and the VB.NET version is a Web Application Project.

Cheers,

Imar
On Monday, February 16, 2009 7:51:24 PM Imar Spaanjaars said:
Hi George,

The fast answer is: I doubt you'll notice the difference. For most scenarios, all DLLs involved need to be loaded anyway as all of them contain part of the puzzle. So, loading a single DLL *might* be slighly faster.

The longer answer is: you can only really find out by measuring it. Try out both scenarios and use a code profiler to measure performance. You're welcome to post your findings here for others to learn from.

Cheers,

Imar
On Monday, February 16, 2009 8:52:10 PM Robin Simmons said:
Hi Imar,  I'm using VS 2005 and the solution file in the VB version of your series is for VS 2008.  Do I just need to create the references as described in Part 1 to get to where I need to be, or is there something else I need to do?

Thank you.
On Tuesday, February 17, 2009 3:28:26 AM rishad said:
yes imaar where can i get the full source and when ?
On Tuesday, February 17, 2009 5:42:56 PM Imar Spaanjaars said:
Hi Robin,

It's not that easy. The Validation framework uses LINQ which is specific to .NET 3.5. You'll need to rewrite parts of the validation code (mainly change LINQ queries to foreach statements) to make it work in .NET 2.0.

Cheers,

Imar
On Tuesday, February 17, 2009 5:44:25 PM Imar Spaanjaars said:
Hi rishad,

You must have troubles with your eyes..... First of all, my name is Imar, not imaar. Secondly, the full source code is available in the Downloads section at the end of the article, and has been there since I published part 2 months ago.

Imar
On Wednesday, February 18, 2009 7:12:33 PM Chaumette said:
Imar,

I just finished reading Lhotka's Expert C# 2005 Business Objects and your book Wrox beggining ASP.NET 3.5. I see alot of Lhotka influence in your coding, but you manage to keep your code easy to follow and understand.  

I am starting to code in C#3.5 now. I am looking forward to reading your current articles. Btw, any plans for creating code generator templates similar to v1 (Mygeneration)?

Thanks for the articles!

Chaumette
On Wednesday, February 18, 2009 7:49:32 PM Imar Spaanjaars said:
Hi Chaumette,

No, no plans to create templates. You're welcome to create them and I'll be happy to host them here for others to use and learn from.

Cheers,

Imar
On Sunday, February 22, 2009 6:32:59 AM mohmaasd said:
hi
hi we can have a agree
On Sunday, February 22, 2009 9:35:13 AM Imar Spaanjaars said:
Hi mohmaasd,

Agree on what?

Imar
On Wednesday, February 25, 2009 10:28:47 AM mohammad said:
agree about translate ur article
On Wednesday, February 25, 2009 10:35:39 AM Imar Spaanjaars said:
Hi mohammad,

E-mail me an offer I can't refuse, and I'll consider it. Otherwise, you are *NOT* allowed to create translated versions of my articles.

So, let's take this off-line and send me an e-mail.

Cheers,

Imar
On Monday, March 02, 2009 3:42:33 PM Bliek said:
Hi Imar,

where would you put your helper class in a webapp, since this type of project can't have an App_Code folder, without getting stuck into circular references?
On Monday, March 02, 2009 6:08:40 PM Imar Spaanjaars said:
Hi Bliek,

Anywhere you want; they are compiled into the central assembly and are accessible as if you'd defined them in App_Code....

Cheers,

Imar
On Thursday, March 05, 2009 4:03:44 AM Vladimir Kelman said:
@Imar,
We were trying to justify separating Web, BO, Bll, and DAL into different projects.

Obviously, helper classes (services, plugins - however we call them) should be placed into separate folders and implemented as separate class libraries, not coupled to each other and to any particular host application. (I would use a form of Dependency Injection, Constructor Injection, for example, to instantiate and initialize those helper classes from a host application). This makes it simpler to re-use helper classes across different host applications.

It is less clear to me, why would we want to separate Web, BO, Bll, and DAL into different projects, turning BO, Bll, and DAL into class libraries. I think, it could make it harder for a team to collaborate on application development. With all files belonging to one WebSite project, all compilation happens in-place, so each team member can just work on her part and then upload individual .ASPX and .CS files to a test and production servers. With BO, Bll, and DAL being class libraries and therefore compiled into DLLs by Visual Studio, it is less convenient for two people to work on one layer (one DLL).

One reason I came with, trying to justify separating BO, Bll, and DAL into class libraries, is as follows:
This would allow for an easier re-use of BO, Bll, and DAL across different front-ends: a Web site, a mobile Web site, desktop + web services application, etc.
What could be other reasons?

With your architecture, would it be enough to create application's web site on a test or production server and to copy class library DLLs into its /Bin sub-folder, or is application distribution more complicated?
On Thursday, March 05, 2009 11:17:18 AM Bliek said:
Hi Imar,
can you tell us when part 6 of this terrific series will be published? Thanks.
On Thursday, March 05, 2009 9:17:49 PM Imar Spaanjaars said:
Hi Vladimir,

>> With your architecture, would it be enough to create application's web site on a test or production server and to copy class library DLLs into its /Bin sub-folder,

Yes, it's as simple as that.

Imar
On Thursday, March 05, 2009 9:19:07 PM Imar Spaanjaars said:
Hi Bliek,

Hopefully this weekend but I can't promise anything as I am a bit busy. But, you can always buy the full PDF version now and get access to part 6.

Cheers,

Imar
On Sunday, March 08, 2009 9:58:28 AM Imar Spaanjaars said:
To Bliek and others,

I just published part 6, the final part in this series here on imar.spaanjaars.com.

Cheers,

Imar
On Monday, March 09, 2009 11:25:53 AM Akhil Kumar said:
Thanks a lot ...
On Monday, March 09, 2009 11:45:00 AM Bliek said:
Thx!
On Tuesday, March 17, 2009 2:57:20 PM Adam Ralph said:
Hi Imar,

Thanks for a great series of articles.

One thing I noticed is that you are exposing a public set method for the Collection type properties on the ContactPerson class.

There is a guideline (http://msdn.microsoft.com/en-gb/ms182327.aspx) which says that you should always make Collection type properties read-only.  What is your opinion on this?

To get around this, in my application I am considering adding GetList() overloads in my BLL which fill a collection passed as an argument rather than return a new one.

Regards
Adam
On Tuesday, March 17, 2009 6:59:02 PM Imar Spaanjaars said:
Hi Adam,

Yes, excellent comment. I am aware of the recommendations and I initially had read-only lists. Can't recall why I changed it later (must have had a good reason though ;-) )
Your solution seems like a good solution.

Cheers,

Imar
On Tuesday, March 17, 2009 10:52:39 PM Adam Ralph said:
Hi Imar,

I believe the reason you made the collection properties read/write is because, within your BLL, you wanted to directly assign the collections returned by your GetList() methods to the relevant property on a business object, e.g. ContactPerson.Addresses = AddressManager.GetList(), etc.

With the GetList() methods as they are, the only other option would be to would be to iterate over the collection returned from GetList(), adding each item to the collection property on the business object, but that would be rather cumbersome.

Cheers
Adam
On Wednesday, March 18, 2009 6:24:40 PM Imar Spaanjaars said:
Hi Adam,

Yes, I think you're right. I guess I was lazy.... ;-)

You could work around it by copying over items from one list to the other using AddRangle for example:

myBO.ListProperty.AddRange(someDal.GetList());

This way, the property can remain read-only.

Cheers,

Imar
On Wednesday, March 18, 2009 10:51:45 PM Adam Ralph said:
Using AddRange did occur to me as well but unfortunately the generic Collection does not expose an AddRange method.  That is only available on the generic List which we can't use, or shouldn't at least ;-).
On Sunday, March 22, 2009 10:33:39 AM Imar Spaanjaars said:
Hi Adam,

Yes, you're absolutely right. Before posting this, I did a quick test but accidentally tried AddRange on the internal list, rather than on the Collection<T> ;-)

Then I thought about using Concat, but it returns the new list, rather than adding to the source list. This means you still need to reassign the original property / variable with the return value from Concat.

So, maybe the easiest way around this is to write an extension method for Collection[T]. It could be as simples as:

public static class Extensions
{
  public static void AddRange<T>(this Collection<T> source, IEnumerable<T> items)
  {
    foreach (T myT in items)
    {
      source.Add(myT);
    }
  }
}

You could then use it as:

myBO.ListProperty.AddRange(someDal.GetList());

Cheers,

Imar
On Sunday, March 22, 2009 3:52:24 PM Adam Ralph said:
Hi Imar,

That's a nice idea.  It leaves the someDal interface cleaner than my idea of adding a GetList() overload.  It does require an extra iteration of the collection members but the cost will be relatively low unless the number of members is huge.  However, for large volumes I would expect low level (e.g. database) paging to be implemented in which case such a scenario should not occur.

Regards
Adam
On Monday, March 23, 2009 1:22:55 AM Vladimir Kelman said:
As soon as you use a recommended form of constructor

public ListCollection() : base(new List[T]()) {  }

you can cast to List[T] inside all the ListCollection's methods and use public methods of List[T]. For example, you can use AddRange() instead of looping through items and using Add().

public void AddRange(IEnumerable[T] values) {
  ((List[T])this.Items).AddRange(values);
}

Look at my example at http://pro-thoughts.blogspot.com/2008/07/generic-listcollection-class-take-2.html, where I defined a generic

public class ListCollection[T] : Collection[T]

to guarantee that proper constructor is always called and to add "missing" methods.

However, using List[T] is not recommended for public APIs only, it doesn't mean it is not recommended at all. If you know that your collections will only be used internally and you never will need to notify a system when collection was modified, there is no point in using Collection[T] instead of List[T]. In "Accelerated C# 2008", Trey Nash said, "It would be tempting to use List[T] in your applications whenever you need to provide a generic list type to consumers. However, instead of using List[T], consider Collection[T]. List[T] doesn’t implement the protected virtual methods that Collection[T] implements. Therefore, if you derive your list type from List[T], your derived type has no way to respond when modifications are made to the list. On the other hand, List[T] serves as a great tool to use when you need to embed a raw list-like storage implementation within a type, since it is devoid of virtual method calls such as Collection[T] and is more efficient as a result."

In our application we first tried to use custom collection types derived from Collection[T], but then realized that we don't need to be able to respond to collection modification, and that by just using custom collection classes we add about a hundred of new classes... we switched back to a direct use of List[T]. No custom collection classes.
On Wednesday, March 25, 2009 6:58:26 AM Vivek said:
Hi Imar,

Thanks a lot for writing such a great article, I learned lots of new things.

Do you know if someone wrote a MyGen template for generating various layer like they did for your earlier article in .NET 2.0?

Regards,
Vivek


On Wednesday, March 25, 2009 7:43:43 AM Imar Spaanjaars said:
Hi Vivek,

Not that I know of. It has been brought up a few times before, but nobody has actually submitted any files....

If you're willing to give it a try yourself, I'll be more than happy to host them here.

Cheers,

Imar
On Sunday, May 03, 2009 12:21:15 AM Juan Brito said:
Your manual is very good. I want to learn OOP in c # I can
advice that can read books or manuals.
On Sunday, May 03, 2009 7:33:45 AM Imar Spaanjaars said:
Hi Juan,

I don't understand what you're saying or asking....

Imar
On Friday, May 08, 2009 12:20:49 PM Jeff said:
I've made sure I set my project up like you described above and when I press F5 and the website opens up in the browser it is at localhost:1234/CompanyName.ProjectName.Web/default.aspx. How can I make it show up as localhost:1234/CompanyName/default.aspx?

Also will I need to do anything special I'll need to do prior to publishing this to my host?
On Friday, May 08, 2009 6:43:44 PM Imar Spaanjaars said:
Hi there,

You can rename the folder of the web site on disk and then readd it to the solution. Alternatively you can run it as a root site as described here.

http://weblogs.asp.net/scottgu/archive/2006/12/19/tip-trick-how-to-run-a-root-site-with-the-local-web-server-using-vs-2005-sp1.aspx

The project uses .NET 3.5 features so it's important your host has 3.5 installed.

Cheers,

Imar
On Friday, May 08, 2009 6:52:07 PM Jeff said:
Cool! it doesn't sound too difficult to do to. I like easy to do things!
On Saturday, May 16, 2009 12:42:57 PM Arya said:
Hi Imar, I came from PERL background and trying to catch up with .net (specially asp.net). I bought couple of books, browsed  online resource but this is the best resource I came across.  This really helped me to speed up my transition. Layered development process is not new to me, but I really like the way put it, especially in .net context.  I have a question for you,

When  you write code, do you write parallel test scripts / driver to check your code functionality?( I don’t think one would write everything and then just hit run button). I know writing test script is not in scope for this article , but I am just curious to know, how you go about writing class and testing them. If possible could please point me to any good resource for this?
On Wednesday, May 20, 2009 6:57:27 AM johnnyo said:
Hi Imar,

Thanks for writing this fantastic article.  It is incredibly informative.

I wanted to follow-up on your discussion with Chuck on 12/1/2008.  I was wondering the same thing as Chuck, whether a base class can be written that handles the common methods (GetList, GetItem, Save, Delete).  You mentioned a couple of possible solutions to this (e.g. a base class that accepts BusinessBase or create a generic class).  Do you know where I can find examples of how I can do this?  I've been searching online, but haven't been able to find anything.

Thanks in advance.
On Sunday, May 24, 2009 9:37:00 AM Imar Spaanjaars said:
Hi Arya,

It depends. Typically, 99% of my starting code comes from one of the code generator templates I use. These generators create basic unit tests as well to test common scenarios like insert, update, delete and select. Once I start building more functionality, I tend to write unit tests for certain database driven scenarios, but most of my unit tests target business logic instead.

The commercial version of this article series contains some unit tests to test some (but certainly not all) areas of this application.

Cheers,

Imar
On Sunday, May 24, 2009 9:38:41 AM Imar Spaanjaars said:
Hi johnnyo,

Sorry, no, no ready-made code or article links available. You can take a look at Rockford Lhotka's CSLA framework that demonstrates these kind of concepts.

Cheers,

Imar
On Tuesday, May 26, 2009 3:18:27 PM ruben ruvalcaba said:
I just want to thank you for sharing this, I'd been looking for a real-world sample application a long time ago. If found the grid-form paradigm the best for users and it's the first sample I see using it.
Best regards
On Tuesday, May 26, 2009 6:54:05 PM Imar Spaanjaars said:
Hi ruben,

You're welcome....

Cheers,

Imar
On Tuesday, May 26, 2009 9:03:52 PM Allan said:
Imar, thanks again for a great set of articles.  We adopted the structure of your first series, created a code generator from it, and have been using it since.

One thing we do differently than your articles do is most of the presentation layers (adding, viewing contacts or what have you) are developed as web user controls instead of aspx pages.  This gives a bit of reusability throughout the project.

We also adopted the NullableReaders class developed by Steve Michelotti over the DataReader class.

There is one issue that we haven't found a good solution for yet and that is when/if the data structure changes there's no way to dynamically update the DAL's FillDataRecord or the BOL objects (or Interfaces if using those).  The other "issue" is to use this model one has to return all columns from the table even if only using a hadnful in presentation.  We're open to suggestions for these issues.  (Dynamic/ORM???).

Kudos and thanks again!
On Tuesday, May 26, 2009 10:05:19 PM Imar Spaanjaars said:
Hi Allan,

Yeah, we use User Controls for that purpose as well. Just found them a little too off-topic for this article series.

With regards to the FillDataRecord: you could generate them into partial classes. That way, it's easier to regenerate them from the database and overwrite them, without breaking existing code or any manual changes you have made.

Cheers,

Imar
On Wednesday, June 03, 2009 11:04:41 AM Shahbaz said:
Hi Imar,

Thanks for such great Article. I have one question, which would be the best practice/approach  for creating BLL and DAL layer. Whether these two should be in App_Code folder or should be as separate Class Library?

Please suggest

Thanks
Shahbaz

On Wednesday, June 03, 2009 4:33:55 PM Imar Spaanjaars said:
Hi Shahbaz,

From a technical point of view, both work equally well.

I prefer separate libraries as I find them a bit easier to share and manage, but you can choose whatever you see fit. I opted for files in App_Code in my first series on N-Layer design but moved to class libraries as soon as they were introduced in the Express Edition of Visual Web Developer (and thus used them in my 3.5 series).

Cheers,

Imar
On Friday, July 03, 2009 6:22:41 AM Rahul said:
Thanks a lot its was really a good code it helped me a lot.
On Saturday, July 04, 2009 1:36:50 AM sushith said:
Please tell me when u r doing complete asp.net 4.0.
On Saturday, July 04, 2009 7:38:44 AM Imar Spaanjaars said:
Hi sushith,

Don't count on anything soon. First, ASP.NET 4.0 is still in beta. Secondly, this series is much more about design, rather than about implementation. Everything you saw here still works in 4.0....

Cheers,

Imar
On Monday, July 20, 2009 6:12:39 AM Jayson said:
Thanks you so much for this marvelous info. I can use this as a reference for my new project..

More power to you.
On Thursday, July 30, 2009 7:01:09 PM shalan said:
Hi Imar, been following this article and its really fantastic!!

Is it possible/advisable to use this same architecture in a Windows-Forms application, and perhaps also use LINQtoSQL in the DAL instead?
On Thursday, July 30, 2009 9:07:48 PM Imar Spaanjaars said:
Hi shalan,

Yes, you can certainly use (most of) these concepts in a Win Form application.

For a LINQ to SQL implementation of these concepts, check out Blogo.NET: http://imar.spaanjaars.com/QuickDocId.aspx?QUICKDOC=445

Cheers,

Imar
On Thursday, July 30, 2009 10:38:30 PM shalan said:
Thanks for the prompt reply Imar! and thanks for the link...downloading the source and pdf right now.  I know this is beyond the scope of this article, but when you say "most of" what is exclusive to ASP.NET, besides the obvious UI Web layer? Is there anything relating to the actual architecture that cannot be used in Winforms?

Sorry for asking, its just that Im starting the logical planning for my app, so I would like to IF there are any gotchas so that I can cater for them in advance.

Thanks!
On Saturday, August 01, 2009 11:15:25 AM Imar Spaanjaars said:
Hi shalan,

Yes, the UI is obviously the biggest part that needs to be changed. However, the BLL and DAL should be usable in Win Forms directly.

Cheers,

Imar
On Saturday, August 01, 2009 9:38:48 PM Kurt Schroeder said:
MVC. I know others have asked about this.

I've come to appreciate the portability of your design pattern almost as much as i dislike having to manage ViewState. So with this attitude i start to ponder MVC. I will not burden you with my marital problems, but my wife is a designer and Webforms are not her favorite. I'm looking into using extjs with MVC. This will make her life much better. It will also hopefully get me away from having to manage ViewState. Have you noticed any issues that hinder using MVC with your design?

(btw, in truth my wife and i are happily married going on 15 years)
http://www.YankeeImperialistDog.com (i don't take myself too seriously)

Thank you my friend i hope all is well with you!
On Sunday, August 02, 2009 7:01:05 AM Imar Spaanjaars said:
Hi Kurt,

Nope, this should work with MVC as well. Simply drop the front-end stuff with the ODS controls and talk to the BLL as your model. You can make strongly typed views targeting your BO instances.

Cheers,

Imar
On Sunday, August 02, 2009 4:13:55 PM Kurt Schroeder (aka YankeeImperialistDog) said:
thank you. No reflection on others i have asked about this potential issue, but i could not get a realistic answer. In one instance the layering provided by MVC was implied to be a replacement. I don't fault this person they are normally answering questions from people that are more beginner and in my case i'm not a beginner and really should know better. However, having made assumptions in the past concerning the obvious i've seen just how "obviously different" the obvious can be. an unrelated childhood lesson has helped me through this a few times:
http://www.kurtsjunkyard.com/TheLighterSideOfIntelligence.aspx?article=10
On Sunday, August 02, 2009 5:02:45 PM Imar Spaanjaars said:
Hi Kurt,

Even though you are using MVC, you can still separate business logic and DAL code....

Imar
On Friday, September 11, 2009 5:56:17 PM Danny said:
Hi there Imar,
What an excellent application architecture series! Phenomenal job.

My main question is this:
I'll looking to use Entity Framework as my DAL, however can foresee a couple problems. I've used EF before, however, never in a N-Layer app.  In your current series, you create the BusinessEntities yourself. Because of this, they sit in the middle (so-to-say) and are accessible from both UI Presentation layer and Data Access.

By using an ORM (EF), these CLR objects are now moved to the DAL and managed by EF. We would not want recreate these classes in BusinessEntites just so the UI can make use of them. That would mean we have duplicate code and any updates to the EDM, would have to be mirrored on our Bus.Entity objects... manually.

Problem #1:
Methods in the Business Logic will be returning EF Entities / Objects. However, unless my UI layer is referencing my Data Access, it won't have any idea what object is returned. Should the UI have any knowledge of the DAL?

I realize in EF v2 (.NET 4.0) we now have internal support for Persistence Ignorance POCO. However, I don't see the advantage of manually creating classes to reflect database tables in full. I would leave POCO for only specific data that I'd like managed. EF alone should generate and manage the EDM which reflects my database.

One solution to this I suppose would be to keep your Business Entities layer. For each Entity that EF creates, make that class partial (can probably be done automatically with T4 templates "EFv2") and extend the partial class on the BusinessEntities layer. That way you can extend functionality for each entity and the UI layer would have access to these objects without needing to reference the DAL. However, this seems kind of a moot point and not true SoC.


In short my real question is, how can the Business Logic layer return entity objects (BusinessEntities) if the now reside on the DAL?

Thanks!
Danny
On Friday, September 11, 2009 7:06:01 PM Imar Spaanjaars said:
Hi Danny,

POCO would indeed be the way to go. If you can't / don't want to use POCO, mapping your entities to BOs in custom code is, IMO, the next best thing. Check out the book "ASP.NET 3.5 Enterprise Application Development with Visual Studio 2008: Problem Design Solution" by Vincent Varallo. In his design he has a (base-class based) solution for mapping entities to custom BOs

http://www.wrox.com/WileyCDA/WroxTitle/ASP-NET-3-5-Enterprise-Application-Development-with-Visual-Studio-2008-Problem-Design-Solution.productCd-0470396865.html

Cheers,

Imar
On Friday, September 11, 2009 8:52:05 PM Danny said:
Beautiful,
Much thanks for the response and article! Will surely check out the book.
On Wednesday, October 14, 2009 9:11:00 AM Matt said:
Hi Imar, thanks for a great detailed article, all the info you want in one place - nice and rare.

I'm still quite a novice in this space and I'm interested in to why you didn't implement any dirty state checking in your design. for example ContactPersonManager will always atempt to Insert/Update the data and its child data even if they haven't changed when the user hits Save - unless i missed something. Seems a bit harsh, is it a case of the contact manager is so small you didn't care about the database hit?

I'm using this artical as a basis of my design, but i don't really want to hit the database if i don't need to.

I would be interested to understand how you would approach this.

I'm thinking a simple approach could be that BusinessBase has a public readonly property IsDirty, on each business object setter property I would check the internal field to the incoming value and if its different mark it as dirty. Then on save check the state.

Your thoughts/advice would be most appreciated.

Many Thanks
Matt







On Saturday, October 17, 2009 8:42:36 AM Imar Spaanjaars said:
Hi Matt,

That's exactly what I do as well when I need to track dirty objects. A property (for a fictitious Fund class) looks like this:

public string FundCode
{
  get
  {
    return _fundCode;
  }
  set
  {
    if (value != _fundCode)
    {
      _fundCode = value;
      _isDirty = true;
    }
  }
}


I then have a read-only property around _isDirty:

public bool IsDirty
{
  get
  {
    return _isDirty;
  }
}

And in the Save / Update methods I use the following code:

if (!myFund.IsDirty)
{
  return true;
}

Cheers,

Imar
On Saturday, October 17, 2009 7:27:09 PM Matt said:
Thanks Imar, I thought such a simple approach was the way to go, but when your're trying to learn this stuff you get swamped in information and then in-decission creeps in.

Thanks for replying.

Matt
On Wednesday, October 28, 2009 9:50:02 PM Ted said:
Thanks Imar.  This is very well written and informative article.  

I have a question regarding a failure during an insert.  If the value passed into the stored proc sprocContactPersonInsertUpdateSingleItem for @firstName is 51 characters I believe the insert will fail, myCommand.ExecuteNonQuery() will set numberOfRecordsAffected to 0 and the exception DBConcurrencyException("Can't update contact person as it has been updated by someone else") is raised. If I’m correct then the error message would be misleading because the insert failed (and not an update).  Am I missing something?
On Wednesday, October 28, 2009 10:01:47 PM Imar Spaanjaars said:
Hi Ted,

Have you tried it out and can you confirm this is actually the case?

Don't you get a true exception when the Insert fails so this code never gets called?

And of course you never hit this if you have a MaxLength validation attribute... ;-)

Cheers,

Imar
On Thursday, October 29, 2009 3:58:28 PM Ted said:
Hi Imar,

I tried adding an email address that was longer than the field length (100 characters) and SQL Server happily truncated it to 100 characters.  So I was not able to get the DBConcurrencyException thrown. So I cannot confirm the problem.   That said, if my understanding of the stored procedures to insert/update are correct, if for some reason an insert fails the data layer classes will throw an error saying that an update failed and not an insert.  Also, it appears the return value from the insert/update procs is never used by the calling functions.  Both are minor points…still really glad you wrote this article!  Are you planning on writing a book on this subject?

Regards,

Ted
On Friday, October 30, 2009 2:07:27 PM Imar Spaanjaars said:
Hi Ted,

I am not sure I see the problem. The strings are truncated at the parameter level, so with a parameter like this:

@street nvarchar (50)

all you ever have available inside the sproc is a string of 50 characters. So, the same rules would apply with regard to concurrency.

Also, take a look at how the concurrency check and error are set up:

if (numberOfRecordsAffected == 0)
{
  throw new DBConcurrencyException("Can't update address as it
           has been updated by someone else");
}

A successful insert always has 1 affected record. The same applies to an update. Two things could wrong:

1. The update doesn't find the correct concurrency ID, no records are updated and an error is thrown.

2. Some other error occurs (a foreign key constraint violation for example). In that case, the code bombs at ExecuteNonQuery and the DBConcurrencyException is never thrown.

To see what I mean, add this code to a stored procedure:

RAISERROR('test', 16, 1)

When the error occurs, your code encounters a System.Data.SqlClient.SqlException, not a DBConcurrencyException even though the number of affected records is 0.

Does that clarify things?

Imar
On Friday, October 30, 2009 6:21:01 PM Ted said:
Imar,

Yes that does clarify things.  I missed the point that if the insert failed an SqlException would be thrown (and later caught in the BLL ).

Thanks again,

Ted
On Sunday, November 01, 2009 5:55:21 PM Mostafa said:
Hi Imar ,
Thank a million for your great article . I've studied your Previous Series and that helped me a lot .
I'm not experienced programmer but your article helps me a lot . I have got 2 questions :
First I'm not familiar with Test Unit , What's that and why we should use it ? Do you have any source for that ?
Second , I'm writing a CodeSmith's Template according your architecture .In addition i have made some change in your DAL , I used "Microsoft.Application.Block" namespace in your Dal and i reduced a lot of code .  Do you think I'm going wrong .
My template produce code like this :
public static Address GetItem(Int64 Id)
{
            Address objAddress = null;
            using (SqlDataReader dr = SqlHelper.ExecuteReader(AppConfiguration.ConnectionString, "spAddress_SelectSingleItem", Idd))
            {
                if (dr.Read())
                {
                    objAddress = FillDataRecord(dr);
                }
                dr.Close();
            }
return objAddress;
}
On Sunday, November 01, 2009 6:35:59 PM Imar Spaanjaars said:
Hi Mostafa,

I didn't mention Test Unit, I mentioned Unit Testing:

http://www.google.com/search?hl=en&source=hp&q=unit+testing+.NET&aq=f&oq=&aqi=g4g-m2

Your code example looks fine to me.

Cheers,

Imar
On Tuesday, November 03, 2009 4:20:30 PM Leslie said:
Imar, What do you call the notation you're using above all your function calls in the .cs files and would you happen to know where I can find the documentation on the proper use of it?
On Tuesday, November 03, 2009 5:52:56 PM Imar Spaanjaars said:
Hi Leslie,

These are called "XML Comments". For more info:

http://msdn.microsoft.com/en-us/magazine/cc302121.aspx
http://msdn.microsoft.com/en-us/magazine/dd722812.aspx
http://www.google.nl/search?hl=nl&source=hp&q=%22xml+comments%22&meta=&aq=f&oq=

And for tools to build help files with them take a look here:

http://sandcastle.codeplex.com/
http://www.codeplex.com/SHFB

Cheers,

Imar
On Sunday, December 13, 2009 6:23:19 PM Jay said:
Hello Imar,
Thank you for sharing the knowledge, it's great...
I have a question for you:
why are you using the so called "magic numbers" in the enums?
you have :
Public Enum PersonType
        None = 0
        [Friend]  = 1
        Family = 2
        Colleague = 3
End Enum

Where one could simply use:
Public Enum PersonType
        None
        [Friend]
        Family
        Colleague
End Enum
Since .Net already assign the same values automatically, then change the table in the database to string type and then access the enums as strings directly like this:
        Dim someType As PersonType = PersonType.Colleague
        MsgBox(someType.ToString)
outputs: Colleague which would be qritten to the DB instead of the magic number.

Please shade some light on this...

Thank you ...
Keep up the good work.
On Sunday, December 13, 2009 6:30:23 PM Imar Spaanjaars said:
Hi Jay,

I am not assigning "magic numbers" to them, I am assigning "explicit numbers" to them. Relying on auto generated numbers can be dangerous when storing the values somewhere, such as in a database. Consider this type:

Public Enum PersonType
        None
        [Friend]
        Family
        Colleague
End Enum

Let's say I change it to:

Public Enum PersonType
        None
        [Friend]
        Family
        Partner
        Colleague
End Enum

If you rely on auto-numbering, get a bigger house; all your co-workers just became your partner.... ;-)

Cheers,

Imar
On Monday, December 14, 2009 7:26:41 AM Adam Ralph said:
@Jay - in most cases it would be better to store the enum's numeric value in the database rather than it's string representation.  Consider that the enum values could be stored in a 'byte' data type in SQL Server which consumes just 1 byte per value, whereas a string would occupy at least 1 byte per character (varchar) or 2 bytes per character (nvarchar) meaning that your 'Colleague' value would occupy at least 9 bytes. Also comparisons (e.g. in a WHERE clause) would be slower if you were using a string value rather then a numeric.

Regards
Adam
On Monday, December 14, 2009 1:19:11 PM Jay said:
@Imar, i kind of figured that would happen, and that is why i was thinking about storing the string representation of it directly in the database....but Adam pointed out the reasons why i shouldn't...
@Adam: i see your point, it makes sense.... thanks for clearing that up...

Jay
On Friday, December 18, 2009 4:47:51 PM Jay said:
Hello Imar,
I'm wondering on the best way to implement the following senario:

i would like to create two Objects let's say (Student, Employee) that will inherit from ContactPerson. so here is what i did:

i created the following classes for each new object:
StudentObject
StudentObjectDB
StudentObjectManager

the same goes for the employee.
the newly created objects each the following properties:

StudentObject has the following new properties:
SchoolID
SchoolName

and the EmployeeObject have the following properties:
EmployerID
EmployerName

now my problems is how do i change the GetList under the studentObjectDB and the getList() under employeeObjectDB to return the complete StudentObject Collection with the contactManager that belongs to that student?????

basically i'm puzzled as to how to concat the ContactManager Object and the studentObject new properties....

i hope this makes sense.

Thanks,
Jay
On Friday, December 18, 2009 4:56:49 PM Jay said:
Here is my attempt at it:

    Public Shared Function GetList() As StudentObjectCollection
        Dim myPersonType As PersonObjectCriteria
        myPersonType = New PersonObjectCriteria
        myPersonType.PersonType = PersonType.Student
        myPersonType.Active = True
        Dim myStudentObjectCollection As PersonObjectCollection = PersonObjectDB.GetList(myPersonType)

        Dim tempList As New StudentObjectCollection()
        Dim myPObject As New PersonObject

           '****below we open the DB and get the studentobject properties like schoolID and so on...
        Using myConnection As New SqlConnection(AppConfiguration.ConnectionString)
            Using myCommand As New SqlCommand("sprocStudentObjectSelectList", myConnection)
                myCommand.CommandType = CommandType.StoredProcedure
                myConnection.Open()
                Using myReader As SqlDataReader = myCommand.ExecuteReader()
                    If myReader.HasRows Then
                        tempList = New StudentObjectCollection()
                        While myReader.Read()
                            myPObject.Id = myReader.GetInt32(myReader.GetOrdinal("ConactPersonID"))
                            tempList.Add(FillDataRecord(myReader, myStudentObjectCollection.Item(myStudentObjectCollection.IndexOf(myPObject))))
                        End While
                    End If
                    myReader.Close()
                End Using
            End Using
        End Using
        Return tempList
    End Function


and the FillDataRecord() looks like this:

    Private Shared Function FillDataRecord(ByVal myDataRecord As IDataRecord, ByVal myPerson As BusinessEntities.PersonObject) As BusinessEntities.StudentObject
        Dim myStudent As New BusinessEntities.StudentObject()

        myStudent = myPerson

        myStudent.Id = myDataRecord.GetInt32(myDataRecord.GetOrdinal("Id"))
        myStudent.SchoolID = myDataRecord.GetInt32(myDataRecord.GetOrdinal("SchoolID"))

myStudent.SchoolName= myDataRecord.GetString(myDataRecord.GetOrdinal("SchoolName"))

        myStudent.ConcurrencyId = DirectCast(myDataRecord.GetValue(myDataRecord.GetOrdinal("ConcurrencyId")), Byte())

        Return myStudent
    End Function

is this the correct way?
On Friday, December 18, 2009 6:38:18 PM Jay said:
Hello again,
hmmmm, after looking at the code again.. i think this should be implemented at the StudentObjectManager, where i would change the getlist, getitem and so on to grab the ContactPerson collection and add that to the StudentObjectCollection and return a complete object, but not sure how i can get it done... i'm confused arrrrrrrrrr

help???????????????
On Friday, December 18, 2009 7:48:40 PM Imar Spaanjaars said:
Hi jay,

Not sure I understand what you're saying / asking. Long week ;-)

If you're asking about loading properties of the parent object, you could create a FillDataRecord on the base class that accepts the reader, and fills the data. E.g.:

Private Shared Function FillDataRecord(ByVal myDataRecord As IDataRecord, ByVal myPerson As BusinessEntities.PersonObject) As BusinessEntities.StudentObject
  Dim myStudent As New BusinessEntities.StudentObject()
  MyBase.FillDataRecord(myDataRecord)
End Function

The base class would then fill just the properties it understands; e.g. the ones from ContactPerson.

Cheers,

Imar
On Saturday, December 19, 2009 1:42:37 AM Jay said:
Hello Imar,
Thank you for the quick reply. thank god it's already Friday.
anyway...
when i tried your code i get the following error:

MyBase is only valid within an instance method.

so let me explain what i'm trying to do:
basically i have a parent object ConatcPerson, in my case it is PersonObject... that will have basic and common properties like firstName, lastName and so on......

Now i have two other Objects Child Objects that will inherit from the parent Object in my case these child objects are called StudentObject and EmployerObject... since these Objects will inherit from the PersonObject they will have the firstName, lastName and so on.... PLUS each will have it's own properties, like schoolName, personObjectID for studentObject and employerName, personObjectID for the employeeObject... which are saved into a separate data table for example student and employer... and the personObjectID is the one that ties them together to the correct personObject...

how do i populate the studentObject with the correct data, that will come from the correct PersonObject table and the student table...

basically what do I need to do to get this to work:
        Dim myStudent As StudentObject = StudentObjectManager.GetItem(someID)
        If myStudent IsNot Nothing Then
            TextBox1.text = myStudent.FirstName
            TextBox2.Text = myStudent.SchoolID
        End If

and the same goes for the StudentObjectManager.GetList and so on....

where the studentObject will always have the correct property from it's correct PersonObject and it's own properties (SchoolID, SchoolName, PersonObjectID....) filled from the appropriate data table...

i hope this is clear now....

Thank you very much for your help
On Saturday, December 19, 2009 8:55:59 AM Imar Spaanjaars said:
Yeah, I knew I would screw it up somehow ;-)  Had forgotten we're in static, not instance methods. Anyway, a few other ways:

1. Create a constructor on the Base object that accepts a DataReader. Also create one on the derrived classes that simply forwards the DataReader to the base class. Inside the base class constructor, read all fields appropriate for that class. Inside FillDataRecord, create a new instance of the class, pass it the DataReader to fill the base properties and then fill the remaining details.

2. You could also create a Protected FillBase method on the base class that accepts a DataReader and does more or less the same.

In both cases, the derrived class executes a stored procedure that gets data from both objects to minimize the number of trips to the database.

Hope this helps,

Imar
On Saturday, December 19, 2009 7:57:06 PM Jay said:
Hi Imar,

Thanks for the recommendation, but...
Wouldn't that defeat the purpose of N-Layer, because doing that will have the same code applied to both StudentObject and Employee Object...

i was thinking it's better if I leaving the PersonObject as is and somehow in the GetList() method of the new studentObject.Getlist() call the original Getlist() of PersonObject.Getlist() let it fill the properties and after that's done somehow run a method that will get the studentObject properties and then copy the personObject Collection that was returned from personObject.Getlist to the new studentObjectCollection and merge them together to return the correct and complete studentObjects with all properties filled in...maybe through cloning/coping the parent Object to the studentObject and then fill the rest of the properties...
or maybe looping through the personObjectCollection returned from personObject.Getlist () and then fill each studentObject by copying from its parent personObject using for example personObjectID property that would exists in both objects…..
I don’t know if I’m making sense anymore….. Crap there goes my weekend…
any help on how to achieve this?

Thanks....
On Saturday, December 19, 2009 10:43:06 PM Imar Spaanjaars said:
Hi Jay,

Why would that break N-Tier? (although I assume you mean good OO principles instead).

You can have the base object load base properties and each child object only load its own child properties.

With regards to your "I don’t know if I’m making sense anymore", the answer is: no, you lost me half way....

Imar
On Sunday, December 20, 2009 1:54:57 PM Jay said:
Hello Imar,
@Imar: You can have the base object load base properties and each child object only load its own child properties.


exactly what i'm trying to do... how do i do it?????
have the parent object load it's own properties and the correct child inherits the parents properties and load it's own... i just can't seem to find the way to do it.... errrrrrrrrrrrrrrr... i dreamed about the damn problem yesterday and didn't solve it.. even in my sleep i couldn't get it done.. now i'm doomed...LOL please help...
On Sunday, December 20, 2009 2:53:10 PM Imar Spaanjaars said:
>> exactly what i'm trying to do... how do i do it?????

Exactly how I suggested: create a constructor on the base class that loads the properties from the reader you pass into it, and load class specific data in FillDataRecord.

Cheers,

Imar
On Sunday, December 27, 2009 8:57:32 PM Raj said:
Hi...recently i downloaded ur project..it helped me a lot to clear my doubts..but when i implement those things,  specially the 'AppConfiguration.cs' in 'Dal'...it shows an error "the configuration doesnot exist in teh current context"..could you please guide where i went wrong..and some tips in implementing security for a website...

Thanking you
On Sunday, December 27, 2009 10:40:24 PM Imar Spaanjaars said:
Hi Raj,

You need to add a reference to the System.Web.Configuration or System.Configuration assembly, depending on the ConfigurationManager class you're using.

For security: check out part 6 of this series.

Cheers,

Imar
On Thursday, December 31, 2009 3:33:39 PM Steve said:
Wonderful work here on the new series.  I have just *upgraded* my project to use the validation / business base framework from this article.

I do have one question, I am trying to implement a Find() method in the BusinessCollectionBase object.

Essentially I want to pass this method an id and have it return to me the object with this id that is in the list (assuming it is).

At first thought, I was thinking (in the BusinessCollectionBase class):

Public Function Find(id as integer) as BusinessBase

    Dim retObj as BusinessBase = Nothing

    For Each i as BusinessBase in Me
        If i.id = id Then
            retObj = i
        End If
    Next

    Return retObj

End Function

That is what  I want to accomplish - but it isn't proving to be quite this easy.  

I have tried:

For Each i as BusinessBase in me....
For Each i as BusinessBase in me.Items...
For Each i as T in Me.....
For each i as T in me.items....

I feel like this should be much simpler than I am making it...I feel like I am re-inventing the wheel...

Can you suggest how this should be done?


Thanks,
Steve

On Saturday, January 02, 2010 6:38:20 PM Imar Spaanjaars said:
Hi Steve,

Sorry about the formatting. It's a bug I need to fix. The formatting gets OK as soon as I approve the message so I deleted your second message.

You can't do this directly, as the BusinessCollectionBase class knows how to work with instances of ValidationBase only (which doesn't define an Id() and not with BusinessBase (which does).

To make this work, you need to do two things:

1. Modify the collection class header like this:

Public Class BusinessCollectionBase(Of T As BusinessBase)
  Inherits ValidationCollectionBase(Of T)

This limits T to BusinessBase (instead of ValidationBase) so you know each T inside your class has an Id.

Then you can implement Find as follows:

Public Function Find(ByVal id As Integer) As T
  For Each item As T In Me
    If item.Id = id Then
      Return item
    End If
  Next
  Return Nothing
End Function

This way, because you're using generics, each implementation returns a T which is the correct type for the class (Address, ContactPerson and so on) enabling you to do something like this:

Dim address10 As Address = MyListOfAddresses.Find(10)

You can also use LINQ in Find instead of iterating over the collection:

Public Function Find(ByVal id As Integer) As T
  Return (From b In Me.Items Where b.Id = id Select b).FirstOrDefault()
End Function

Same result, slight simpler to type and read.

Hope this helps,

Imar
On Thursday, January 07, 2010 3:59:14 AM Brian said:
Hi Imar:

I think this is the best informative article about the N-Layered Architecture. Thanks for sharing your knowledge.

I have some questions, the first is about that:

The day 12/19/2009 you suggested Jay the next solution:

"1. Create a constructor on the Base object that accepts a DataReader. also create one on the derrived classes that simply forwards the DataReader to the base class. Inside the base class constructor, read all fields appropriate for that class. Inside FillDataRecord, create a new instance of the class, pass it the DataReader to fill the base properties and then fill the remaining details."

In this case, only as a basic idea, we will have the next inheritanced objects:
        
           Person
           Employee:Person
           Student:Person

           PersonBLL
           EmployeeBLL:PersonBLL
           StudentBLL:PersonBLL

           PersonDAL
           EmployeeDAL:PersonDAL
           StudentDAL:PersonDAL          

This is true?          

And what do you think about the next option?

We can use the base object Person (without the inheritance) with all atributes including the specific atributes of the Employee and the student so when we'll need to use the object Employee the atribute SchoolId will have a null value.

This is in case that the difference between the Employee and the Student isn't big.

Could you give me a little example when I could use my solution or this has many disadvantages?

Also, I read another article and someone said that he used the DAL only to return readers and later he filled the atributes of the objects and the object lists in the BLL, this is a valid use of the N-Layered architecture? what do you think?

Thanks in advance for your answers.
On Thursday, January 07, 2010 7:39:01 AM Imar Spaanjaars said:
Hi Brian,

It depends. You may not need a PersonDB if the class is just an abstract base class.

Not sure I understand your other questions. Why would you use a Student when you need an employee.

With regards to filling objects, isn't that exactly what's happening here? You may want to read the introduction of the 2.0 series for the different options you have.

Cheers,

Imar
On Monday, January 11, 2010 6:22:53 AM Brian said:
Hi Imar, I'm a beginner, I'm sorry, I tried to show you an example based in the example of Jay, but , in a concrete situation, if I have two objects: EmployeeHourly and EmployeeSalaried inherited from the base class Employee, then if the atributtes are very similar, I could have a base class which won't be an abstract class because I'll have an EmployeeList (get and fill Employee objects) with EmployeeHourly and EmployeeSalaried objects in the same list, and when I select an Employee I only need to instance an EmployeeHourly or an EmployeeSalaried, it depends of the type of Employee. Is this true?

And with regards to filling objects, with your class ContactPerson, in your code first in the DAL you have the method FillDataRecord, in this layer you generate the datareader and fill the atributtes of the object (ContactPerson.Id=myDataRecord.....), then you return the filled object ContactPerson. In the BLL you have the method GetItem, in this, you have the code "return GetItem(id, false);". In a few words, you fill the object in the DAL and later in the BLL you return the filled object.

In another code, somebody have the method "public Dataset getCountries()", then it returns the dataset. In the BLL in a method he recives the dataset, later in the same method he generates the instances of the objects and fills them to return the object list:

            foreach (DataRow objRow in.....
                  {            
                        CountryEntity objCountry=new CountryEntity;
                        objCountry.CountryId=Convert.toInt16(objRow[0];
                        objCountry.Name.......
                        CountryList.Add(objCountry);            
                  }
             return CountryList;

Well, almost this is only a pseudocode, but basically he only generates the dataset in the DAL, he returns the dataset and in the BLL he fills the objects.

In conlusion,
          YOUR CODE                       HIS CODE
       DAL:  you obtain the reader,    DAL: he only obtains and
        in this layer you instancied             returns the  dataset
       and filled the objects                      without knowledge
       (every attribute of the object)          about the
                                                          objects.
  
        BLL:  you recive                    BLL: He recives the dataset
                the filled object and      and creates the instances of the  
                return the same filled   objects and fills them (every
                object.                        attribute) in this layer.

I hope this is useful as an explanation :)

So, what do you think about the idea of the use of datasets, datatables or readers in the DAL without filling attributes of the objects in this layer? (at least with the purpose of showing reports, gridviews, etc).

Thanks for your opinion.
On Monday, January 11, 2010 8:32:49 PM Imar Spaanjaars said:
Hi Brian,

I see what you mean now. Yes, that would certainly be an option too. In my case, I don't mind that much as it's OK for me if the Dal and Bll share some common knowledge (through the BO's).

But your ideas would certainly work well.

Cheers,

Imar
On Monday, January 11, 2010 10:57:28 PM moji said:
Hi Imar ,
You have Implemented your DAL Static , It doesn't limit you ?
On Tuesday, January 12, 2010 8:02:34 PM Imar Spaanjaars said:
Hi moji,

Not in this design. But it would be easy to use a different design without static classes....

Imar
On Tuesday, January 12, 2010 9:17:47 PM Adam Ralph said:
@Brian - one disadvantage of the DAL returning a Dataset rather than a collection (e.g. System.Collections.Generic.Collection) of business objects is that a Dataset will usually occupy considerably more memory due to various overheads. If you anticipate returning a relatively large amount of data from your DAL then this may be worth taking into consideration.
On Friday, January 22, 2010 12:01:41 PM Raj said:
Even though i am using system.configuration assembly..the same error is coming as 'configurationManager doesnot exist in the cuurent context'
the intellisence also not showing configuration manager in codebehind..but i can view it in objectExplorer..tel me where i went wrong
On Friday, January 22, 2010 12:12:30 PM Imar Spaanjaars said:
Hi Raj,

Hard to say as it should work as described. Here's what works for me:

1. File | New Website or File | New Project | ASP.NET Web Application
2. Right-click references, choose Add Reference and add System.Configuration (should be there already for a Web App)
3. Add a using statement for System.Configuration
4. Use ConfigurationManager

Maybe you missed step 3?

Imar
On Saturday, January 23, 2010 9:23:09 PM Michael said:
Hi Imar,
Thank you so much for posting this tutorial.  I am currently using your framework to design an application for my company but I have a question: In your application example, you use ENUM classes, in my application, I have lookup tables.  I have almost as many lookup tables as I do regular data tables.  How woud you implement lookup tables in place of the ENUMs?  By lookup table I mean this table structure example for tblkp_email_type:

ID, value
1, "None"
2, "Business"
3, "Personal"

I hope my question makes sense.

Thanks!
On Monday, January 25, 2010 8:00:36 AM Imar Spaanjaars said:
Hi Michael,

If these tables are relatively static, you could still create enums for them.
Otherwise, you could create NameValueCollections or a generic Dictionary such as Dictionary<int, string>, make them statically available and lazy load them, or cache their values for some time.

Cheers,

Imar
On Wednesday, January 27, 2010 11:10:43 AM raju said:
is there any way of downloading all the parts of this great article in a PDF format. as the article can share to people who dosent have net facility and print facility
On Wednesday, January 27, 2010 1:46:15 PM Imar Spaanjaars said:
Hi raju,

You can buy the entire series as a PDF here: http://imar.spaanjaars.com/QuickDocId.aspx?quickdoc=482

However, the PDF is meant for personal use only, and you're not allowed to share it unlimitly...

Cheers,

Imar
On Tuesday, February 02, 2010 5:26:41 PM George said:
Hi Imar,

I have a question, If I have a Web Site with the N-Layered Architecture, when I need to do a lot of operations like averages, then, can I create a new object in the BLL (for example the Object Operation with the method Average)? or can I create a this new object in the Entities Layer with that object and the methods that I mentioned?

What is the better option (add the object to the BLL or the Entities Layer)?
of Will I need to add two objects (one in the BLL and other for the Entities Layer?

Thanks.
On Thursday, February 04, 2010 9:23:29 AM Imar Spaanjaars said:
Hi George,

I guess it all depends on where the data comes from and where the calculations take place. If they are calculated by the business layer, a class in that layer would make the most sense to me.

Cheers,

Imar
On Monday, February 08, 2010 6:08:43 AM joedotnot said:
"Dumbed" down business objects just don't do it for me. Essentially your business objects have a one-to-one correspondence to Database tables, which begs the question what is the point of all these layers, just to look fancy ?

Admitedly the demo application is simple, but how would you apply this with more "clever" business objects with several layers of inheritance, this is what i would like to see you attempt in a series of articles.

In any case i like your writing style.
On Monday, February 08, 2010 7:20:01 AM Imar Spaanjaars said:
Hi joedotnot

If they don't do it for you, don't use this methodology...

And yes, in this example, there is a direct mapping. However, the infrastructure is in place to create layer specific behavior. It's now easy to add stuff to the BLL (secrurity, business rules etc), or to add a new layer on top of this (caching for example) without a lot of work.

No plans to write a new series any time soon; I first need to finish my new book.

Cheers,

Imar
On Monday, February 08, 2010 6:49:31 PM Rajasekhar said:
Hi Imar, Please clear my doubt..
why to use id in Businessbase and the is overriding in each Entitie?.
Is this necessary to Override it in child class?
is this 'id' is the Uniqueidentifier(PrimaryKey) of the table in DB?

First Time i'm trying to Implementing the Validation Frame work that you have expalined here. But The problem i'm facing here is When i try to make use of collection, it's not giving the general methods that a collection must have the only method it is showing in Intellisence is Sort That was implemented in BusinessCollectionBase..can please tell me What my mistake is?

I'm very Thankfull for your great supprot.
On Monday, February 08, 2010 7:14:44 PM Imar Spaanjaars said:
Hi Rajasekhar,

You may want to take another look at the source to answer these kind of questions. From BusinessBase.cs it's pretty easy to see Id is an int, not a Guid. And yes, you need to override it, as it's marked abstract. You can change that if you wanted to.

With regard to the question about collections: you're probably instantiating the wrong type. Difficult to say without seeing your code. Can you post that on a forum such as http://p2p.wrox.com/index.php?referrerid=385 as send me the link?

Glad you appreciate my supprot ;-)

Cheers,

Imar
On Tuesday, February 09, 2010 4:22:19 AM Rajasekhar said:
May be i'm not clear in my previoues question.
Actually i'm using primary keys of type String, int and Uniqueidentifier (guid) in a single project (multiple tables). So is there any thing to change in BusinessBase class. if i'm not going make any changes to the BusinessBase class id property, then the child class automatically hides 'id' of Base class (if type is not int).
On Tuesday, February 09, 2010 7:11:22 AM Imar Spaanjaars said:
Hi Rajasekhar,

Then simply drop the Id from BusinessBase and define your own properties in your child classes....

Imar
On Tuesday, February 16, 2010 7:30:09 PM Michael said:
Hi Imar,

I'm using the VB version of your project.  Thank you again for posting this excellent article.  I noticed that "nq" inside the placeholder in the DebuggerDisplay constructor doesn't seem to work with VB.  With the "nq" in place, all I see is Person: (), if I remove it, I see Person: "Michael" Type: ({Family(2)})

I just thought I would mention this in case anyone else is having a similar issue.

Thanks!
On Thursday, February 18, 2010 1:21:06 PM capster said:
Can you please write an article on refractoring and the steps to do that with a nice example.
On Thursday, February 18, 2010 3:12:00 PM Imar Spaanjaars said:
Hi capster,

Not any time soon, probably But you can check out some books on this topic. For instance: http://www.wrox.com/WileyCDA/WroxTitle/Professional-Refactoring-in-C-ASP-NET.productCd-047043452X.html If you search Amazon for "refactoring" you'll find some more interesting stuff.

Cheers,

Imar
On Friday, February 19, 2010 11:11:24 AM Dave said:
Hi Imar,

Great article, it has been a great help while developing my first N-Layer architecture application. I do have one question though. I see you have three layers one of them being called the Business Logic layer but you validate all of your business rules by overriding the Validate method in the business objects themselves. I can understand why you have implemented it in this manner but I would have though the Business Logic layer would have been the place for these rules. Just wondered if you could clarify your thoughts regarding this as if you are handling the business logic directly in the objects I’m not sure if Business Logic would be the correct description for the middle layer.

Thanks
Dave
On Monday, February 22, 2010 9:40:07 AM Imar Spaanjaars said:
Hi Dave,

I consider the validation objects as part of the business layer as well, although they do live in a slightly different namespace.

Cheers,

Imar
On Wednesday, February 24, 2010 12:15:28 PM Imar Spaanjaars said:
Hi Michael,

Sorry for my late response. Had to test this out before I could post a reply.

It turns out that in VB 2008 you can't have a space following the comma. E.g. you need to use:

FirstName,nq

instead of

FirstName, nq

This appears to have been fixed in VS 2010.

Hope this helps,

Imar
On Wednesday, February 24, 2010 2:17:28 PM Michael said:
Ah, thank you for finding that!

Michael
On Thursday, February 25, 2010 7:10:41 AM Kevin said:
Hi Imar,

First, have to thanks you for sharing these article. It really helps me a lot on understand n-layered architecture, especially novice like me. I have planned to use your framework for my current project. But i have 2 questions that would need your helps.

#1
In your business entities, they have a common primary key which is Id field. For my case, the primary key is often more than 1 column. Eg. CustomerId + PropertyId
This made me hard to generalize the CRUD function. From your opinion, should i add additional single column primary key to all the tables?

#2
In my case, i have 2 business entities.
Customer
- Name
- CustomerTypeId

CustomerType
- CustomerTypeId
- CustomerTypeName

My question is should i make Customer.CustomerTypeId to Customer.CustomerType?


Thanks.
On Thursday, February 25, 2010 9:15:03 AM Imar Spaanjaars said:
Hi Kevin,

Re 1: No, probably not. You would introduce a surrogate key which may not be necessary if your two columns represent a true ID. However, it's not too hard to modify this model to support multiple keys. I've done that quite a lot as well. Simply have methods like GetItem accept multiple parameters, and change the "new tracking" mechanism (checking for -1 now).

Re 2: You could do both (that's how Entity Framework 4 does it now). That enables you to set the ID directly which is convenient if, for example, you're trying to set it based on a value in a DropDownList for example. At the same time you could preload or lazy load the CustomerType.

Cheers,

Imar
On Friday, February 26, 2010 9:52:01 AM Kevin said:
Hi Imar,

Exactly, it is more convenient if assign the value using Id property and it save db round trip for getting that object. But sometimes i do need to display it's name/description on the screen. Like you said, i can maintain both properties. Would the class look like this? Is this right how i handle the CustomerTypeId is changed?

Public Class Customer
...

Public Property CustomerTypeId As String
Get
     Return _customerTypeId
End Get
Set(ByVal value As String)
     'If the CustomerTypeId is changed, refresh the CustomerType
     If value <> _customerTypeId AndAlso _customerType IsNot Nothing Then
        _customerType = CustomerTypeManager.GetItem(value)
     End If
     _customerTypeId = value
End Set

Public ReadOnly Property CustomerType As CustomerType
Get
     If _customerType Is Nothing Then
        _customerType = CustomerTypeManager.GetItem(_customerTypeId)
     End
     Return _customerType
End Get
End Property

End Class

Another question is how to achieve lazy-load? Coz i don't want to preload CustomerType as it is not always needed.


Thanks
On Friday, February 26, 2010 9:56:31 AM Imar Spaanjaars said:
Hi Kevin,

I would make the CustomerTypeId property a simple Get / Set property and then do the logic with regard to change tracking in the CustomerType property. That way, you accomplish lazy loading at the same time. You can set and get CustomerTypeId without performance implications, but only when you access CustomerType and the Id has changed or the underling CustomerType is still null do you access the database to get a copy of the CustomerType using GetItem.

Cheers,

Imar
On Friday, February 26, 2010 10:32:33 AM Kevin said:
Hi Imar,


Public ReadOnly Property CustomerType As CustomerType
Get
     If _customerType Is Nothing OrElse _customerType.CustomerTypeId <> _customerTypeId Then
        _customerType = CustomerTypeManager.GetItem(_customerTypeId)
     End
     Return _customerType
End Get
End Property

Yes, your suggestion is more compact and it didn't impact when CustomerTypeId is changed.

Thanks for everything.
On Friday, February 26, 2010 10:37:33 AM Imar Spaanjaars said:
Hi Kevin,

Yes, that's exactly what I mind in mind. You could also implement a Setter if you wanted to. If you do so, you need to sync _customerTypeId with the Id of the incoming customerType value.

Cheers,

Imar
On Saturday, February 27, 2010 1:10:30 AM Michael said:
bump
On Saturday, February 27, 2010 9:57:52 AM Imar Spaanjaars said:
Hi Michael,

Heuh? What's there to bump?

Imar
On Sunday, February 28, 2010 3:17:37 PM Kevin said:
Hi Imar,

In your framework, when a collection is update/insert, it involves multiple call to db. Do you have any idea i can modify it to reduce the db round-trip? something just like the way dataset is updated.


Thanks.
On Sunday, February 28, 2010 3:22:24 PM Kevin said:
Hi Imar,

Any reason you using TransactionScope rather than transaction in sql server?
On Sunday, February 28, 2010 3:37:47 PM Imar Spaanjaars said:
Hi Kevin,

With a TransactionScope it's easy to control transactions that span multiple databases from code. If you do it "in SQL Server", you're limited to the stored procedure that is tranactional.

With regards to batch updating: you could make the collection classes responsible for this. You could create a Save method that collects the changes, creates an INSERT / UPDATE statement that spans multiple records and send that to the database.

Cheers,

Imar
On Sunday, February 28, 2010 4:09:34 PM Michael said:
Sorry, Imar.  I accidently un-subscribed from the thread and couldn't find the link to re-susbscribe without posting again.
On Wednesday, March 03, 2010 7:03:53 AM Kevin said:
Hi Imar,

Regarding the multiple INSERT/UPDATE method you suggested, seem like need to construct dynamic SQL script in one string and send to db.

something like....

INSERT INTO Customer(Id,Name) VALUES('1','A')
GO
INSERT INTO Customer(Id,Name) VALUES('2','B')
GO
INSERT INTO Customer(Id,Name) VALUES('3','C')

There is one disadvantage, cant use stored procedure to prevent sql injection. If the SQLCommand can attach multiple set of parameters then it will be great.
On Wednesday, March 03, 2010 7:09:49 AM Kevin said:
Hi Imar,

I'm using MyGeneration to create template for my Entity class and Data Access Class. I encountered an issue regarding convert table name to class name where the table name is on plural noun and the class name should in singular noun. Any template i can refer on singularize the table name?
On Wednesday, March 03, 2010 11:12:35 AM Imar Spaanjaars said:
Hi kevin,

I don't think My Generation supports pluralization (not 100% sure though), but there are C# classes available that can do this for you:

http://www.google.com/#hl=en&source=hp&q=pluralize+C%23&aq=f&aqi=&aql=&oq=&fp=db64f927cfe7b756

Cheers,

Imar
On Thursday, March 04, 2010 4:02:58 AM Kevin said:
Hi Imar,

Thanks. I think i will change my table name to singular noun for ease of creating template.

I'm in the middle of decide using Linq to SQL or DataReader as my DAL. Any suggestion for me?
For the LinqToSQL, I have checked the Blogo.Net that you mentioned. It will map the persistent object generate by LinqToSQL to the custom business entity. Why should we still using custom business entity since LinqToSQL already provided?
On Thursday, March 04, 2010 2:43:14 PM Imar Spaanjaars said:
Hi Kevin,

With your own business entities, it's much easier to implement features such as validation and security. I find the way you need to extend classes with L2S a bit awkward at times...

Cheers,

Imar
On Wednesday, March 24, 2010 9:05:11 PM Rolle said:
Thanks for an interesting article! I have one question (it may be covered later, sorry, I have only read this far yet :) ).

Would it be possible to use AutoMapper to do the work in FillDataRecord. Ie. to mapp the data reader to the business entity?
On Wednesday, March 24, 2010 9:14:10 PM Imar Spaanjaars said:
Hi Rolle,

I am not 100% sure, but I don't think you can. AFAIK, AutoMapper relies on matching properties. IDataRecord doesn't expose properties but relies on method calls.

Cheers,

Imar
On Thursday, March 25, 2010 7:07:51 AM Rolle said:
Thank you for your swift response Imar!

I have only little experience with AutoMapper, I have used it for mapping before but more on the level of "monkey see, monkey do".

I was only thinking that there has to be a "better" (easier/less code) way (than code generation with eg. CodeSmith) to do the work of FillDataRecord. It looks kind of repetitive, all methods basically doing the exact same thing. I am looking at StructureMap right now, I have no experience with it so I don't know yet.
On Thursday, March 25, 2010 7:17:12 AM Imar Spaanjaars said:
Hi Rolle,

StructureMap is an Inversion of Control tool and is not going to help you with this.

It should be possible to use .NET reflection to do the following:

1. Loop over the properties of the Business Object
2. For each property, determine the name and type.
3. Based on that info, determine the right method to call on the IDataRecord (e.g. GetString, GetInt32 whatever) and pass in the right column name
4. Assign the returned value to the object.

Not terribly difficult to implement, but not very straightforward either. Also, because it's automatic, it may not be easy to determine which properties to ignore or handle differently.

Cheers,

Ima
On Tuesday, March 30, 2010 9:13:16 PM Kevin said:
Imar,

I have found your articles very useful, but I am running into limitations as the application gets more complex. I found them more useful for my winforms application than my ASP application.

The problem I have is that with ObjectdataSource you only have access to CRUD methods. My database has two related tables with a many to one relationship. My web form has fields for the Primary table and a gridview for the related table. I want the user to be able to add records to the grid, but I can't perform CRUD actions before the user submits whole form. There is no record in the primary table until the user completes the form and hits submit, so I can save gridview without the foreign key.    I guess the think is that since this is a browser that the objects are stateless and you can not persist an collection of objects. You can use these objects to pass to DAL, but you cannot collect a group of them and wait until the user clicks 'Submit'

In my winforms version of this application the main objects contains sub objects for the related tables and the save is only done with the user clicks 'Save' button. If they pass validation, then go through the objects and save them in order.

I am struggling to figure out how to create the same functionality in web forms.

Thanks,

Kevin
On Wednesday, March 31, 2010 11:11:26 AM Rolle said:
Regarding the mapping of DataReader to DTO using AutoMapper, I found this. Haven't tried any of it yet though, and I'm not sure I will. :)

http://stackoverflow.com/questions/1973351/automapper-mapping-between-a-idatareader-and-dto-object

On Friday, April 02, 2010 8:20:58 PM Imar Spaanjaars said:
Hi Rolle,

Interesting; thanks for the update.

Cheers,

Imar
On Sunday, April 04, 2010 11:25:41 AM Imar Spaanjaars said:
Hi Kevin,

Yes, this can indeed be problematic. I see a few solutions, including:

1. Store everything in temporary storage: View State, Session State or tables in the database, depending on the size of the data.

2. Store the data in the database, but mark it as temporary / invalid. Once you collect all data, mark the item as valid, or delete the item from the database if it's not complete or valid.

Option 1 means a bit more work and may cause some storage overhead. With option 2 you run the risk of invalid or stale data in your database.

Hope this helps,

Imar
On Wednesday, April 14, 2010 6:08:41 PM Steve Bell said:
Quick question about best practices here - and organizing the project properly:

Assume you have an Order object - contains customer first name / last name / shipping address / billing address / phone / email / order details

and order details contains:

product / qty / price

Assuming I am using the framework you have set up here - each object has its own FillDataRecord - and each object is encapsulated so that it contains only code that pertains to itself.

Everytime I grab an order from the db, I also want the details.  In addition, I have some scenarios where I will just want to grab individual details from the db.

Therefore, my OrderDetials object has a fill data record - which is private (like in your examples) - how is the best way to handle grabbing an order from the database - given that I don't want to have to maintain 2 sets of code for grabbing order details.

Thanks
sb
On Wednesday, April 14, 2010 6:37:16 PM Imar Spaanjaars said:
Hi Steve,

In FillDataRecord, you do something like:

myOrder.OrderDetails = OrderDetailManager.GetDetailsFor(id);

Hope this helps,

Imar
On Wednesday, April 14, 2010 6:49:19 PM Steve Bell said:
When I wrote this I thought about doing it that way, however, I forgot to mention -

I wrote my stored procedure in such a way that it returns both order and order detail information - to a dataset and then i setup a relationship...

That seemed to be the most efficient way to do it - 1 round trip to the db rather than 2??

Thanks for the quick reply.
On Wednesday, April 14, 2010 7:20:53 PM Imar Spaanjaars said:
You can use SqlDataReader.NextResult (http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.nextresult.aspx) to read multiple sets from a stored procedure. That removes the need for the DataSet....

Imar
On Friday, April 16, 2010 1:12:31 PM jay said:
Hi Imar,
I'm not sure if this has been asked before, but i though i ran it by you and see your take on it...
Once again, great article... and for the following question i did my research and got more confused on what to use Refelction, ComponentModel... so on.... it's go to be a way...in your nlayered design,  I'd like to be able to give Base class the ability to add itself a set of
properties that match a datatable structure once the constructor is executed, and also have the posibility to add a customattribute to any of these properties. instead of hard coding the properties and their attributes to match the database fields... is that possible../ recommended... or should i just stick to how you're doing it?

Thanks for your contribution.
Jay.
On Friday, April 16, 2010 1:15:35 PM Imar Spaanjaars said:
Hi jay,

If I understand you correctly, the answer is: it can't be done. Attributes are added at design time. And data you pass to it needs to be resolvable at compile time.

Cheers,

Imar
On Friday, April 16, 2010 1:25:04 PM Jay said:
Hi Imar,
That was quick. thanks... while doing my research i did run into this post which describes how to do it, or gets close and it's in C#...i'm vb.net guy for now, so i kind of got lost while reading through it... please take a look ..

http://tinyurl.com/3b6wxz

Jay
On Friday, April 16, 2010 1:30:04 PM Imar Spaanjaars said:
A bit too much to read for me right now. But it looks like this is about accessing dynamic properties, not about applying attributes to them.

You could emulate the behavior through standard code. E.g. not with attributes but by using methods as is now done inside the validation code.

Cheers,

Imar
On Friday, April 16, 2010 1:35:38 PM Jay said:
Thanks, i scanned through the article i did see attribues being mentioned somewhere... anyway i'll wait untill you go through the above article and hear your take on it. in the mean time i will examine the validation class more closely...
thanks, and have a great weekend.

Jay.
On Friday, April 16, 2010 1:37:23 PM Imar Spaanjaars said:
>> anyway i'll wait untill you go through the above article

Don't wait for it, as I probably don't have the time to look at it...

Imar
On Friday, April 16, 2010 1:44:02 PM Jay said:
LOL, i was hopping you won't catch that...but i will keep digging, and if i figure it out i will let know.
thanks,
On Friday, April 16, 2010 1:47:55 PM Test said:
You're welcome....
On Thursday, May 06, 2010 12:34:43 PM Geoff said:
Hi Imar

Thanks for a great set of articles. I have a question that I would appreciate your thoughts on.

Say, for example, I needed to implement a UI feature to remove all contacts who had no email addresses via a single button click.

I imagine that there would be a method added to the ContactPersonManager class to request this processing. At this point I see two options. This method could load the list of ContactPersons and, within a transaction, iterate through them deleting those that had no email addresses.

Alternatively it could delegate a call direct to the DAL which could hand off the processing to a stored procedure to perform the processing which wuld then be all local to the database server.

I would be interested to see which of the two methods you would implement.

Once again, thanks
Geoff
On Tuesday, August 03, 2010 12:52:59 PM Dave said:
Hi Imar, excellent article, I have three questions, a person named Mohamed told you that he wanted to create a report, but if I need to create a lot of reports and every report has a lot of fields so, do I need to create one identity by report? In addition to LINQ what is another option to create the reports? and can you provide me a link with a post related with the design of reports? because sometimes I need reports with dynamic fields.

Thanks
On Tuesday, August 03, 2010 12:59:40 PM Imar Spaanjaars said:
Hi Dave,

As always, the answer is: it depends. If your report types are summaries of your entities, you could query the entire entity, and use just the fields you need. Alternatively, indeed, you could create separate objects for each report, or group of reports.

LINQ isn't designed to create reports; it's designed to work with objects and data. You can use it as the source for reports. Alternatives (if you actually mean LINQ to SQL) are the Entity Framework, NHibernate and more.

For report design the answer is, again: it depends. If you build custom reports, all you need is Visual Studio and some design skills. For a more tool oriented approach, look into Crystal Reports or SQL Server Reporting Services. For both you find loads of books on Amazon.com.

Hope this helps.

Cheers,

Imar
On Saturday, January 22, 2011 7:05:44 AM Marc said:
Hi Imar,

I just finished working through the first series and WOW, there is nothing like it anywhere else on the internet (that I have been able to find anyway).

I am about to embark on a winforms project and would just like to confirm that this design and prinicples (DAL,BLL) can also be used for winforms and not just web applications.

Thanks again for providing me with such an interesting and informative read.

Marc
On Saturday, January 22, 2011 8:07:38 AM Imar Spaanjaars said:
Hi Marc,

Yes you certainly can. The DAL and BLL layers don't rely on stuff like HttpContext so they can certainly be used in Win Forms or other type of applications.

In case you want to express your WOW factor with something more tangible: http://imar.spaanjaars.com/482/first-part-of-new-article-series-on-n-layer-design-in-aspnet-35-published ;-)

Cheers,

Imar
On Saturday, January 22, 2011 8:37:19 AM Marc said:
Hi again,

Thanks Imar! Going to that new article right away!  You should write a book on this.

I just read every comment on this page and that question has been asked (and therefore answered) before.  Sorry, I did not see it in the first instance !

I would  like to know your thoughts on using LINQ to SQL as the DAL as per BLOGO.Net.  My understanding (having read his article) is that he has to fetch the data from the database and into a Data Object and then fill the BO's from the Data Objects.  It seems pointless to do this if you can fill the BO's in one hit from a datareader (as per your design).  

I'm not trying to play either design off against the other here.  I am relativley new to the .NET world (12 years as a delphi developer)  I would just like to get some insight as to why one would consider modifying your design to utilize LINQ.  Does it simplify the Save/Update procedures when complexity is stepped up?

Sorry if I have gone off topic here, I'm just trying to understand the pros' and cons' of the different approaches.  I've done my fair share of googling but only seem to come up with conflicting opinions (arguments) which I find extremely confusing. Having read a great deal of your articles and comments, I value your opinion.

Many thanks,
Marc
On Saturday, January 22, 2011 8:43:13 AM Marc said:
Whoops!  I thought you had a new article out.  I see what you mean by more tangible.  Great idea.  More than happy to oblige.

Regards,
Marc
On Saturday, January 22, 2011 9:52:36 AM Imar Spaanjaars said:
Hi Marc,

Thanks for buying the article series! Much appreciated. I just sent them to you.

What I like about LINQ to SQL is that you don't have to write data access code manually. E.g., no more stored procedures, SqlConnection objects, parameters and so on. For many applications, this works very well. Also the fact you can query stuff dynamically using query composition and projection (to get parts of entities without the complete data) can be compelling.

If you want to look into an ORM though, you're better off looking into the ADO.NET Entity Framework, L2S's bigger brother. Microsoft is putting more efforts in EF than in L2S. EF is also part of my new N-Layer design, due out somewhere this century.

Cheers,

Imar
On Wednesday, March 09, 2011 7:21:20 PM Alex said:
Good article.  Imar, my observation is that for every entity you basically create a Manager and DAL object.  So in essence you have a 1 to 1 relationship between tables and entities.  As opposed to for example in Domain Driven Design where you would have one Repository per Aggregate Root.  What about perhaps grouping your Managers and DAL classes into one logical unit.  For example assuming you had Phone, Email, and Address entities.  Looking at your sample you would create 3 Managers and 3 DAL classes.  Would you consider combining them perhaps into ContactsManager and ContactsDB?
On Wednesday, March 09, 2011 7:24:25 PM Imar Spaanjaars said:
Hi Alex,

That would certainly work, and is indeed something I do in more domain oriented designs with repositories.

Cheers,

Imar
On Wednesday, March 09, 2011 7:33:21 PM Alex said:
Understood, although I am not at all trying to push towards a DDD solution.  I am more wondering if you ever try to group/combine your Managers/DAL classes into more "logical" groups based on what they do.  So something like TradingManager (which in turn would operate on Stock, Price, etc. entities) or do you tend to stick to entity centric Managers?
On Wednesday, March 09, 2011 7:37:08 PM Imar Spaanjaars said:
Hi Alex,

Yes, I do that as well. In your example, it would indeed make sense to group everything under a single Contacts manager.

Cheers,

Imar
On Friday, April 15, 2011 4:45:14 AM Casper said:
Your current objects are one-to-many, but how would you handle many-to-many objects?
On Friday, April 15, 2011 4:48:26 AM Imar Spaanjaars said:
Hi Casper,

With a specialized collecton that has a reference to the objects. Then in its Save method you have all IDs / objects available so you can save data in a junction table.

Imar
On Thursday, April 21, 2011 8:15:29 AM Amit Trivedi said:
Why Linq ( .dbml file ) is not used in this architecture ?
On Thursday, April 21, 2011 8:18:53 AM Imar Spaanjaars said:
Hi Amit,

You may want to check out Blogo.net. It uses my design, but Linq to Sql for data access:

http://s3maphor3.org/blogo.net/

Cheers,

Imar
On Tuesday, May 03, 2011 12:32:26 AM Muhammed Zakeer said:
nice article
On Monday, September 26, 2011 4:20:19 PM Christian said:
Hi Imar,

Thank you very much for you great articles on n-layered web applications.

After reading the articles I have been wondering how to implement lazy-loading in your solution.

To lazy-load the Addresses collection in the ContactPerson class I would implement is at below. But the problem with this (as I see it), is that it is necessary to add a reference to the Spaanjaars.ContactManager.Bll project from the Spaanjaars.ContactManager.BusinessEntities project, which would cause a circular dependency.

public AddressCollection Addresses
{
    get
    {
        if (Addresses == null)
        {
            Addresses = AddressManager.GetList(this.Id);
        }

        return Addresses;
    }
    set { Addresses = value; }
}


Any suggestions?

Regards,
Christian
On Tuesday, September 27, 2011 1:43:25 PM Imar Spaanjaars said:
Hi Christian,

Yes, that's not easy with this model. You could merge the two class libraries into one. Or you could generalize the data access and inject it to the objects, but that feels a bit funky. Then your Data Objects are no longer pure, dumb, data objects.

I would probably look into merging the projects, or look at other solutions outside this model.

Cheers,

Imar
On Tuesday, November 29, 2011 9:34:05 AM Jay said:
Hi Imar,

I have the VB version, which I have used as a basis for a template for our web projects internally. There is only one problem, in AppConfiguration, I have imported System.Configuration but the error "ConfigurationManager is not declared" comes up. I don't understand how it the Dal project can reference the Web.Config in the Web application project to fix this issue.

Thanks!
On Tuesday, November 29, 2011 4:49:55 PM Imar Spaanjaars said:
Hi Jay,

You need to add a reference to the System.Configuration assembly.

Cheers,

Imar
On Sunday, January 22, 2012 7:52:38 PM Saheel said:
I want a database of this project is their any possiblility plz give me a link or send me a database.
Thanks
On Sunday, January 22, 2012 7:56:52 PM Imar Spaanjaars said:
Hi Saheel,

Want want want. We all want something. Did you bother to read this article to learn how to acquire the source including the database?

Imar
On Friday, March 09, 2012 6:50:20 AM kiran chavan said:
Hi!! First, have to thanks you for sharing these article. I am really impressed a lot.
I am looking for code generator templates similar to v1. is it included in pdf ?
On Friday, March 09, 2012 11:38:34 AM Imar Spaanjaars said:
Hi kiran

Nope, they don't exist at all. It has been brought up a few times before, but nobody has actually submitted any files....

If you're willing to give it a try yourself, I'll be more than happy to host them here.

Cheers,

Imar
On Thursday, September 06, 2012 9:57:09 AM Kailash Patil said:
First of all I must thank you for great work Imar!!

Secondly I want to know whether you have any plans for any updates on this with reference to many new updates to .net after 3.5?

I am typical .net 2.0 developer and now want to upgrade my self to 4.0 / 4.5 directly. Recently purchased your book Beginning asp.net 4.0.
Need to start a new project but not sure whether to go for 3 tier or something else?

Thanks
On Thursday, September 06, 2012 10:08:54 AM Imar Spaanjaars said:
Hi Kailash,

I have an upgrade to .NET 4.5 using Entity Framework Code First high on my Todo list, but it'll take quite some time before it's finished.

Cheers,

Imar
On Thursday, December 27, 2012 5:12:59 PM Rethabile said:
I tried following the tutorial by creating mine from scratch. When i try to update the PhoneNumber I'm getting the following error message:

Can't update phone number as it has been updated by someone else
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Data.DBConcurrencyException: Can't update phone number as it has been updated by someone else
On Thursday, December 27, 2012 5:45:19 PM Imar Spaanjaars said:
Hi Rethabile,

Hard to say without knowing what you did and how you set it up. It sounds like the ConcurrencyId is not persisted correctly so when you update the number, the old value doesn't match the one submitted by the user. Look at the code that sets and gets the value from ViewState and see if you can discover something there.

Cheers,

Imar
On Friday, December 28, 2012 3:58:52 PM Rethabile said:
Hi Imar,

Initailly i had this on the phoneNumber gridview "DataKeyNames="Id"

after i changed it like i have shown below it worked

DataKeyNames="Id,ConcurrencyId"


thanx
On Sunday, December 30, 2012 8:55:28 AM Imar Spaanjaars said:
Hi Rethabile,

Ah, I see; yes, that explains the persistence issue with that value.

Cheers,

Imar
On Friday, June 07, 2013 9:07:50 PM Brad said:
Hi Imar,
In DAL.AddressDB.vb, I am trying to populate the AddressCollection using Dapper ORM, but receive the following error:

Unable to cast object of type 'System.Collections.Generic.List`1[BusinessEntities.AddressCollection]' to type 'BusinessEntities.AddressCollection'.


Public Class AddressDB
    Public Shared Function GetList(ByVal ContactID As Integer, ByVal sortExpressions As String) As AddressCollection


        Dim tempList As AddressCollection = Nothing
        tempList = New AddressCollection()
      
''****Dapper****
        Using conn As New SqlConnection(AppConfiguration.ConnectionString)
            tempList = conn.Query(Of AddressCollection) _
            ("dbo.GetAddress", New With {.ContactID = ContactID}, _
             commandType:=CommandType.StoredProcedure)
        End Using
    
        Return tempList


    End Function

End Class

I can load BusinessEntities.Address from Dapper into an IList and populate AddressCollection from that, but that seems like an unnecessary step.

Do you know how I can load AddressCollection directly using Dapper?
Thanks,
Brad
On Saturday, June 08, 2013 12:25:32 PM Imar Spaanjaars said:
Hi Brad,

I am not familiar with Dapper so I can't recommend anything. Doesn't the framework allow you to configure mapping rules? For example, like AutoMapper does it?

Imar
On Monday, July 22, 2013 7:18:32 AM Saroop Trivedi said:
Hello Sir,

I have some query regarding to BusinessManager and DAL logic.
1.Why you create both library methods static?
2.In many article I read that  static classes are notoriously hard to test - and they don't play well in environments like WCF/SOA .
3.What about the memory management and release for Static class?

Please Guide me I like your article but I am shucked because of These question.
On Sunday, July 28, 2013 7:12:43 PM Imar Spaanjaars said:
Hi Saroop,

You are correct. That's why I have written a new series targeting .NET 4.5 that addresses issues like this. You can follow it here:

http://imar.spaanjaars.com/573/aspnet-n-layered-applications-introduction-part-1

Cheers,

Imar
On Sunday, December 08, 2013 12:45:04 PM moh said:
truly ,you are the best
On Wednesday, March 26, 2014 4:33:23 PM Steve Bell said:
I built an ASP.net application based on this framework a few years back that we are still using today.

A new requirement just came up where we need to provide a limited functionality windows forms application as part of this product.  We already have the business entities, data access layer, and business logic layer from the web application - that contains all of the methods that we need to use for the windows application - so I would like to leverage this as much as possible.

My question is -  in the data access layer, I am getting the connection string from the web.config file in each of the methods in this layer.  If I am looking to leverage these same methods, both in the BLL and DAL, but from a windows application, where the web.config file does not exist - what is the best way to tackle this?  Should my BLL functions take a parameter of a connection string?  I am a bit confused on the bet way to handle this situation.

Thanks
On Wednesday, March 26, 2014 7:15:37 PM Imar Spaanjaars said:
Hi Steve,

Win forms applications have an app.config file which serves the same purpose, so you should be able to use this as-is.

Cheers,

Imar

Talk Back! Comment on Imar.Spaanjaars.Com

I am interested in what you have to say about this article. Feel free to post any comments, remarks or questions you may have about this article. The Talk Back feature is not meant for technical questions that are not directly related to this article. So, a post like "Hey, can you tell me how I can upload files to a MySQL database in PHP?" is likely to be removed. Also spam and unrealistic job offers will be deleted immediately.

When you post a comment, you have to provide your name and the comment. Your e-mail address is optional and you only need to provide it if you want me to contact you. It will not be displayed along with your comment. I got sick and tired of the comment spam I was receiving, so I have protected this page with a simple calculation exercise. This means that if you want to leave a comment, you'll need to complete the calculation before you hit the Post Comment button.

If you want to object to a comment made by another visitor, be sure to contact me and I'll look into it ASAP. Don't forget to mention the page link, or the QuickDocId of the document.

For more information about the Talk Back feature, check out this news item.