Page 1 of 1

How to correctly use VisitUrlCookies?

PostPosted: Sun Feb 21, 2016 10:24 pm
by gwynjudd
Hello,

I'm having a hard time getting this to work reliably with CefGlue. I want to run VisitUrlCookies to get all cookies. Based on a suggestion in some other posts, it looks like the Visit method in my CefCookieVisitor will be called repeatedly, and once all of the cookies are found, the Dispose method will be called. What I find is that this seems to be unreliable. I'm finding that the Visit method is being called for the cookies (of which there is only one), but once that has happened, the Dispose method isn't always called. Some of the time it is called ok, but in other cases, it isn't called. Here is the code for my visitor:

namespace MyCookieVisitor
{
using System.Net;
using System.Threading.Tasks;
using Xilium.CefGlue;

internal class CookieVisitor : CefCookieVisitor
{
private TaskCompletionSource<CookieCollection> completionSource;

public CookieVisitor()
{
this.Cookies = new CookieCollection();
}

public CookieCollection Cookies { get; private set; }

protected override bool Visit(CefCookie cookie, int count, int total, out bool delete)
{
this.Cookies.Add(new Cookie(cookie.Name, cookie.Value, cookie.Path, cookie.Domain));

delete = false;
return true;
}

public void GetCookies(string address, TaskCompletionSource<CookieCollection> completionSource)
{
CefCookieManager.GetGlobal(null).VisitUrlCookies(address, false, this);
this.completionSource = completionSource;
}

protected override void Dispose(bool disposing)
{
this.completionSource.SetResult(this.Cookies);
}
}
}

Is there anything wrong with what I'm doing here?

Re: How to correctly use VisitUrlCookies?

PostPosted: Sun Feb 21, 2016 10:36 pm
by amaitland
Evaluate total and count to determine when there are no more cookies.

Also you haven't taken into account when there are no cookies present the call will never be made, so I'd suggest some sort of timeout.

Re: How to correctly use VisitUrlCookies?

PostPosted: Mon Feb 22, 2016 12:56 pm
by magreenblatt
amaitland wrote:Also you haven't taken into account when there are no cookies present the call will never be made, so I'd suggest some sort of timeout.

In C++ the CefCookieVisitor destructor will still be called even if there are no cookies. I'm not sure if C# exposes a similar concept.

Re: How to correctly use VisitUrlCookies?

PostPosted: Mon Feb 22, 2016 3:51 pm
by gwynjudd
magreenblatt wrote:In C++ the CefCookieVisitor destructor will still be called even if there are no cookies. I'm not sure if C# exposes a similar concept.


C# uses garbage collection - the Dispose method will eventually be called, but it is not guaranteed to be done in a timely fashion. Also relying on destructors (finalizers) is considered very bad practice in .Net programming. An explicit "done" event would be a lot more usable.

I came up with a different plan, but I don't know if it is right:

Code: Select all
namespace MyCookieVisitor
{
   using System;
   using System.Net;
   using System.Threading.Tasks;
   using Xilium.CefGlue;

   internal class CompletionCallback : CefCompletionCallback
   {
      public delegate void CompletionCallbackDelegate();
      private CompletionCallbackDelegate completionCallbackDelegate;

      public CompletionCallback(CompletionCallbackDelegate completionCallbackDelegate)
      {
         this.completionCallbackDelegate = completionCallbackDelegate;
      }

      protected override void OnComplete()
      {
         this.completionCallbackDelegate();
      }
   }

   internal class CookieVisitor : CefCookieVisitor
   {
      private TaskCompletionSource<CookieCollection> completionSource;

      public CookieVisitor()
      {
         this.Cookies = new CookieCollection();
      }

      private CookieCollection Cookies { get; set; }

      protected override bool Visit(CefCookie cookie, int count, int total, out bool delete)
      {
         this.Cookies.Add(new Cookie(cookie.Name, cookie.Value, cookie.Path, cookie.Domain));

         delete = false;
         return true;
      }

      public void GetCookies(string address, TaskCompletionSource<CookieCollection> completionSource)
      {
         CefCookieManager manager = null;
         manager = CefCookieManager.GetGlobal(new CompletionCallback(() =>
         {
            if (manager != null)
            {
               manager.VisitUrlCookies(address, false, this);
               completionSource.SetResult(this.Cookies);
            }
         }));
      }
   }
}


The idea is that in the completion callback for the GetGlobal call (which runs in the IO thread), call VisitUrlCookies and then set the result in a synchronous way. It seems to work in my use case, but I don't know if VisitUrlCookies is actually synchronous in the IO thread.

amaitland wrote:Evaluate total and count to determine when there are no more cookies.

Also you haven't taken into account when there are no cookies present the call will never be made, so I'd suggest some sort of timeout.


This is the only other alternative that I've come up with, but it's quite distasteful so hopefully I don't have to rely on that.

Re: How to correctly use VisitUrlCookies?

PostPosted: Wed Mar 23, 2016 6:17 am
by fddima
Hello.

1. This method executed synchronously on IO thread. But there is looks like implementation detail.

2. Dispose method now will be called, so cookie visitor implementation can rely on Dispose method.
With one note, to previous post, that you should always call base.Dispose(disposing) otherwise you will get memory leak.