2.) If you need to support legacy operating systems then you may need to write your own filesystem or virtual disk driver. Bo Brantén has an example virtual disk driver that uses the HTTP protocol that could probably be modified to use FTP instead:Windows driver examples[^]
There are some new features in Windows 10 that actually allow you to mount a remote filesystem. The 'Cloud' filesystem is protocol agnostic. So you could easily implement this with FTP, HTTP, Bittorrent or whatever.
you can create a table and add columns to it when the need arises, however that would be bad design for several reasons; the table structure would be unpredictable, it would probably be very sparse (most fields remain empty), and processing it could be quite cumbersome.
I'd suggest you use a very simple table with essentially two columns, say my_key and my_value, both string.
The problem is that "expanding tables" is a pain - or you waste a huge amount of space on many rows if they don't want to store much.
Instead, I'd use a number of tables:
ID INT, IDENTITY
this ties all the other data for the row together. You may want other columns, but only if they will always be needed.
This holds the types of data the user may select
ID INT, IDENTITY
MasterID INT, FOREIGN KEY to Master.ID
RowID INT, FOREIGN KEY to RowDesc.ID
VALUE Your type for the data
When your user inserts a row, it creates a row in MASTER, and as many rows as necessary in RowData
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
Further to the very sound advice given by @OriginalGriff and @Luc_Pattyn, you need to know what type of data you are collecting. Are all of the values strings / numbers or a mix of strings, numbers, dates etc? Your sample has numbers masquerading as strings. As a general principle, saving non-strings as strings is a bad idea. If you have a limited set of data types, you could consider extending the simple Key / Value pattern to Key / DataType / ValueIfString / ValueIfNumber / ValueIfDate. This would mean you would be returning to a limited version of the waste space issue that the others have warned you about and is a solution that I would try to avoid. Anything that deals with non-homogeneous data is awkward; if it is homogeneous (e.g. all values are string or all values are numbers) then the methods given by @OriginalGriff and @Luc_Pattyn are preferred.
This is a genuine "why" question (as in the technical reason why the language prohibits what I want to do) rather than a "how do I get round the limitation?"*
I'm writing a WPF app and implementing a base class for a Command. The base implementation contains common logic to a set of subclasses which must have the Database connection in a non-busy state before they can execute. If the busy state changes, calling CanExecuteChanged?.Invoke(this, e); is naturally fine in this base. The problem is I have secondary conditions in the subclasses which also prevent execution - on those conditiond changing I'd want to call CanExecuteChanged?.Invoke(this, e); from the subclass - this isn't allowed and I can't work out the reasoning.
My current working theory is the even is like syntactic sugar over a delegates (or something) and the part to raise the event is private (which would prevent raising outside the base class) the whereas the subscription side is public (so you can subscribe from an unrelated type).That doesn't explain why the "raise" part isn't protected, or somehow optionally private/protected. There is a gap in my knowledge somewhere.
I have a couple of solutions for this: like exposing the delegate with a backing field and calling that, or the one I'll probably adopt which is to expose a protected event to raise the event seems more explicit.
Inside the same type, you will either reference the private field (for assignment, Invoke, etc.) or the event (for adding and removing handlers). The compiler will decide which.
Outside of the class, you only have access to the event. All you can do is add or remove a handler.
I believe this is to prevent other classes from raising events without the cooperation of the base class, or swapping out the entire list of handlers. But obviously you'd need to ask the original language designers to know their reasoning.
Of course, the simple workaround is to provide a protected method in the base class which raises the event on demand.
Oh wow thanks, that's exactly what I was hoping for. It's also along the the "syntactic sugar" line of thinking. I've been off C# as my main work for 4/5years now so I'm getting to grips with it all again. I won't utter the name of the language I have been principally using, but it rhymes with Lavascript
I am trying to data from a serial port to store in a text file. I want to save each data burst (which are infrequent and relatively short) in discrete text files, but some data bursts may include a pause of a minute or so.
Even for short bursts without the pause, .ReadExisting does not capture everything, breaking it up into several pieces when displaying it on screen and creating several text files. I came up with an unsatisfactory hack-y solution for that, but I need advice/help with how to continue capturing until I reach a timeout duration of some number of milliseconds with no further data received and store all data received from the DataReceived event firing until the timeout is reached.
My original whack at it, would always break the data up into chunks and create multiple files:
String tempReadData = myPort.ReadExisting(); // read data from the line
showLoggedData(tempReadData); // display data //create filename
catch (Exception ex)
// handle exception
Throwing some sleep cycles into a while(myPort.BytesToRead > 0) loop gives it time to wait for more to arrive and keeps it all together in one file and displays it in a text box without having to stitch it all together.
while(myPort.BytesToRead > 0)
logText += myPort.ReadExisting(); // read data from the line
showLoggedData(logText); // display data // create filename
catch (Exception ex)
But I can't figure out how to get it to to read all data from the time that myPort_DataReceived(object sender, SerialDataReceivedEventArgs e) fires until some specified amount of time has passed, and store it all in one text file.
serial ports are tricky, and the best approach depends very much on what exactly it is you need.
A few facts that may help you find the best way for your situation:
1. the DataReceived event isn't very reliable, what I mean is for N bytes coming in on the serial port it may fire an arbitrary number of times, anywhere from 1 to N.
2. Asynchronous event handlers get executed on threads from the ThreadPool, not on the main (or "UI") thread, so you cannot directly manipulate your Form's Controls.
3. We all hope only one DatReceived event will be active at any one time, although I have never seen that being promised...
4. incoming data is buffered several times before it reaches your C# code (hardware in the serial port, buffers in the driver, etc).
5. when asking for a delay (e.g. by using Thread.Sleep) what you get will not exactly be what you asked for, the system clock may have limited resolution (e.g. 15 msec) and the system may not immediately put your thread back in charge.
Here is one concept that has worked for me on several occasions:
if you are sure all data will arrive in a period of M milliseconds once the first byte is sent, then have a very simple DataReceived handler that starts by sleeping slightly more than M milliseconds (so all the message data is guaranteed to have gotten time to be received), and then perform a ReadExisting or a Read(chararray) when working with text, or a Read(bytearray) when not working with text.
The one advantage of it is simplicity. However there are a few drawbacks to this approach:
1. there is artificial latency, i.e. nothing happens while the handler is sleeping, e.g. you don't see the data slowly coming in.
2. you are not immediately ready to get the next burst of data, as your sleep period must be slightly larger than your worst-case time required to get one message, and then you still need to process the data.
3. Your sleep period depends on your port settings (baud rate, number of stop bits, etc).
If the above isn't suitable, I tend to go to the other extreme:
1. consider it binary data (even when it is text) so you don't get confused by newline handling, multibyte Unicode characters and the like.
2. set up a mechanism that reads into a byte array; you can do this in the DataReceived handler; I don't, I prefer to do it periodically (e.g. in a BackGroundWorker that uses a loop
with a Thread.Sleep in there).
3. You can set a ReadTimeout to the serialport to keep the loop spinning, and to make an abort or application exit slightly easier.
4. Make sure to use the return value of the Read(bytearray) method, indicating the number of bytes actually read. Append the newly received bytes to a large buffer holding all bytes not yet processed.
5. Do whatever it takes to detect message boundaries in that larger buffer, then process and remove the messages when appropriate.
Luc Pattyn [My Articles]
If you can't find it on YouTube try TikTok...
I'm OK with all of the points you posted - It's a fairly simple data logger, so wonky multiple events firing and millisecond timing isn't important (75-100ms was still occasionally creating a second file for the last dozen or two characters, so I just bumped it up to .75s) and I'm manipulating the UI by display code in another class from within the thread.
The artificial latency of the first suggestion doesn't bother me, but I don't think that will work. Although all of the data from a single burst would arrive in X ms, occasionally two data bursts may come close together, so a static wait time could feasibly end too early.
I need to figure out a way to to capture everything from the initial DataReceived event until X ms after the line goes silent. I had a ReadTimeout set on the port, but it didn't behave the way I was expecting with ReadExisting (that is, it didn't keep trying to read until hitting the time limit). I'll look into the rest of your second suggestion. Thanks again.
ReadExisting() does not block, it simply returns whatever the buffer holds.
I forgot to mention: if your data is lines of text, terminated by a specific sequence (say CR LF), you should consider using ReadLine() without timeout; ReadLine() waits for whatever string you have set as SerialPort.NewLine; again I would not use DataReceived if I can avoid it, a simple loop containing ReadLine() and checking DateTime.Now could suffice.
All too often the documentation isn't clear, I assume the NewLine property is used both by WriteLine() and ReadLine(), and I haven't used it for anything other than CR LF yet.
BTW: I don't trust the default values for SerialPort properties much, in my experience it is worth setting them explicitly... This applies mostly to .NET 2.0/3.5; .NET 4.0 is said to have some improvement in the SerialPort class, I haven't seen any detailed info though.
Luc Pattyn [My Articles]
If you can't find it on YouTube try TikTok...
What makes you "read" in the first place? I've never worked on a "port" application where you just read all the time.
You request, then read before the timeout interval.
There exists an appliance that barfs out serial data whenever it does something. A request for it to barf out data needn't be made. It does a thing, it barfs out data. I am endeavoring to capture that data.
It seems to be operating as expected, with the acceptable artificial latency discussed in comments while it waits for the timer to expire, capturing and storing subsequent data bursts received within the timer interval in a single chunk.
I call COM object method, it generate exception. If call from VB project or from Excel VBA I get detail exception information (original text exception message from COM object method). But if call from C# project I receive only NullReferenceException. InnerException field is empty. What can do to get detail exception info from c#?