Click here to Skip to main content
15,892,674 members
Articles / DevOps / Load Testing

Measuring and Monitoring WCF Web Service Performance

Rate me:
Please Sign up or sign in to vote.
5.00/5 (17 votes)
4 Oct 2012GPL310 min read 55.4K   2.2K   47  
Using ServiceMon to obtain performance statistics for web services
using System;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using JetBrains.Annotations;
using Kaleida.ServiceMonitor.Model;
using System.Linq;

namespace Kaleida.ServiceMonitor.UI
{
    public partial class ScriptWorkspaceControl : UserControl
    {
        private ScriptWorkspace workspace = new ScriptWorkspace();
        private bool suppressSelectedIndexChangedEvent;
        private string scriptDirectoryPath;

        public ScriptWorkspaceControl()
        {
            InitializeComponent();
            cbScripts.SelectedIndexChanged += cbScripts_SelectedIndexChanged;
            cbScripts.DisplayMember = "NameAndDirtyStatus";

        	scriptEditor.SaveRequested += (s, e) => SaveCurrentScript();
        }

        [NotNull]
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public ScriptWorkspace Workspace
        {
            get { return workspace; }
            set
            {
                if (value == null) throw new ArgumentNullException("value");
                workspace = value;
                workspace.CurrentScriptChanged += CurrentScriptChanged;
                workspace.CurrentScriptContentChanged += CurrentScriptContentChanged;
                workspace.LoadedScriptListChanged += LoadedScriptListChangedHandler;
            }
        }

        public string ScriptDirectoryPath
        {
            get { return scriptDirectoryPath; }
            set { scriptDirectoryPath = value; }
        }

        public void CurrentScriptChanged(object sender, EventArgs e)
        {
            var currentScript = workspace.CurrentScript;

            var selectedIndex = workspace.LoadedScripts.IndexOf(currentScript);
            cbScripts.SelectedIndex = selectedIndex;
            scriptEditor.Script = currentScript;

            UpdateSaveButtonState();
        }

        public void CurrentScriptContentChanged(object sender, EventArgs e)
        {
            UpdateSaveButtonState();

            cbScripts.Text = workspace.CurrentScript.GetNameAndEditState();
            RefreshComboBoxInPlace();
        }

        public void LoadedScriptListChangedHandler(object sender, EventArgs e)
        {
            ReloadComboBoxAndReselect();
        }

        private void ReloadComboBoxAndReselect()
        {
            var selectedScriptName = workspace.CurrentScript.Name;

            suppressSelectedIndexChangedEvent = true;
            cbScripts.Items.Clear();
            foreach (var script in workspace.LoadedScripts)
            {
                cbScripts.Items.Add(script.GetNameAndEditState());
            }
            suppressSelectedIndexChangedEvent = false;

            TrySelectScript(selectedScriptName);
        }

        private void RefreshComboBoxInPlace()
        {
            suppressSelectedIndexChangedEvent = true;
            for (int i = 0; i < workspace.LoadedScripts.Count; i++)
            {
                cbScripts.Items[i] = workspace.LoadedScripts[i].GetNameAndEditState();
            }
            suppressSelectedIndexChangedEvent = false;
        }

        public void TrySelectScript(string scriptName)
        {
            var matching = workspace.LoadedScripts.FirstOrDefault(i => string.Equals(i.Name, scriptName, StringComparison.OrdinalIgnoreCase));
            workspace.CurrentScript = matching ?? workspace.LoadedScripts.FirstOrDefault() ?? new NullScriptSource();
        }

        private void cbScripts_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (suppressSelectedIndexChangedEvent) return;

            var isValidScriptIndex = cbScripts.SelectedIndex >= 0 && cbScripts.SelectedIndex < workspace.LoadedScripts.Count();
            workspace.CurrentScript = isValidScriptIndex ? workspace.LoadedScripts[cbScripts.SelectedIndex] : new NullScriptSource();

            scriptEditor.Script = workspace.CurrentScript;
            
            UpdateSaveButtonState();
            scriptEditor.Focus();
        }

        private void btnNewScript_Click(object sender, EventArgs e)
        {
            var dialog = new NewScriptDialog();
            if (dialog.ShowDialog(this) == DialogResult.OK)
            {
                var newPath = Path.Combine(scriptDirectoryPath, dialog.ScriptName + ".mscr");
                if (File.Exists(newPath))
                {
                    MessageBox.Show(string.Format("A script already exists with the name '{0}'", dialog.ScriptName), "Cannot create new script", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }

                workspace.NewScript(newPath);
                
                scriptEditor.Focus();
            }
        }

        private void btnReload_Click(object sender, EventArgs e)
        {
            bool cancelled = AllowUserToSaveDirty();
            if (!cancelled)
            {
                var selectedScriptName = workspace.CurrentScript.Name;
                workspace.UnloadAllScripts();
                LoadScriptsFromScriptsDirectory();
                TrySelectScript(selectedScriptName);
            }
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            SaveCurrentScript();
        }

        public void LoadScriptsFromDisk()
        {
            LoadScriptsFromScriptsDirectory();
            UpdateSaveButtonState();
        }

        private void LoadScriptsFromScriptsDirectory()
        {
            if (!Directory.Exists(scriptDirectoryPath))
                throw new InvalidOperationException(string.Format("The required Scripts directory '{0}' does not exist", scriptDirectoryPath));

            var scriptPaths = Directory.GetFiles(scriptDirectoryPath, "*.mscr", SearchOption.AllDirectories);
            
            foreach(var scriptPath in scriptPaths)
            {
                workspace.LoadScript(scriptPath);
            }
        }

        private void UpdateSaveButtonState()
        {
            btnSave.Enabled = !(workspace.CurrentScript is NullScriptSource) && workspace.CurrentScript.IsDirty;
        }

        private void SaveCurrentScript()
        {
            workspace.SaveCurrentScript();
            UpdateSaveButtonState();
            RefreshComboBoxInPlace();
        }

        public bool AllowUserToSaveDirty()
        {
            bool cancelled = false;
            var unsavedScripts = workspace.LoadedScripts.Where(i => i.IsDirty);

            foreach (var unsavedScript in unsavedScripts)
            {
                workspace.CurrentScript = unsavedScript;

                var result = MessageBox.Show(string.Format("Save changes to '{0}'?", unsavedScript.Name), "Unsaved script", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);

                if (result == DialogResult.Cancel)
                {
                    cancelled = true;
                    break;
                }

                if (result == DialogResult.Yes)
                {
                    SaveCurrentScript();
                }
            }
            return cancelled;
        }

        private void ScriptWorkspaceControl_Resize(object sender, EventArgs e)
        {
            bool hasConstrainedHeight = Height < 100;
            bool hasConstrainedWidth = Width < 360 ;

            lblAvailableScripts.Visible = !hasConstrainedWidth && !hasConstrainedHeight;

            cbScripts.Visible = !hasConstrainedHeight;
            scriptEditor.Location = hasConstrainedHeight ? new Point(3, 8) : new Point(3, 29);
            scriptEditor.Height = hasConstrainedHeight ? Height - 10 : Height - 29;

            cbScripts.Location = hasConstrainedWidth ? new Point(8, 2) : new Point(97, 2);
            cbScripts.Width = hasConstrainedWidth ? Width - 16 : Width - 274;

            btnNewScript.Visible = !hasConstrainedWidth && !hasConstrainedHeight;
            btnReload.Visible = !hasConstrainedWidth && !hasConstrainedHeight;
            btnSave.Visible = !hasConstrainedWidth && !hasConstrainedHeight;
        }

    }
}

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, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Architect BlackJet Software Ltd
United Kingdom United Kingdom
Stuart Wheelwright is the Principal Architect and Software Developer at BlackJet Software Ltd.

He has over 16 years commercial experience producing robust, maintainable, web-based solutions and bespoke systems for Microsoft platforms.

His latest project is Shopping UK, an elegantly simple shopping list for iPhone.

Comments and Discussions