WebView2 log http traffic (inbound and outbound) - c#

As stated in the title i'm interested in the management (reading is sufficient by now) of the the incoming and outgoing data from the WebView2 istance user are using.
I'have try do add listener to WebMessageResourceRequested and WebMessageReceived but i have the sensation i missinterpreted their behaviour becasue they don't work as i expected (so is very likely that i am using that handler in a wrong way)
public partial class SimpleWebView2 : Form
{
public SimpleWebView2 ()
{
InitializeComponent();
this.Initialization();
}
private async void Initialization ()
{
await webView21.EnsureCoreWebView2Async();
webView21.CoreWebView2.WebResourceRequested += new EventHandler<CoreWebView2WebResourceRequestedEventArgs>(this.webView21_WebMessageResourceRequested);
}
private void webView21_WebMessageResourceRequested(object sender, CoreWebView2WebResourceRequestedEventArgs e)
{
//does not fire
}
}

A common solution is Fiddler. Just start it and you'll see the inbound and outbound traffic of any application, including the one that is using WebView2.

Related

Blazor StateHasChanged() doesnt update global class values on page

So im trying to implement a multi-site server-side blazor application that has two services implemented as singletons like this:
services.AddSingleton<MQTTService>();
services.AddHostedService(sp => sp.GetRequiredService<MQTTService>());
services.AddSingleton<DataCollectorService>();
services.AddHostedService(sp => sp.GetRequiredService<DataCollectorService>());
The MQTT Service is connecting to the broker and managing the subscriptions and stuff, while the DataCollectorService subscribes to an event from the MQTT Service to be notified when a new message arrives. The business logic with the received data is then happening within the DataCollectorService, stuff like interpreting the topic and the payload of the mqtt message. If its valid, the DataCollectorService stores the Data in a (example) global static class:
if (mqtt.IsTopic(topic, MQTTService.TopicDesc.FirstTopic))
{
if(topic.Contains("Data1"))
{
if(topic.Contains("Temperature"))
{
DataCenter.Data1.Temperature= Encoding.UTF8.GetString(message, 0, message.Length);
}
}
}
The DataCenter is just a static class in the namespace:
public static class DataCenter
{
public static DataBlock Data1 = new DataBlock();
public static DataBlock Data2 = new DataBlock();
public static string SetMode;
public class DataBlock
{
public string Temperature { get; set; }
public string Name{ get; set; }
}
}
My Goal with this approach is that every different page in my project can just bind these global variables to show them.
The first problem that occurs then is that obviously the page is not aware of the change if the DataCollectorService updates a variable. Thats why i implemented a notifying event for the pages, which can then call StateHasChanged. So my examplePage "Monitor" wants to just show all these values and injects the DataCollectorService:
#page "/monitor"
#inject DataCollectorService dcs
<MudText>DataBlock Data1: #DataCenter.Data1.Temperature/ Data2: #DataCenter.Data2.Temperature</MudText>
#code
{
protected override void OnInitialized()
{
dcs.OnRefresh += OnRefresh;
}
void OnRefresh()
{
InvokeAsync(() =>
{
Console.WriteLine("OnRefresh CALLED");
StateHasChanged();
});
}
}
This actually works, but adds a new problem to the table, everytime i switch to my monitor site again a NEW OnRefresh Method gets hooked to the Action and that results in multiple calls of "OnRefresh". I find this behaviour rather logical, cuz i never delete an "old" OnRefresh Method from the Action when I'm leaving the site, cuz i dont know WHEN i leave the site.
Thinking about this problem i came up with a solution:
if (!dcs.IsRegistered("monitor"))
{
dcs.OnRefresh += OnRefresh;
dcs.RegisterSubscription("monitor");
}
I wrapped the action subscription with a system that registers token whenever the handler is already correctly assigned. the problem now: the variables on the site dont refresh anymore!
And thats where i'm not sure how to understand whats going on anymore. If i keep it like in the first example, so just adding dcs.OnRefresh += OnRefresh; and letting it "stack up", it actually works - because there is always a "new" and "correctly" bound method which, in my limited understanding, has the correct context.
if i forbid this behaviour i only have an somehow "old" method connected which somehow cant execute the StateHasChanged correctly. But i dont know why.
I'm not sure if i could:
"Change" the context of the Invoke Call so that StateHasChanged works again?
Change the way I register the Action Handling method
I'm additionally confused as to why the first way seems to call the method multiple times. Because if its not able to correctly call StateHasChanged() in the old method, why can it be called in the first place?
I would very much appreciate some input here, googling this kind of stuff was rather difficult because i dont know the exact root of the problem.
Not only do you have multiple calls, you also have a memory leak. The event subscription will prevent the Monitor object to be collected.
Make the page IDisposable:
#page "/monitor"
#inject DataCollectorService dcs
#implements IDisposable
...
#code
{
protected override void OnInitialized()
{
dcs.OnRefresh += OnRefresh;
}
...
public void Dispose()
{
dcs.OnRefresh -= OnRefresh;
}
}

How to make Redis notify my service about events

I have a remote computer with Redis. From time to time new entries are added to it (key-value pair). I want Redis to send notifications to my C# Service about events like this (i'm interested in value part). I've searched online and found simple code example to subscribe my Service to Redis. How to make Redis send notifications?
Service:
public partial class ResultsService : ServiceBase
{
private ConnectionMultiplexer connection = ConnectionMultiplexer.Connect(ConfigurationManager.AppSettings["RedisConnection"]);
private const string ChatChannel = "__keyspace#0__:*";
public VerificationResultsService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
Start();
}
public void Start()
{
var pubsub = connection.GetSubscriber();
pubsub.Subscribe(ChatChannel, (channel, message) => MessageAction(message));
while (true)
{
}
}
private static void MessageAction(RedisValue message)
{
// some handler...
}
}
Making redis send automatic keyspace notifications is a redis server configuration piece, which can be enabled via the .conf file (notify-keyspace-events), or via CONFIG SET at runtime; the documentation for this is here.
You can see how this works with example code:
using StackExchange.Redis;
using System;
using System.Linq;
static class P
{
private const string ChatChannel = "__keyspace#0__:*";
static void Main()
{
// connect (allowAdmin just lets me use ConfigSet)
using var muxer = ConnectionMultiplexer.Connect("127.0.0.1,allowAdmin=true");
// turn on all notifications; note that this is server-wide
// and is NOT just specific to our connection/code
muxer.GetServer(muxer.GetEndPoints().Single())
.ConfigSet("notify-keyspace-events", "KEA"); // KEA=everything
// subscribe to the event
muxer.GetSubscriber().Subscribe(ChatChannel,
(channel, message) => Console.WriteLine($"received {message} on {channel}"));
// stop the client from exiting
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}
which works like:
However, in many scenarios you may find that this is too "noisy", and you may prefer to use either a custom named event that you publish manually when you do things that need notification, or (again manually) you could make use of the streams features to consume a flow of data (streams can be treated as a flow of events in the "things that happened" sense, but they are not delivered via pub/sub).

Handling suspend, resume, and activation in windows 10 UWP

In the windows 8.1 universal apps, the suspend/resume modes were handled using the NavigationHelper.cs ans SuspensionManager.cs classes included in the APP template. These classes doesn't seem to be there in the windows 10 UWP apps. Is there a way by which we can handle the suspend/resume states?
There's an interesting framework being developed by the community (but mostly I think Jerry Nixon, Andy Wigley etc.) called Template10. Template10 has a Bootstrapper class with OnSuspending and OnResuming virtual methods that you can override. I am not sure that there's an exact example of doing suspension/resuming yet with Template10, but the idea seems to be to make App.xaml.cs inherit from this Bootstrapper class so you can easily override the methods I mentioned.
sealed partial class App : Common.BootStrapper
{
public App()
{
InitializeComponent();
this.SplashFactory = (e) => null;
}
public override Task OnStartAsync(StartKind startKind, IActivatedEventArgs args)
{
// start the user experience
NavigationService.Navigate(typeof(Views.MainPage), "123");
return Task.FromResult<object>(null);
}
public override Task OnSuspendingAsync(object s, SuspendingEventArgs e)
{
// handle suspending
}
public override void OnResuming(object s, object e)
{
// handle resuming
}
}
The above solution will only work for people who install Template10.
The generic solution is,
paste these lines in the constructor of App.xaml.cs
this.LeavingBackground += App_LeavingBackground;
this.Resuming += App_Resuming;
It will look like this
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
this.LeavingBackground += App_LeavingBackground;
this.Resuming += App_Resuming;
}
These are the methods, although you can press TAB and they will autogenerate.
private void App_LeavingBackground(object sender, LeavingBackgroundEventArgs e)
{
}
private void App_Resuming(object sender, object e)
{
}
The methods LeavingBackground and the one not mentioned here EnteredBackground are newly added to uwp.
Before these methods we would use resuming and suspending to save and restore ui, but now the recommended place to do that work is here.Also these are the last places to perform work before the app is resumed. So the work on these methods should be small ui or other stuff like remaking values which are stale as a long held method here will affect app startup time while resuming.
Source
Windows dev material ,
Windoes dev material 2
Thanks , and have a good day.

C# Waiting for an action in a parallel thread

I have a C# form application to send CAN messages.
At the start, I start a thread which monitors incoming messages, and displays them on a DataGridView.
Currently the app is set so that the user can send a CAN message one at time, and view its response.
All this works fine, and reliably.
Phase 2 of my application requires me to send a full list of CAN messages automatically.
For this I need to send a CAN message, and wait for its response, and then send the next.
How can I monitor the receive thread, and halt my send function long enough for the response to be received?
As the send message is not in a separate thread, Thread.Sleep(n) halts the entire program.
My approach:
public class DataViewModel
{
public AsynchronousCommand Send;
public DataViewModel()
{
Send = new AsynchronousCommand(() =>
{
SendData();
});
}
private void SendData()
{
}
}
public class SomewhereInForm
{
private DataViewModel dataViewModel = new DataViewModel();
public SomewhereInForm()
{
dataViewModel.Send.Executed += SendOnExecuted;
}
private void SendOnExecuted(object sender, CommandEventArgs args)
{
}
private void DoSome()
{
dataViewModel.Send.DoExecute(new int());
}
}
It's example with 1 command. You can put commands in List, whatever.
If you don't want build your own library witch commands, use this: Commands in MVVM

How do I update a WPF Window with information from a background thread?

I'm creating a wpf application which performs many tasks in the backgound, but still requires the UI to be responsive and to display the status of the various background tasks. It also has the option to not display the UI at all, in which case the status messages should be discarded without creating an instance of the main form at all.
What I've attempted is to remove
StartupUri="MainWindow.xaml"
from App.xaml. Then, in App.xaml.cs, I have
`
public App()
{
Startup += new StartupEventHandler(App_Startup);
}
void App_Startup(object sender, StartupEventArgs e)
{
// Code which loads application settings is here
if (pf.ShowUI)
{
MainWindow mainWindow = new MainWindow();
mainWindow.Show();
}
// The background processes will begin here.
}`
This shows the main form, if necessary, and starts all the background processes. This part works.
In order to send messages from the background to the UI, I've implemented a very basic messenger:
`
internal interface IMessageHandler
{
void ReceiveMessage(string message);
}
internal class Messenger
{
private static List<IMessageHandler> _handlers;
internal static void AddHandler(IMessageHandler handler)
{
_handlers.Add(handler);
}
internal static void RemoveHandler(IMessageHandler handler)
{
try
{
_handlers.Remove(handler);
}
catch (Exception ex) {}
}
internal static void Broadcast (string message)
{
foreach (IMessageHandler handler in _handlers)
{
handler.ReceiveMessage(message);
}
}
}`
The main form implements the IMessageHandler interface, and adds itself to the Messenger as a handler when it starts up. Any process that needs to send a status to the main form just needs to call the Broadcast method of the messenger.
The problem I'm having, is that the messages are not being shown on the form until the background processes complete, and the UI is locked up until then as well.
The code in the UI which handles receiving messages is as follows:
`
public void ReceiveMessage(string message)
{
Dispatcher.Invoke(DispatcherPriority.Normal,
new Action<string>(AddText),
message);
}
private void AddText(string text)
{
Label myLabel = new Label();
myLabel.Content = text;
stackPanel1.Children.Add(myLabel);
if (stackPanel1.Children.Count > 5)
{
stackPanel1.Children.RemoveAt(0);
}
}`
Why are my background processes freezing my UI? What can I do to prevent it? And why is my UI not updating with the status messages?
Maybe this is your problem:
Dispatcher.Invoke(DispatcherPriority.Normal,
new Action<string>(AddText),
message);
Try change this to,
Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new Action<string>(AddText),
message);
Because when you use Invoke, the method gets executed and the application waits for it to complete, but with BeginInvoke the method is invoked Asychnronously and the application continues to execute while the method referenced in BeginInvoke is executed.
Read this: whether to use Invoke or BeginInvoke
Use the below code to avoid freezing the UI. In my application I have used a BackgroundWorker class. By changing anything on the form using code, a run time error is thrown.
I am using the below code to avoid this and it works perfectly for me.
Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate()
{
rtf_status.AppendText("Validating XML against schema...Please wait\n");
}));
Note the part after the between braces ('{}') this is where you should place your code if you wish to change something on the form.

Categories