How do I use UI Automation with ChromiumWebBrowser? - c#

I'm trying to use UI automation with ChromiumWebBrowser, so I managed to make it work by passing force-renderer-accessibility command line option to settings. It got available on inspect.exe tool but I still couldn't find it by code. Could anyone just give me a code sample?
Here's how I initialize the ChromiumWebBrowser:
void InitializeChromiumWebBrowser()
{
var settings = new CefSettings()
{
CefCommandLineArgs = {
new KeyValuePair<string, string>("force-renderer-accessibility", "true")
},
MultiThreadedMessageLoop = false
};
Cef.Initialize(settings);
m_chromeBrowser = new ChromiumWebBrowser("http://127.0.0.1/calc.html");
m_chromeBrowser.Name = "chromiumWebBrowser";
var t = new Timer { Interval = 5 };
t.Start();
t.Tick += (s, e) => BeginInvoke((Action)(() => Cef.DoMessageLoopWork()));
m_chromeBrowser.LoadingStateChanged += M_chromeBrowser_LoadingStateChanged;
browser_tabPage.Controls.Add(m_chromeBrowser);
}
I'm trying to manipulate them with UI Automation, but I couldn't find even the top window:
using (var proc = Process.GetCurrentProcess())
{
var root = AutomationElement.FromHandle(proc.MainWindowHandle);
var browser = root.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.ClassNameProperty, "CefBrowserWindow")); // Always null
}
But browser always is null. What am I missing?

Related

Devops: Add a variable to an existing ReleaseEnvironment Pipeline using c#

I am trying to add a new variable to an existing Devops ReleaseEnvironment and redeploy this existing releaseEnvironment.
I'm using Microsoft.VisualStudio.Services.Release.Client version 16.199.0-preview.
var connection = new VssConnection("someUrl", new VssBasicCredential(string.Empty, "somePAT"));
var client = connection.GetClient<ReleaseHttpClient>();
var projectHttpClient = connection.GetClient<ProjectHttpClient>();
var project = await projectHttpClient.GetProject("xxx");
var metadata = new ReleaseEnvironmentUpdateMetadata
{
Status = EnvironmentStatus.InProgress
};
metadata.Variables.Add("someVariable",
new ConfigurationVariableValue()
{
Value = "xxx",
AllowOverride = true,
IsSecret = true
});
await client.UpdateReleaseEnvironmentAsync(metadata, project.Id, 999,999);
However, cause this variable does not exist yet, I'm getting the error:
Unhandled exception. Microsoft.VisualStudio.Services.Common.VssServiceException: Variable(s) someVariable do not exist in the release environment at scope: PRD. New variables cannot be added while creating deployment.
However it looks like it's possible to do it via the UI. So I was wondering how I can automate this. Does anyone have an idea?
Thx in advance.
Best regards,
JeffVN
Found the solution.
You'll just need to fetch the Release and update the variables in the Environment:
var connection = new VssConnection("someUrl", new VssBasicCredential(string.Empty, "somePAT"));
var client = connection.GetClient<ReleaseHttpClient>();
var project = await projectHttpClient.GetProject("xxx");
var release = await client.GetReleaseAsync(project.Id, 999);
if (release == null)
{
Console.WriteLine("Release 999 not found");
return;
}
var releaseEnv = release.Environments.FirstOrDefault(x => x.Id == 999);
if (releaseEnv == null)
{
Console.WriteLine("ReleaseEnvironment 999 not found");
return;
}
if (!releaseEnv.Variables.ContainsKey("someVariable"))
{
releaseEnv.Variables.Add("someVariable", new ConfigurationVariableValue()
{
Value = "xxx",
AllowOverride = true,
IsSecret = true
});
}
else
{
releaseEnv.Variables["someVariable"].Value = "xxx";
}
await client.UpdateReleaseAsync(release, project.Id, 999);

C# Selenium 4: Setup request interception

I'm trying to use Selenium 4 to log requests during manual usage of Chrome browser.
The issue is that request interception stops after around 40 seconds of usage (approximately).
I've tried to change commandTimeout but it didn't change anything.
Also I've tried to look into chromedriver logs but I didn't find anithing there.
Here's my code:
static void Main(string[] args)
{
// Enable chromedriver logging
var service = ChromeDriverService.CreateDefaultService();
service.LogPath = AppDomain.CurrentDomain.BaseDirectory + "chromedriver.log";
service.EnableVerboseLogging = true;
var options = new ChromeOptions();
var webDriver = new ChromeDriver(service, options);
var devToolsSession = webDriver.CreateDevToolsSession();
devToolsSession.Network.Enable(new EnableCommandSettings());
EventHandler<RequestInterceptedEventArgs> requestIntercepted = (sender, e) =>
{
Console.WriteLine(e.Request.Url);
};
RequestPattern requestPattern = new RequestPattern();
requestPattern.InterceptionStage = InterceptionStage.Request;
requestPattern.ResourceType = ResourceType.Image;
var setRequestInterceptionCommandSettings = new SetRequestInterceptionCommandSettings();
setRequestInterceptionCommandSettings.Patterns = new RequestPattern[] { requestPattern };
devToolsSession.Network.SetRequestInterception(setRequestInterceptionCommandSettings);
devToolsSession.Network.RequestIntercepted += requestIntercepted;
while (true)
{
webDriver.Url = "https://translate.google.com/";
Thread.Sleep(5000);
webDriver.Navigate().Refresh();
}
}
As of Selenium 4 beta-1, you can use the Fetch API and retrieve the same resluts (SetRequestIntercepted is deprecated in ChromeTools as late as December 29, 2020).
In either case, the key point for both RequestIntercepted (prior to deprecation) and Fetch to be able to continue after intercepting the request is to capture the RequestId.
With Fetch this can be done in ContinueRequest():
fetch.ContinueRequest(new Fetch.ContinueRequestCommandSettings()
{
RequestId = e.RequestId
});
Below is your code updated to use Fetch which allowed the query to run for 2+ minutes and 5+ minutes before I manually stopped it:
(Note: ensure all of your DevTools as using the same version (i.e. 89 in my case) or you will get errors):
using V89 = OpenQA.Selenium.DevTools.V89;
using V89Net = OpenQA.Selenium.DevTools.V89.Network;
using OpenQA.Selenium.DevTools.V89.Log;
var service = ChromeDriverService.CreateDefaultService();
service.LogPath = AppDomain.CurrentDomain.BaseDirectory + "chromedriver.log";
service.EnableVerboseLogging = true;
var options = new ChromeOptions();
new DriverManager().SetUpDriver(new ChromeConfig(), VersionResolveStrategy.MatchingBrowser);
var driver = new ChromeDriver(service, options);
IDevTools devTools = driver as IDevTools;
var devToolsSession = devTools.GetDevToolsSession();
var fetch = devToolsSession.GetVersionSpecificDomains<V89.DevToolsSessionDomains>()
.Fetch;
var enableCommandSettings = new V89.Fetch.EnableCommandSettings();
var requestPattern = new V89.Fetch.RequestPattern();
requestPattern.RequestStage = V89.Fetch.RequestStage.Response;
requestPattern.ResourceType = V89Net.ResourceType.Document;
enableCommandSettings.Patterns = new V89.Fetch.RequestPattern[] { requestPattern };
fetch.Enable(enableCommandSettings);
void RequestIntercepted(object sender, V89.Fetch.RequestPausedEventArgs e)
{
e.Request.Url.Dump();
fetch.ContinueRequest(new V89.Fetch.ContinueRequestCommandSettings()
{
RequestId = e.RequestId
});
}
fetch.RequestPaused += RequestIntercepted;
while (true)
{
driver.Url = "https://translate.google.com/";
Thread.Sleep(5000);
driver.Navigate().Refresh();
}
Screenshot (From left-to-right): LinqPad output Console.Write.Url equivalent, Above code in LINQPad, and view of Chrome log file)

How can I create a textbox that opens Google search in a Windows application with CefSharp

I have a CefSharp WPF application and I need a textbox that will open Google searching the query in the application without closing and reopening it.
I'm working on it for something. Is this achievable?
Yes it is achievable if you use CefSharpBrowser control.
There is a browser implemented in WPF in this sample:.
This constructor logic from the same sample should help you to get started:
public BrowserTabViewModel(string address)
{
Address = address;
AddressEditable = Address;
GoCommand = new RelayCommand(Go, () => !String.IsNullOrWhiteSpace(Address));
HomeCommand = new RelayCommand(() => AddressEditable = Address = CefExample.DefaultUrl);
ExecuteJavaScriptCommand = new RelayCommand<string>(ExecuteJavaScript, s => !String.IsNullOrWhiteSpace(s));
EvaluateJavaScriptCommand = new RelayCommand<string>(EvaluateJavaScript, s => !String.IsNullOrWhiteSpace(s));
ShowDevToolsCommand = new RelayCommand(() => webBrowser.ShowDevTools());
CloseDevToolsCommand = new RelayCommand(() => webBrowser.CloseDevTools());
JavascriptBindingStressTest = new RelayCommand(() =>
{
WebBrowser.Load(CefExample.BindingTestUrl);
WebBrowser.LoadingStateChanged += (e, args) =>
{
if (args.IsLoading == false)
{
Task.Delay(10000).ContinueWith(t =>
{
WebBrowser.Reload();
});
}
};
});
PropertyChanged += OnPropertyChanged;
var version = string.Format("Chromium: {0}, CEF: {1}, CefSharp: {2}", Cef.ChromiumVersion, Cef.CefVersion, Cef.CefSharpVersion);
OutputMessage = version;
}
Hope this helps.

WF6 Workflow Foundation resume without applying changes to PersistentStore

I need to simulate an existing WF process "on dry", meaning it was persisted to db and now I resume it to collect various "what-if" data.
After it completes, I Abort() it, but it leaves WF instance void.
app = new WorkflowApplication(flowChart);
app.Load("guid");
app.InstanceStore = CreateInstanceStore();
var evt = new AutoResetEvent(false);
app.PersistableIdle = e =>
{
evt.Set();
return PersistableIdleAction.None;
};
app.ResumeBookmark("bookmark");
evt.WaitOne();
app.Abort();
private SqlWorkflowInstanceStore CreateInstanceStore()
{
SqlWorkflowInstanceStore instanceStore = new SqlWorkflowInstanceStore(connectionString)
{
InstanceCompletionAction = InstanceCompletionAction.DeleteNothing
};
var instanceHandle = instanceStore.CreateInstanceHandle();
var view = instanceStore.Execute(instanceHandle,
new CreateWorkflowOwnerCommand(), TimeSpan.FromSeconds(10));
instanceHandle.Free();
instanceStore.DefaultInstanceOwner = view.InstanceOwner;
return instanceStore;
}
I need to "undo" any changes the wf state may have done to persistent store.
Any suggestions?

Best way to run multiple workflows concurrently in WF 4.0

I have a routine that creates n instances of a particular workflow and runs them each serially. How could I fire them off async?
Current p-code:
forloop
// Create
var syncEvent = new AutoResetEvent(false);
WorkflowInstance myInstance = new WorkflowInstance(new SomeWorkflow(), parameters);
// Events
// Completed
myInstance.OnCompleted = delegate(WorkflowCompletedEventArgs e) { syncEvent.Set(); };
// Unhandled Exception
myInstance.OnUnhandledException = delegate(WorkflowUnhandledExceptionEventArgs e)
{
// Message
Console.WriteLine(e.UnhandledException.ToString());
return UnhandledExceptionAction.Terminate;
};
// Aborted
myInstance.OnAborted = delegate(WorkflowAbortedEventArgs e)
{
// Message
Console.WriteLine(e.Reason);
syncEvent.Set();
};
// Run
myInstance.Run();
// Wait
syncEvent.WaitOne();
I think the easiest way to get from here to there would be just to create multiple wait handles and end with a WaitAll(). Not the most elegant solution, but it will work for you. BTW, I would recommend using a real class that holds reference to the associated wait handle and avoiding the anon methods.
List<ManualResetEvent> items = new List<ManualResetEvent>();
foreach (Type job in queue)
{
WorkflowInstance myInstance = new WorkflowInstance(job, parameters);
ManualResetEvent syncEvent = new ManualResetEvent(false);
items.Add(syncEvent);
// Completed
myInstance.OnCompleted = delegate(WorkflowCompletedEventArgs e)
{
syncEvent.Set();
};
// Unhandled Exception
myInstance.OnUnhandledException = delegate(WorkflowUnhandledExceptionEventArgs e)
{
// Message
Console.WriteLine(e.UnhandledException.ToString());
return UnhandledExceptionAction.Terminate;
};
// Aborted
myInstance.OnAborted = delegate(WorkflowAbortedEventArgs e)
{
// Message
Console.WriteLine(e.Reason);
syncEvent.Set();
};
// Run
myInstance.Run();
}
// Wait
WaitHandle.WaitAll(items.ToArray());
Use parallel framework, it will be easier.
Do you really need them running on separate threads? I'm thinking since you are using Workflow already it should be easiest to solve the problem by using workflow to 'organize your work'.
{
var ArgsToProcess = new List<string> { "arg_one", "arg_two", "arg_three" };
var delegateArg = new DelegateInArgument<string> { Name = "s" };
Activity toRun = new ParallelForEach<string>
{
Body = new ActivityAction<string>
{
Argument = delegateArg,
Handler = new Workflow1() //Plug your workflow here
{
Arg = delegateArg
}
}
};
WorkflowInvoker.Invoke(toRun, new Dictionary<string, object>
{
{"Values", ArgsToProcess}
});
}

Categories

Resources