WCSF 1.1 and Enterprise Library 3.1 Sample

Topics: Web Client Software Factory, User Forum
Jun 27, 2007 at 9:59 PM
I get a lot of requests for simple starter examples of using the WCSF with Enterprise Library 3.1 so I provided an example you can download:

Web Client Software Factory Sample - Validation, Data Access, Policy Injection, Model-View-Presenter

It is a pretty simple example but shows off a number of features:

Web Client Software Factory 1.1 Features:

  • View-Presenter Pattern
  • Dependency Injection - [CreateNew] and [ServiceDependency] Attributes
  • Business Module Self-Discovery
  • ObjectContainerDataSource Control

Enterprise Library 3.1 Features:

  • Business Object Validation using Validation Application Block
  • ASP.NET Integration of Validation Application Block to avoid redundant Validation Rules
  • Validation of Method Parameters using Policy Injection Application Block's ValidationCallHandler
  • Caching of Database Results using Policy Injection Application Block's CachingCallHandler
  • Data Access Application Block for accessing SQL Server Express Database

Miscellaneous Features

  • AJAX UpdatePanel for Partial-Page Refreshes

I will add a screencast at some point that walks through the example. In the meantime, you can check out my other screencasts.

I wrote another post on it here, too.

Various Enterprise Library Tutorials and WCSF Tutorials on my other blog.


I hope it provides useful.

Regards,

Dave

_________________________________

David Hayden
Microsoft MVP C#
Jun 27, 2007 at 11:09 PM
Edited Jun 28, 2007 at 8:50 AM
Good example, David.

Delete didnt work as well as hoped. Some caching problems or?

I get some weird sideeffekts.

If you dont have any customers in the list, the list doesnt get updated after the first insert, but after the next you se all customers added.


Regards
Benny
Jun 27, 2007 at 11:26 PM
It is the caching. Just turn it off. I wanted to show you that the CachingCallHandler in the Policy Injection Application Block does indeed work :)

Remove or comment out the CachingCallHandler from the ICustomerDAO Class as shown below. There is a 15 second cache delay from the last time the GetAllCustomers method was called. This means the grid does not display the database contents in real time.

    public interface ICustomerDAO
    {
        Customer GetCustomerByCustomerId(int customerId);
 
        [CachingCallHandler(0,0,15)]
        List<Customer> GetAllCustomers();
 
        [ValidationCallHandler]
        void InsertCustomer(Customer customer);
 
        [ValidationCallHandler]
        void UpdateCustomer(Customer customer);
 
        void DeleteCustomer(int customerId);
    }

Regards,

Dave

_____________________________

David Hayden
Microsoft MVP C#
Jun 28, 2007 at 8:39 AM
Damn, didnt look for that.

Was late last night, should have seen in the code first or read your documentation.

Sorry.

Regards
Benny
Jul 5, 2007 at 10:45 AM
Dear David

If I want to create a master-detail relationship, how to handle it in a better way?

For example, Customer have multiple Customer Address.

I will create a new CustomerAddress Entity.
Should I bind this object to the original Customer Entity?
or
use the Controller to control the CustomerAddress Entity separately?

Thanks.
Alex
Jul 5, 2007 at 2:11 PM
In most cases I would add the relationship to the Customer Entity. Hence you may have a Addresses property on the Customer Entity like:

public class Customer {
    CustomerAddressCollection Addresses { get; set; }
}

And when I retrieve a customer from a datastore I just retrieve the addresses at the same time. In my example, you could then add a CustomerAddressDAO into the mix that allows one to FetchCustomerAddressByCustomerId(int customerId) or FetchCustomerAddressByCustomer(Customer customer) dependending on the intention you want to reveal.

You get into the need for a Unit of Work in this case as you will probably logically want to select, update, and delete these entities within a transaction, etc.

Hence one often thinks of this as a CustomerRepository.

Therefore when you select a Customer it may look like this:

public class CustomerRepository {
 
    Customer FetchCustomerByCustomerId(int customerId) {
 
        CustomerDAO dao = new CustomerDAO();
        Customer customer = dao.FetchCustomerByCustomerId(int customerId);
 
        if (customer != null)
        {
            CustomerAddressDAO addressDAO = CustomerAddressDAO();
            customer.Addresses = addressDAO.FetchCustomerAddressesByCustomer(customer);
        }
 
        return customer;
    }
}

This is when an O/R Mapper or at least a code generator can save you tons of work. You don't want to be building this by hand unless you just want the experience. There are other ways to pull this off using multiple resultsets from a single database call, too.

In your controller, if you feel you need one, you can then just do

public class CustomersController {
 
    Customer FetchCustomerByCustomerId(int customerId) {
 
        CustomerRepository repository = new CustomerRepository();
        return repository.FetchCustomerByCustomerId(customerId);
    }
}

You may want to toss some interfaces into the mix as well as RepositoryFactory for a little bit of indirection if you think you will need it, but only if you think you need it.

Then in your UI Code you can just display the addresses by binding to them via the property and you don't have to make multiple calls to a controller, etc.

I can probably add this to the example sometime to make it more "real."

Regards,

Dave

________________________________

David Hayden
Microsoft MVP C#
Jul 6, 2007 at 4:10 PM
Thanks. It is very useful for me.
Jul 6, 2007 at 7:06 PM
David,

I was using your sample as an example for another project and for some reason, my install of WCSF does not have the Microsoft.Practices.EnterpriseLibrary.PolicyInjection. Is this something new? OR where can I find it?

Thanks!


DavidHayden wrote:
I get a lot of requests for simple starter examples of using the WCSF with Enterprise Library 3.1 so I provided an example you can download:

Web Client Software Factory Sample - Validation, Data Access, Policy Injection, Model-View-Presenter

It is a pretty simple example but shows off a number of features:

Web Client Software Factory 1.1 Features:

  • View-Presenter Pattern
  • Dependency Injection - [CreateNew] and [ServiceDependency] Attributes
  • Business Module Self-Discovery
  • ObjectContainerDataSource Control

Enterprise Library 3.1 Features:

  • Business Object Validation using Validation Application Block
  • ASP.NET Integration of Validation Application Block to avoid redundant Validation Rules
  • Validation of Method Parameters using Policy Injection Application Block's ValidationCallHandler
  • Caching of Database Results using Policy Injection Application Block's CachingCallHandler
  • Data Access Application Block for accessing SQL Server Express Database

Miscellaneous Features

  • AJAX UpdatePanel for Partial-Page Refreshes

I will add a screencast at some point that walks through the example. In the meantime, you can check out my other screencasts.

I wrote another post on it here, too.

Various Enterprise Library Tutorials and WCSF Tutorials on my other blog.


I hope it provides useful.

Regards,

Dave

_________________________________

David Hayden
Microsoft MVP C#

Jul 6, 2007 at 7:09 PM
Nevermind...looking to the wrong place for it....ugh.


plstovall wrote:
David,

I was using your sample as an example for another project and for some reason, my install of WCSF does not have the Microsoft.Practices.EnterpriseLibrary.PolicyInjection. Is this something new? OR where can I find it?

Thanks!


DavidHayden wrote:
I get a lot of requests for simple starter examples of using the WCSF with Enterprise Library 3.1 so I provided an example you can download:

Web Client Software Factory Sample - Validation, Data Access, Policy Injection, Model-View-Presenter

It is a pretty simple example but shows off a number of features:

Web Client Software Factory 1.1 Features:

  • View-Presenter Pattern
  • Dependency Injection - [CreateNew] and [ServiceDependency] Attributes
  • Business Module Self-Discovery
  • ObjectContainerDataSource Control

Enterprise Library 3.1 Features:

  • Business Object Validation using Validation Application Block
  • ASP.NET Integration of Validation Application Block to avoid redundant Validation Rules
  • Validation of Method Parameters using Policy Injection Application Block's ValidationCallHandler
  • Caching of Database Results using Policy Injection Application Block's CachingCallHandler
  • Data Access Application Block for accessing SQL Server Express Database

Miscellaneous Features

  • AJAX UpdatePanel for Partial-Page Refreshes

I will add a screencast at some point that walks through the example. In the meantime, you can check out my other screencasts.

I wrote another post on it here, too.

Various Enterprise Library Tutorials and WCSF Tutorials on my other blog.


I hope it provides useful.

Regards,

Dave

_________________________________

David Hayden
Microsoft MVP C#


Jul 9, 2007 at 1:32 AM
Hello David

I have another query again.

What I want to do is some lookup function.

For example, I have an order entity which store the customer key field and I would like to use key to lookup the customer entity module to retrieve the customer name.

How could I implement this?
Should I build this logic under OrderService?? But if I build it under OrderService. Will it be too messy for the OrderService entities?

Thanks
Alex






Jul 10, 2007 at 8:21 PM
Similar to above, I would think that Customer would be a part of the order. Hence within your order you would probably have a 1:1 relationship with Customer:

public class Order {
 
    Customer Customer { get; set; }
 
}

Hence, getting the Customer's Name would be as simple as accessing the Customer Entity within the Order.

Although I use a customers module in my sample for simplicity, a module is not associate with an enity but with an application. Each business module actually representes a LOB Application, which is why in the RI they use Mortgages and EFT.

If you are doing a commerce or store application, you may call your business module Commerce or Store and it would have Order, OrderDetail, Customer, CustomerAddress, ShoppingCart, Payment, etc. entities.

Regards,

Dave

________________________________

David Hayden
Microsoft MVP C#
Jul 11, 2007 at 3:48 AM
Thanks David

However, I am facing another problem now.

Now. I would like to add a searching function to the customer that using the same Grid and object container data source.

However, when I pass the search parameter to the presenter through a button click, the onload function being involved and it calls GetAllCustomers first before called my newly created searching function.

But if I tried to disable GetAllCustomers under onload, it won't show any record after I click on the edit under the Grid since it won't do anything to load the record again after postpack.

If this GetAllCustomers function still reminds , it is fine to edit one of the records under the Grid.
But I couldn't edit my filtered record since it will reload all customer again.

How could I solve this issue?

Thanks.
Alex
Jul 12, 2007 at 6:33 AM
David,

I have a similar master detail requirement. I have a common master grid which gets loaded on page_load and when user selects a row, the details grid gets loaded. Also, the master grid is same accross multiple pages only the detail grid changes entity objects.

Can you provide me some help on how I should proceed using WCSF to achive the functionality. Can I have one example using Castle ActiveRecord in WCSF.


Thanks,
KK
Jul 12, 2007 at 2:51 PM
These are all great questions.

I think you can find much of what you are looking for on the ASP.NET website. There are quite a few examples showing how to display, filter, and sort data along with some good examples of master-detail relationships. There is nothing different about doing it with WCSF other than you have the option of using the ObjectContainerDataSource Control.

Here is a URL:

ASP.NET 2.0 Data Access Tutorials

Regards,

Dave

__________________________________

David Hayden
Microsoft MVP C#
Jul 12, 2007 at 6:14 PM
Thanks David,

I was actually looking at that site but got confused if it does work the same way in WCSF due to Model View pattern.
Sorry..I have 2 more question..

What is the difference in using ObjectContainerDataSource and ObjectDataSource in WCSF?

Since I will be using same Master grid and dataset accross many pages to select records, what will be the best OO page design? Is it possible to place the master grid in master page and cache the dataset on init so it will be available for all derived pages?


Thanks in advance!
KK

Jul 25, 2007 at 1:12 AM
David,

I have few question on trying to use your sample...

1) Do we need to use both Presenter and Controller layer or is it to many layers to maintain?

2) If I use the above model, what is the best location( presenter/controller) to include business/init logic in update/insert operations? say Saved date,User or some calculations.

I am trying to use your sample as reference for my application development using WCSF...not sure if I need to change something with respect to Controller/Presenter or just use the same model.

Thanks,

Jul 25, 2007 at 10:42 PM
The purpose of the presenter class is to maximize the amount of code you can test in the presentation layer, because web pages are hard to test with their dependency on the HttpRuntime. Hence, you end up testing the presenter class and mocking the view, which allows you to more easily write automated tests. If you don't plan on testing the presentation layer, the Presenter class and use of the View-Presenter Pattern is unnecessary as long as you make sure you don't add logic that will need to be re-used throughout the application in the page's code-behind class. Reusable business logic would happen in the business module or perhaps a transaction script service layer.

In my simple CRUD example, I could have bypassed the controller and worked directly with the ICustomerDAO Service in my Presenter Class or Page Code-Behind because my controller class is doing nothing useful. It is only passing on the request to the ICustomerDAO Service. However, typically the call may do a number of things like check role privileges, look in the cache, and perhaps route the user to another page using Workflow, etc., which you wouldn't want to do in the Presenter Class, Code-Behind Class of the Page, or ICustomerDAO Service.

The presenter class does not do business initialization logic. It only responds to view requests ( events ) and manipulates the state of the view. Most developers don't normally put the presenters in the business layer / business module. Typically the presenters go in their own assembly / project which better shows that their intention is not to contain any sort of business logic. They are really only there for testability and encourage better separation of view / UI logic from business logic.

My purpose of adding the application controller was only to introduce it as an asset described in the documentation. It would have much more use in a non-CRUD only example.

Regards,

Dave

________________________________

David Hayden
Microsoft MVP C#
Aug 7, 2007 at 9:13 PM
Hello David,

I have a quick question on modularity /Helper class using your sample.

If I have common class/interface files that can be shared in all Business modules , what will be the best option keeping business modularity seperate from global class files?

Eg: In your sample we can use *IDatabase.cs and CustomerDatabase.cs * to be a data utility that can be shared in all business modules ( not to duplicate) and keep them seperate from Business module .

I was thinking to add them in an foundation module..but its not a global service .....not sure what will be a best approch .

Will be great if you can explain using * IDatabase.cs and CustomerDatabase.cs * files seperate from Customer Module but in a more share/utility folder


Please advice!


Aug 8, 2007 at 3:33 PM
I think you answered your own question :)

Chances are you will have some infrastructure layer services in one or more foundation modules that are to be shared by mulitple business modules. This might be things like low-level data access, logging, caching, validation, etc. You could also add them to the Shell Module, too, which is a foundation module already added via the WCSF Recipes.

IDatabase and CustomerDatabase ( properly renamed to something else ) would be more appropriate in a foundation module if you were to use them with multiple business modules. The same would be true of other services I mentioned above like logging, caching, etc.

If you find it overkill, you certainly don't have to wrap the Enteprise Library DAAB which is basically what I did with CustomerDatabase / IDatabase. You could have CustomerDAO use the DAAB directly and save you some wrapping effort if you don't need the abstraction. I was mainly showing off various features and parts of the WCSF and Enterprise Library and how they can work together.

Best Regards,

Dave

___________________________

David Hayden
Microsoft MVP C#
Aug 22, 2007 at 5:56 PM
I have a very silly question..just want to confirm from you if I was correct. This is in reference to WCSF Reference Implementation Example..
I have multiple sub modules and need to add them to the sitemap.. But I cannot do then from each ModuleInitializer class b'cos I cannot refer to Root Module.

Should I add the RootModule nood from Shell and Make " moduleRoot " as Public Static and refer in Sub Modules ( Which works)...is it the way to do it.


protected virtual void RegisterSiteMapInformation(ISiteMapBuilderService siteMapBuilderService)
{
NameValueCollection attributes = new NameValueCollection(1);
attributes"imageName" = "funds";

//Root Module Nood ( In Shell ModuleInitializer )
moduleRoot = new SiteMapNodeInfo("FIDO Main", "~/DataPoints/Default.aspx", "FIDO Main",
"Field Data Collection module", null, attributes, null, null);

siteMapBuilderService.AddNode(moduleRoot, 1);

//Sub Module node ( Need to move to sub ModuleInitializer )
SiteMapNodeInfo createEstimateNode =
new SiteMapNodeInfo("Estimates", "~/DataPoints/Estimates/Estimates.aspx", "Yield Estimates",
"New Yield Estimates");
siteMapBuilderService.AddNode(createEstimateNode, moduleRoot, "AllowCreateTransfer");

//Sub Module nood ( Need to move to sub ModuleInitializer )

SiteMapNodeInfo createPlantingNode =
new SiteMapNodeInfo("Planting", "~/DataPoints/Planting/Planting.aspx", "Planting",
"New Planting");
siteMapBuilderService.AddNode(createPlantingNode, moduleRoot, "AllowCreateTransfer");
}



Thanks
Sep 5, 2007 at 4:58 PM
Edited Sep 6, 2007 at 11:41 PM
Hello David,

I was trying to use propertyproxyvalidator in my application but I have a problem bcos of the post back. Is there any work around?

I have a master and child grid. On selection of master grid my child loads data. I can only do that on PageLoadComplete bcos I need to get the selected Row value. I have propertyproxyvalidator on the child table. If I do the child load from PageLoad with a hardcoded Selected Row value all works fine.

Here is the code ..

protected void Page_Load(object sender, EventArgs e)
{ if (!this.IsPostBack)
{
this._presenter.OnViewInitialized();
gridFPO.SelectedIndex = 0;
}
}
// **** propertyproxyvalidator works from here *******
/// this._presenter.OnSelect(89102);
}

protected void Page_LoadComplete(object sender, EventArgs e)
{

if (this.IsPostBack)
{
// **** propertyproxyvalidator DOES NOT work from here *******
this._presenter.OnSelect((int)gridFPO.SelectedValue);

}

}