WPFでCefSharp（Chromiumの.NET向け実装）を使う - 2

# 経緯

[前回](http://qiita.com/GHKEN/items/d2d8b0745ef2622a2bbc)の続きです。

今回は具体的なWebBrowserとの比較として、以下の機能の実装方法について検証します。

* UserAgentの設定
* ページ遷移のハンドリング
* Cookieの操作

# UserAgentの設定

## WebBrowserの場合

`urlmon.dll`の`UrlMkSetSessionOption`を利用すると実現できます→[参考](http://www.nuits.jp/entry/2016/06/25/141427)

難しいことはないんですがアンマネージドなコードを触るのがちょっともやっとします。

## Cefの場合

`CefSharp.Wpf.ChromiumWebBrowser`のインスタンスを生成する前に、`Cef.Initialize(cefSettings)`を呼び出すことでUserAgent等の設定を行うことができます。

この関数の引数である`CefSettings`は他にもいろいろ設定できる項目があるので後々検証します。

今回はUserAgentを設定したいだけなので、UIスレッドでUserAgentを指定したCefSettingsを使ってCefをInitializeするだけです。

```Csharp
public static void Init()
{
    var cefSettings = new CefSettings
    {
        UserAgent = "CefSample",
    };
    Cef.Initialize(cefSettings);
}
```

![kakuninkun.PNG](https://qiita-image-store.s3.amazonaws.com/0/47597/b849d827-f130-6510-0013-89e0a1440aa5.png)


ちゃんとUserAgentがCefSampleになってます。

# ページ遷移のハンドリング

## WebBrowserの場合

`WebBrowser.Navigating`, `WebBrowser.Navigated`イベントがあるので、それぞれ遷移前、遷移後の処理をハンドリングすることができます。

また、Navigatingのイベントハンドラに第二引数として渡される`NavigatingCancelEventArgs`のCancelプロパティをtrueにしておくことで、遷移をキャンセルさせることができます。

## Cefの場合

`ChromiumWebBrowser.FrameLoadStart`, `ChromiumWebBrowser.FrameLoadEnd`イベントがあるので、それぞれ遷移開始、遷移後の処理をハンドリングすることができます。

ただ、このFrameLoadStartイベントでは遷移をキャンセルすることができず、リクエストの書き換えや遷移のキャンセルを制御するには`ChromiumWebBrowser.RequestHandler`プロパティを実装する必要があります。

RequestHandlerは多機能なので別途検証を行います（今回は行いません）。

```Csharp
Browser = new ChromiumWebBrowser();
Browser.FrameLoadStart += (sender, e) =>
{
    var uri = new Uri(e.Url);
    if (uri.Host == "www.google.co.jp")
    {
        MessageBox.Show("www.google.co.jpのページに遷移します");
    }
};
```

みたいなことができます。

# Cookieの操作

実際にやりたかったのは"クッキーを削除する"ボタンの実装なので、それをどうやって実現できそうかを見ていきます。

## WebBrowserの場合

Cookieをまとめて削除するような機能はなさそうです（あったら教えてください）。

一応アンマネージドなコードを触ってInternetSetOptionでいろいろやれば既存のCookieを無視したブラウザを立ち上げることは可能なのですが、

直接消すわけではないので"クッキーを削除する"とは違う挙動になってしまいます。（オプションを無効化して再起動すると前のCookieが残ってる）

WebBrowserにはDocumentプロパティが存在して、HTMLにjsを挿入することができるので、そのjsでそのドメインのCookieのExpireをいじることは可能なのですが、

すべてのページのCookieを削除することは難しそうです。

## Cefの場合

Cookieを操作するためのCookieManagerクラスが用意されていて、`Cef.GetGlobalCookieManager()`でCookieManagerを取得することができます。

CookieManagerには特定のUrlのCookieを消すためのDeleteCookiesが実装されているので、一つだけ消す場合であればそれを呼べばOKです。

複数のドメインのCookieを処理するためにはアプローチを少し変える必要があって、ICookieVisitorを実装したクラスを用意して、そのインスタンスをCookieManagerのVisitAllCookiesに渡す必要があります（VisitUrlCookiesってのもあったのでドメインごとに消すとかも簡単にできそう）。

またasyncに処理してくれるVisitAllCookiesAsyncというものもあって、こちらは返り値でCookieのListを返してくれるのですが、返ってきたところでどうやって消せばいいのかはよくわかりませんでした。

```CSharp
void ClearAllCookies()
{
    var cookieManager = Cef.GetGlobalCookieManager();

    cookieManager.VisitAllCookies(new CookieEater());
}

class CookieEater : ICookieVisitor
{
    public void Dispose()
    {
    }

    public bool Visit(Cookie cookie, int count, int total, ref bool deleteCookie)
    {
        deleteCookie = true;
        return true;
    }
}
```

# まとめ

* CefのInitializeにCefSettingsを渡すといろいろできる（UserAgentとかCacheのパスとか）
* FrameLoadStartとFrameLoadEndでページのロード開始とページのロード完了のイベントが取れる
  * リクエスト自体をいじりたいとかならRequestHandlerを実装する必要がある（また今度検証）
* CookieManagerとCookieVisitorを使ってCookieを簡単に操作できる

今回はここまでです。

次回はRequestHandlerあたりについて書こうと思います。

[元記事](http://ghken.hatenablog.com/entry/2017/04/26/233406)