Click here to Skip to main content
15,881,092 members
Articles / Web Development / HTML

Implementing WS-SecureConversation in Microsoft IssueVision

Rate me:
Please Sign up or sign in to vote.
4.61/5 (12 votes)
27 Sep 20056 min read 73.1K   776   38  
Adding secure communications to the Microsoft IssueVision sample application using WSE 2.0.
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.Windows.Forms;
using ThreadHelper;
using IssueVision.localhost;

namespace IssueVision
{
	public enum SyncThread
	{
		MainThread = 0,
		BackgroundThread = 1
	}

	public class IssueSubject : Component, ISubject
	{

#region Delagate and Event Declarations
		public delegate void PositionChangedEventHandler(object sender, EventArgs e);
		public delegate void IssueDataChangedEventHandler(object sender, EventArgs e);
		public delegate void ConflictDataChangedEventHandler(object sender, EventArgs e);
		public delegate void LookupDataChangedEventHandler(object sender, EventArgs e);
		public delegate void Synchronization_StartedEventHandler(object sender, EventArgs e);
		public delegate void Synchronization_FinishedEventHandler(object sender, EventArgs e);
		public delegate void DataChanged(IVDataSet newIssues);
		
		// PositionChanged is raised when a different issue is selected from the list
		public virtual event PositionChangedEventHandler PositionChanged;
		
		// IssueDataChanged is raised when the data changes, either because the user
		// edited the data, or because fresh data has arrived from the server
		public virtual event IssueDataChangedEventHandler IssueDataChanged;
		
		// ConflictDataChanged changes when a conflict is resolved, or new conflicts are 
		// detected.
		public virtual event ConflictDataChangedEventHandler ConflictDataChanged;
		
		// LookupDataChanged is raised when lookup data is downloaded from the server
		public virtual event LookupDataChangedEventHandler LookupDataChanged;
		
		// Synchronization_Started is raised when a background synchronization starts.
		public virtual event Synchronization_StartedEventHandler Synchronization_Started;
		
		// Synchronization_Started is raised when a background synchronization finishes.
		public virtual event Synchronization_FinishedEventHandler Synchronization_Finished;
#endregion

#region Internal Members
		private IVDataSet m_dataSet = null;
		private Timer tmrBackgroundThread;
		private BackgroundWorker BackgroundWorkerThread;

		private bool m_isBackgroundThreadRunning = false;
		private Control m_parent = null;
		private bool m_showClosedIssues = true;
		private DataView m_currentView = null;
		private DataRowView m_currentItem = null;
		private Hashtable m_conflictItems = null;
		private string m_filterTable = string.Empty;
		private string m_filterMember = string.Empty;
		private string m_filterValue = string.Empty;
		private int m_loggedInStafferID = 0;
		private string m_loggedInDisplayName = string.Empty;
		private bool m_isOnline = true;
		private static DateTime m_lastModified = new DateTime(1900, 1, 1);
#endregion

#region Public Properties
		public IVDataSet.StaffersDataTable Staffers
		{
			get
			{
				return m_dataSet.Staffers;
			}
		}

		public DataRowView CurrentItem
		{
			get
			{
				return m_currentItem;
			}

			set
			{
				m_currentItem = value;
				if (PositionChanged != null)
				{
					PositionChanged(this, EventArgs.Empty);
				}
			}
		}

		public DataView CurrentView
		{
			get
			{
				return m_currentView;
			}

			set
			{
				m_currentView = value;
			}
		}

		public Hashtable ConflictItems
		{
			get
			{
				return m_conflictItems;
			}

			set
			{
				m_conflictItems = value;
			}
		}

		public IVDataSet.ConflictsDataTable Conflicts
		{
			get
			{
				return m_dataSet.Conflicts;
			}
		}

		public bool HasConflicts
		{
			get
			{
				return Conflicts.Rows.Count > 0;
			}
		}

		public bool IsOnline
		{
			set
			{
				m_isOnline = value;
				tmrBackgroundThread.Enabled = m_isOnline;
			}
		}

		public IVDataSet.IssuesDataTable Issues
		{
			get
			{
				return m_dataSet.Issues;
			}
		}

		public IVDataSet.IssueHistoryDataTable IssueHistory
		{
			get
			{
				return m_dataSet.IssueHistory;
			}
		}

		public IVDataSet.IssueTypesDataTable IssueTypes
		{
			get
			{
				return m_dataSet.IssueTypes;
			}
		}

		public Control Parent
		{
			get
			{
				return m_parent;
			}

			set
			{
				m_parent = value;
			}
		}

		public bool ShowClosedIssues
		{
			get
			{
				return m_showClosedIssues;
			}

			set
			{
				m_showClosedIssues = value;
				PrepareCurrentView();
			}
		}
#endregion

#region Component Designer generated code
		private IContainer components = null;
		
		public IssueSubject(IContainer Container) : this()
		{
			Container.Add(this);
		}

		public IssueSubject()
		{
			InitializeComponent();
		}

		protected override void Dispose(bool disposing)
		{
			if (disposing && components != null)
			{
				components.Dispose();
			}
			base.Dispose(disposing);
		}

		[DebuggerStepThroughAttribute()]
		private void InitializeComponent()
		{
			components = new Container();
			tmrBackgroundThread = new Timer(components);
			BackgroundWorkerThread = new BackgroundWorker();
			BackgroundWorkerThread.WorkerReportsProgress = true;
			BackgroundWorkerThread.WorkerSupportsCancellation = true;
			
			tmrBackgroundThread.Tick += new EventHandler(this.tmrBackgroundThread_Tick);
			
			BackgroundWorkerThread.DoWork += new ThreadHelper.DoWorkEventHandler(this.OnDoWork);
			BackgroundWorkerThread.RunWorkerCompleted += new ThreadHelper.RunWorkerCompletedEventHandler(this.OnCompleted);
		}
#endregion

#region IssueSubject Initialization
		// Initialize the application's data and state
		public void Initialize()
		{
			// load data
			LoadIssueData();
			UpdateLastModifiedDate();
			
			if (!UserSettings.Instance.WorkOffline)
			{
				SendReceiveIssueData(SyncThread.MainThread);
			}
			
			m_showClosedIssues = true;
			
			RenderIssuesToUI();
			
			// set current user
			DataRow[] rows = Staffers.Select("UserName = \'" + UserSettings.Instance.Username + "\'");
			m_loggedInStafferID = (int)rows[0]["StafferID"];
			m_loggedInDisplayName = (string)rows[0]["DisplayName"];
			tmrBackgroundThread.Interval = int.Parse(ConfigurationSettings.AppSettings["SyncInterval"]);
		}
#endregion

#region Background Update Code
		// tmrBackgroundThread.Tick: background thread is started on timer tick
		private void tmrBackgroundThread_Tick(object sender, EventArgs e)
		{
			if (!m_isBackgroundThreadRunning)
			{
				SendReceiveIssueData(SyncThread.BackgroundThread);
			}
		}

		// entry point for Send/Receive data
		public void SendReceiveIssueData(SyncThread behavior)
		{
			if (Synchronization_Started != null)
			{
				Synchronization_Started(this, EventArgs.Empty);
			}
			
			if (behavior == SyncThread.BackgroundThread)
			{
				m_isBackgroundThreadRunning = true;
				BackgroundWorkerThread.RunWorkerAsync(m_lastModified);
			}
			else
			{
				IVDataSet newIssues = GetNewIssues(m_lastModified);
				MergeNewIssues(newIssues);
			}
		}

		// BackgroundWorkerThread.DoWork: this method is run on the background thread to do its work
		private void OnDoWork(object sender, DoWorkEventArgs doWorkArgs)
		{
			DateTime lastAccessed = (DateTime)doWorkArgs.Argument;
			doWorkArgs.Result = GetNewIssues(lastAccessed);
		}

		// sends and received data to/from the web service
		private IVDataSet GetNewIssues(DateTime lastAccessed)
		{
			IVDataSet newIssues = null;
			
			try
			{
				DataSet changesDataSet = m_dataSet.GetChanges(DataRowState.Added | DataRowState.Modified);
				newIssues = WebServicesLayer.SendReceiveIssues(changesDataSet, lastAccessed);
			}
			catch 
			{
				// Eat this exception.  It is logged on the service side, and the caller of this 
				// method tests if newIssues is null to decide whether the service is currently 
				// available.
			}
			
			return newIssues;
		}

		// BackgroundWorkerThread.RunWorkerCompleted: This method runs on the timer thread
		// when the background thread finishes it's work
		private void OnCompleted(object sender, RunWorkerCompletedEventArgs completedArgs)
		{
			// newIssues is return from the background thread to the timer thread
			IVDataSet newIssues = (IVDataSet)completedArgs.Result;
			
			// Parent.Invoke passes the newIssues data to MergeNewIssues on the MainForm thread
			m_parent.Invoke(new DataChanged(this.MergeNewIssues), new object[]{newIssues});
		}
#endregion

#region Data Merging/Display Methods
		// Merge the issue data
		private void MergeNewIssues(IVDataSet newIssues)
		{
			// Process new data, if any
			if (newIssues != null && newIssues.HasChanges(DataRowState.Unchanged))
			{
				m_dataSet.Merge(newIssues, false);
				m_dataSet.AcceptChanges();
				UpdateLastModifiedDate();
				RenderIssuesToUI();
			}
			
			m_isBackgroundThreadRunning = false;
			
			if (Synchronization_Finished != null)
			{
				Synchronization_Finished(this, EventArgs.Empty);
			}
		}

		private void RenderIssuesToUI()
		{
			PrepareLookupTables();
			PrepareConflicts();
			PrepareCurrentView();
		}

		public void SetFilter(string filterTable, string filterMember, string filterValue)
		{
			m_filterTable = filterTable;
			m_filterMember = filterMember;
			m_filterValue = filterValue;
			
			PrepareCurrentView();
		}

		// Filters current view to hide/show closed issues
		private void PrepareCurrentView()
		{
			string filterString = string.Empty;
			
			if (m_filterValue != string.Empty)
			{
				filterString = m_filterMember + " = " + m_filterValue;
			}
				
			if (!ShowClosedIssues)
			{
				if (filterString == string.Empty)
				{
					filterString = "IsOpen = 1";
				}
				else
				{
					filterString += " AND IsOpen = 1";
				}
			}
				
			if (m_filterTable == "Issues" || m_filterTable == string.Empty)
				m_currentView = new DataView(Issues);
			else
				m_currentView = new DataView(Conflicts);
				
			m_currentView.RowFilter = filterString;
			m_currentView.Sort = "IssueTypeID";
			
			if (IssueDataChanged != null)
			{
				IssueDataChanged(this, EventArgs.Empty);
			}
		}
		
		private void PrepareConflicts()
		{
			if (Conflicts != null && Conflicts.Rows.Count > 0)
			{
				ConflictItems = new Hashtable(Conflicts.Rows.Count + 1);
				
				foreach (IVDataSet.ConflictsRow clientRow in Conflicts.Rows)
				{
					clientRow.HasConflicts = true;
					IVDataSet.IssuesRow serverRow = (IVDataSet.IssuesRow)Issues.Rows.Find(clientRow.IssueID);
					ConflictItems.Add(clientRow.IssueID, new ConflictItem(clientRow, serverRow));
				}
				
				if (ConflictDataChanged != null)
				{
					ConflictDataChanged(this, EventArgs.Empty);
				}
			}
		}
		
		private void PrepareLookupTables()
		{
			if (m_dataSet.Staffers.Count == 0 && m_dataSet.IssueTypes.Count == 0)
			{
				IVDataSet lookupTables = WebServicesLayer.GetLookupTables();
				m_dataSet.Merge(lookupTables, true);
				
				if (LookupDataChanged != null)
				{
					LookupDataChanged(this, EventArgs.Empty);
				}
			}
		}

		private void UpdateLastModifiedDate()
		{
			DataView dv = new DataView(Issues);
			dv.Sort = "DateModified DESC";
			if (dv.Count > 0)
				m_lastModified = (DateTime)dv[0]["DateModified"];
		}

#endregion

#region Issue Adding, Updating and Resolving
		// Add new issue
		public void AddIssue(int stafferID, int issueTypeID, string title, string description)
		{
			DataRow rowStaffer = m_dataSet.Staffers.Select("StafferId=" + stafferID.ToString())[0];
			DataRow rowIssueType = m_dataSet.IssueTypes.Select("IssueTypeID=" + issueTypeID.ToString())[0];
			
			IVDataSet.IssuesRow row = m_dataSet.Issues.AddIssuesRow(stafferID, 
																	issueTypeID, 
																	title, 
																	description, 
																	DateTime.Now, 
																	DateTime.MinValue, 
																	true, 
																	DateTime.Now, 
																	(string)rowStaffer["UserName"], 
																	(string)rowStaffer["DisplayName"], 
																	(string)rowIssueType["IssueType"], 
																	false, 
																	true);
			
			
			if (IssueDataChanged != null)
			{
				IssueDataChanged(this, EventArgs.Empty);
			}
		}

		public void UpdateIssue(int issueID, int stafferID, string stafferName, string comment, bool isOpen)
		{
			// Find this issue in the current dataset
			DataRow dr = m_dataSet.Issues.Rows.Find(issueID);
			dr.BeginEdit();
			
			if (isOpen)
			{
				dr["IsOpen"] = 1;
			}
			else
			{
				dr["IsOpen"] = 0;
			}
			
			dr["StafferID"] = stafferID;
			dr["DisplayName"] = stafferName;
			dr.EndEdit();
			
			if (comment.Trim() != string.Empty)
			{
				m_dataSet.IssueHistory.AddIssueHistoryRow(m_loggedInStafferID, issueID, comment, DateTime.Now, m_loggedInDisplayName);
				if (IssueDataChanged != null)
				{
					IssueDataChanged(this, EventArgs.Empty);
				}
			}
		}

		public void ResolveConflict(ConflictItem conflict, bool keepClientVersion)
		{
			if (keepClientVersion)
			{
				conflict.ServerVersion["StafferID"] = conflict.ClientVersion["StafferID"];
				conflict.ServerVersion["DisplayName"] = conflict.ClientVersion["DisplayName"];
				conflict.ServerVersion["IsOpen"] = conflict.ClientVersion["IsOpen"];
			}
			
			Conflicts.Rows.Remove(conflict.ClientVersion);
			ConflictItems.Remove(conflict.ServerVersion["IssueID"]);
			((IVDataSet.IssuesRow)conflict.ServerVersion).HasConflicts = false;
			
			if (ConflictDataChanged != null)
			{
				ConflictDataChanged(this, EventArgs.Empty);
			}
			
			if (IssueDataChanged != null)
			{
				IssueDataChanged(this, EventArgs.Empty);
			}
		}
#endregion

#region DataSet Serialization Methods
		public void SaveIssueData()
		{
			string filePath = Application.UserAppDataPath + "\\" + ConfigurationSettings.AppSettings["DataSetFileName"];
			SerializationHelper.Serialize(m_dataSet, filePath);
		}

		private void LoadIssueData()
		{
			m_dataSet = GetOfflineData();
			
			if (m_dataSet == null)
			{
				m_dataSet = new IVDataSet();
			}
			
			m_dataSet.DataSetName = "IssueSubject";
			
			if (LookupDataChanged != null)
			{
				LookupDataChanged(this, EventArgs.Empty);
			}
		}

		public static IVDataSet GetOfflineData()
		{
			IVDataSet ivDataSet = null;
			
			try
			{
				string filePath = Application.UserAppDataPath + "\\" + ConfigurationSettings.AppSettings["DataSetFileName"];
				ivDataSet = (IVDataSet)SerializationHelper.Deserialize(filePath);
			}
			catch 
			{
				// Eat this exception.  The caller of this method tests if ivDataSet is null to decide whether 
				// offline data is available.
			}
			
			return ivDataSet;
		}
#endregion

#region Reporting methods
		public int GetClosedCount()
		{
			char[] delimiter = " ".ToCharArray();
			string[] filterParts = m_currentView.RowFilter.Split(delimiter);
			DataView dv = new DataView(Issues);
			
			if (filterParts[0] == "StafferID")
			{
				dv.RowFilter = "StafferID = " + filterParts[2] + " AND IsOpen = 0";
			}
			else
			{
				dv.RowFilter = "IsOpen = 0";
			}
			
			return dv.Count;
		}

		public int GetEscalatedCount()
		{
			int open = GetOpenCount();
			return (int)Math.Round(open * 0.3);
		}

		public int GetOpenCount()
		{
			char[] delimiter = " ".ToCharArray();
			string[] filterParts = m_currentView.RowFilter.Split(delimiter);
			DataView dv = new DataView(Issues);
			
			if (filterParts[0] == "StafferID")
			{
				dv.RowFilter = "StafferID = " + filterParts[2] + " AND IsOpen = 1";
			}
			else
			{
				dv.RowFilter = "IsOpen = 1";
			}
			
			return dv.Count;
		}
#endregion
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior)
United States United States
Weidong has been an information system professional since 1990. He has a Master's degree in Computer Science, and is currently a MCSD .NET

Comments and Discussions