Corporate Purchase Process

.NET Framework (current version)
 

This sample shows how to create a very basic Request for Proposals (RFP) based purchase process with automatic best proposal selection. It combines Parallel, ParallelForEach<T>, and ForEach<T> and a custom activity to create a workflow that represents the process.

This sample contains an ASP.NET client application that allows interacting with the process as different participants (as the original requester or a particular vendor).

  • Visual Studio 2012.

  • .NET Framework 4.6.1.

  • Custom activities.

  • Composition of activities.

  • Bookmarks.

  • Persistence.

  • Schematized persistence.

  • Tracing.

  • Tracking.

  • Hosting WF in different clients (ASP.NET Web applications and WinForms applications).

System_CAPS_ICON_important.jpg Important

The samples may already be installed on your machine. Check for the following (default) directory before continuing.

<InstallDrive>:\WF_WCF_Samples

If this directory does not exist, go to Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4 to download all Windows Communication Foundation (WCF) and WF samples. This sample is located in the following directory.

<InstallDrive>:\WF_WCF_Samples\WF\Application\PurchaseProcess

This sample shows an implementation of a Windows Workflow Foundation (WF) program to gather proposals from vendors for a generic company.

  1. An employee of Company X creates a Request for Proposal (RFP).

    1. The employee types in the RFP title and description.

    2. The employee selects the vendors that he wants to invite to submit proposals.

  2. The employee submits the proposal.

    1. An instance of the workflow is created.

    2. The workflow is waiting for all vendors to submit their proposals.

  3. After all proposals are received, the workflow iterates through all the received proposals and selects the best one.

    1. Each vendor has a reputation (this sample stores the reputation list in VendorRepository.cs).

    2. The total value of the proposal is determined by (The value typed in by the vendor) * (The vendor's recorded reputation) / 100.

  4. The original requester can see all the submitted proposals. The best proposal is presented in a special section in the report.

The core logic of the sample uses a ParallelForEach<T> activity that waits for the offers from each vendor (using a custom activity that creates a bookmark), and registers the vendor proposal as an RFP (using an InvokeMethod activity).

The sample then iterates through all of the received proposals stored in the RfpRepository, calculating the adjusted value (using an Assign activity and System.Activities.Expressions activities), and if the adjusted value is better than the previous best offer, assigns the new value as the best offer (using If and Assign activities).

This sample contains the following projects.

ProjectDescription
CommonThe entity objects used within the process (Request for Proposal, Vendor, and Vendor Proposal).
WfDefinitionThe definition of the process (as a WF program) and host (PurchaseProcessHost) used by client applications for creating and using instances of the purchase process workflow.
WebClientAn ASP.NET client application that allows the users to create and participate in instances of the purchase process. It uses a custom-created host to interact with the workflow engine.
WinFormsClientA Windows Forms client application that allows the users to create and participate in instances of the purchase process. It uses a custom-created host to interact with the workflow engine.

WfDefinition

The following table contains a description of the most important files in the WfDefinition project.

FileDescription
IPurchaseProcessHost.csInterface for the host of the workflow.
PurchaseProcessHost.csImplementation of a host for the workflow. The host abstracts the details of the workflow runtime and is used in all the client applications to load, run, and interact with PurchaseProcess workflow instances.
PurchaseProcessWorkflow.csAn activity that contains the definition of the Purchase Process workflow (derives from Activity).

Activities that derive from Activity compose functionality by assembling existing custom activities and activities from the .NET Framework 4.6.1 activity library. Assembling these activities is the most basic way to create custom functionality.
WaitForVendorProposal.csThis custom activity derives from NativeActivity and creates a named bookmark that must be resumed later by a vendor when submitting the proposal.

Activities that derive from NativeActivity, like those that derive from CodeActivity, create imperative functionality by overriding Execute, but also have access to all of the functionality of the workflow runtime through the ActivityContext that gets passed into the Execute method. This context has support for scheduling and canceling child activities, setting up no-persist zones (execution blocks during which the runtime does not persist the workflow’s data, such as within atomic transactions), and Bookmark objects (handles for resuming paused workflows).
TrackingParticipant.csA TrackingParticipant that receives all tracking events and saves them to a text file.

Tracking participants are added to workflow instance as Extensions.
XmlWorkflowInstanceStore.csA custom InstanceStore that saves workflow applications to XML files.
XmlPersistenceParticipant.csA custom PersistenceParticipant that saves an instance of request for proposal to an XML file.
AsyncResult.cs / CompletedAsyncResult.csHelper classes for implementing the asynchronous pattern in the persistence components.

Common

The following table contains a description of the most important classes in the Common project.

ClassDescription
VendorA vendor that submits proposals in a Request for Proposals.
RequestForProposalA request for proposals (RFP) is an invitation for vendors to submit proposals on a specific commodity or service.
VendorProposalA proposal submitted by a vendor to a concrete RFP.
VendorRepositoryThe repository of Vendors. This implementation contains an in-memory collection of instances of Vendor and methods for exposing those instances.
RfpRepositoryThe repository of Requests for Proposals. This implementation contains uses Linq to XML to query the XML file of Requests for Proposal generated by the schematized persistence. This class implements T:System.Runtime.Persistence.IDataViewMapper.
IOHelperThis class handles all I/O-related issues (folders, paths, and so on.)

Web Client

The following table contains a description of the most important Web pages in the Web Client project.

FileDescription
CreateRfp.aspxCreates and submits a new Request for Proposals.
Default.aspxShows all active and completed Requests for Proposals.
GetVendorProposal.aspxGets a proposal from a vendor in a concrete Request for Proposals. This page is used only by vendors.
ShowRfp.aspxShow all the information about a Request for Proposals (received proposals, dates, values, and other information). This page is only used by the creator of the Request for Proposal.

WinForms Client

The following table contains a description of the most important forms in the Win Forms project.

FormDescription
NewRfpCreates and submits a new Request for Proposals.
ShowProposalsShow all active and finished Requests for Proposals. Note: You may need to click the Refresh button in the UI to see changes in that screen after you create or modify a Request for Proposal.
SubmitProposalGet a proposal from a vendor in a concrete Request for Proposals. This window is used only by vendors.
ViewRfpShow all the information about a Request for Proposals (received proposals, dates, values, and other information). This window is only used by the creator of the Request for Proposals.

Persistence Files

The following table shows the files generated by the persistence provider (XmlPersistenceProvider) are located in the path of the current system's temporary folder (using GetTempPath). The tracing file is created in the current execution path.

File NameDescriptionPath
rfps.xmlThe XML file with all the active and finished Requests for Proposals.GetTempPath
[instanceid]This file contains all the information about a workflow instance.

This file is generated by the schematized persistence implementation (PersistenceParticipant in XmlPersistenceProvider).
GetTempPath
[instanceId].trackingA text file with all the events that occurred within a concrete instance.

This file is generated by TrackingParticipant.
GetTempPath
PurchaseProcess.Tracing.TraceLog.txtThe tracing file generated by the workflow based on the configuration parameters in the App.config or Web.config files.Current execution path

To use this sample

  1. Using Visual Studio 2010, open the PurchaseProcess.sln solution file.

  2. To execute the Web Client project, open Solution Explorer and right-click the Web Client project. Select Set as Startup Project.

  3. To execute the WinForms Client project, open Solution Explorer and right-click the WinForms Client project. Select Set as Startup Project.

  4. To build the solution, press CTRL+SHIFT+B.

  5. To run the solution, press CTRL+F5.

Web Client Options

  • Create a new RFP: Creates a new Request for Proposals (RFP) and starts a Purchase Process workflow.

  • Refresh: Refreshes the list of Active and Finished RFPs in the main window.

  • View: Shows the content of an existing RFP. Vendors can submit their proposals (if invited or the RFP is not finished).

  • View As: The user can access the RFP using different identities by selecting the desired participant in the View as combo box in the active RFPs grid.

WinForms Client Options

  • Create RFP: Creates a new Request for Proposals (RFP) and starts a Purchase Process workflow.

  • Refresh: Refreshes the list of Active and Finished RFPs in the main window.

  • View RFP: Shows the content of an existing RFP. Vendors can submit their proposals (if invited or the RFP is not finished)

  • Connect As: The user can access the RFP using different identities by selecting the desired participant in the View as combo box in the active RFPs grid.

Show: