Question

I am using fiddlercore to capture session information to run a compare on the data in a particular response. One of the things I am noticing that I don't understand is that I am getting session information from the second environment into the List collection I have for the first.

public class ManageCompares
{
    public static string _test2BaseURL = "https://test2/";
    public static string _dev1BaseURL = "http://dev1/";


    private void RunCompares(string email, string handler, Reporting report)
    {
        ManageProcess.ShutDownProcess("iexplore");

        RunExports exportTest2 = new RunExports();
        RunExports exportDev1 = new RunExports();

        string password = "d";

        List<Session> oAllSessions_Test2 = exportTest2.RunExportGeneration
          (email, password, _test2BaseURL, handler);

        ManageProcess.ShutDownProcess("iexplore");

        List<Session> oAllSessions_Dev1 = exportDev1.RunExportGeneration
            (email, password, _dev1BaseURL, handler);

        exportTest2.ExtractResponse(oAllSessions_Test2, handler, report);

        //report.SetEnvironment2Body(ManageExports.ExtractResponse
        //  (oAllSessions_Dev1, handler, report, report.Environment2));

        if (report.Test2ResponseCode != 500 && report.Dev1ResponseCode != 500)
        {
            bool matches = CompareExports.CompareExportResults
              (report.Environment1Body, report.Environment2Body);

            if (matches)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine("Exports matched");
                Console.ResetColor();
            }
            else
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Export does not match");
                Console.ResetColor();

                report.GenerateReportFiles();
            }
        }
        else
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine
              ("A exception was returned.  Please review the log file.");
            Console.ResetColor();


        }
    }


}

public class RunExports
{
    public List<Session> RunExportGeneration
     (string email, string password, string baseUrl, 
          string handlersUrlwithParams)
    {
        IWebDriver driver = new InternetExplorerDriver();

        FiddlerApplication.Startup(8877, FiddlerCoreStartupFlags.Default);

        List<Session> oAllSessions = new List<Session>();

        LoginPage login = new LoginPage(driver);

        FiddlerApplication.AfterSessionComplete += delegate(Session oS)
        {
            Monitor.Enter(oAllSessions);
            oAllSessions.Add(oS);
            Monitor.Exit(oAllSessions);
        };

        try
        {
            driver.Navigate().GoToUrl(baseUrl);
            login.LoginToView(email, password);
            driver.Navigate().GoToUrl(baseUrl + handlersUrlwithParams);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
        finally
        {
            FiddlerApplication.Shutdown();                
            driver.Quit();
        }

        return oAllSessions;
    }
}

List oAllSessions_Test2 and List oAllSessions_Dev1 are my two collections. When I debug the capture I typically see 15 rows in the oAllSessions_Test2 collection. Then after capturing oAllSessions_Dev1 I see the count has jumped up 14 or 15 and when I look at what is contained by the colleciton some of the Dev1 captures are now in there. oAllSessions_Dev1 has just the sessions I am expecting. I am guessing there must be a pointer someplace I am not expecting but I am stumped at this point how to clear it up. The other thing that I am noticing is that the session counter continues to increment while the application is cycling through the various cases.

I am also using Selenium WebDriver and IE to initiate the browser session but I don't think that is particularly relevant to this particular issue.

So what am I missing here?

Was it helpful?

Solution

Do this :

SessionStateHandler tAction = oS =>
        {
            Monitor.Enter(oAllSessions);
            oAllSessions.Add(oS);
            Monitor.Exit(oAllSessions);
        };

FiddlerApplication.AfterSessionComplete += tAction;

......

//at the end before your return statement:

 FiddlerApplication.AfterSessionComplete -= tAction;

So here is what's going on.

this: FiddlerApplication.Startup(8877, FiddlerCoreStartupFlags.Default);

(this specifically) FiddlerApplication

is holding onto references in an external application (fiddler) and administrating them for you. When you += and add a delegate FiddlerApplication.AfterSessionComplete += tAction;, the fiddler application was adding this to the list of methods it calls when the AfterSession event fires.

Because it's singleton (You are only dealing with one Fiddler application instance in your code), every time you do a += it adds it to the same list. This list in the FiddlerApplication doesn't get recreated every time you call your method. It's the same one that you called the first time, so even though your delegate falls out of it's scope declaration space (like local objects normally do in a method), the FiddlerApplication EventList maintains a reference to it and fires that delegate each time (and every other one).

So.....

In your method you create List<Session> oAllSessions = new List<Session>(); and access it in your delegate. This local variable is now passed back to the calling method, List<Session> oAllSessions_Test2 = exportTest2.RunExportGeneration.... and the delegate FiddlerApplication calls is the exact same list. So each time you call that method and the AfterSessionComplete fires, it updates the list even after it's been returned to the calling function.

To stop it you have to add: FiddlerApplication.AfterSessionComplete -= tAction; which tells the system "Hey, don't push updates to this method anymore. It's done receiving notifications."

OTHER TIPS

In .NET languages class objects are passed by reference in almost all cases. If you assign an object reference to a variable, that variable will still refer to the original object. Changes to the original will be visible through all references. This is similar to how things used to happen in C/C++ when you stored pointers or references to structures in memory. The implementation details are different, but the results are the same.

Here's an example of what happens when you store list instances that might be changed later:

class ListTest
{
    List<string> l = new List<string>();
    public List<string> GetList() { return l; }
    public void Add(string v) { l.Add(v); }
}

class Program
{
    static void Main(string[] args)
    {
        ListTest t = new ListTest();
        t.Add("a"); t.Add("b"); t.Add("c"); t.Add("d");
        List<string> x1 = t.GetList();
        List<string> x2 = t.GetList().ToList();
        t.Add("e"); t.Add("f"); t.Add("g"); t.Add("h");
        List<string> y1 = t.GetList();
        List<string> y2 = t.GetList().ToList();

        Console.WriteLine("{0}, {1}", x1.Count, y1.Count);
        Console.WriteLine("{0}", string.Join(", ", x1));
        Console.WriteLine("{0}", string.Join(", ", y1));

        Console.WriteLine();

        Console.WriteLine("{0}, {1}", x2.Count, y2.Count);
        Console.WriteLine("{0}", string.Join(", ", x2));
        Console.WriteLine("{0}", string.Join(", ", y2));
    }
}

When you run that you get one set of identical results, because x1 and y1 are references to the same object. The second set of results are different because the call to ToList creates a new List<string> instance to hold the results.

This might be what is happening with the list that is returned by your Fiddler code.

-- Update after code review

What it looks like is that the delegate you're assigning to the AfterSessionComplete event is causing the code to treat oAllSessions as a static object bound to the event handler delegate. Various side-effects like this happen when you start playing around with code that generates closures and so on.

I would suggest changing the code to use a class method rather than an inline method - shift your oAllSessions variable and the code you're assigning to AfterSessionComplete out into the body of the class. That will at least establish whether the inline delegate is the cause of the problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top