Here is another quick example of serialising a few text fields - three in this case - I just created a standard from with three text boxes and a save button, this is the code behind the form.

A simple example of serialising - hope it helps

[Serializable]
    public class Args
    {
        //Class to hold the data - marked as Serializable
        public string a = string.Empty;
        public string b = string.Empty;
        public string c = string.Empty;

        public Args()
        {
        }
    }

//Save clicked
        private void btSave_Click(object sender, EventArgs e)
        {
            
            Args args = new Args();
            args.a = txt1.Text;
            args.b = txt2.Text;
            args.c = txt3.Text;

            try
            {
                FileStream fs = new FileStream(@"C:\Test.bin", FileMode.Create);
                BinaryFormatter bf = new BinaryFormatter();
                bf.Serialize(fs, args);
                fs.Close();
            }
            catch (FileNotFoundException fnfe)
            {
                MessageBox.Show(fnfe.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);

            }
        }

 //This method is called once the form is open
        public void LoadData()
        {
            try
            {
                FileStream fs = new FileStream(@"C:\Test.bin", FileMode.Open);
                BinaryFormatter bf = new BinaryFormatter();
                Args args = (Args)bf.Deserialize(fs);
                txt1.Text = args.a;
                txt2.Text = args.b;
                txt3.Text = args.c;
                fs.Close();
            }
            catch (FileNotFoundException fnfe)
            {
                MessageBox.Show(fnfe.Message);
                
            }
            catch (Exception e)
            {
                MessageBox.Show(ex.Message);
            }
        }

My original thought was that you would track the current editor as a frmEditor in your code. Upon further thought and contemplation (see reading the manual) I have revised my opinion.

We can use this.ActiveMdiChild but it is of type Form and not the class we want (frmEditor). We need to 'cast' it to our type so we can call our method (as our method is not defined in the Form class).

We can use the c# 'as' to make the conversion for us, without throwing an exception if the cast fails. (If the cast fails, as returns null.)

frmEditor currentEditor = this.ActiveMdiChild as frmEditor;
if (currentEditor != null)
    currentEditor.method(arguments);

Okay I'm going to give this a try and see what happens. Thank you so much for your help again...you are helping me so much!

Here is another quick example of serialising a few text fields - three in this case - I just created a standard from with three text boxes and a save button, this is the code behind the form.

A simple example of serialising - hope it helps

[Serializable]
    public class Args
    {
        //Class to hold the data - marked as Serializable
        public string a = string.Empty;
        public string b = string.Empty;
        public string c = string.Empty;

        public Args()
        {
        }
    }

//Save clicked
        private void btSave_Click(object sender, EventArgs e)
        {
            
            Args args = new Args();
            args.a = txt1.Text;
            args.b = txt2.Text;
            args.c = txt3.Text;

            try
            {
                FileStream fs = new FileStream(@"C:\Test.bin", FileMode.Create);
                BinaryFormatter bf = new BinaryFormatter();
                bf.Serialize(fs, args);
                fs.Close();
            }
            catch (FileNotFoundException fnfe)
            {
                MessageBox.Show(fnfe.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);

            }
        }

 //This method is called once the form is open
        public void LoadData()
        {
            try
            {
                FileStream fs = new FileStream(@"C:\Test.bin", FileMode.Open);
                BinaryFormatter bf = new BinaryFormatter();
                Args args = (Args)bf.Deserialize(fs);
                txt1.Text = args.a;
                txt2.Text = args.b;
                txt3.Text = args.c;
                fs.Close();
            }
            catch (FileNotFoundException fnfe)
            {
                MessageBox.Show(fnfe.Message);
                
            }
            catch (Exception e)
            {
                MessageBox.Show(ex.Message);
            }
        }

Wonderful! Let me see if I can stumble through it and see if I can get something to work.

Thanks!

I think I may have succeeded...and I really am starting to get this through my head. I never realized how structured and strict C# was...VBA is lazy...

Anyway, could you review my code and see if it is sloppy or marked-up incorrectly in some way? I would really appreciate it!

frmMain

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace WindowsFormsApplication1
{
    public partial class frmMain : Form
    {
        public frmMain()
        {
            InitializeComponent();
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            frmEditor currentEditor = this.ActiveMdiChild as frmEditor;
            if (currentEditor != null)
                currentEditor.saveme();
        }

        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            frmEditor Editor = new frmEditor();
            Editor.Show();
            Editor.MdiParent = this;
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                frmEditor Editor = new frmEditor();
                Editor.Show();
                Editor.MdiParent = this;
                frmEditor actEditor = this.ActiveMdiChild as frmEditor;
                FileStream fs = new FileStream("Test.bin", FileMode.Open);
                BinaryFormatter bf = new BinaryFormatter();
                actEditor.editortext.Text = (String)bf.Deserialize(fs);
            }
            catch (FileNotFoundException fnfe)
            {
                MessageBox.Show(fnfe.Message);
            }
            catch (Exception excep)
            {
                MessageBox.Show(excep.Message);
            }
        }
    }
}

frmEditor

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace WindowsFormsApplication1
{
    [Serializable]
    public partial class frmEditor : Form
    {
        public frmEditor()
        {
            InitializeComponent();
        }
        public void saveme()
        {
            FileStream fs = new FileStream("Test.bin", FileMode.Create);
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(fs, this.editortext.Text);
            fs.Close();
        }
    }
}

Right now I can have multiple instances of the editor, but when I save something it saves it over any other open editors...useless, but that's my next step to get a save and open prompt...but that's for later. My main concern, now that it seems to work, is to have my code marked up well.

When I write in VBA, I normally prefix everything based on it's type, like txt____ for text fields and str____ for variables that hold strings etc...is that standard to do in C#? seems like the examples I have been seeing here do not follow any real naming scheme?

commented: Indeed C# is structured and strict to make programs clear and concise +6
[Serializable]
    public class Args
    {
        //Class to hold the data - marked as Serializable
        public string a = string.Empty;
        public string b = string.Empty;
        public string c = string.Empty;

        public Args()
...

Quick question...what if the number of strings is unknown, or is dynamic? Or in a situation like that would it be better to use a database?

Quick question...what if the number of strings is unknown, or is dynamic? Or in a situation like that would it be better to use a database?

As a general answer to your question I would say no. You can serialize an array or use a generic List<string> and serialize that, then access the strings by index. If you're wanting to do reporting and share information then a database might be a better bet.

However if you're just wanting to save the contents of a listview that has N items in it (unknown number of strings) to restore the application state after a user closes the program then serialization would be a perfect fit.

As a general answer to your question I would say no. You can serialize an array or use a generic List<string> and serialize that, then access the strings by index. If you're wanting to do reporting and share information then a database might be a better bet.

However if you're just wanting to save the contents of a listview that has N items in it (unknown number of strings) to restore the application state after a user closes the program then serialization would be a perfect fit.

Thanks a ton for the quick reply! I'll play around a bit with it. My "test" application (what I'm playing with) is slowly turning into a journaling type solution. I don't know how or why, but it's turning out that way.

So, if this were to become a journaling type of software where a journal file is made for each user, and all journal entries are stored in a single file for each user...would that work with serialization? or would a database be better for that?

My concern with a database application would be that a user would need to install additional software wouldn't they? (the db server?)

Many people have provided answers here, and I do not wish to step on any of this good advice. I just thought I would toss in mine, because it is my opinion that the more different viewpoints you find, the more likely it is that you will find one that makes perfect sense to you.

I learned that in Calculus. They didn't teach that in High School when I was young, but the topic always fascinated me. After reading about a dozen books on the topic, it still made no sense. Most of them were textbooks predicated on the assumption that there was a professor to fill in the blanks. I finally found a book that explained calculus from basic principles, and that was my Eureka. It made perfect sense, to the point where I started kicking myself for not thinking of it myself.

To make things easier, I will put several articles in here, starting with this one, on Objects.

OOP is often thought about as a 'different' programming paradigm. It isn't really. It's the same old paradigm. People (like one example here) like to describe OOP in terms of real world things. I like to describe it in terms that make sense to a programmer, because if you want to know, you are, or aspire to be one.

An object is a data type. Boom. That's the big mystery. That's all it is. It's a user-defined data type. All data types have behaviors that are defined for that data type. For example it makes sense to use the operation "concatenate" on data of type "char", but that makes no sense if the data type is "int". Similarly, you can "add" two "int"s, but it makes no sense to concatenate them.

This was the big 'difference'. OOP differs from 'procedural' languages in that it formalizes the relationship between data and the operations that affect that data. This is the 'structure' of object-oriented programming.

Some data types are variations of others. For example, in the general data type "number", C# defines the variants short, ushort, int, uint, long, ulong, byte, sbyte, float, double, and decimal. Some operations are common to all of them. They can all be added, subtracted, divided, multiplied and so on. This is called "inheritance". Each numeric data type "inherits" the basic characteristics and operations of the basic data type "number".

Some data types have operations that are peculiar to them. For example some can use the operation "square root" and others "modulo". Sometimes the individual data types can be converted to other data types with varying degrees of accuracy. Some data types are variations of others, for example byte, ushort, uint and ulong are all variants of the general sub-type 'integer" of type "number", their distinction being in their individual storage capacity. Similarly, the types sbyte, short, int and long are another family descended the same way that are different from the first set in that they have the ability to be 'signed', and thus be negative values, at a slight cost to their maximum value.

The confusion generally arises because the data types you define (classes) can be assigned a hugely arbitrary number of behaviors (methods) and contain a hugely arbitrary amount of other data types (fields). So there is not really any legitimate limit on what can be done with them.

It was helpful to me to maintain this simple relationship in mind. I was making data types and defining the relationships between by data types. That helps me write better better code. There is nothing so axiomatically 'ugly' as code that has been written in an object-oriented language that attempts to ignore this basic relationship. An example is painting. If you understand how colors affect each other in association, then you can use painting to make things very beautiful. If you do not understand this, you can use painting to make things very hideous. The paint itself is not involved in any way.

Of course, new data types can be defined that combine older data types in new ways, and do new things with them. This is what makes computers so tremendously useful, and every useful thing that a computer can do, it can do because this is true.

If you are writing a program in C#, you should step all the way back and look at what it has already done for you. In code that you seldom ever look at, but is there, the compiler has created a 'program' object for you and asked it to perform an operation that causes it to execute itself. The "Form" object is the ascendant class of your "main form", whatever you called it, and its sole distnction is that it is the thing that program object will create first by default. By the time you edit your first page of code, you are already working in an object contained in an object.

That leads me into scope, which is the next subject.

Very helpful! At least to me! Thanks! Did you write that or is that from a website? Where can I read the rest of it?

Scope can be confusing to some. In C or C++, it was useful to think of scope in terms of braces. In C#, this relationship holds, but with some minor but important differences.

First, there are two types of variable. Global and local. In C#, a global variable is called 'static' and is preceded by the 'static' keyword. A static variable is class-specific. That is, if it is public, it can be used as if it were a property of the class. If it is protected, it is accessible as a property of the class, but only to that class and its descendents. If it is private, it is accessible as a property of the class, but only to instances of that class. Thus, a 'public static' variable can be used by anything anywhere in a program, so these are truly global variables in every sense.

In my code, I frequently have a class that I define that specifies all of the data that can be stored in the registy, and how to read it from the registry and write it to the registry. I normally make the only instance of this class a public static variable of the main form object, so that the values can be accessed and/or set from anywhere else in the program. In general, you should constrain your use of static variable to where they are actually necessary and useful. Over-using them constrains the flexibility of your code uneccessarily.

The other type is 'local' variables. These have sharper scoping rules. Basically, if you declare a variable without the 'static' keyword, it is local. That means it is available to instances of the class, in the level of braces that contains it, and any level of braces contained within that set of braces. Period.

Once the program leaves that set of braces in the instance of the class where the local variable was defined, it cannot be seen, and no longer exists in any form. If you are familiar with how memory is used, then it is helpful to know that while objects are typically allocated in heap memory, the references to those objects (the variables you use) are stored in the 'stack'. Thus, when the stack unwinds after leaving a set of braces, anything that was defined as local within those braces is no longer on the stack, and thus no longer exists.

There are ways to bypass this, of course. If you pass the reference to something else that stores it, then when you leave the declaring scope, the object will persist, but in the thing that stored it. If you return it from a method to a calling object, and the calling object stores it, then the calling object has access to it. Basically, the rule is that, "As long as a reference to an object persists anywhere, the object itself persists." If no reference persists anywhere, the Garbage Collector will release it the next time it runs.

Thus, if you declare a local variable as a propery of a class, and then declare an instance of that class, the local variable will persist as long as the containing instance persists.

If that property is public, then anything can access that variable as long as the containing instance exists by referencing the containing instance. That rule percolates up as far as it needs to. Thus, when the ultimate containing instance (the program) goes out of scope (ends), then anything and everything declared in it goes out of scope with it.

Now, if you have an class named "Foo" with a public variable called "Bar", and declare two instances of class "Foo" called "Baz and "Blargh", then you have two distinct and separate values of variable "Bar". They are Baz.Bar and Blargh.Bar. If you assign Baz to a reference of type Foo called "Bust", then you STILL have two instances of Bar. Baz.Bar, and Blargh.Bar. However, you can now also access Baz.Bar under the alias Bust.Bar;

public class Foo
{
    public int Bar;
}

// (elsewhere)
Foo Baz = new Foo();
Foo Blargh = new Foo();
Baz.Bar = 5;
Blargh.Bar = 10;

Foo Bust = Baz;

// Now Baz.Bar = 5, Blargh.Bar = 10, and Bust.Bar = 5

Bust.Bar = 15;

// Now Baz.Bar = 15, Blargh.Bar = 10, and Bust.Bar = 15

In this example, Bust is merely a reference to the instance Baz, not a new instance of Foo.

You can create what used to be called copy constructors that will allow instances of a class to be copied into new, discrete instances, or you may overload the '=' operator for class Foo so that when assignment occurs, a new, distinct copy is made of the RValue and assigned to the LValue. The default behavior, however, is to create a reference to the RValue in the LValue if they are reference types. Note that this doesn't apply to value types (structures and primitives), which are actually copied into new instances of the type, so:

int a = 5;
int b = 6;
int c = a;

c = c + 5;

Now you have three separate instances of int, and a = 5, b = 6, and c = 10.

(By the way RValue and LValue mean "Right Value" and "Left Value", of course, and are old-school references to the values on the right and left of an operator, respectively, so in a = b, 'a' is the LValue and 'b' is the RValue.)

Keep in mind the importance of braces {} - they are the main scope delimiters. This applies to control statements in the same way, but they look a little different in that context:

int a = 5;

for( int i = 0; i < 5; i++ )
{
    a += i;
}

int d = a;
int e = i;

At the end of this, the variable 'a' will have the value 15, as one would expect, and 'd' would be assigned the value 15 as well. This will not compile, though, because there is a syntax error here. In the last line, an attempt was made to assign 'e' the value of 'i'. The problem is that there is no 'i'. Not there. Since 'i' was declared as a part of the for(){} construction, it is local to that construction. It went out of scope when the for() construct ended. Compare that to this:

int a = 5;
int i = 0;

for( i = 0; i < 5; i++ )
{
    a += i;
}

int d = a;
int e = i;

Now 'e' will be assigned the value 5. It's all good because 'i' and 'e' were both declared in the same scope - outside the for() construction - and are thus accessible to each other.

As a side-note, "Why 5?" Somebody asked, trust me. The order of operations in a for() statement. The assignment i = 0 occurs first and only once - when the for() begins. Then the comparison i < 5 is made. If it is true, then the body of the loop is executed. Then the operation i++ is executed, and the condition i < 5 re-evaluated to see if the loop should be executed again. In the final pass, i is incremented to 5, the condition i < 5 fails, and the loop ends. 'i', however, is still 5.

Now, I will describe the scoping rule that tends to mess people up, especially if they've programmed in C or C++ before:

for( int i = 0; i < 5; i++ )
{
   {
       int i = 6;
   }
}

This would compile if it were in C or C++, and run. In those languages, there are two instances of 'i' here. The outer one, declared in the for() loop, and the inner one in the inner braces, which, while it is in scope, conceals the value from the for() loop.

In C#, however, this will not compile, because the 'i' defined in the for() loop can be the only instance of 'i' that exists while it is in scope. Thus the second attempt to create an instance of 'i' will fail, because there already is an instance of 'i'. C# sees it as an attempt to re-declare a variable. From the standpoint of C#, it is no different than attempting this:

int i = 0;
int i = 6;

So in C#, scoping rules apply from outside-in, and while a variable is in scope, it can be the only instance of that variable in that scope. Now look at this:

for( int i = 0; i < 5; i++ )
{
    // do something
}

for( int i = 0; i < 5; i++ )
{
    // do something
}

This is perfectly legal C# code. Each instance of 'i' is declared in a different for() loop and is therefore local to that loop. Outside of its declaring loop, the variable does not exist, and can therefore be declared again. Note that I did not say 're-declared' because it is not being re-declared - that is illegal.

So basically, when you're just starting out, think in terms of braces. If you declared a local variable inside a set of braces, then everything inside that set of braces can see it. Look at this class definition:

public class Foo
{
    private int Bar;

    public int ShowBar()
    {
        int b = Bar;
    }
}

This is perfectly legitimate. The assignment of Bar to b inside the function is legal because both the function definition and the variable Bar are in the same scope - the class definition. However, to avoid confusion, that would be better written as this:

public class Foo
{
    private int Bar;

    public int ShowBar()
    {
        int b = this.Bar;
    }
}

Both code snippets are exactly the same. The use of the 'this' keyword in the second simply states clearly that at that point in the code 'Bar' is used as a member of the containing instance of class Foo.

Some will argue that the extra typing is unnecessary because they are functionally identical, but I maintain that clarity is paramount and you should always code exactly what you mean, assuming nothing. The scope of Bar in this case is obvious and trivial because it is an obvious and trivial example. In the real world, things are seldom so obvious or trivial, and while the scope of a variable might be obvious to you when you're writing the code, it might not be so obvious to you in six months when you have to come back to it to fix a bug, and it certainly is not axiomatically obvious to somebody working on your code that has never seen it before. The 'this' keyword then clarifies much by telling the reader exactly where to find the declaration of 'Bar' - it must be a part of the containing class definition.

Very helpful! At least to me! Thanks! Did you write that or is that from a website? Where can I read the rest of it?

There is no web-site. I wrote that, and that's all there is to it - for now. My other activities keep me tied up most of the time, but when I can find a moment, I like to toss in my two cents.

Most of what I know is synthesized from years of reading and experience, so I can't really even point you at a specific book that would be good to read. I can tell you this, though. C# is a manifestation of a style that is common to C, C++, Java, Javascript, and other languages. If you understand C#, example code in C++ or Java will be clear enough to understand, and those are both object-oriented languages, so if you're looking for books or web-sites, don't get tunnel-vision. The truth does not depend on where you find it.

There is no web-site. I wrote that, and that's all there is to it - for now. My other activities keep me tied up most of the time, but when I can find a moment, I like to toss in my two cents.

Most of what I know is synthesized from years of reading and experience, so I can't really even point you at a specific book that would be good to read. I can tell you this, though. C# is a manifestation of a style that is common to C, C++, Java, Javascript, and other languages. If you understand C#, example code in C++ or Java will be clear enough to understand, and those are both object-oriented languages, so if you're looking for books or web-sites, don't get tunnel-vision. The truth does not depend on where you find it.

Good point! Thanks!

I'm starting to pick up on it quickly I think. I appreciate your help :)

Now, we arrive at the subject of the thread, at last. The question was, "Is that the correct way to save data?" It is the only way to save data. It is the only way to move data. At the end of the day, a hard-disk drive is nothing more spectacular than a very sophisticated, elaborate magnetic tape drive. The material is organized in a different way, there are more heads, and so on, but in terms of how they store data, a cassette tape and a disk drive are identical. The cassette tape and drive are just a lot more primitive than the disk and disk drive.

The real question is, "Is the C# Serialization implementation the correct way to save data? The correct answer is, "It depends."

If you're streaming text data or XML data, then the built-in Text and XML Serialization formatters will save you a lot of work. If you're streaming arbitrary data types, then the Binary formatter will preserve and transmit a lot of information about the data you are transmitting. These are all useful tools, and in many cases will be very useful and time-saving.

If you are, however, saving a fixed data structure of a specific size to a file over and over again, then any of the existing formatters are, at best, a cumbersome and bloated solution to the problem. Whether that disqualifies them as candidates depends on what you are prepared to sacrifice in terms of computing resources or programming time to get the job done to your satisfaction.

The BinaryFormatter doesn't just preserve the data. Make a simple class with a couple of fields, make it serializable, and write it to a disk file with the BinaryFormatter. The file is a lot bigger than it should be. The BinaryFormatter is writing not only the data, but the class type, version, field descriptors and so on with the data. It writes enough information into the file that, even if you didn't know what the file contained, you could figure it out.

Now, this could be a good thing. If you have a class that contains some fields that may be variable length, and you make that class Serializable, and then you make a template (or Generic, if you prefer) List<>() implementation for that class, you can save the entire list to disk with a binary formatter and preserve the entire list, every field, all of the variable-length data, and it will all read back in perfectly. You can save or restore the list with a single call. It's a fabulous time-saver, if you don't mind wasting the processor time and storage space, and it will save you from having to write a ton of code specifying exactly how to serialize the class.

If you want to do something that's tricky, off the beaten path a little, or requires a great deal of efficiency, then the correct thing to do is to do one of two things:

A) Write a custom serialization formatter for your data. This can be done, but it's really complicated. In fact, it's a heck of a lot of effort to put into what you require, which is efficient, customized streaming of data. The C# libraries don't contain such formatters because they are, by their nature, infinite in variety and the only thing that could justify the expense of effort required is either learning how to write a custom serialization formatter, or writing a serialization formatter that is common to a large group of data that must be stored in a similar format, so it will see a great deal of re-use. For example, if you store a lot of information in .INI file format (still), it might be worthwhile for you to write a custom INI file formatter.

B) Stream your data by hand, which is to say, stuff it in buffers according to your own pre-defined rules, and then write the routines to stream that buffer to and from something else, packing and unpacking it using custom code. This sounds like a lot of work, and it is, but it is considerably less work than writing a custom formatter, and it has the benefit of being infinitely customizable.

In most cases, B) is the correct approach, but as I said, that depends. Each situation has to be evaluated on its own merit. I have programs that use the built-in formatters, and ones that use technique B). I still have yet to write a custom formatter, because I only just recently had a cause to even consider it as a viable option, so I have only just learned how to do it. Having learned how to do it, I am now wondering if the amount of effort it will ultimately cost will be worth what I get from it. I'm already back to considering option B).

From the examples that have been bandied around, I would suggest, off my head, that for the subject of this thread, using the BinaryFormatter or using approach B) would likely be the best way to go. There is seldom ever a reason to go to writing a custom formatter.

If you are considering option B) however, I would suggest a little ground-work is in order. If compression and/or encryption are going to be considerations, then write libraries that will do compression and or encryption (or use existing ones) separately. If BitConverter and the Security library offer what you need, then you can use what already exists.

The question that needs to be answered is seldom "Is <technique> correct?", but rather, "Is <technique> viable for <problem> assuming <mitigating factors>?" All other things being equal, even the time of day may ultimately prove to be the deciding factor - and I only wish that was a joke.

If you're programming as a hobby, or programming to learn something (and yes, I do both), then you can afford the luxury of the perfect answer. If you're programming for pay (which I also do), then the answer that will serve is seldom ever the perfect one - it's usually the one that will be good enough for now that you know how to implement right now.

commented: Concise, clear and I agree with it +2

If you're programming as a hobby, or programming to learn something (and yes, I do both), then you can afford the luxury of the perfect answer. If you're programming for pay (which I also do), then the answer that will serve is seldom ever the perfect one - it's usually the one that will be good enough for now that you know how to implement right now.

Right now this is a hobby. I program VBA and get paid for it, but I don't have deadlines. The solution is finished, I am just working on updates and feature additions now.

But VBA is very limited, and requires another application to run. Solutions are hard, if even possible, to distribute and are sometimes version based.

C# on the other hand allows for a single solution to be written and deployed based on the targeted environment (or so it seems). This is very appealing to me.

The solutions that I work on now are very data driven. Most of the VBA I have written has been in MS Access. I would eventually like to convert my "pride and joy" of a VBA application to a C# project so that everyone's experience is the same. Right now it works, but end-users like to "tinker" with settings in the main Access program...some more than others. This sometimes is a problem. Having a compiled executable program that is stand-alone would be very appealing to me...but that seems like it might be way in the future...

The reason why I posed this question on this discussion board, was 3 fold:

1) To actually get the answer to the question.
2) To learn how the process is completed.
3) To decide for myself if this is a language I would be willing to pursue.

I have my answers to all 3 for the most part. Yes. I may not feel all that confident with myself right now, but slowly the process and logic behind the language is sinking in.

All I need to do now is figure out the best way to do what I want to do, and then do it.

I do have an additional question that doesn't seem to have been answered...maybe I didn't clearly ask it.

If I decide to create a solution that uses a database...does the process involve creating a "database file" or does the end-user need to install something like an SQL server? I always hate installing software that requires third party software to function.

If you include a SQL database, even a .mdf file, then the user will need an instance of the SQL Server Service installed.
However, i havent done it myself, but i believe there is a SQL Server Compact Edition which you can use to embed the SQL functionality in your application, removing the requirement for the user to install an y version of SQL Server: http://www.microsoft.com/Sqlserver/2005/en/us/compact.aspx

If you include a SQL database, even a .mdf file, then the user will need an instance of the SQL Server Service installed.
However, i havent done it myself, but i believe there is a SQL Server Compact Edition which you can use to embed the SQL functionality in your application, removing the requirement for the user to install an y version of SQL Server: http://www.microsoft.com/Sqlserver/2005/en/us/compact.aspx

What about accessing data across multiple users? Like over a network? Is the .mdf file accessable to anyone?

If you're wanting to support multiple users across a network, you're probably going to want more of a real database, whether your users have to install it manually or not.

If you're wanting to support multiple users across a network, you're probably going to want more of a real database, whether your users have to install it manually or not.

Would it be possible to have one computer host the mdf file and have other network clients access it? Or will a "file in use" error occur if more than one person tries to use the mdf file at once?

It would be possible to share the file across a network. However whether or not multiple people can use your application to access it at one time would depend on the file locking performed either by your code, or the library you use.

If your application or library supports file locking, it can either support whole-file locking or locking for part of the file. How your application / library handle the failures (due to someone else having a lock) would determine what if any error messages the user might see.

It would be possible to share the file across a network. However whether or not multiple people can use your application to access it at one time would depend on the file locking performed either by your code, or the library you use.

If your application or library supports file locking, it can either support whole-file locking or locking for part of the file. How your application / library handle the failures (due to someone else having a lock) would determine what if any error messages the user might see.

The obvious concern would be data integrity. Limiting the number of users that can access the file at once would probably be a good idea...but the question would be, if userA is working on Record1 and userB is working on Record1, and no file locking is performed at all so that all users can read/write at once...the problem becomes, if userA saves changes...unless there is some sort of looping done to check for changes to the records while it is open chances are people are going to get frustrated saving over each other's changes.

Is there a way to lock certain records? Maybe create a field in the database called locked that is either true or false or something? and when the record is open, set it to true, and when it's closed set it to false? That doesn't seem like a good idea because if the application doesn't close cleanly it might leave a record locked. Right?

I'm just trying to straighten this out in my head. I'm going to start working on transferring my Access VBA project to C#, and since Access is a database application, it's easy there, Access does all the work. I would just use an Access .accdb file but they have lousy security...course I don't know if a .mdf file is any better?

Any suggestions?

.mdf is just a file extension, in a database context, it is usually associated with SQL Server. The file doesn't have any intrinsic support for anything. It's the database libraries that handle the file.

You stated that Access has 'lousy security' which I won't argue, but what level of security do you really need?

The level of security relates to how critical the information is and what you need to protect it from. Do you need to secure the data against reading? Against modification? Something else?

What is the impact (cost?) if the data is not secured?

What value is there to a third party to access the data?

The greater the impact (and/or the greater the value) the more that you will need to do to secure the data. If the impact and value are low, then you don't have to try very hard.

.mdf is just a file extension, in a database context, it is usually associated with SQL Server. The file doesn't have any intrinsic support for anything. It's the database libraries that handle the file.

You stated that Access has 'lousy security' which I won't argue, but what level of security do you really need?

The level of security relates to how critical the information is and what you need to protect it from. Do you need to secure the data against reading? Against modification? Something else?

What is the impact (cost?) if the data is not secured?

What value is there to a third party to access the data?

The greater the impact (and/or the greater the value) the more that you will need to do to secure the data. If the impact and value are low, then you don't have to try very hard.

The Access Application that I have written is used in a clinical setting. Right now it is not distributed/sold (whatever) because of security. The system has multiple functions, most of which don't need much security, however, the system also holds social security numbers, names associated with them as well as some medical record information.

It would be useless to me if I got a hold of that kind of information (I wouldn't know what to do with it even if I wanted to do something), but as you probably know...that kind of information is gold to some people.

Obviously it would be better to have that type of data stored in a system that is not based on sharing a file across a network. Thumb drives and CDs are common place in my office. One rouge employee just needs to copy the back-end of the database to it, play with it for a bit and they get access to everything that they probably shouldn't.

Granted, to work in the place I do, a certain level of trust is extended to the employees in the front office, but why make it easy if they want to steal data? I would rather install a free version of an SQL server on a host computer, and have the clients connect to the server over the network without even needing to access a shared file. But I don't see how to do that, and I'm not sure if it's even possible.

Either way, before I start developing too much further I need to figure out how to store the data that needs to be stored in a secure fashion and is easy to distribute. Using a .mdf file wouldn't be bad I guess, I just need to find a way to keep the data safe.

The data would only be somewhat harder to access in a SQL database than in an access database if you can get access to the file.

That's one of the benefits of a true SQL Server, your application talks to the SQL Sever application and you don't have to have access to the data file. The computer with the data file could be physically secured and wouldn't have to share the file for others.

If you can't secure the file, (and maybe even if you can,) you're going to have to secure the data, probably using a form of encryption. If this is the route you take, you will have to put extra effort into securing the encryption (decryption) keys. (I don't recall if SQL Server has any direct support for ecrypted fields.)

Secondarily, the data you want to secure would appear to be readily available to the user at the terminal. Should the data be secured there as well? Is the data your trying to secure being printed on any forms? (Say insurance claims or something?)

I think some of the data you have may be protected by HIPAA and I'm not familiar with the standards. If you're writing the program, you should probably be familiar with the requirements and make sure that you're supporting them as well.

The data would only be somewhat harder to access in a SQL database than in an access database if you can get access to the file.

That's one of the benefits of a true SQL Server, your application talks to the SQL Sever application and you don't have to have access to the data file. The computer with the data file could be physically secured and wouldn't have to share the file for others.

If you can't secure the file, (and maybe even if you can,) you're going to have to secure the data, probably using a form of encryption. If this is the route you take, you will have to put extra effort into securing the encryption (decryption) keys. (I don't recall if SQL Server has any direct support for ecrypted fields.)

Secondarily, the data you want to secure would appear to be readily available to the user at the terminal. Should the data be secured there as well? Is the data your trying to secure being printed on any forms? (Say insurance claims or something?)

I think some of the data you have may be protected by HIPAA and I'm not familiar with the standards. If you're writing the program, you should probably be familiar with the requirements and make sure that you're supporting them as well.

Yes, HIPAA is an obvious concern and I am looking into that as well. However I don't know if HIPAA really covers how the data is stored or encrypted electronically, it's more how the data is used and to whom it is disclosed to. But that's unimportant for this...that's what we pay our attorney for :)

Anyway, I guess the main question now is...SQL servers. I think I would prefer to take the route of a true SQL server. I've used them many times on web applications via PHP. Wonderful servers in my opinion. But the question is...how do you get C# to interact with a remote SQL server? Just a different connection string?

The reason why I ask is, when I click "Add a Connection" under the database explorer in C# it asks me to select a data source...I only have 3 options:

MS Access Database File (boo!)
MS SQL Server Compact (double boo!)
MS SQL Server Database File (this makes a .mdf file?!?)

Am I missing something here? Is .mdf the best choice here? I'd rather have the end-users specify an IP or a network path to a server with a port # etc...to connect to?

Encryption is for another time, getting a database setup is my first priority...I have a feeling encryption is going to be a major pain...

Any suggestions? Am I missing something? I don't see a way to connect to a remote SQL server.

Wow I just realized that my original question was answered like 300 posts ago.

I'm going to mark this one solved :)

Thanks a ton for everyone's help!

I guess the summary of all this is....if I want to create a file that holds all settings, all data and any future data...is serialization the way to go? If your familiar with Intuit's Quickbooks...think of the "company file." I need something that can save info, but can't be easily compromised by someone opening a binary file in notepad and retrieving a username or password.

Whether serialization is "the way to go" depends a lot on what the purpose of your app is and how much data you are planning to serialize.

There are apps which use flat files to serialize data (FileMaker), but most apps use a relational database. Storing a few app configuration settings in a text file works well, but flat file serialization doesn't scale as the volume of data increases. Sql Server Express is bundled with Visual Studio. If you are using VS2008 you should be all set. If you are not using Visual Studio as your IDE, you should be able to get a copy of Express for free from Microsoft. You could also use MySQL.

I would serialize to a flat text file or xml for now as you implement your tutorial, and think about how you want to structure your data in a database. I would spend your time learning about ADO and relational databases. This will provide you with marketable skills. I learned about binary serialization in school, but have never used it at work. I use xml serialization when I prototype, but not for production-quality software.

Good luck,

Dorothy

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.