edit
it's A known problem with some microsoft security issue
https://social.msdn.microsoft.com/Forums/en-US/58da3fdb-a0e1-4161-8af3-778b6839f4e1/bluetooth-bluetoothledevicefromidasync-does-not-complete-on-10015063?forum=wdk
adding registery CoInitializeSecurity values as mentioned fixed the problem!
i'm trying to read A BLE device services using An Advertisment watcher.
i've implemnted the service read inside the listenter, the Code:
private async void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs args)
{
if (!gotSignal)
{
gotSignal = true;
device = await Windows.Devices.Bluetooth.BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);
service = await GattDeviceService.FromIdAsync(device.DeviceId);
}
...
}
the problem is that I can't get the BluetoothLEDevice object, when I reach this line, it is not getting back any value and it skips the next lines inside the listener.
NOTE: I've installed windows creators update and before the installation, the function BluetoothLEDevice.FromBluetoothAddressAsync has worked.
Solution
it's A known problem with some microsoft security issue https://social.msdn.microsoft.com/Forums/en-US/58da3fdb-a0e1-4161-8af3-778b6839f4e1/bluetooth-bluetoothledevicefromidasync-does-not-complete-on-10015063?forum=wdk
adding registery CoInitializeSecurity values as mentioned fixed the problem!
Related
Installed Unity Version is 2020.2.1f1
I'm developing an online multiplayer game using Unity. I have 2 different connection types; Http and Websocket(using Websocketsharp: https://github.com/sta/websocket-sharp, I've installed it using Nuget). Http get/post, Websocket connect/send/close works totally fine but when I call function (directly or by sending events) after response, most of the time my code inside that called function is not completed on editor(works fine on builds-android,ios). I'm not sure if this problem is related to http/websocket but it's related to online connection because I've experienced the same issue when I was developing a real-time multiplayer game using Unity & Gamesparks.
I can do basic functions like print etc. until I call one of the following functions loadscene, update UI, or call another function in same/different script(only first one of these works, everything after that won't run). Console doesn't show any error and game doesn't pause or crash. It runs on same fps but that part of the code won't continue. Other scripts/updates works fine. I've searched a lot but couldn't even find a related topic.
WebSocket Client:
void OnBattleResponse(object sender, MessageEventArgs messageEventArgs) {
string message = messageEventArgs.Data;
if (messageEventArgs.Data.Equals(Constants.WEBSOCKET_ERROR))
return;
var webSocketData = JsonUtility.FromJson<BattleResponseSerializable>(message);
switch (webSocketData.type) {
case 0:
seed = webSocketData.user1.seed;
opponentSeed = webSocketData.user2.seed;
_connectionManager.BattleGetStart(seed, opponentSeed);
break;
.
.
.
}
Connection Manager:
public void BattleGetStart(int userSeed, int opponentSeed) {
_gameManager.StartWave(userSeed, opponentSeed);
}
Game Manager
public void StartWave(int userSeed, int opponentSeed)
{
UserSeed = userSeed;
OpponentSeed = opponentSeed;
UserRandom = new System.Random(UserSeed);
OpponentRandom = new System.Random(OpponentSeed);
StartWaveTimer(); // After this nothing will be run, it's not related to startWaveTimer, any function that I've mentioned causes the same issue.
print("DOESN'T WORK"); // This doesn't work on Editor but works on builds
_spawner.ActivateSpawner(true); // doesn't work
}
I've found a trick to handle this situation but I didn't like it as a proper solution and don't wanna spend resources for Update calls. When I call function (directly or by sending events) after response, inside the called function I set bool to true and in Update call I call the necessary function when the bool is true and the code works totally fine.
---The Trick---
Game Manager
bool startWave;
public void StartWave(int userSeed, int opponentSeed)
{
UserSeed = userSeed;
OpponentSeed = opponentSeed;
UserRandom = new System.Random(UserSeed);
OpponentRandom = new System.Random(OpponentSeed);
startWave = true;
}
void Update() {
if (startWave) {
startWave = false;
StartWaveTimer();
print("WORKS"); // With this trick, it works on editor too.
_spawner.ActivateSpawner(true); // works
}
}
What can be the reason of my script working on builds but not on unity editor?
Thank you!
Advice for those who will experience that kind of issue:
As I've found out Unity is not Thread safe. Unity limits us on calling their API from another Thread, which causes this issue.
So you have to call your functions/methods from main thread instead of another thread.
I'm using BluetoothLEAdvertisementWatcher to find nearby BLE devices and it's working well. After finding them I want to connect and read/write data via GATT. But I can't figure out how to use the API after getting the BluetoothLEAdvertisement (https://msdn.microsoft.com/de-de/library/windows/apps/windows.devices.bluetooth.genericattributeprofile).
public class Adapter
{
private readonly BluetoothLEAdvertisementWatcher _bleWatcher = new BluetoothLEAdvertisementWatcher();
public Adapter()
{
_bleWatcher.Received += BleWatcherOnReceived;
}
private void BleWatcherOnReceived(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{
// how to connect?
// I know, it's the wrong place to to this, but this is just an example
}
public void StartScanningForDevices(Guid[] serviceUuids)
{
_blewatcher.advertisementfilter.advertisement.serviceuuids.clear();
foreach (var uuid in serviceuuids)
{
_blewatcher.advertisementfilter.advertisement.serviceuuids.add(uuid);
}
_blewatcher.start();
}
}
I've found Samples that are using DeviceInformation.FindAllAsync instead of BluetoothLEAdvertisementWatcher but these are not working / finding any device.
UPDATE
After digging around some time, I found the following way. But unfortunately, the pairing fails. The device is just an Arduino with a BLE shield. I can definitely connect with Android and iOS. So it must be possible with UWP somehow. :/
private void BleWatcherOnReceived(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{
var dev = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);
// dev.DeviceInformation.Pairing.CanPair is true
// dpr.Status is Failed
DevicePairingResult dpr = await dev.DeviceInformation.Pairing.PairAsync(DevicePairingProtectionLevel.None);
var service = await GattDeviceService.FromIdAsync(dev.DeviceInformation.Id);
}
UPDATE #2
I'm now able to discover and pair (unstable, but ok for now), but
var service = await GattDeviceService.FromIdAsync(args.Id);
throws the following Exception
System.IO.FileNotFoundException:
The system cannot find the file specified. (Exception from HRESULT: 0x80070002)
I have no clue why.
UPDATE 04/17 - CREATORS UPDATE
Microsoft have just updated their Bluetooth APIs. We now have unpaired BLE device communication!
They have very little documentation up at the moment but here is the much simplified new structure:
BleWatcher = new BluetoothLEAdvertisementWatcher
{
ScanningMode = BluetoothLEScanningMode.Active
};
BleWatcher.Start();
BleWatcher.Received += async (w, btAdv) => {
var device = await BluetoothLEDevice.FromBluetoothAddressAsync(btAdv.BluetoothAddress);
Debug.WriteLine($"BLEWATCHER Found: {device.name}");
// SERVICES!!
var gatt = await device.GetGattServicesAsync();
Debug.WriteLine($"{device.Name} Services: {gatt.Services.Count}, {gatt.Status}, {gatt.ProtocolError}");
// CHARACTERISTICS!!
var characs = await gatt.Services.Single(s => s.Uuid == SAMPLESERVICEUUID).GetCharacteristicsAsync();
var charac = characs.Single(c => c.Uuid == SAMPLECHARACUUID);
await charac.WriteValueAsync(SOMEDATA);
};
Much better now. As I said there is next to no documentation at the moment, I have a weird issue where my ValueChanged callback stops being called after 30 seconds or so, though that seems to be a separate scoping issue.
UPDATE 2 - SOME WEIRDNESS
After some more playing around with the new creators update there are a few more things to consider when building BLE apps.
You no longer need to run the Bluetooth stuff on the UI thread. There doesn't seem to be any permissions windows for BLE without pairing so no longer necessary to run on UI thread.
You may find that your application stops receiving updates from the device after a period of time. This is a scoping issue where objects are being disposed of that shouldn't. In the code above if you were listening to ValueChanged on the charac you may hit this issue. This is because the GattCharacteristic is disposed of before it should be, set the characteristic as a global rather than relying on it being copied in.
Disconnecting seems to be a bit broken. Quitting an app does not terminate connections. As such make sure you use the App.xml.cs OnSuspended callback to terminate your connections. Otherwise you get in a bit of a weird state where Windows seems to maintain (and keep reading!!) the BLE connection.
Well it has its quirks but it works!
OLD ANSWER
Following on from Jason's correct answer about devices needing to be paired to have their services be discovered, here is some sample code to address this:
private void SetupBluetooth()
{
Watcher = new BluetoothLEAdvertisementWatcher { ScanningMode = BluetoothLEScanningMode.Active };
Watcher.Received += DeviceFound;
DeviceWatcher = DeviceInformation.CreateWatcher();
DeviceWatcher.Added += DeviceAdded;
DeviceWatcher.Updated += DeviceUpdated;
StartScanning();
}
private void StartScanning()
{
Watcher.Start();
DeviceWatcher.Start();
}
private void StopScanning()
{
Watcher.Stop();
DeviceWatcher.Stop();
}
private async void DeviceFound(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs btAdv)
{
if (_devices.Contains(btAdv.Advertisement.LocalName))
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Low, async () =>
{
Debug.WriteLine($"---------------------- {btAdv.Advertisement.LocalName} ----------------------");
Debug.WriteLine($"Advertisement Data: {btAdv.Advertisement.ServiceUuids.Count}");
var device = await BluetoothLEDevice.FromBluetoothAddressAsync(btAdv.BluetoothAddress);
var result = await device.DeviceInformation.Pairing.PairAsync(DevicePairingProtectionLevel.None);
Debug.WriteLine($"Pairing Result: {result.Status}");
Debug.WriteLine($"Connected Data: {device.GattServices.Count}");
});
}
}
private async void DeviceAdded(DeviceWatcher watcher, DeviceInformation device)
{
if (_devices.Contains(device.Name))
{
try
{
var service = await GattDeviceService.FromIdAsync(device.Id);
Debug.WriteLine("Opened Service!!");
}
catch
{
Debug.WriteLine("Failed to open service.");
}
}
}
private void DeviceUpdated(DeviceWatcher watcher, DeviceInformationUpdate update)
{
Debug.WriteLine($"Device updated: {update.Id}");
}
The key things to note here are:
DeviceWatcher needs both Added and Updated properties set to work.
You need to catch the exception FileNotFound which occurs when attempting to interrogate a service which is not paired, or not yet ready.
UPDATE (5/5/16): The "Element Not Found" error issue seems to only happen when the bluetooth settings screen isn't open/scanning. I don't remember that being the case before 10586.218 but I haven't checked. Obviously, not every issue is fixed in the update.
UPDATE (4/29/16): The 10586.218 windows update appears to have fixed the problem of pairing with a device that has never been paired to the machine (or phone) before. The process I've outlined here and Gerard Wilkinson's sample code in his answer should work more consistently now.
If you are lucky enough to get this to work, it requires waiting a considerable amount of time for the driver to install. I've done it by having both BluetoothLEAdvertisementWatcher and a DeviceWatcher running simultaneously.
Save the DeviceInformation from the BluetoothLEDevice that you get from FromBluetoothAddressAsync() then Dispose() the BluetoothLEDevice before initiating pairing. This is important. If you don't, it won't see the Gatt Services after pairing.
Then wait for the DeviceWatcher to see the paired device. It can take minutes but you'll usually get it before the progress bar for device installation (in the Bluetooth control panel) gets to 100%. If FromIdAsync still fails, it usually means there was a driver installation error. You can unpair and then do the pairing process over again. That usually works for me.
It's very unstable, though, and it seems to be dependent on which Bluetooth chipset and driver the machine has. I often get an Element Not Found error with FromBluetoothAddress but if it gets past there, pairing usually works on the first or second try.
PairAsync and UnpairAsync also need to be posted to the UI thread. If it isn't able to pop up a blue dialog asking for authorization, you'll get exceptions. You can use Post() from a saved UI SynchronizationContext or Windows.ApplicationModel.Core.CoreApplication.MainView.Dispatcher.RunAsync() with an async delegate to do this.
I've seen multiple posts from MS employees on the forums saying FromBluetoothAddressAsync() only works for paired devices. This isn't the case but it is buggy and seems to work best if the device has been paired manually at least once in the past.
Gerard Wilkinson's answer is correct. To make life easier, I turned it into an awaitable method using Reactive Extensions (). Any comments are welcome.
So once you found the device using the BluetoothLEAdvertisementWatcher and paired with it, you can use this to enable GATTServices.
private async Task<GattDeviceService> GetGATTServiceAsync(string deviceName)
{
//devicewatcher is abused to trigger connection
var deviceWatcher = DeviceInformation.CreateWatcher(); //trick to enable GATT
var addedSource = Observable.FromEventPattern(deviceWatcher, nameof(deviceWatcher.Added))
.Select(pattern => ((DeviceInformation)pattern.EventArgs));
var updatedSource = Observable.FromEventPattern(deviceWatcher, nameof(deviceWatcher.Updated))
.Select(pattern =>
{
var update = ((DeviceInformationUpdate)pattern.EventArgs);
return Observable.FromAsync(() => DeviceInformation.CreateFromIdAsync(update.Id).AsTask());
}).Concat();
var source = addedSource.Merge(updatedSource);
source.Publish().Connect(); //make sure the event handlers are attached before starting the device watcher
deviceWatcher.Start();
var result = await source.Where(di => di.Name == deviceName) //find the relevant device
.Select(di => Observable.FromAsync(() => GattDeviceService.FromIdAsync(di.Id).AsTask())) //get all services from the device
.Concat() //necessary because of the async method in the previous statement
.Where(service => service.Uuid == SERVICE_UUID) //get the service with the right UUID
.Retry() //GattDeviceService.FromIdAsync can throw exceptions
.FirstAsync();
deviceWatcher.Stop();
return result;
}
Basically you have the answer partly included in the questions. In essence you use the BluetoothLEAdvertisementWatcher for finding the devices only, basically they work just as beacons.
And you are not suppose to connect these devices by only using this API. To connect the devices you must use DeviceInformation.FindAllAsync(), and to get it to show you any devices, you do need to pair them first.
Anyway, if you are interested on getting data from some specific BLE characteristics, you could try using GattCharacteristicNotificationTrigger, for full example & a bit of additional explanations see my blog.
Ive been working on some communication between a PC and a Raspberry PI 2 with Windows 10 IoT (build 10586 TH2) using "StreamSocketListener". This seems to work fine in debug mode, but when testing the code in release mode the "StreamSocketListener" seems to randomly stop responding to requests.
In debug mode, on the RPI2, I've had sessions with 100k requests without a single issue, but when I push the release build it stops, randomly, quite quickly (typically after a couple of hundreds requests). The request is of static type, so the input is the same every time.
Has anyone experienced the same issue, and is there a solution to this problem?
The code is based on this blog post:
A simple in-process HTTP server for Windows 8 Metro apps
private void Listen()
{
_listener = new StreamSocketListener();
_listener.ConnectionReceived += (s, e) => ProcessRequestAsync(e.Socket);
_listener.BindServiceNameAsync(requestPort.ToString());
}
private async void ProcessRequestAsync(StreamSocket socket)
{
try
{
// this works for text only
StringBuilder request = new StringBuilder();
using (IInputStream input = socket.InputStream)
{
byte[] data = new byte[BufferSize];
IBuffer buffer = data.AsBuffer();
uint dataRead = BufferSize;
while (dataRead == BufferSize)
{
await input.ReadAsync(buffer, BufferSize, InputStreamOptions.Partial);
request.Append(Encoding.UTF8.GetString(data, 0, data.Length));
dataRead = buffer.Length;
}
}
using (IOutputStream output = socket.OutputStream)
{
string requestMethod = request.ToString().Split('\n')[0];
string[] requestParts = requestMethod.Split(' ');
if (requestParts[0] == "GET")
await WriteResponseAsync(requestParts[1], output);
else
throw new InvalidDataException("HTTP method not supported: "
+ requestParts[0]);
}
}
catch (Exception e)
{
Debug.WriteLine("Main ex: " + e);
}
RequestCount++;
}
After a whole day long term testing with the "Compile with .NET Native tool chain" setting turned ON for my UWP project this issue seems to be fixed. When disabling this feature the issue occur after just a couple of minutes.
Because I cant accept a comment as an answer, I'll just answer my own question, and accept it. But all thanks to Matt for pointing me in the right direction.
Interesting... does this still reproduce if you disable .NET Native compilation? (Project properties > BUILD > "Enable .NET Native toolchain") – Matt Whilden
Matt, Gnm:
I've had exactly the same issue on a RPi3 running on Win-IoT 10.0.14393.693, with a C# code very similar to that in Gnm's first post: StreamSocketListener just stopping to listen to/receive http POST messages while the rest of the app (a web server background service) remained responsive.
Two differences though:
a) on my machine, that happened already within one minute after app launch, and after only one or two requests.
b) And it happened with the "Compile with .NET Native Tool chain" option switched to "ON"!
Inspired by Gnm's findings I have now switched this option to OFF, and: my problem appears to be solved. At the time of writing this, the code has been running for one hour only, but it appears to be working and stable now. So, surprisingly, for me the exact opposite of Gnm's solution works...
FYI I had the same problem for a Windows 10 Iot c# app. Mine was fixed by "Compile with .NET Native Tool chain" option switched to "ON" then "Compile with .NET Native Tool chain" option switched to "OFF"!
I'm using 2 WebClients in my app, for 2 different weather API's.
When my internet connection is slow I get an exception from one of the API's.. It returns a 404 Notfound error.
I have tested this by disabling my WiFi, and put the data connection to '2G'. The first API returns the data with no problem, the second API however crashes my app with a WebException.
When I turn on the WiFi again it works flawlessly. Looks like the second API has a very little patience with slow connections.
Is there a way to fix this? I have also tried to change the WebClient into a HttpWebRequest but the problem still occurs.
Kind regards,
Niels
EDIT
My code:
private void GettingTheData()
{
WebClient Client = new WebClient();
Client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Client _DownloadStringCompleted);
Client.DownloadStringAsync(new Uri("http://theURI.com"));
}
void Client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
string result = e.Result.ToString();
// Let's do the cool stuff overhere
}
There exist HTTP Client library for WP which contains support for timeout. Article about it.
Some sample code for Windows Phone 8:
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
var httpClient = new HttpClient {Timeout = TimeSpan.FromSeconds(30)};
var responseBodyAsText = await httpClient.GetStringAsync("www.contoso.com");
}
Maybe the problem isn't the network latency. Perhaps your second API has a requirement that callers send a user-agent string, or some other HTTP header that you aren't sending. The fact that it works over WiFi and not 2G could have something to do with the fact that any device connecting from your WiFi network would appear to be the same to the server hosting the API (from an IP Address standpoint) and may allow access based on some cached identity (maybe you browsed the service to test it from your development PC). I would be interested to see what would happen if you connected to a different WiFi network if the response would be similar.
My immediate suggestion would be to catch the WebException and give the user a chance to retry.
I would have added this as a comment but I guess I don't have enough reputation for that.
Try increasing the ServicePointManager.DefaultConnectionLimit though the default is 2.
I implemented windows service with eventLog and FileSystemWatcher that looks for changes in specific directory and writes messages into MyLog.
strange thing 1:
I install it via installUtil.exe (since the VS2012 doesn't have installer templates) and in some situations when I go to "Services" and start the service I get:
The [service name] service on local computer started and then stopped. Some Services stop automatically if they are not in use by another services or programs.
I've already seen this question. 2 answeres from this post why it can be so:
1) There is no thread starting in OnStart() method.
I use the designer and set most of the properties in the Properties window and I never started any thread manually, but in some cases everything was working, so I think this is not the case.
2) An exception occures in OnStart() method. I think it's not the case cause I don't change the code. I just uninstall, build and install again the same service and in some cases it runs, in some not.
When I was stuck for mabby 2 hours with this thing I noticed that the Source property of eventLog is too long: "FilesMonitoringServices". I changed it to "MonitorSource" and everything started to work. Than I reinstalled it cauple of times and got the same warning as the above. I changed the Source property again and now the service runs.
This is the first strange thing.
strange thing 2: worse. Even if it runs it logs only OnStart() and OnStop() methods, I mean the fileSystemWatcher event handler never excutes. It is strange because today I reinstalled this service mabby hundred times and 3 times it was working but after I reinstalled it once again it stoped. And I haven't changed the code between the reinstallations at all.
Here is the methods and constructor from my class (MonitoringService) that inherits ServiceBase:
public MonitoringService()
{
InitializeComponent();
if (!EventLog.SourceExists(eventLog.Source))
{
EventLog.CreateEventSource(eventLog.Source, eventLog.Log);
}
// haven't changed it between the reinstallations
fileWatcher.Path = #"path";
}
protected override void OnStart(string[] args)
{
fileWatcher.EnableRaisingEvents = true;
eventLog.WriteEntry("start", EventLogEntryType.Information);
base.OnStart(args);
}
protected override void OnStop()
{
fileWatcher.EnableRaisingEvents = false;
fileWatcher.Dispose();
eventLog.WriteEntry("stop", EventLogEntryType.Information);
base.OnStop();
}
And file system watcher event handler:
private void fileSystemWatcher1_Changed(object sender, FileSystemEventArgs e)
{
using (var conn = new SqlConnection(GetConnectionString()))
{
conn.Open();
var productId = Convert.ToInt32(Regex.Match(e.Name, #"\d+").Value);
const string cmd = "UPDATE Products SET ImageModifiedDate=#date WHERE ProductId=#productId";
using (var command = new SqlCommand(cmd, conn))
{
command.Parameters.AddWithValue("#productId", productId);
command.Parameters.AddWithValue("#date", DateTime.Now);
command.ExecuteNonQuery();
}
}
eventLog.WriteEntry(string.Format("{0} has been changed: {1}", e.Name, DateTime.Now), EventLogEntryType.Information);
}
Question: it seems to me that this behavior is caused not by my code but rather by operation system settings . Can it be so?
****Edits: just discovered more specific stuff:**
1) If it shows the message (when I want to start the service):
The [service name] service on local computer started and then stopped. ....
I need to change Source property of eventLog, rebuild and reinstall. And this message will not show up; mabby next time.
2) I have the following folders hierarchy: images/prod-images. images and prod-images directories both contain image files. When the service is runing and I change the image from prod-images folder the message is written into the log as I wanted and the database is updated. But after one this event the service stops! (I checked this 3 times). And when I restart it and repeat this again a couple of times it updates database, writes logs and on the 3d time I get
The [service name] service on local computer started and then stopped. ....
But this is not the best part) If I change the image that is in images directory I can do it multiple times and the service doesn't stop. (only images from images/prod-images are bound to entries in the database).
So, mabbe this feature somehow referes to the database accessing?
Edits 2: in visual studio I use DEBUG -> Attach to Process to debug the service. I set up the breakpoints and change the image. First time the event handler executes flawlessly: the database is updated and the log message is written. But than I continue to press F11 (Step Into) and this event handler executes second time. At the line
var productId = Convert.ToInt32(Regex.Match(e.Name, #"\d+").Value);
I get "FormatException was unhandled". After this I stop debugging and the service stops! That's it: the exception occures in event handler.
Do You have any idea why it executes second time? Thanks!
P.S. I've already submited Davut Gürbüz answer cause he pointed me in the right direction.
Anyway, check out my own answer that explains the actual problem.
If you got start-stop error, this means you have an error in constructor.
Put a try catch into your ctor. You may log the error to eventlog in catch block.
Beside this I create a main method and start win service as a console app. If I get an instance of service in my main method I can also Debug it.
//You should select Console Application from Application properties
static void Main(string[] args)
{
MyWindowsService service = new MyWindowsService();
if (Environment.UserInteractive)
{
service.OnStart(args);
Console.WriteLine("Press any key to stop program");
Console.Read();
service.OnStop();
}
else
{
ServiceBase.Run(service);
}
}
Hope helps
The reason why the fileSystemWatcher1_Changed event handler method was executing twice is because I was monitoring images folder included subdirectories. And this event handler was monitoring all LastWrite events.
So, when I changed the image in images/prod-images directory this handler reacted to the image changing and also to the folder changing.
In this situation I either can change the monitoring path to prod-images or insert an if statement when updating the DB.
Such a silly mistake took me a couple of days to find it out))