This project is read-only.

Admin Module implementation

In this module, the user (with administrator privileges) can get all registered users information, get orders details and change the order status.
structure.png
Fig. 1 | On the left, the solution structure showing the modules implemented. On the right, an initial diagram showing Product and Admin modules definitions and dependencies.

Some notes regarding the structure described in the picture:

  • The Admin business module would be created as a sub Web Application Project (sub WAP) in order to have it as a separate project and allow us to work separately on the different parts of the application.
  • The Security foundational module exposes AspNetXmlMembershipProvider service (Authentication provider) and AspNetXmlRoleProvider service (Authorization provider) that store membership data in an XML file.

Update order status using ObjectContainerDataSource

In the View-Presenter pattern, the presenter contains the logic to respond to user events (such as updating or retrieving data) and manipulates the state of the view. The WC-SF contains the data source control ObjectContainerDataSource. This control implements data binding in a way that easily integrates with the View-Presenter pattern.

The presenter for the DefaultView calls the ShowOrders method of the view when the view loads. This means that after the view loads it will display all available orders.
public void ShowOrders(ICollection<Order> orders)
{
    OrdersObjectContainerDataSource.DataSource = orders;
}


To support update operations, the view forward the OnUpdated event to the presenter, as shown in the following code.
  • Default.aspx:
protected void OrdersObjectContainerDataSource_Updated(object sender, ObjectContainerDataSourceStatusEventArgs e)
{
    _presenter.OnEditOrder((Order)e.Instance);
}

  • DefaultViewPresenter:
public void OnEditOrder(Order order)
{
    _controller.UpdateOrderStatus(order);

    LoadOrders();
}

  • AdminController:
public void UpdateOrderStatus(Order order)
{
    _ordersService.ChangeOrderStatus(order.OrderId, order.OrderStatus);
}

Security

AspNetXmlMembershipProvider (and AspNetXmlRoleProvider) uses an XML file with a schema matching that of the below as its data source. Each <User> element defines one membership user.
<Users>
  <User>
    <UserName>admin</UserName>
    <Password>P@$$w0rd</Password>
    <EMail>admin@contoso.com</EMail>
    <Roles>Members,Administrators</Roles>
  </User>
  <User>
    <UserName>member</UserName>
    <Password>P@$$w0rd</Password>
    <EMail>member@contoso.com</EMail>
    <Roles>Members</Roles>
  </User>
</Users>


AspNetXmlMembershipProvider (and AspNetXmlRoleProvider) supports one custom configuration attribute: xmlFileName. The provider's Initialize method initializes a private field named _XmlFileName with the attribute value and defaults to ~/App_Data/MembershipUsers.xml if the attribute isn't present.

The Web.config file below registers AspNetXmlMembershipProvider (and AspNetXmlRoleProvider), makes it the default membership provider, and points it to ~/App_Data/Users.xml (located in the application root) as the data source.
<membership defaultProvider="AspNetXmlMembershipProvider">
  <providers>
    <add name="AspNetXmlMembershipProvider" type="WCSFContrib.ECommerceCatalog.Security.Services.Authentication.XmlMembershipProvider" xmlFileName="~/App_Data/Users.xml" description="Stores membership data in an XML file"/>
  </providers>
</membership>

<roleManager enabled="true" defaultProvider="AspNetXmlRoleProvider">
  <providers>
    <add name="AspNetXmlRoleProvider" type="WCSFContrib.ECommerceCatalog.Security.Services.Authorization.XmlRoleProvider" xmlFileName="~/App_Data/Users.xml" description="XML role provider"/>
  </providers>
</roleManager>

Test driven developing our global services

The next step after creating the services was to create our views. WC-SF encourages the usage of the Model-View-Presenter (MVP) pattern in our views. This pattern allows us to do TDD in order to model the relationship between the presenter and its views.

Let’s take the Admin’s Default view as an example. This would be a simple view, it should:
  • Show orders list.
  • Show user accounts list.
  • Update order status.

We used mock views and services in order to test our interactions without having to deal with the real implementations. For this view we would use a mock Default view and a mock Admin Controller.

So first we created the Default view and presenter inside the Admin module. The result of running the recipe was:
  • IDefaultView (Interface) and DefaultViewPresenter inside the Admin project.
  • DefaultViewPresenterFixture inside the Admin.Tests project.
  • Default page inside the Admin.Web sub Web Application Project.

Below are the tasks that were followed to create this view:
1. Create the view interface.
public interface IDefaultView
{
    void ShowOrders(ICollection<Order> orders);
    int TotalOrdersCount { get; set; }
    void ShowUsers(MembershipUserCollection users);
}


2. Create a mock view.
class MockDefaultView : IDefaultView
{
    public bool ShowOrdersCalled = false;
    public bool TotalOrdersCountCalled = false;
    public bool ShowUsersCalled = false;
    public bool TotalUsersCountCalled = false;

    private int _totalOrders = 2;
    private int _totalUsers = 5;

    #region IDefaultView Members

    public void ShowOrders(ICollection<Order> orders)
    {
        ShowOrdersCalled = true;
    }

    public int TotalOrdersCount
    {
        get
        {
            return _totalOrders;
        }
        set
        {
            _totalOrders = value;
            TotalOrdersCountCalled = true;
        }
    }

    public void ShowUsers(MembershipUserCollection users)
    {
        ShowUsersCalled = true;
    }

    public int TotalUsersCount
    {
        get
        {
            return _totalUsers;
        }
        set
        {
            _totalUsers = value;
            TotalUsersCountCalled = true;
        }
    }

    #endregion
}


3. Create a mock controller.
public class MockAdminController : IAdminController
{
    public bool GetOrdersCalled = false;
    public bool UpdateOrderStatusCalled = false;

    private ICollection<Order> _orders = new Collection<Order>();

    #region IAdminController Members

    public ICollection<Order> GetOrders()
    {
        _orders.Add(new Order(1, "userTest", DateTime.Now, null, null, OrderStatus.Open, null, null));
        _orders.Add(new Order(2, "userTest", DateTime.Now, null, null, OrderStatus.Open, null, null));

        GetOrdersCalled = true;

        return _orders;
    }

    public void UpdateOrderStatus(Order order)
    {
        UpdateOrderStatusCalled = true;
    }

    #endregion
}


4. Make a list of tests:
  • ShouldShowInfoOnViewLoaded
  • ShouldChangeOrderStatus

5. Take a test and code it. Try to compile, it shouldn’t.
[TestMethod]
public void ShouldChangeOrderStatus()
{
    DefaultViewPresenter presenter = GetDefaultViewPresenterInitialized();
    OrderStatus newOrderStatus = OrderStatus.ReadyToShip;
    Order order = new Order(1, "userTest", DateTime.Now, null, null, newOrderStatus, null, null);

    presenter.OnEditOrder(order);

    Assert.IsTrue(_controller.UpdateOrderStatusCalled);
    Assert.IsTrue(_controller.GetOrdersCalled);
    Assert.IsTrue(_view.ShowOrdersCalled);
    Assert.AreEqual(2, _view.TotalOrdersCount);
}


6. Write enough code to make it compile. Then run your test: it should fail.
public void OnEditOrder(Order order)
{
}

testFailed.png

7. Write enough code to make the test pass. Run your test: it should pass.
public void OnEditOrder(Order order)
{
    _controller.UpdateOrderStatus(order);
    LoadOrders();
}


8. You should repeat these steps for all your tests. After that, the result should be:
testPassed.png

E-Commerce Catalog – Admin Module - Walkthrough

1. If you have administrator privileges, click on the Admin node from the navigation TreeView control.

2. Here, you can see all user orders and accounts information.
adminPage.png
Fig. 2 | E-Commerce Catalog - Administrator Site.

3. Also, you can change the order status, just click in the Edit icon (editIcon.png)
editOrder.png
Fig. 3 | Change order status.

Last edited Mar 14, 2008 at 4:29 PM by mconverti, version 2

Comments

No comments yet.