Installing and Running Guidance | Technical Challenges

Scenarios and Solutions

This topic describes the solution notes for a set of technical challenges the reference implementation handles.

Authentication

The reference implementation uses Forms Authentication with a custom ASP.NET membership provider to authenticate users:
  • User names: jblack, sbuch, msuya, a-jdoe, and a-lcal
  • Password: P@ssw0rd
To log in to the reference implementation
  1. Run the reference implementation.
  2. Click Login.
  3. When the Web page displays the Log In prompt, enter a user name and password, and then click the Log In button. The site will display the Order Management Module home page.

Implementation Notes

The reference implementation uses forms authentication with a simplistic implementation of an ASP.NET membership provider (the custom provider uses an XML file and allows the reference implementation to run without requiring a database). The Web.config file specifies the authentication mechanism and the provider as illustrated in the following XML.

<authentication mode="Forms">
  <forms loginUrl="login.aspx" name=".ASPXFORMSAUTH"/>
</authentication>
. . . 
<membership defaultProvider="RepositoryMembershipProvider">
  <providers>
    <clear/>
    <add name="RepositoryMembershipProvider" type="OrdersRepository.Services.Authentication.RepositoryMembershipProvider, OrdersRepository.Services"/>
  </providers>
</membership>

This provider reads the employee information from the OrdersData.xml file in the OrdersRepositoryService project. The employee information is shown in the following XML.

<Employees>
  <EmployeeId>jblack</EmployeeId>
  <LastName>Black</LastName>
  <FirstName>Joe</FirstName>
</Employees>
<Employees>
  <EmployeeId>a-jdoe</EmployeeId>
  <LastName>Doe</LastName>
  <FirstName>John</FirstName>
</Employees>
<Employees>
  <EmployeeId>sbuch</EmployeeId>
  <LastName>Buchanan</LastName>
  <FirstName>Steven</FirstName>
</Employees>
<Employees>
  <EmployeeId>msuya</EmployeeId>
  <LastName>Suyama</LastName>
  <FirstName>Michael</FirstName>
</Employees>
<Employees>
  <EmployeeId>a-lcal</EmployeeId>
  <LastName>Callahan</LastName>
  <FirstName>Laura</FirstName>
</Employees>

Authorization

The reference implementation supports two types of users.
  • Regular. A regular user can create orders, save orders to be submitted later, and submit orders. The following users are regular users:
    • Joe Black
    • Steven Buchanan
    • Michael Suyama
  • Approver. An approver can create orders and also approve orders that have been submitted. The following users have approval authority:
    • John Doe
    • Laura Callahan
To log in as a regular user
  1. Run the reference implementation.
  2. Click Login.
  3. When the Web page displays the Log In prompt, type jblack in the User Name text box, type P@ssw0rd in the Password text box, and then click the Log In button. The site will display the Order Management Module home page.
To log in as an approver
  1. Run the reference implementation.
  2. Click Login.
  3. When the Web page displays the Log In prompt, type a-lcal in the User Name text box, type P@ssw0rd in the Password text box, and then click the Log In button. The site will display the Order Management Module home page.

Implementation Notes

The reference implementation uses the Enterprise Library Security Application Block to implement authorization. The application is configured to use the Rules Authorization Provider, a provider that uses authorization rules that you define in the Web.config file, as shown in the following XML.

<securityConfiguration defaultAuthorizationInstance="RuleProvider" defaultSecurityCacheInstance="">
  <authorizationProviders>
    <add type="Microsoft.Practices.EnterpriseLibrary.Security.AuthorizationRuleProvider, Microsoft.Practices.EnterpriseLibrary.Security, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" name="RuleProvider">
      <rules>
        <add expression="R:Approver" name="AllowApprovals"/>
        <add expression="R:User" name="AllowAutocomplete"/>
        <add expression="R:User" name="AllowCreateOrders"/>
        <add expression="R:User" name="AllowBrowseOrders"/>
      </rules>
    </add>
  </authorizationProviders>
</securityConfiguration>

Profile-based User Interface

The application uses role-based authorization to determine what features it exposes to the current user. The commands that appear in the left side of the Web page are specific to the user’s role. Figure 1 illustrates the differences in the user interface (UI) for a regular user and an approver.
RoleSpecificUserInterface.png
Figure 1
Role-specific user interface.

Implementation Notes

The reference implementation uses a custom site map provider to display the role-based tasks. A site map is an in-memory representation of the navigation structure for a site, which is provided by one or more site map providers. The Composite Web Application Block includes the custom site map data provider class ModuleSiteMapProvider. This class supports authorization rules that control whether a site map node can be viewed by the current user. This class uses the IAuthorizationService to implement the IsAccessibleToUser method.
The reference implementation Web.config file defines the custom site map provider as shown in the following XML.

<siteMap defaultProvider="DefaultSiteMapProvider" enabled="true">
  <providers>
    <add name="DefaultSiteMapProvider" type="Microsoft.Practices.CompositeWeb.Providers.ModuleSiteMapProvider, Microsoft.Practices.CompositeWeb" securityTrimmingEnabled="true" />
  </providers>
</siteMap>

Modularity

The reference implementation includes the following two modules:
  • Customers module. This module handles and search of customer information.
  • Orders module. This module handles the creation and approval of orders.
The following descriptions apply to the modules:
  • Each module is designed to demonstrate different technical challenges. Each one is an independent entity that can be developed, deployed, and tested in isolation from each the other modules.
  • Each module has a collection of artifacts and abstractions, such as views, presenters, controllers, and business components; these artifacts follow the design patterns documented in the software factory (for example, the View-Presenter pattern).
  • Each module uses the Composite Web Application Block. This means they all follow a common architecture. For example, they all use dependency injection to manage component dependencies and simplify object creation.
  • The presenters for the views and user controls, the business entities, and any other non-visual components are implemented and packaged in one or more assemblies. The visual components of the modules (the views) are implemented as Web pages and are located in corresponding module folders under the DevelopmentWebsite project

Implementation Notes

When your Web client application starts, the Composite Web Application Block locates the Web.config files in the Web site and looks for a configuration section that contains module information. The application block uses this information to load module assemblies. The declaration of the Customers module assembly information, contained in the Web.config file for that module, is shown in the following XML.

<modules>
  <module name="Customers" assemblyName="Customers" virtualPath="~/Customers">
    <dependencies>
      <dependency module="Shell" />
    </dependencies>
    <services>
      <service registerAs="OrdersRepository.Interfaces.Services.ICustomerService, OrdersRepository.Interfaces" type="OrdersRepository.Services.CustomerService, OrdersRepository.Services" scope="Global" />
    </services>
  </module>
</modules>

Initialization for each module is performed in the module's ModuleInitializer class. The modules perform the following tasks in this class:
  • Registration of the module node in the site map
  • Registration of any module's permissions to the PermissionsCatalog class
The following code from the Customers module illustrates how the module adds two nodes to the site map. The custom site map provider uses the specified authorization rule (AllowSearchCustomers) to evaluate whether the site map node is displayed for the current user.

protected virtual void RegisterSiteMapInformation(ISiteMapBuilderService siteMapBuilderService)
{
  SiteMapNodeInfo moduleNode = new SiteMapNodeInfo("Customers", "~/Customers/Default.aspx", "Customers");
  siteMapBuilderService.AddNode(moduleNode, "AllowSearchCustomers");

  SiteMapNodeInfo searchCustomerNode =
                new SiteMapNodeInfo("SearchCustomer", "~/Customers/SearchCustomers.aspx", "Search Customers");
  siteMapBuilderService.AddNode(searchCustomerNode, moduleNode, " AllowSearchCustomers ");
} 

The Web.config file for the Customers module specifies that the AllowSearchCustomers rule is to be used to evaluate whether a user can browse directly to the Web pages in the Customers module.

<authorization>
  <rule Url="~/Customers/Default.aspx" Rule="AllowBrowseOrders" />
  <rule Url="~/Customers/SearchCustomers.aspx" Rule="AllowBrowseOrders" />

  <rule Url="~/Customers/CustomerAutoCompleteService.asmx/GetCustomersName" Rule="AllowAutocomplete" />
</authorization>

The Web.config file for the DevelopmentWebsite Web site defines the authorization rules. In the reference implementation, the AllowSearchCustomers rule evaluates to true if the current user is a regular user. The following XML illustrates the rules defined in the DevelopmentWebsite Web site Web.config file.

<rules>
  <add expression="R:Approver" name="AllowApprovals"/>
  <add expression="R:User" name="AllowAutocomplete"/>
  <add expression="R:User" name="AllowCreateOrders"/>
  <add expression="R:User" name="AllowBrowseOrders"/>
  <add expression="R:User" name="AllowSearchCustomers"/>
</rules>

Page Composability

The reference implementation demonstrates Web pages that are composed of user controls. A user control can exist in one module and be used both by that module and by other modules.
To view the SearchCustomer user control
  1. Run the reference implementation and log on to the application (you can log on as either a regular user or an approver).
  2. Click Search Customers in the left sidebar. The application displays the SearchCustomer user control, as illustrated in Figure 2.
SearchCustomerUserControl.png
Figure 2
SearchCustomer user control.

Implementation Notes

The Customers module contains the SearchCustomer user control (you can find the user control in the Parts folder under the Customers folder in the DevelopmentWebsite Web site). The user control is used both by a Web page in the Customers module and also by a Web page in the Orders module.
The SearchCustomer user control derives from the Microsoft.Practices.CompositeWeb.Web.UI.UserControl class of the Composite Web Application Block.

public partial class Customers_SearchCustomer : Microsoft.Practices.CompositeWeb.Web.UI.UserControl, ISearchCustomer


This base class contains code that initiates dependency injection for the user control. For example, the user control has an associated presenter, SearchCustomerPresenter, and the application block injects the presenter into the user control.

[CreateNew]
public SearchCustomerPresenter Presenter
{
  set
  {
    this._presenter = value;
    this._presenter.View = this;
  }
} 

Through dependency injection, the presenter obtains a reference to two services, as illustrated in the following code.

public SearchCustomerPresenter(
[ServiceDependency] IFindCustomerService findCustomerService,
[ServiceDependency] IPostalInfoLookupService postalInfoLookupService)
{
  _findCustomerService = findCustomerService;
  _postalInfoLookupService = postalInfoLookupService;
} 

The Customers module contains an implementation of the IFindCustomerService service and registers it as a global service, as shown in the following code.

protected virtual void AddGlobalServices(IServiceCollection globalServices)
{
  globalServices.AddNew<FindCustomerService, IFindCustomerService>();
} 

The service must be a global service to allow Web pages in other modules to use the user control. (If the Customers module registered the service as a module service, the Orders module Web pages would not have access to the service, and therefore would not be able to use the user control).
In the OrderInformation user control, the Select and Cancel buttons are part of the OrderInformation user control, and not part of the SearchCustomers control. Figure 3 illustrates the boundary of the SearchCustomers user control as it appears on the OrderInformation Web page.
SearchCustomerUserControl_OrderInformationWebPage.png
Figure 3
SearchCustomer user control on the OrderInformation Web page.

When you click Select, the OrderInformation user controls calls the SearchCustomer user control to retrieve the selected company.

Responsive User Interface

The reference implementation demonstrates the user of ASP.NET AJAX to provide a responsive user interface.
To view the ModalPopupExtender control
  1. Run the reference implementation and log on to the application (you can log on as either a regular user or an approver).
  2. Click Create New Order in the left sidebar.
  3. Click the magnifier glass to the right of the Customers text box.
To view the ConfirmButtonExtender control
  1. Run the reference implementation and log on to the application (you can log on as either a regular user or an approver).
  2. Click Create New Order in the left sidebar.
  3. Enter the details for the new order, and then click Next.
  4. On the Order Details page, add a new product, and then click Preview Order.
  5. On the Review page, click Submit.
To view the AutoCompleteExtender control
  1. Run the reference implementation and log on to the application (you can log on as either a regular user or an approver).
  2. Click Create New Order in the left sidebar.
  3. Type the letter L in the Customers text box and pause. The reference implementation displays a list of suggested values.
To view the CollapsiblePanelExtender control
  1. Run the reference implementation.
  2. Click the Technical Information panel CollapsiblePanel control in the top-right region of the Welcome page.

Implementation Notes

The reference implementation uses several controls provided by Microsoft ASP.NET AJAX and the AjaxControlToolkit to improve the user interface responsiveness. The following code (extracted from the DevelopmentWebSite\OrderEntry\OrderInformation.ascx file) shows the declaration of the ModalPopupExtender control used to display the customer search dialog box, together with the pop-up panel and the button that fires the ModalPopupExtender.

<asp:ImageButton 
  ID="SearchCustomerButton" ... />
<ajaxtoolkit:ModalPopupExtender
  ID="CustomerModalPopupExtender"
  runat="server"
  TargetControlID="SearchCustomerButton"
  BackgroundCssClass="modalBackground"
  PopupControlID="SearchCustomerModalPopupPanel"
  OkControlID="SelectButton"
  DropShadow="true">
</ajaxtoolkit:ModalPopupExtender>
<asp:Panel
  Style="display: none"
  ID="SearchCustomerModalPopupPanel" 
  ...>
  ...
</asp:Panel>

The following code (extracted from the DevelopmentWebSite\OrderEntry\OrderReview.ascx file) shows the declaration of the ConfirmButtonExtender control used to display the confirmation dialog box, together with the button that fires the dialog box.

<asp:ImageButton
  ID="SubmitButton"
  runat="server"
  OnClick="SubmitButton_Click"
  SkinID="NavButtonDefault"
  ImageUrl="~/Images/submit_light.png"/>
<ajaxtoolkit:ConfirmButtonExtender
  ID="SubmitButtonConfirmationExtender"
  runat="server"
  TargetControlID="SubmitButton"
  ConfirmText="Are you sure you want to submit this order?" />

The following code (extracted from the DevelopmentWebSite\OrderEntry\OrderInformation.ascx file) shows the declaration of the AutoCompleteExtender control used to provide a list of suggested customers for the customerTextBox control, together with the customerTextBox control declaration.

<asp:TextBox
  ID="customerTextBox"
  runat="server"
  Width="320px">
</asp:TextBox>

...

<ajaxtoolkit:AutoCompleteExtender
  ID="CustomerAutoComplete"
  runat="server"
  TargetControlID="customerTextBox"
  CompletionSetCount="30"
  CompletionInterval="400"
  MinimumPrefixLength="1"
  ServiceMethod="GetCustomersName"
  ServicePath="~/Customers/CustomerAutoCompleteService.asmx"
  EnableCaching="true">
</ajaxtoolkit:AutoCompleteExtender>

The following code (extracted from the DevelopmentWebSite\Default.aspx file) shows the declaration of the CollapsiblePanelExtender control used to dynamically show and hide the Technical Information panel, together with the related elements that collaborate to compose the dynamic panel.

<asp:Panel ID="PanelDevInfo" runat="server">
  <asp:Panel ID="CollapsingDevPanelHeader" ...>...</asp:Panel>
  <asp:Panel ID="CollapsingDevPanel" ...>...</asp:Panel>
</asp:Panel>

...

<ajaxtoolkit:CollapsiblePanelExtender
  ID="bob"
  runat="server"
  CollapseControlID="CollapsingDevPanelHeader"
  ExpandControlID="CollapsingDevPanelHeader"
  TargetControlID="CollapsingDevPanel"
  CollapsedImage="~/Images/expand.jpg"
  ExpandedImage="~/Images/collapse.jpg"
  ImageControlID="ImageExpandCollapse"
  SuppressPostBack="true"
  Collapsed="true"
  CollapsedSize="0"
  ExpandDirection="Vertical" />

Respond to Browser Field Events

To see the application respond to browser field events
  1. Run the reference implementation and log on to the application (you can log on as either a regular user or an approver).
  2. Click Create New Order in the left sidebar.
  3. Enter the details for the new order, and then click Next.
  4. Click Add.
  5. Click the magnifier glass next to the Sku text box.
  6. Type L in the Product text box.
  7. Click Teatime Chocolate Biscuits.
  8. Change the value in the Quantity text box to 5, and then press the TAB key.

Implementation Notes

The reference implementation includes a custom extender control named ClientScriptCallExtender that enables developers to invoke client (JavaScript) functions declaratively in response to browser field events. When you use the extender, a client function will be invoked whenever the extended control changes its value. You can pass parameters to the client function. The following code extracted from the file DevelopmentWebSite\Orders\OrderEntry\OrderDetails.ascx shows the declaration of the ClientScriptCallExtender control used to calculate the total price of a line item, together with the text box that it extends.

<ce:ClientScriptCallExtender
  ID="QtyTextBoxCallExtender"
  CustomScript="CalculateTotal"
  TargetControlID="QtyTextBox"
  runat="server">
  <CustomScriptParameters>
    <ce:CustomScriptParameter ControlId="PriceLabel" />
    <ce:CustomScriptParameter ControlId="ItemTotalLabel" />
    <ce:CustomScriptParameter Value="$" />
  </CustomScriptParameters>
</ce:ClientScriptCallExtender>
<asp:TextBox
  ID="QtyTextBox"
  runat="server"
  Text='<%# Bind("Quantity") %>'
  Columns="5">
</asp:TextBox>

Responsive Validation

To see the application perform responsive validation
  1. Run the reference implementation and log on to the application (you can log on as either a regular user or an approver).
  2. Click Create New Order in the left sidebar.
  3. Leave the order details blank, and then click Next.
Figure 4 illustrates the Order Information form with validators indicating that the input fields cannot be empty.
ValidatorsInTheOrderInformationPage.png
Figure 4
Validators in the Order Information page.

Implementation Notes

The OrderInformation user control uses ASP.NET validation controls, as shown in the following code. With these controls, validation is performed both on the client and on the server.

<asp:RequiredFieldValidator ID="ApproverRequiredValidator" runat="server" 
  ControlToValidate="ApprovedByDropDown" Display="Dynamic" 
  ErrorMessage="*">
</asp:RequiredFieldValidator>

The Web page also uses the ASP.NET CustomValidator control. This control performs user-defined validation on an input control. With the following code from the OrderInformation user control, ASP.NET will call the ExistenceApproverValidator_ServerValidate method to validate the value in the ApprovedDropDown control.

<asp:CustomValidator ID="ExistenceApproverValidator" runat="server" 
  ControlToValidate="ApprovedByDropDown" Display="Dynamic" 
  ErrorMessage="Invalid approver" 
  OnServerValidate="ExistenceApproverValidator_ServerValidate">
</asp:CustomValidator>

Finally, the reference implementation uses the ServerSideValidationExtender ASP.NET AJAX control extender. It uses this extender with the CustomValidator control to perform asynchronous server-side validation for a control without requiring a full Web page postback.

<ajaxtoolkitwcsfextensions:ServerSideValidationExtender 
  ID="CustomerServerSideValidation"
  runat="server" TargetControlID="ExistenceCustomerValidator" />

<asp:CustomValidator
  ID="ExistenceCustomerValidator" runat="server" 
  ControlToValidate="customerTextBox"
  ErrorMessage="Invalid customer" 
  OnServerValidate="ExistenceCustomerValidator_ServerValidate">
</asp:CustomValidator>

Installing and Running Guidance | Technical Challenges

Last edited Nov 8, 2007 at 1:25 PM by siacomuzzi, version 2

Comments

No comments yet.