pmbaseball1
pmbaseball1

Reputation: 15

Try statement not executing - goes straight to catch

I am setting up a winform that takes the first name, last name, and student ID of a student into an sql database named college, and performs a stored procedure which searches for that student, then displays the results in a DataGridView when the search button is pressed. Whenever I press the search button I get the following error

"A first chance exception of type 'System.TypeInitializationException' occurred in Search2.exe".

My program is skipping over the Try block shown, and going to the Catch statement. Can anyone tell me why this is?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Search2
{
    public partial class frmSearch : Form
    {
        public frmSearch()
        {
            InitializeComponent();
        }

        private void btnSearch_Click(object sender, EventArgs e)
        {
            string studid, fname, lname;

            try
            {
                // get the values
                fname = txtFname.Text.Trim();
                lname = TxtLname.Text.Trim();
                studid = txtStudentID.Text.Trim();

                //instantiate datatier
                Class1 astudent = new Class1();
                DataSet ds = new DataSet();

                ds = astudent.GetStudents(studid, fname, lname);

                // populate the datagrid with dataset
                dgvStudents.DataSource = ds.Tables[0];
            }
            catch (Exception ex)
            {

            }
        }

        private void frmSearch_Load(object sender, EventArgs e)
        {
            // TODO: This line of code loads data into the 'collegeDataSet.STUDENT' table. You can move, or remove it, as needed.
            //this.sTUDENTTableAdapter.Fill(this.collegeDataSet.STUDENT);

        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualBasic;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Data.SqlClient;
using System.Globalization;

namespace Search2
{
    class Class1: frmSearch
    {
        static String connString = ConfigurationManager.ConnectionStrings["Data Source=EVEDELL17;Initial Catalog=College;Integrated Security=True"].ConnectionString;
        static SqlConnection myConn = new SqlConnection(connString);
        static System.Data.SqlClient.SqlCommand cmdString = new System.Data.SqlClient.SqlCommand();

        public DataSet GetStudents(string studid, string fname, string lname)
        {
            try
            {
                // Open Connection
                myConn.Open();
                //clear command argument
                cmdString.Parameters.Clear();
                //command
                cmdString.Connection = myConn;
                cmdString.CommandType = CommandType.StoredProcedure;
                cmdString.CommandTimeout = 1500;
                cmdString.CommandText = "SearchStudent";
                // define input parameter

                cmdString.Parameters.Add("@fname", SqlDbType.VarChar, 1).Value = fname;
                cmdString.Parameters.Add("@lname", SqlDbType.VarChar, 25).Value = lname;
                // adapter and daraset
                SqlDataAdapter aAdapter = new SqlDataAdapter();
                aAdapter.SelectCommand = cmdString;
                DataSet aDataSet = new DataSet();
                // fill adapter
                aAdapter.Fill(aDataSet);
                //return Dataset
                return aDataSet;
            }
            catch (Exception ex)
            {
                throw new ArgumentException(ex.Message);
            }
            finally
            {
                myConn.Close();
            }
        }
    }
}

Upvotes: 0

Views: 112

Answers (2)

Christopher
Christopher

Reputation: 9824

Xander got the answer I think: Something goes "bump" when initializing those static fields. And static/type constructors are notoriously poor at communicating exceptions:

https://learn.microsoft.com/en-us/dotnet/api/system.typeinitializationexception

The underlying problem however, is one of pattern. And there are several issues. However you can often fudge these parts for simple learning examples.

Disposeable

SqlConnectons is Disposeable, as it contains some unmanaged resources. Always dispose of disposeables. My personal rule is:

  • never split the Creation and Disposing of a Disposeable resource. Create, Use, Dispose. All in the same piece of code - ideally using a using statement/block.
  • The rare exception is if you wrap around something disposeable that you can not Dispose (or even just might ocassionally). In that case implent the Dispose pattern yourself, with the sole purpose of relaying the Dispose() call. (Approxmialtey 95% of all classes are only Disposeable because of this).

Avoid Globals/Static

Static variables are global variables. And quicklly after inventing those, we realized that using either was a terrible idea 90% of the time. Particular for exchanging/sharing data.

While I go even a bit further, never have a field that is static and can be written. constant and readonly (runtime constants) should be the only statics you ever use. If you can not make it that, do not make it static. Stuff like connection strings are way up on that rule. If you can not tag it like that, do not make it a static to begin with.

At tops I make a class, struct or tupple. And assign a instance of it to a static readonly/constant variable. Stuff like connection strings are either a instance variable, or handed in on each call of a function like GetStudents. Indeed, Class1 looks a lot like a DB access abstraction. And those in particular fall under the "do not make static" rule.

Upvotes: 0

xander
xander

Reputation: 1709

Judging by the exception type--TypeInitializationException--I suspect the problem is with the static field initializers:

static String connString = ConfigurationManager.ConnectionStrings["Data Source=EVEDELL17;Initial Catalog=College;Integrated Security=True"].ConnectionString;
static SqlConnection myConn = new SqlConnection(connString);
static System.Data.SqlClient.SqlCommand cmdString = new System.Data.SqlClient.SqlCommand();

Those initializers will run the first time their containing class (Class1) is "touched" by the runtime. Because they aren't in a method, it's hard for the compiler to give a helpful stack trace when they fail. Try replacing the inline initializers with a static constructor:

static String connString;
static SqlConnection myConn;
static System.Data.SqlClient.SqlCommand cmdString;

static Class1() {
    connString = ConfigurationManager.ConnectionStrings["Data Source=EVEDELL17;Initial Catalog=College;Integrated Security=True"].ConnectionString;
    myConn = new SqlConnection(connString);
    cmdString = new System.Data.SqlClient.SqlCommand();
}

I think you'll get a better error message that way. You can also set a breakpoint in the constructor to see exactly what happens during initialization.

Read more here: https://learn.microsoft.com/en-us/dotnet/api/system.typeinitializationexception?view=netframework-4.8#Static

Upvotes: 3

Related Questions