C# Webbrowser Ajax Call

C# WebBrowser Ajax call

WebBrowser control (both WPF and WinForms versions) behaves in many ways differently from the full IE. You may want to implement Feature Control to bring its behavior as close to IE as possible (particularly, FEATURE_BROWSER_EMULATION), this often solves the script compatibility issues. Here is some code, note that it does not require admin rights to run:

private void SetBrowserFeatureControlKey(string feature, string appName, uint value)
{
using (var key = Registry.CurrentUser.CreateSubKey(
String.Concat(@"Software\Microsoft\Internet Explorer\Main\FeatureControl\", feature),
RegistryKeyPermissionCheck.ReadWriteSubTree))
{
key.SetValue(appName, (UInt32)value, RegistryValueKind.DWord);
}
}

For example:

private void SetBrowserFeatureControl()
{
// http://msdn.microsoft.com/en-us/library/ee330720(v=vs.85).aspx

// FeatureControl settings are per-process
var fileName = System.IO.Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName);

// make the control is not running inside Visual Studio Designer
if (String.Compare(fileName, "devenv.exe", true) == 0 || String.Compare(fileName, "XDesProc.exe", true) == 0)
return;

SetBrowserFeatureControlKey("FEATURE_BROWSER_EMULATION", fileName, GetBrowserEmulationMode()); // Webpages containing standards-based !DOCTYPE directives are displayed in IE10 Standards mode.
SetBrowserFeatureControlKey("FEATURE_AJAX_CONNECTIONEVENTS", fileName, 1);
SetBrowserFeatureControlKey("FEATURE_ENABLE_CLIPCHILDREN_OPTIMIZATION", fileName, 1);
SetBrowserFeatureControlKey("FEATURE_MANAGE_SCRIPT_CIRCULAR_REFS", fileName, 1);
SetBrowserFeatureControlKey("FEATURE_DOMSTORAGE ", fileName, 1);
SetBrowserFeatureControlKey("FEATURE_GPU_RENDERING ", fileName, 1);
SetBrowserFeatureControlKey("FEATURE_IVIEWOBJECTDRAW_DMLT9_WITH_GDI ", fileName, 0);
SetBrowserFeatureControlKey("FEATURE_DISABLE_LEGACY_COMPRESSION", fileName, 1);
SetBrowserFeatureControlKey("FEATURE_LOCALMACHINE_LOCKDOWN", fileName, 0);
SetBrowserFeatureControlKey("FEATURE_BLOCK_LMZ_OBJECT", fileName, 0);
SetBrowserFeatureControlKey("FEATURE_BLOCK_LMZ_SCRIPT", fileName, 0);
SetBrowserFeatureControlKey("FEATURE_DISABLE_NAVIGATION_SOUNDS", fileName, 1);
SetBrowserFeatureControlKey("FEATURE_SCRIPTURL_MITIGATION", fileName, 1);
SetBrowserFeatureControlKey("FEATURE_SPELLCHECKING", fileName, 0);
SetBrowserFeatureControlKey("FEATURE_STATUS_BAR_THROTTLING", fileName, 1);
SetBrowserFeatureControlKey("FEATURE_TABBED_BROWSING", fileName, 1);
SetBrowserFeatureControlKey("FEATURE_VALIDATE_NAVIGATE_URL", fileName, 1);
SetBrowserFeatureControlKey("FEATURE_WEBOC_DOCUMENT_ZOOM", fileName, 1);
SetBrowserFeatureControlKey("FEATURE_WEBOC_POPUPMANAGEMENT", fileName, 0);
SetBrowserFeatureControlKey("FEATURE_WEBOC_MOVESIZECHILD", fileName, 1);
SetBrowserFeatureControlKey("FEATURE_ADDON_MANAGEMENT", fileName, 0);
SetBrowserFeatureControlKey("FEATURE_WEBSOCKET", fileName, 1);
SetBrowserFeatureControlKey("FEATURE_WINDOW_RESTRICTIONS ", fileName, 0);
SetBrowserFeatureControlKey("FEATURE_XMLHTTP", fileName, 1);
}

private UInt32 GetBrowserEmulationMode()
{
int browserVersion = 7;
using (var ieKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Internet Explorer",
RegistryKeyPermissionCheck.ReadSubTree,
System.Security.AccessControl.RegistryRights.QueryValues))
{
var version = ieKey.GetValue("svcVersion");
if (null == version)
{
version = ieKey.GetValue("Version");
if (null == version)
throw new ApplicationException("Microsoft Internet Explorer is required!");
}
int.TryParse(version.ToString().Split('.')[0], out browserVersion);
}

UInt32 mode = 11000; // Internet Explorer 11. Webpages containing standards-based !DOCTYPE directives are displayed in IE11 Standards mode. Default value for Internet Explorer 11.
switch (browserVersion)
{
case 7:
mode = 7000; // Webpages containing standards-based !DOCTYPE directives are displayed in IE7 Standards mode. Default value for applications hosting the WebBrowser Control.
break;
case 8:
mode = 8000; // Webpages containing standards-based !DOCTYPE directives are displayed in IE8 mode. Default value for Internet Explorer 8
break;
case 9:
mode = 9000; // Internet Explorer 9. Webpages containing standards-based !DOCTYPE directives are displayed in IE9 mode. Default value for Internet Explorer 9.
break;
case 10:
mode = 10000; // Internet Explorer 10. Webpages containing standards-based !DOCTYPE directives are displayed in IE10 mode. Default value for Internet Explorer 10.
break;
default:
// use IE11 mode by default
break;
}

return mode;
}

You should come up with your own set of features and register them before WebBrowser has initialized, e.g., in the main form constructor:

public MainWindow()
{
SetBrowserFeatureControl();

InitializeComponent();
//...
}

Updated, I currently use and recommend a set of features that can be found here.

WebBrowser Control — Get Document Elements After AJAX Call — Null Exception

while ((wb.ReadyState != WebBrowserReadyState.Complete)) {
Application.DoEvents();
}

;)

Waiting for WebBrowser ajax content

Don't block the main thread's message pump. Since the browser is an STA component, xmlhttprequest won't be able to raise events from the background thread if you block the message pump.
You can't navigate in a background thread. The Windows Forms wrapper of the webbrowser ActiveX does not support access from other threads than the UI thread. Use a timer instead.

Can I read the contents of an Ajax request using the WebBrowser control?

No, you cannot capture XMLHTTPRequests from the web-browser control using the methods of the Web Browser control. You might want to have a look at http://www.fiddler2.com/core/

C# Facing problem to read ajax data using web browser control

AJAX is simple GET or POST request.

Using regular Browser dev tools I've found that page sends simple GET request and receive JSON data. JSON can be deserealized or explored via reader.

For JSON parsing i used Newtonsoft.Json NuGet package

Here's simple example based on WinForms app.

public partial class Form1 : Form
{
private static readonly HttpClient client = new HttpClient();

private async Task<T> GetJsonPageAsync<T>(string url)
{
using (HttpResponseMessage response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
{
response.EnsureSuccessStatusCode();
string text = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(text);
}
}

public Form1()
{
InitializeComponent();
ServicePointManager.DefaultConnectionLimit = 10; // to make it faster
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
}

private async void button1_Click(object sender, EventArgs e)
{
try
{
dynamic newsList = await GetJsonPageAsync<dynamic>("https://www.wsj.com/news/types/newsplus?id={%22query%22:%22type:=\\%22NewsPlus\\%22%22,%22db%22:%22wsjie,blog,interactivemedia%22}&type=search_collection");
List<Task<dynamic>> tasks = new List<Task<dynamic>>();
foreach (dynamic item in newsList.collection)
{
tasks.Add(GetJsonPageAsync<dynamic>($"https://www.wsj.com/news/types/newsplus?id={item.id}&type=article"));
}
dynamic[] newsDataList = await Task.WhenAll(tasks);
foreach (dynamic newItem in newsDataList)
{
textBox1.Text += newItem.data.headline + Environment.NewLine;
textBox1.Text += new string('-', 200) + Environment.NewLine;
}
}
catch (Exception ex)
{
textBox1.Text = ex.Message;
}
}
}

Sample Image

UPD: Added fix for .NET Framework 4.5.2

WebBrowser Control blocking ajax

while(webbrowser1.isBusy); and Thread.Sleep(2000); would block the main message pump, and ajax requires a message pump for asynchronous callback. I suggest you to start a timer in DocumentComplete to poll the web page regularly until you think the page is complete. Remember to stop the timer in BeforeNavigate2



Related Topics



Leave a reply



Submit