Database Creation Differences Amongst Language Versions

The issues that come with working with non-English language versions of Visual Studio are becoming more apparent as readers write to me about them. Here is the essential problem that you need to consider when reading this post. I strongly endorse use of the downloadable source when working with one of my books. Using the downloadable source means that you don’t have to worry about problems with internationalization or with typos for that matter. All you need to do is load the example into your copy of Visual Studio and follow along as you read the book.

However, many people learn by doing and that’s when problems come into play. If you recreate the examples from scratch, you could encounter problems that have nothing to do with your programming skills or your ability to follow directions. In this case, the problem isn’t the fault of the reader, but of Visual Studio. Databases are created differently by the Entity Framework designer when working with various language versions.

A German reader was kind enough to send me some screenshots of a particular issue that I don’t discuss in the book because I was unaware of it when I wrote it (and a lack of international beta readers kept me from learning about it until now). If you look at the Entity SQL example that begins in the “Creating a basic query using Entity SQL” section of Chapter 4 (page 86), you see that the code interacts with the Customers table. You create this table earlier in the book and it should appear as Customers in SQL Server Management Studio. However, it doesn’t appear under that name if you’re working with the German version of Visual Studio. The IDE appends the word Satz (set) to the table name as shown here (all screenshots are courtesy of my German reader):

TableCreation01

Consequently, when you try to create the code shown on page 87, it doesn’t work. It would work if the table had the right name or if the code used the right name, but the two are out of sync. In order to make this example work, you must change the example code as shown here:

TableCreation02

Of course, making the code change (circled in red) does solve the problem, but it’s not something the developer should have to deal with. In addition, consider how things will work if you’re interacting with a number of team members in different countries—all of whom are using their own language versions of Visual Studio. The resulting chaos must be impressive indeed.

The true source of the problem is the Entity Framework Designer. When you initially create your design, the name of the entity might be Customers, but the Properties window will automatically add Satz to the name for you as shown here:

TableCreation03

To make the book examples work as they appear in the book, you need to ensure that the entity names match those in the book. In this case, all you need to do is remove the Satz part of the name.

Unfortunately, these sorts of problems will continue to crop up with various languages. I’d like to hear about them because knowing what could happen will help me write better books in the future and to provide updates to you here. I really appreciate all of the help my German reader provided in this case. Contact me with any other language-specific glitches you find at John@JohnMuellerBooks.com.

 

DateTimePicker Control Data Type Mismatch Problem

A reader recently made me aware of a problem with the Get User Favorites example in Chapter 2 that could cause a lot of problems depending on which language you use when working with Visual Studio 2012. This issue does affect some of the examples in Microsoft ADO.NET Entity Framework Step by Step so it’s really important you know about it.

Look at the model on page 30 of the book (the “Creating the model” section of Chapter 2). The Birthday field is defined as type DateTime. When you finish creating the model, you right click the resulting entity and choose Generate Database from Model to create a database from it. The “Working with the mapping details” section of Chapter 1 (page 19) tells you how to use the Generate Database Wizard to create the database. The Birthday field in the database will appear as a datetime type when you complete the wizard, which is precisely what you should get.

At this point, you begin creating the example form to test the database (the “Creating the test application” section on page 36). The example uses a DateTimePicker control for the Birthday field by default. You don’t add it, the IDE adds it for you because it sees that Birthday is a datetime data type. The example will compile just fine and you’ll be able to start it up as normal.

However, there is a problem that occurs when working with certain languages when you start the “Running the basic query” section that starts on page 39. The DateTimePicker control appears to send a datetime2 data type back to SQL Server when you change the birthday information. You’ll receive an exception that says the data types don’t match, which they don’t. There are several fixes for this problem. For example, you could coerce the output of the DateTimePicker control to output a datetime data type instead of a datetime2 data type. However, the easiest fix is to simply change the data type of the Birthday field in the database from datetime to datetime2. After you make this change, the example will work as it should. You only need to make this change when you see the data type mismatch exception. I haven’t been able to verify as of yet which languages are affected and would love to hear from my international readers about the issue.

As far as the book is concerned, this problem is quite fixable using the manual edit (although, manually editing the database shouldn’t be something you should have to do). However, it does bring up the question of how teams working across international boundaries will interact with each other if they can’t depend on the controls acting in a particular way every time they’re used. This is a problem that you need to be aware of when working with larger, international, teams. Let me know if you have any questions or concerns about the book example at John@JohnMuellerBooks.com. You’ll have to contact Microsoft about potential fixes to the DateTimePicker control since I have no control over it.

 

Extra File in Entity Framework Book Downloadable Source

At least one reader has noted that there is an extra file in the Databases.zip file which is part of the downloadable source for Microsoft ADO.NET Entity Framework Step by Step. The Rewards2 RowVersion.mdf file isn’t used by any of the examples in the book. This was a test file that I used for experimentation purposes and you can safely delete it or simply ignore it. You certainly don’t need to install it in SQL Server. I had actually forgotten about that file and uploaded it with the rest of the downloadable source. I’m sorry about any confusion that the extra file has caused. Please let me know if you have any questions about it at John@JohnMuellerBooks.com.

 

Accessing Sample Database Data (Part 4)

The previous post, Accessing Sample Database Data (Part 3), discussed the need to change the connection string for a database in the App.CONFIG file. However, you haven’t actually gained access to the database as of yet. Depending on how the book is written, you may have to create the database using code and manually inputting the entries, run a script, or add a database file to SQL Server. Of the three, writing the database code and manually inputting the entries is the most straightforward. All you need to do is perform the instructions written in the book. As mentioned in my first post, many readers find this method the least acceptable because database management tasks of this sort are supposedly in the realm of DBAs.

In order to work with databases in Visual Studio, you must have a connection to the database. All of my books show how to create such a connection using Server Explorer. The project will not include a connection when you open the downloadable source code. The connection to the server is part of your Visual Studio setup and you must create it when you begin working with the downloadable source. The short take on creating a connection is to right click the Data Connections folder in Server Explorer and choose Add Connection from the context menu. You’ll see a wizard that will lead you through the steps for creating the connection.

Using Scripts

The next level of complexity is the script. A number of my books use scripts in order to make it at least reasonable to use something other than SQL Server as the database manager. More and more of my readers want to use other solutions. Accommodating this need is proving difficult, but using scripts does have the advantage of reducing the work required to use non-SQL Server solutions. I’m going to assume that you’re working with Visual Studio and that you have a connection to your database manager, whatever that database manager might be. The following steps tell how to use scripts in a general way (you may find slight variations in the steps between different versions of Visual Studio).

  1. Choose File | Open | File. You see an Open File dialog box.
  2. Highlight the script you want to use (a script always has a .SQL extension) and click Open. You see the script opened in Visual Studio.
  3. Right click anywhere in the editor window and choose Execute SQL from the context menu. Visual Studio interacts with your database manager to run the script.

Using a Database File

The third level of complexity is actually using a database file. The advantage of using this option is that the database is completely configured and contains everything needed to use it. This level represents the least amount of work on the part of the reader in most cases. It’s also the least flexible because it only works with SQL Server and the version of SQL Server must be able to support the features in the database file. Use these steps to work with a SQL Server database file from Visual Studio.

  1. Open Server Explorer by choosing View | Server Explorer. You see the Server Explorer window open as shown here.
    AccessDataPart4_01
  2. Right click Data Connections and choose Add Connection from the context menu. You see the Choose Data Source dialog box shown here.
    AccessDataPart4_02
  3. Select Microsoft SQL Server Database File. The wizard automatically chooses the correct Data Provider option for you. Click Continue. You see the Add Connection dialog box shown here.
    AccessDataPart4_03
  4. Click Browse. You see the Select SQL Server Database File dialog box shown here.
    AccessDataPart4_04
  5. Highlight the file you want to use and click Open. You return to the Add Connection dialog box.
  6. Click Test Connection. You should see a success message. If your version of SQL Server doesn’t support the features needed to use the database file, you’ll see an error message that states the file can’t be downgraded. The message will also tell you which version of SQL Server you require to use the database file.
  7. Click OK. Visual Studio creates the connection for you. What has actually happened in the background is that SQL Server has created the connection at the request of Visual Studio.

Summary

I try to choose the database option for my books with care. Many of my books use more  than one option to allow more people to work with the option that best suits their needs. However, it’s impossible to please everyone with the choices I make. When you encounter problems using one of the database options I’ve selected, I’ll try my best to help you work through the difficulties. As with every other aspect of my books, working with the databases is a learning experience. Let me know your thoughts on database access in my books or if you have additional database access questions at John@JohnMuellerBooks.com.

 

Accessing Sample Database Data (Part 3)

The previous installment of this series, Accessing Sample Database Data (Part 2), discussed the Windows-specific setup required to use your database from Visual Studio. It includes setting the file for read/write usage and also verifying that you have permission to work with the files. This part of the series will discuss one of the most important settings within Visual Studio itself, the connection string. In order to use a data source from within a Visual Studio application, you must tell Visual Studio where to find the data source—a sensible requirement when you think about it.

The problem for me as an author who is trying to provide you with downloadable source code is that I have no idea of what SQL Server configuration you plan to use on your system. I can make some educated guesses, but that’s about it. So, there is every chance that the connection string is going to be wrong when it comes to the actual location of the data source on your system; especially when you use a different setup from the one in the book.

In most cases, you’re most interested in locating a string similar to data source=.\SQLEXPRESS in your application. This string normally appears in the App.Config file. Over the years I have tried a number of permutations of this string, but none work out quite so well as .\SQLEXPRESS. The period represents the local machine, but you can replace it with any machine name desired. For example, if you use a separate server named WinServer, you’d use WinServer\SQLEXPRESS instead of .\SQLEXPRESS.

The SQLEXPRESS part of the data source attribute is also dependent on your setup. When you install SQL Express on your system, it usually installs as a named instance called SQLEXPRESS. However, you could just as easily install it as the default instance or you might not use SQL Express at all. To specify that you want to use the default instance of SQL Server, you use a period (.). So the default instance on the local machine would appear as .\.. Otherwise, you must provide the name of a named instance of SQL Server to use.

There is always a question of whether you have found every instance of the data source string in your application. Newer versions of Visual Studio place the string in one location when you create a connection using a wizard, App.Config. However, depending on how the application is put together, you could conceivably find the string in other locations. To ferret out these other locations, use the FindStr utility at the command line. I describe how to use this utility to locate errors in your application code in the Using the FindStr Utility to Locate Errors in Visual Studio post. You can use precisely the same approach for locating the data source. In this case, you’d open a command prompt at the main folder for the downloadable source, type FindStr \m \s “\SQLEXPRESS” *.*, and press Enter. FindStr will locate all instances of that particular data source.

In order to change the example code so that it works with your system, you must modify the data source string wherever it appears in the sample code to match your particular system. Let me know if you encounter problems making this change at John@JohnMuellerBooks.com. You can see the next post in this series at Accessing Sample Database Data (Part 4).

 

Accessing Sample Database Data (Part 2)

In my previous post, Accessing Sample Database Data (Part 1), you learned about the various ways in which an author can provide database examples as part of a learning experience. This post is going to look at the process for gaining access to the database files in Windows, no matter what sort of database is used (including XML databases). In order to perform the tasks in this post, you need a copy of Windows Explorer opened with Administrator privileges. Choose Start | All Programs | Accessories to see the Windows Explorer shortcut. Right click the Windows Explorer shortcut and choose Run As Administrator from the context menu. Provide the requires credentials (username and password) to run in administrator mode, if asked.

Checking File Access

Some of the databases you obtain for my books appear on a CD or other device that provides read-only access. When you copy the files from the CD or other device to your hard drive, Windows keeps the files set to read-only access. In order to use the files, you must be able to read and write them. To change this setting, right click the folder that holds the files and choose Properties from the context menu. You see a properties dialog box similar to the one shown here.

AccessDataPart2_01

Clear the Read-only checkbox and click OK. You’ll see a Confirm Attribute Changes dialog box like the one shown here.

AccessDataPart2_02

Make sure the Apply Changes to this Folder, Subfolders and Files options is selected. Click OK. Windows will make all of the files read/write so that you can work with them. If you see a User Account Control (UAC) dialog box telling you that Administrator permission is required, click Continue and provide the required credentials (username and password) if required.

Checking Folder Security

It’s essential that you check folder security to avoid all sorts of weird problems that arise when you don’t have access. Never assume you actually have access; always check it to be sure. Right click the folder holding the files and choose Properties. You see the Properties dialog box again. This time select the Security tab as shown here.

AccessDataPart2_03

Make sure that your account, or a group account to which you belong, is listed in the Group or User Names list as having Full Control (as shown in the Permissions list in the bottom half of the dialog box). If you don’t have the required access, click Edit. You’ll see a Permissions dialog box for the affected folder as shown here.

AccessDataPart2_04

Verify that your name or a group of which you are a part appears in the Group or User Names list. If not, click Add. You’ll see a Select Users or Groups dialog box like the one shown here.

AccessDataPart2_05

Type your login name or the name of the group that should have access to the folder. Click Check Names to ensure you typed the name correctly. If you didn’t type the name correctly, Windows will tell you it didn’t find the name and provide you with another dialog box for searching for the correct name. Otherwise, you’ll see the fully qualified name used to access the folder. Once you have a correct name in place, click OK. You’ll see the Permissions dialog box again.

Select the name you want to use to access the folder from the list. Check the Full Control option in the Allow column of the Permissions list at the lower half of the Permissions dialog box. Click OK. If everything goes correctly, you’ll see the Security tab of the Properties dialog box again, but this time it will contain your selected group with full control access.

Something odd can happen and it confuses a lot of readers. You might see a dialog box similar to this one during the security setting process:

AccessDataPart2_06

When you see this dialog box, it usually means that the SQL Server service is running and it has the requested file open. Click Continue for each of the disallowed changes to ensure that your folder remains in a usable state.

Now, open the Services console found in the Administrative Tools folder of the Control Panel. Locate the SQL Server service and click the Stop link on the left side of the right pane to stop the service as shown here.

AccessDataPart2_07

Try setting the security again. If the error persists, you need to try to set the security on the individual database files using the same technique you tried to use for the folder as a whole. (When working with individual files, the security tab may display a message saying you need administrative privileges to view the individual file security. Simply click Continue to work with the privileges.) Yes, it’s a nuisance setting individual file security, but that’s the way Windows works at times. After you successfully set security on each of the database files, remember to restart the services that you stopped.

A number of readers stumble on these file access and security permission issues. Please let me know if this post solves the problems for you. If not, make sure you send your questions to John@JohnMuellerBooks.com. You see see the next post in this series at Accessing Sample Database Data (Part 3).

 

Accessing Sample Database Data (Part 1)

It’s always hard to figure out the best way to provide access to sample data in a book. No matter how you do it, someone is going to find the amount of data limited or unrealistic, too hard to understand, too hard to access, or too hard to install.

One of the most common ways to provide sample data is to use a predefined database, such as Northwind or the newer AdventureWorks, that the reader can download and install. However, there are several problems with using these databases. For one thing, installing Northwind requires running a script that may not succeed (and then I get questions about why my script failed—unfortunately, it isn’t my script, it’s Microsoft’s script). Using AdventureWorks requires a copy of the SQL Server tools because you install the actual database and the tools don’t come with Visual Studio’s copy of SQL Server Express any longer, so now I also need to tell the reader how to install the required tools. In both cases, many readers find the process of working with these predefined databases too complicated. Once the databases are installed, many readers find the database design unrealistic and overly complicated (especially in the case of AdventureWorks, which really is complex). In addition, as more of my books move toward the open source realm, I can’t assume the reader will even have a copy of SQL Server. (If someone has a suggestion for a great open source alternative, please let me know.)

Another technique is to create a predefined database that I supply with the book’s downloadable code and ask the reader to install it as necessary. When working with a book that uses SQL Server, this means including the actual database file or creating a script to reproduce it. Again, the reader would need to install these files in some way—either by running the script or installing the database file using the SQL Server tools. When writing open source books, I’m leaning toward using XML databases because they’re text-based, simple to work with, and work on any platform. At least XML databases don’t require installation or scripts because they appear in the same folder as the application does. Because these databases specifically model the book environment, readers don’t complain about complexity or applicability, but some readers complain that they also don’t model their environment very well.

Of course, there is always the approach that I take in some books of having the reader build the database as part of the learning experience and then typing the data into it. The amount of data is small in most cases, so it’s not as if the reader is working for hours to input the information. However, this solution garners criticism because it’s too simplistic (doesn’t model the real world well enough) and readers feel that it’s more important to see working code, rather than work with the database. After all, database design is an entirely different specialty (some developers will be surprised when their employer asks them to create databases as part of their job). There is also that constant problem with the availability of tools—many of which are solved with Server Explorer when working with Visual Studio, but again, many of my projects are moving more toward open source.

In an effort to address the complaint about not spending enough time in the IDE and in creating code, there is always the approach of having the reader build an application that creates the database and fills it with data. The complaint this time is that most readers will never build such an application (I disagree because such applications are used all the time for storing settings and other application-specific information). What the reader really wants to see is the code that manipulates the database data and lots of it (sometimes without the level of explanation that less experienced readers require to actually understand the example). It’s important that I address all reader needs with the examples I create, so you’ll continue to see examples that create the database and fill it with data. The examples will always include full explanations so that no one is left behind. However, I am providing more references to online examples that emphasize code, lots of it, over any sort of explanation.

The point is that there are a number of ways in which an author can attempt to satisfy reader needs when writing a book that contains database management techniques. To make the book useful, the reader must have a database of some sort to work with. Whether the database is XML-based, SQL Server-based, or some new type of data source isn’t the problem for the most part—it’s creating a database that works well with the book’s material, models a real world environment to some degree, and is still easy enough to understand that the reader doesn’t become lost in detail. In order to accomplish these goals, more of my books now employ multiple database scenarios so that each reader type has enough data of the right type to get the maximum possible benefit from the book examples.

Of course, undertaking such a gargantuan task isn’t easy. Every one of you seems to have an entirely different set of needs. The next post in this series is going to attempt to demystify the process of getting the databases installed when working with SQL Server and Visual Studio. I also include instructions in my books, but this additional information is based on feedback from less experienced readers who are having trouble gaining access to the databases. What I’d like is to hear your questions so that I can address them in future posts. If you’ve had a problem getting one of my database examples to work because you can’t access the data, please let me know at John@JohnMuellerBooks.com. You can find the next post in this series at Accessing Sample Database Data (Part 2).

 

Starting SQL Server Browser

A number of my books contain database examples in them—most of which rely on SQL Server. One of the issues I’ve encountered over the years is that a reader will write in to say that the example doesn’t work as written. In most cases, the procedure and the example source code is just fine. In addition, there is nothing wrong with the user’s system, the Visual Studio installation, or the version of SQL Server used. The problem lies in the fact that the SQL Server Browser service isn’t started. Visual Studio relies heavily on this particular service and it isn’t started by default, in most cases, when you install SQL Server or SQL Server Express.

Unfortunately, the error message you receive will say nothing at all about SQL Server Browser. In fact, the message will complain about something completely unrelated and it may not even point to the database as the problem. This particular error has caused me (and many others) a lot of lost time. In fact, it’s such a nuisance that I immediately check to ensure the service is actually running before I look for other sources of problems (unless there is another obvious problem source). When you encounter an odd problem, especially an odd problem with source code that has worked in the past, and the application relies on a database, consider checking the SQL Server Browser service to ensure its running.

There are commonly two places in which you can look for the SQL Server Browser service. Because the SQL Server tools don’t install with the copy of SQL Server Express that comes with Visual Studio, I’ll discuss the place that everyone can look first, which is the Services console found in the Administrative Tools folder of the Control Panel. Simply open the console up, locate the SQL Server Browser entry, and ensure that it’s running as shown here.

SQLServerBrowser01

Notice that the service is set to start automatically each time the machine is booted. Using this setting usually ensures that the service will be available when needed. However, don’t assume that this setting means the service is always going to be available. If the service encounters a problem during the boot process, there is every chance that it won’t be available when you need it. Always verify that the service is indeed running when you encounter problems.

You can start a service by clicking the Start link on the left side of the right pane. The figure shows the Stop, Pause, and Restart options because the services is already started, but the Start option will appear when the service is stopped. If the service isn’t set up to start automatically, right click the service’s entry in the list and choose Properties from the context menu. Set the Startup Type field value to Automatic and click OK to configure the service to start automatically.

The second place you can look for this setting (when you have the SQL Server tools installed) is the SQL Server Configuration Manager. You’ll find the SQL Server Browser entry in the SQL Server Services folder as shown here.

SQLServerBrowser02

Again, make sure the service is actually running and that you have it configured to start automatically. Otherwise, you’ll find that you spend a lot of time chasing ghost problems that don’t actually exist. Of course, I’m always here to help you with any book-related problems you might have. Feel free to contact me about any issues with my books at John@JohnMuellerBooks.com.

 

Exploring the TimeCheck Application (Part 10)

Last week you learned about the remaining major elements of the GroupSettings class in the Exploring the TimeCheck Application (Part 9) post. Like many modern applications, you now see how to create an application that relies on both localized user settings (the UserSettings class) and work group-wide settings (the GroupSettings class). Both classes rely on XML data files to create a database of settings that the application relies upon for configuration needs. The use of XML data files makes the application incredibly portable. It’s important to remember the sources of settings information this application:

 

  • The user manually configures some of the settings in the UserSettings class by selecting items such as the default task and project.
  • The administrator manually configures some settings in the UserSettings class by selecting items that only the administrator can see.
  • The application automatically provides default settings in the UserSettings class when the application hasn’t been configured by either the user or the administrator.
  • The administrator manually configures all settings in the GroupSettings class.
  • The application doesn’t automatically supply any defaults for the GroupSettings class and simply displays blank screen areas when there are no values to display.


I wanted to reiterate these settings requirements before moving on because there were some questions on the part of a few readers as to how the settings worked. I’m not showing the security features of this example just yet—for right now, it’s important to focus on the functionality required to perform the desired tasks. However, I do encourage developers creating production applications to include security as part of the application design and development process (as I did when putting this example together). You can’t bolt security on as an afterthought. However, I have chosen to not discuss the security features just now in order to make the example easier to understand.

Because I’m still answering some questions about this application, I’ve decided to keep today’s post simple. Look carefully at frmConfigure (see Exploring the TimeCheck Application (Part 3) for details on the frmConfigure configuration). This form contains two combo boxes and two list boxes that you must fill at various times during the use of the form. For example, you must fill all four of them when initially displaying the data. Any change to the two list boxes must also appear in the two combo boxes. In addition, changes to group data must appear every time the user decides to make any sort of change to the user settings, so you have an opportunity here for interactions between multiple sessions. Because of the potential for problems, the frmConfigure class uses a method named FillList() to fill all four lists any time there is a chance for changes. The following code shows how FillList() works.

private void FillLists()
{
   // Check for a list of tasks.
   if (GroupData.TaskList != null)
 
   // Fill the default and administrator lists with data.
   {
      foreach (Task Item in GroupData.TaskList)
      {
         lstStandardTasks.Items.Add(Item.Name);
         cbWorkType.Items.Add(Item.Name);
      }
   }
 
   // Check for a list of projects.
   if (GroupData.ProjectList != null)
 
   // Fill the default and administrator lists with data.
   {
      foreach (Project Item in GroupData.ProjectList)
      {
         lstStandardProjects.Items.Add(Item.Name);
         cbProjectName.Items.Add(Item.Name);
      }
   }
 
   // Add the "None" entry to the two user lists.
   cbWorkType.Items.Add("None");
   cbProjectName.Items.Add("None");
 
   // Choose the user-supplied default (if any).
   if (UserData.DefaultTask != null)
      cbWorkType.SelectedItem = UserData.DefaultTask;
   if (UserData.DefaultProject != null)
      cbProjectName.SelectedItem = UserData.DefaultProject;
}

Any time there is any change to any of the data that frmConfigure manages, the code calls FillList() to ensure all of the lists are updated. Using a single method like this makes it possible to update the application without any potential problem with method interactions.

In this case, the code works with GroupData.TaskList and GroupData.ProjectList to obtain entries for the two lists associated with a particular data type. The user lists must also contain a None entry, so the code adds this item to the two combo boxes after the lists are filled. Having the None option last helps ensure that the user actually reviews the lists of potential choices before accepting the None option. Using a foreach loop to fill each list is extremely efficient.

The FillList() method must also interact with UserData to automatically choose the user’s selection of a default task and a default project. Remember that the default selection, the one automatically created by the application, is None. When the user hasn’t made a selection, the Configure TimeCheck dialog box displays None for these two entries.

This code provides a subtle form of error handling. Theoretically, GroupData.TaskList, GroupData.ProjectList, UserData.DefaultTask, and UserData.DefaultProject should never be null when this piece of code is called. However, the code makes a quick null check anyway just to ensure it doesn’t attempt to work with a null data value. This quick check will reduce potential errors without affecting performance in any noticeable way. Using this sort of check will help make your applications more robust too.

Well, that’s it for this week. Please keep those questions coming. I realize that this example is a bit more complicated than the ones you’re used to seeing in books, so I want to be sure I don’t leave anyone behind. Be sure to send your questions to me at John@JohnMuellerBooks.com.

 

Exploring the TimeCheck Application (Part 9)

The Exploring the TimeCheck Application (Part 8) post helped you explore the first part of the GroupSettings class. As promised, this week’s post will help you complete the GroupSettings class. Of course, one of the most essential tasks you perform with this sort of class is creating a new instance of the class as needed. In many cases, you can use the default constructor, which requires no input and produces no output. However, when working with settings, you need to create a constructor that sets the settings to a known state as shown here.

// Define a constructor to initialize default values.
public GroupSettings()
{
   CustomProject = false;
   CustomTask = false;
   ProjectList = null;
   TaskList = null;
}

Setting CustomProject and CustomTask to false makes sense because you don’t want the user to be able to create custom projects or tasks unless the administrator wants to allow it. You may have heard the phrase principle of least privilege used in regard to application security and this is an example of such a setup. The application assumes that the user doesn’t have the right to perform some special task unless the administrator specifically allows it.

What may concern some people is the setting of ProjectList and TaskList to null. When an administrator uses the application for the first time, there aren’t any projects or tasks assigned for the application, so that’s one reason to set these List objects to null. However, the second reason is to signal an error to the application. When a user starts the application and the application can’t find the network drive containing the group settings, it’s important to signal the application that an error has happened. This error won’t prevent the application from continuing, but it will prevent the user from logging in using standardized projects and tasks. As a result, the application must have some way of signaling this problem and dealing with it. You’ll see how this all works in a later post.

In addition to creating new GroupSettings objects, the class must be able to read and write GroupSettings to the network drive as an XML file. This one file contains the settings that everyone will use. There are many permutations to discuss with regard to this sort of file. For example, you need to consider whether multiple administrators could possibly modify the file at one time. If so, you need to implement some sort of locking strategy to ensure that only one administrator can open the file for modification at a time. Of course, you don’t want regular users making modifications to the file. For the purposes of clarity, I chose to make things as simple as possible. I’m assuming that there is only one administrator. In addition, I’m assuming that because of the interface modifications you’ll learn about in a later post, that only the administrator will have access to the interface elements required to make the changes. With these restrictions in mind, here is the code the example uses to save data to the file.

// Create a method for saving the settings.
public static void SaveSettings(GroupSettings Settings)
{
   // Obtain the network path.
   String NetworkPath = UserSettings.GetUserSettings().NetworkPath;
 
   // Exit when the application hasn't been configured yet.
   if (NetworkPath == null)
      return;
 
   // When the path doesn't exist, the group hasn't been set up to
   // use the application, so you need to create the path.
   if (!Directory.Exists(NetworkPath + @"\GroupData"))
      Directory.CreateDirectory(NetworkPath + @"\GroupData");
 
   // Check for the file. If it doesn't exist, create it.
   if (!File.Exists(NetworkPath + @"\GroupData\AppData.Config"))
   {
      FileStream NewFile = File.Create(
         NetworkPath + @"\GroupData\AppData.Config");
      NewFile.Close();
   }
 
   // Create an XML serializer.
   XmlSerializer DataWriter = new XmlSerializer(typeof(GroupSettings));
 
   // Define a data stream.
   StreamWriter Output = new StreamWriter(
      NetworkPath + @"\GroupData\AppData.Config");
 
   // Perform the data write.
   DataWriter.Serialize(Output, Settings);
 
   // Close the stream.
   Output.Close();
}

The code begins by creating a path variable that holds the location of the network storage location. This location is unique for an individual machine and is stored as part of the UserSettings (see Exploring the TimeCheck Application (Part 7)). When NetworkPath is null, it means that the application hasn’t been properly configured and there is nothing for the application to do, so it returns a null value to the caller. The application must also ensure that the GroupData folder exists and that it contains the AppData.Config file. When the AppData.Config file is missing, the application must create it.

 

Remember that this task takes place across a network connection. Normally, I’d include some error trapping code here, but left it out for the sake of clarity. A production version of this application will include the required error trapping and error handling code.


Once the application establishes that there is a file to use to hold the data, it creates an XmlSerializer object, DataWriter, and defines its output as type GroupSettings. The application then creates a StreamWriter to actually output the data and then serializes the data as XML in the output. This entire process is precisely the same one that is used for the UserSettings class, except that it happens across a network connection (with all of the potential for problems that a network connection can cause). In fact, I encourage you to compare this method to the one used for the UserSettings class.

Everyone will use the method to obtain the data from the file. You don’t need to implement much in the way of special handling because the file is read and immediately closed. If there are a lot of users to accommodate, you may possibly need to add file locking features to the application. However, since there is no modification of data taking place, allowing shared access works just fine in most cases. Here is the code used to read data from the AppData.Config file.

// Create a method for obtaining the current settings.
public static GroupSettings GetSettings()
{
   // Obtain the network path.
   String NetworkPath = UserSettings.GetUserSettings().NetworkPath;
 
   // Exit when the application hasn't been configured yet.
   if (NetworkPath == null)
      return null;
 
   // Check for the existence of the group settings file. If it
   // doesn't exist, exit.
   if (!File.Exists(NetworkPath + @"\GroupData\AppData.Config"))
      return null;
 
   // Create an XML deserializer.
   XmlSerializer DataReader = new XmlSerializer(typeof(GroupSettings));
 
   // Define a data stream.
   StreamReader Input = new StreamReader(
      NetworkPath + @"\GroupData\AppData.Config");
 
   // Perform the data read.
   GroupSettings GroupData = (GroupSettings)DataReader.Deserialize(Input);
 
   // Close the stream.
   Input.Close();
 
   // Return the data.
   return GroupData;
}

It’s a good idea to compare this method to the one used with the UserSettings class to read the user data. The basic concept is the same. The only difference is that this class works across a network connection, so the production version of the application will likely contain additional error trapping and error handling code.

Well, that’s it for this week. Next week we’ll discuss any remaining internal elements or possibly move on to a few of the user interface elements depending on what sorts of questions I receive about the application. In the meantime, please let me know about any questions or concerns you have about the application at John@JohnMuellerBooks.com. You can find the next post in this series at Exploring the TimeCheck Application (Part 10).