SAZClipboard
The goal of this *incomplete* example is to show how you can build an extension which accepts drag/drop of Fiddler Sessions.
SAZClipboardFactory.cs
// The SAZClipboardFactory extension creates SAZClipboardForms. These allow the user to manage collections of // session items. This is useful, for instance, when testing webservices by replaying traffic using the Composer. using System; using System.Collections.Generic; using System.Windows.Forms; using Fiddler; namespace SAZClipboard { public class SAZClipboardFactory : IFiddlerExtension { List<SAZClipboardForm> oSAZClipboards = new List<SAZClipboardForm>(); public void OnLoad() { MenuItem oMI = new MenuItem("New Session Clip&board..."); oMI.Click += new EventHandler(oMI_Click); FiddlerApplication.UI.mnuTools.MenuItems.Add(oMI); } void oMI_Click(object sender, EventArgs e) { SAZClipboardForm oNew = new SAZClipboardForm(); oNew.Left = FiddlerApplication.UI.Left + 50; oNew.Top = FiddlerApplication.UI.Top + 50; oSAZClipboards.Add(oNew); oNew.Show(); } public void OnBeforeUnload() { foreach (SAZClipboardForm oEach in oSAZClipboards){ oEach.Close(); } oSAZClipboards = null; } } }
SAZClipboardForm.cs
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using Fiddler; using System.Diagnostics; using System.IO; namespace SAZClipboard { public partial class SAZClipboardForm : Form { public SAZClipboardForm() { InitializeComponent(); } /// <summary> /// Allow drag drop of sessions or SAZ files /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void lvSessionClip_DragEnter(object sender, DragEventArgs e) { e.Effect = (e.Data.GetDataPresent("Fiddler.Session[]") || e.Data.GetDataPresent(DataFormats.FileDrop)) ? DragDropEffects.Copy : e.Effect = DragDropEffects.None; } private void lvSessionClip_DragDrop(object sender, DragEventArgs e) { Session[] oSessions = (Session[])e.Data.GetData("Fiddler.Session[]"); if ((oSessions == null) || (oSessions.Length < 1)) { Debug.Assert(false, "Unexpected drop type."); return; } AddSessionsToUI(oSessions); } /// <summary> /// Adds one or more Sessions to the SAZClipboard UI /// </summary> /// <param name="oSessions"></param> private void AddSessionsToUI(Session[] oSessions) { foreach (Session oSession in oSessions) { ListViewItem oLVI = new ListViewItem(new[] { oSession.RequestMethod, oSession.oRequest.headers.UriScheme, oSession.host, oSession.oRequest.headers.RequestPath, oSession.GetRequestBodyAsString(), oSession.oFlags["ui-comments"]}); oLVI.Tag = oSession; lvSessionClip.Items.Add(oLVI); } } private void lvSessionClip_ItemDrag(object sender, ItemDragEventArgs e) { Session[] toDrag = GetSelectedSessions(); if (toDrag.Length > 0) { lvSessionClip.DoDragDrop(toDrag, DragDropEffects.Copy); } } private void lvSessionClip_DoubleClick(object sender, EventArgs e) { Session[] arrSess = GetSelectedSessions(); if (arrSess.Length > 0) { arrSess[0].actInspectInNewWindow(); } } private void lvSessionClip_KeyDown(object sender, KeyEventArgs e) { switch (e.KeyCode) { case Keys.X: if (e.Control) { lvSessionClip.Items.Clear(); this.Text = "Session Clipboard"; e.Handled = e.SuppressKeyPress = true; } return; case Keys.C: { Session[] arrSess = GetSelectedSessions(); if (arrSess.Length > 0) { FiddlerApplication.DoComposeByCloning(arrSess[0]); e.Handled = e.SuppressKeyPress = true; } return; } case Keys.R: FiddlerApplication.UI.actReissueSessions(GetSelectedSessions(), false); e.Handled = e.SuppressKeyPress = true; return; case Keys.Enter: { Session[] arrSess = GetSelectedSessions(); if (arrSess.Length > 0) { arrSess[0].actInspectInNewWindow(); } e.Handled = e.SuppressKeyPress = true; return; } case Keys.Delete: if (lvSessionClip.SelectedItems.Count < 1) return; ListView.SelectedListViewItemCollection lvisToRemove = lvSessionClip.SelectedItems; lvSessionClip.BeginUpdate(); foreach (ListViewItem lviToRemove in lvisToRemove) { lviToRemove.Remove(); } lvSessionClip.EndUpdate(); if (lvSessionClip.FocusedItem != null) { lvSessionClip.FocusedItem.Selected = true; } e.Handled = e.SuppressKeyPress = true; return; } } [CodeDescription("Returns a Session[] array containing all sessions. Note: returns an empty non-null array if no sessions selected")] public Session[] GetAllSessions() { Session[] oResults = new Session[lvSessionClip.Items.Count]; for (int x = 0; x < oResults.Length; x++) { oResults[x] = lvSessionClip.Items[x].Tag as Session; // Should never be null, but... } return oResults; } public Session[] GetSelectedSessions() { ListView.SelectedListViewItemCollection lvSI = lvSessionClip.SelectedItems; Session[] oResults = new Session[lvSI.Count]; int x = 0; // Using Foreach here makes this loop 200x faster than using indexes due to how the Framework works internally. foreach (ListViewItem oLVI in lvSI) { oResults[x] = oLVI.Tag as Session; x++; } return oResults; } private void tsbSaveSAZ_Click(object sender, EventArgs e) { if (lvSessionClip.Items.Count < 1) { MessageBox.Show("The Clipboard is empty. There is nothing to save.", "Nothing to do..."); return; } try { this.UseWaitCursor = true; Application.DoEvents(); FiddlerApplication.UI.actSaveSessionArchive(this, GetAllSessions(), null); } finally { this.UseWaitCursor = false; } } private void tsbLoadSAZ_Click(object sender, EventArgs e) { if (dlgOpenSAZ.ShowDialog(this) == DialogResult.OK) { try { this.UseWaitCursor = true; Application.DoEvents(); Session[] oSessions = Utilities.ReadSessionArchive(dlgOpenSAZ.FileName, true); if (null == oSessions) return; // Update form caption with name of loaded file this.Text = String.Format("{0} [{1}]", this.Text, Path.GetFileNameWithoutExtension(dlgOpenSAZ.FileName)); AddSessionsToUI(oSessions); } finally { this.UseWaitCursor = false; } } } private void tsbPin_CheckedChanged(object sender, EventArgs e) { this.TopMost = tsbPin.Checked; } } }