tag:blogger.com,1999:blog-2401814087953736312024-02-20T11:57:24.194-08:00C# LearningsUnknownnoreply@blogger.comBlogger12125tag:blogger.com,1999:blog-240181408795373631.post-51839666726361486582010-03-03T11:15:00.000-08:002010-03-03T11:53:19.566-08:00DateTime.Date not supported by EF GroupByI ran into this issue today where the Entity Framework does not support the GroupBy method against DateTime.Date and you won't find out until runtime. Here is what the original statement looked like:<br /><br /><blockquote>myTable.GroupBy(mt => mt.ActivityDate.Date).<br />OrderBy(mt => mt.Key).<br />Select(mt => new{Date= mt.Key, Count = mt.Count()}).Take(90).ToList()</blockquote><br /><br />This resulted in the following exception:<br />NotSupportedException: The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.<br /><br />This was problematic because I need to report on a count of items in the database for each day of the last 90 days. <br /><br />I found a post on the MSDN forums that gave a workaround for doing the group by that worked great, <a href="http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/cb58ae5f-5db9-4054-92b6-a1bf63764574">MSDN</a>. So I updated my original statement to this:<br /><br /><blockquote>myTable.GroupBy(mt => new {mt.ActivityDate.Year, mt.ActivityDate.Month, mt.ActivityDate.Day}).<br />OrderBy(mt => mt.Key).<br />Select(mt => new{Date= mt.Key, Count = mt.Count()}).Take(90).ToList()</blockquote><br /><br />This works but then you have this funny anonymous type and displaying it isn't pretty. So my next problem was figuring out how to display this data. I updated my statement to convert the Key into a DateTime type:<br /><br /><blockquote>myTable.GroupBy(mt => new {mt.ActivityDate.Year, mt.ActivityDate.Month, mt.ActivityDate.Day}).<br />OrderBy(mt => mt.Key).<br />Select(mt => new{Date = new DateTime(mt.Key.Year, mt.Key.Month, mt.Key.Day), Count = mt.Count()}).Take(90).ToList()</blockquote><br /><br />At first glance you might think this works but it doesn't. Instead you get the following exception at runtime.<br /><br />NotSupportedException: Only parameterless constructors and initializers are supported in LINQ to Entities.<br /><br />A link over on <a href="http://thedatafarm.com/blog/data-access/a-few-things-you-can-t-do-with-ef-queries-which-you-won-t-find-out-until-runtime/">Don't Be Iffy</a> took me back to <a href="http://social.msdn.microsoft.com/forums/en-US/adodotnetentityframework/thread/d700becd-fb4e-40cd-a334-9b129344edc9/">MSDN</a> to find out <blockquote>The idea of supporting only parameter-less constructor was one of the hard decisions we made as a product team. The main idea with this approach was we shouldn't open up new surface area in LINQ over Entities that is not supported by EDM. EDM in general doesn't allow you to construct in random objects (using the NEW constructor in eSQL). To make it consistent with the whole stack, we decided to implement it like wise. Limiting the constructions only to:<br /> - Parameterless constructors <br /> - Anonymous types (as it’s the only way to do multi-project in LINQ over Entities)<br /></blockquote><br /><br />I obviously wasn't going to be able to do what I needed in Linq to Entities so I had to find a work around. I figured once I had the data from the DB that I needed I shouldn't have any problems doing this, especially since I didn't have these same problems in Linq to SQL. Note: I considered going the Linq to SQL route but I wasn't quite ready to give up on Linq to Entities yet.<br /><br />What I decided to do instead was to grab the data from EF without using deferred execution and then create a new anonymous type locally. Below is the completed solution.<br /><br /><blockquote>var data = myTable.<br />GroupBy(ra => new {ra.ActivityDate.Year, ra.ActivityDate.Month, ra.ActivityDate.Day}).<br />OrderBy(ra => ra.Date).<br />Select(ra => new{Key = ra.Key, Count = ra.Count()}).<br />Take(90).ToList();<br /><br />data.Select(ra => new {Date = new DateTime(ra.Key.Year, ra.Key.Month, ra.Key.Day), Count = ra.Count});</blockquote><br /><br />This worked exactly as I expected it to and it only required some minor modification on my part to get it there. Hopefully this helps someone else out there that is having a similar issue.Unknownnoreply@blogger.com9tag:blogger.com,1999:blog-240181408795373631.post-84459111274578032822009-05-06T15:03:00.000-07:002009-05-06T15:17:39.683-07:00Joining DataTablesRecently, I needed to perform several joins in a SQL query and return that data to a DataGrid. Normally this works great because I only have 2-3 tables I am performing a join on and the number of records being returned is relatively low. In this latest case I had many tables to join together and some of them had millions of rows in them. <br /><br />The query to pull all the data I needed would run for several minutes before returning anything to me. I decided that to speed this up I would handle the joins in the application and just pull the rows I needed in the queries themselves. This took a query that would return in 15+ minutes down to less than 1 minute.<br /><br />Microsoft has some code here: <a href="http://support.microsoft.com/kb/326080/en-us"></a> on how to do this. The code they had was over-engineered for what I needed to do so I decided to write my own. <br /><br />The main method takes 2 tables and returns a new table. It is quick and dirty and can still be fleshed out if needed. <br /><br />public static class MergeData<br /> {<br /> public static DataTable Merge(DataTable tableOne, DataTable tableTwo)<br /> {<br /> DataTable output;<br /><br /> output = new DataTable();<br /><br /> CopyColumns(tableOne, ref output);<br /> CopyColumns(tableTwo, ref output);<br /> CopyData(tableOne, tableTwo, ref output);<br /><br /> return output;<br /> }<br /><br /> public static void CopyData(DataTable tableOne, DataTable tableTwo, ref DataTable destinationTable)<br /> {<br /> foreach (DataRow row in tableOne.Rows)<br /> {<br /> DataRow nr;<br /> DataRow[] joinedRows;<br /><br /> nr = destinationTable.NewRow();<br /><br /> foreach (DataColumn dc in tableOne.Columns)<br /> {<br /> nr[dc.Table.TableName + "." + dc.ColumnName] = row[dc.ColumnName];<br /> }<br /><br /> string selectStatement = tableTwo.Columns[1].ColumnName + " = '" + row[tableOne.Columns[1].ColumnName] + "'";<br /> joinedRows = tableTwo.Select(selectStatement);<br /><br /> foreach (DataColumn dc in tableTwo.Columns)<br /> {<br /> nr[dc.Table.TableName + "." + dc.ColumnName] = joinedRows[0][dc.ColumnName];<br /> }<br /><br /> destinationTable.Rows.Add(nr);<br /> }<br /> }<br /> <br /> public static void CopyColumns(DataTable table, ref DataTable output)<br /> {<br /> foreach (DataColumn dc in table.Columns)<br /> {<br /> DataColumn nc;<br /><br /> nc = new DataColumn(table.TableName + "." + dc.ColumnName, dc.DataType);<br /> AddColumn(nc, ref output);<br /> }<br /> }<br /><br /> public static void AddColumn(DataColumn dc, ref DataTable dt)<br /> {<br /> if (!dt.Columns.Contains(dc.ColumnName))<br /> {<br /> dt.Columns.Add(dc);<br /> }<br /> }<br /> }Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-240181408795373631.post-46480881081560375852009-04-10T11:12:00.000-07:002009-04-10T11:22:41.579-07:00Back to C#After about 6 months of being away from C# I am finally able to get back to working with the language again. My first project went very smooth. It consisted of creating a class to read and write INI files. The most difficult part was the regex needed to determine what sections, settings and values. I need to perform some more research on regex, tokens and how C# uses them. <br /><br />My next project is a bit more interesting and complicated. The basics of it are I need to parse a csv file and import it into a database. It isn't just 1 csv file but literally 10s of thousands of csv files and they get updated twice a day or more. The app will have to update the database at least once a day possibly more. <br /><br />Parsing the csv will be interesting since some fields have quotes and just about any character can appear inside those quotes. I also need to look for certain strings and set them to DBNull since most fields from the csv file will be Ints or Floats in the database. <br /><br />Some new tools in my arsenal since I last posted here. <br /> XtUnit - Extension framework provides better support for unit tests with a database.<br /> Log4Net - If you aren't using it for logging you don't know what you are missing.<br /> <br />I am glad to be back and look forward to updating this blog again.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-240181408795373631.post-9987444190016075492008-10-02T10:44:00.000-07:002008-10-02T11:34:28.172-07:00Does C# need the Template pattern?My understanding of the Template pattern is that it allows a programmer to provide a hook for outside use into a classes methods. With the advent of C# a new type has come into use, the Delegate. From the <a href="http://msdn.microsoft.com/en-us/library/ms173171(VS.80).aspx">MSDN </a>site <blockquote>A delegate is a new type that references a method. Once a delegate is assigned a method, it behaves exactly like that method. The delegate method can be used like any other method, with parameters and a return value...</blockquote> <br /><br />This sounds to me like a perfect candidate to hook into a method. Now maybe the Template pattern is still useful in other ways, although I haven't come up with one, but maybe Delegates can make it largely obsolete.<br /><br />Some quick sample code I did to just test it out.<br /><br />namespace DelegateTest<br />{<br /> public delegate int Test(int MyInt);<br /> class Program<br /> {<br /> public static Test MyTest;<br /> static void Main(string[] args)<br /> {<br /> int SomeNumber = 5;<br /> MyTest += new Test(MyInt);<br /> <br /> if (MyTest != null)<br /> {<br /> SomeNumber = MyTest(SomeNumber);<br /> }<br /> Console.WriteLine(SomeNumber);<br /> Console.Read();<br /> }<br /><br /> public static int MyInt(int TestInt)<br /> {<br /> return 6;<br /> }<br /> }<br />}Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-240181408795373631.post-83976757546991019492008-09-19T14:36:00.000-07:002008-09-19T14:57:28.913-07:00Strategy PatternI found a very useful purpose for the strategy pattern. I am writing an application that will move all or part of a database depending on the users selection. Since 90% of the code was the same I decided to use an abstract class with concrete methods for the business logic that was the same and abstract classes for where it differed. The strategies I have to choose from are:<br /><br />1. Move entire DB<br />2. Move all rows from X number of tables.<br />3. Move X number of rows from X tables. <br /><br />Doing a quick mock I came up with <br /><br />public abstract class DBMoveStrategy<br />{<br /> //properties...<br /><br /> //events...<br /><br /> //concrete methods<br /><br /> public abstract void GetSource();<br /> public abstract void AddConstraints(DataSetFacade Data);<br /><br />}<br /><br />Then I sub-class for the different branches of logic.<br /><br />public class DBMoveAll : DBMoveStrategy<br />{<br /> public override void GetSource()<br /> {<br /> //some code<br /> }<br /><br /> public override void AddConstraints(DataSetFacade Data)<br /> {<br /> //some code<br /> }<br />}<br /><br />public class DBTables : DBMoveStrategy<br />{<br /> public override void GetSource()<br /> {<br /> //some code<br /> }<br /> <br /> public override void AddConstraints(DataSetFacade Data)<br /> {<br /> //some code<br /> }<br />}<br /><br />public class DBMoveRows : DBMoveStrategy<br />{<br /> public override void GetSource()<br /> {<br /> //some code<br /> }<br /> <br /> public override void AddConstraints(DataSetFacade Data)<br /> {<br /> //some code<br /> }<br />}<br /><br />To use this inside another class I just do the following:<br /><br />public class MyControllerClass<br />{<br /> private DBMoveStrategy movedb;<br /><br /> public MyControllerClass()<br /> {<br /> if (IsMoveAll)<br /> movedb = new DBMoveAll();<br /> }<br /> <br /> public void Connect(string Server, string Database, string UserName, string Password)<br /> {<br /> movedb.connect(string Server, string Database, string UserName, string Password)<br /> }<br /> <br /> public void GetData()<br /> {<br /> movedb.GetSource();<br /> movedb.AddConstraints();<br /> }<br />}<br /><br /><br />There is more logic involved but this will give a flavor for how I am using the pattern. There are probably some better ways I could use it or other patterns that might be better but I am still learning the language and better ways to write code.Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-240181408795373631.post-70096892886267605322008-09-05T08:25:00.001-07:002008-09-05T10:20:27.302-07:00Event Driven Error HandlingI have been reading a new titled "Design Patterns in C#". It is a great book, tons of information and it is quite understandable. While reading through the observer pattern it struck me. Why do we need to use so may try/catch statements in our code when we could fire off the exceptions from an event handler. <br /><br />So I wrote up some quick code to test it out. <br /><br />public delegate void TestErrorHandler(string message);<br /><br />public class TestClass<br />{<br /> public event TestErrorHandler test;<br /><br /> public void TriggerHandler(object blah)<br /> {<br /> if (blah == null)<br /> {<br /> test("Null argument in TriggerHandler");<br /> }<br /> }<br />}<br /><br />static void Main(string[] args)<br />{<br /> TestClass MyTest = new TestClass();<br /> MyTest.test += new TestErrorHandler(OhCrap);<br /> MyTest.TriggerHandler(null);<br />}<br /><br />public static void OhCrap(string e)<br />{<br /> Console.WriteLine(String.Format("Oh CRAP! {0}", e));<br /> Console.Read();<br />}<br /><br />I can see some pitfalls to this solution like:<br />1. You fire off the same Exception Event from multiple methods, i.e. ArgumentNullException. <br />2. How do you tell what observing method called the method that threw the Exception Event? For instance what if you had a private property that had the same methods being called multiple times? <br />3. What about if I call the same method multiple times from the same piece of code. a for loop for instance?<br /><br />These are definitely challenging issues to solve but I feel it may be possible. I already have some ideas but right now don't have the time to fully test these out. If it is possible then it could take decoupling code to a whole new level.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-240181408795373631.post-55867924688269230012008-08-11T13:58:00.000-07:002008-08-11T15:22:03.105-07:00Updating identity columns in a DatasetOne of the things I have noticed about working with DataSets is that there is not a lot of information out there on how to work with Foreign Key constraints and merging 2 databases together. Let me rephrase that, there is a but it feels scattered about and I felt it didn't teach me what I needed to know. After spending some time researching the subject here is the best way I have found to deal with the issue.<br /><br />First you need to setup your connection.<br /><br />string ConnectionString = "server=" + _DatabaseServer + ";user id=" + UserName + ";password=" + Password + ";Trusted_Connection=no;connection timeout=30";<br /><br />Establish your connection<br /><br />Connection = new SqlConnection(ConnectionString);<br />Connection.Open();<br /><br />Now we setup our adapter<br />string ParentQuery = "SELECT * FROM ParentTable";<br />string ChildQuery = "SELECT * FROM ChildTable";<br />SqlDataAdapter ParentAdapter = new SqlDataAdapter(ParentQuery, Connection);<br />SqlDataAdapter ChildAdapter = new SqlDataAdapter(ChildQuery, Connection);<br /><br />At this point we can fill our DataSet. Before we do we need to setup an event handler for updating the Identity column in each row when it gets written back to the database. The reason for this is depending on how you you merge DataSets or add rows to a DataSet the Identity column will have a place holder. This place holder will not necessarily be the same value as what the database will contain. This wouldn't be a problem if you were only updating 1 table but when you have child tables that need the same value you will run into issues. <br /><br />Here is where you add the event handler<br /><br />ParentAdapter.RowUpdated += new SqlRowUpdatedEventHandler(AdapterRowUpdated);<br /><br />And here is the event handler<br /><br />private void AdapterRowUpdated(object sender, SqlRowUpdatedEventArgs e)<br /> {<br /> SqlCommand IdentityCommand = new SqlCommand("SELECT @@IDENTITY", e.Command.Connection);<br /> <br /> e.Row["ID"] = IdentityCommand.ExecuteScalar();<br /> e.Row.AcceptChanges();<br /> }<br /><br />Now when you Update the database all your rows will have the same IDs. <br /><br />Go ahead and fill our DataSet.<br /><br />ParentAdapter.FillSchema(MyDataSet, SchemaType.Source, "ParentTable");<br />ProfileAdapter.Fill(MyDataSet, "ParentTable");<br />ChildAdapter.FillSchema(MyDataSet, SchemaType.Source, "ChildTable");<br />ChildAdapter.Fill(MyDataSet, "ChildTable");<br /><br />We have 1 DataSet with 2 DataTables in it, ParentTable and ChildTable. The database has an Identity field and a Foregn Key constraint. Those are not replicated down to the DataSets so we have to do this manually.<br /><br />The Unique constraint<br />UniqueConstraint ParentConstraints = new UniqueConstraint(new DataColumn[] { MyDataSet.Tables["ParentTable"].Columns["ID"] });<br />MyDataSet.Tables["ID"].Constraints.Add(ParentConstraints);<br /><br />Pay attention to the UpdateRule setting for the Foreign Key constraint. We set it as Rule.Cascade. This is done so that when we update the ID column for a row that ID gets propagated to any row within the child tables that contain the same Identity.<br /><br />ForeignKeyConstraint ParentFK = new ForeignKeyConstraint("IDFK",<br />MyDataSet.Tables["ParentTable"].Columns["ID"],<br />MyDataSet.Tables["ChildTable"].Columns["ID"]);<br />ProfileFK.UpdateRule = Rule.Cascade;<br />MyDataSet.Tables["ChildTable"].Constraints.Add(ParentFK);<br /><br />If you are merging 2 databases together I would recommend following the same steps above for the second database. That way you have 2 identical DataSets when you go to merge them together and you can reuse all the same code again. You don't have to do this if you don't want to as there are ways around it by using MissingSchemaAction but I prefer to have identical DataSets to work from.<br /><br />We have 2 DataSets and we need to merge them together. The problem is that when you Fill your DataSet by default it sets all Rows to a RowState of NoChange. This means when you merge your 2 DataSets nothing will get written to your database because nothing has changed. Any new data should be marked as Added so the Adapter will Insert it into the database when you perform the Update. This is not very efficient if you have multiple tables that need to be updated. In that case wrap the below foreach loop in another foreach loop to iterate through each table.<br /><br />foreach (DataRow row in NewData.Tables["ParentTable"].Rows)<br />{<br /> row.BeginEdit();<br /> row.SetAdded();<br /> row.EndEdit();<br />}<br /><br /><br />Merge the 2 DataSets. This is very easy using the Merge method in your Destination DataSet, NewData being the DataSet I want to merge into my existing data. You have to set preserveChanges to true or the Merge will throw out all your changes and nothing will make it into the new database.<br /><br />MyDataSet.Merge(NewData, true, MissingSchemaAction.Add);<br /><br />Our DataSets are now merged and ready to be Updated in the new location. This is pretty trivial. The only thing to remember is that the Identity column is marked as ReadOnly, therefore you can't update it without first changing it. <br /><br />SqlCommandBuilder ParentCommandBuilder = new SqlCommandBuilder(ParentAdapter);<br />SqlCommandBuilder ChildCommandBuilder = new SqlCommandBuilder(ChildAdapter);<br />MyDataSet.Tables["ParentTable"].Columns["ID"].ReadOnly = false;<br />ParentAdapter.Update(MyDataSet.Tables["ParentTable"]);<br />MyDataSet.Tables["ParentTable"].Columns["ID"].ReadOnly = true;<br />ChildAdapter.Update(MyDataSet.Tables["ChildTable"]);<br /><br />Now just check the destination database and everything should be there. Just repeat the steps above for multiple tables and multiple databases and you can merge as many databases and tables as you need to.Unknownnoreply@blogger.com6tag:blogger.com,1999:blog-240181408795373631.post-84152055654288214452008-08-01T10:18:00.001-07:002008-08-01T10:18:36.124-07:00Mocks and stubsI am getting to a point where I am designing more and more complex applications. Since I am doing this alone I sometimes find it over whelming when I realize everything I am going to need to do as I progress though an application. Combine this with performing TDD at the same time and you begin to realize just how much work you have ahead of yourself. <br /><br />Some of the things that I have begun to use in order to make things easier are mocks and stubs. I first heard about mocks and stubs while researching TDD and am beginning to use them for more than just testing. There are some subtle differences between mocks and stubs but they are similar.<br /><br />Stubs are methods or functions that are only meant as place holders. I have yet to see a stub actually do anything. An example of a stub would be:<br /><br />public static void SomeMethod(string MyString)<br />{<br /> <br />}<br /><br />It doesn't do anything but it will allow code to compile that will need to use this method. Stubs are one of the first steps towards getting your unit tests to pass, if you are following a test driven approach.<br /><br />Mocks can be anywhere from a little more complex to a lot more complex than a stub. Mocks allow you to create methods/functions that return expected data. They are usually the next logical step in TDD after a stub. Building on the above stub a mock could be:<br /><br />public static string SomeMethod(string MyString)<br />{<br /> return "This is my new modified string"; <br />}<br /><br />This will get a test to pass and it will allow you to test other portions of your code that depend on this method without fully implementing it before you are ready.<br /><br />Now where mocks really shine is when you start using interfaces. The way I use this is as follows.<br /><br />public interface IStringManipulator<br />{<br /> public static string SomeMethod(string MyString)<br /> public static bool IsNull(string MyString)<br />}<br /><br />Now that the interface is designed you can start with your mock.<br /><br />public class mockStringManipulator : IStringManipulator<br />{<br /> public static string SomeMethod(string MyString)<br /> {<br /> return "This is my new modified string";<br /> }<br /> public static bool IsNull(string MyString)<br /> {<br /> return true;<br /> }<br />}<br /><br />You have your mock, now you can use the mock as a placeholder.<br /><br />public class WebConnector<br />{<br /> public void Connection(string Username)<br /> {<br /> String NewUsername;<br /> if(!mockStringManipulator.IsNull(Username))<br /> {<br /> NewUsername = mockStringManipulator.SomeMethod(Username)<br /> return NewUsername;<br /> }<br /> else<br /> {<br /> throw NullReferenceException;<br /> }<br /><br /> }<br />}<br /><br />You will of course be writing unit tests on the WebConnector class and when you get around to fully implementing the StringManipulator class you will be using the IStringManipulator interface. This ensures that all the only difference between your mock class and your production class is in the implementation. The signatures and everything else matches exactly and since you will be performing TDD on the production class you will have a high degree of confidence that it will work as expected before you change from the mock to the fully developed class.Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-240181408795373631.post-19892678456481371592008-07-24T13:28:00.001-07:002008-07-24T13:44:35.248-07:00Merging Datasets and UpdatingAfter about 4 days of frustration I finally found out how to get this working. <br /><br />I have a table in a database that I am looking to move to the same table in another database. This seems like an ideal solution for datasets and it is. If you follow the MSDN documentation I found it doesn't work. I have been pulling my hair out and researching datasets for 4 days now trying to figure out why it wouldn't work. When you view the dataset after performing the merge all the data is there and when you perform the update it doesn't error out or throw an exception, however, it didn't work. <br /><br />What was comforting through this learning experience is that I was no the only one running into this issue. I found hundreds of posts from 2004 to present about this very same issue but not one solution, until today. Some of the seasoned .NET programmers probably already know why, but for those that are still learning I will tell you why. <br /><br />When you create an adapter, any adapter, and fill your dataset, all rows will be marked as unchanged. This sounds reasonable since you haven't changed anything yet but when you are migrating data it will not work for you. The reason it doesn't work is when you call the update method on your adapter to move it to the new location the method is going to look for rows that are added, deleted, or changed. It is going to completely ignore the rows marked as unchanged. This I understood, what I couldn't figure out was how to mark those rows as changed without manually iterating through each row and making some change.<br /><br />Enter William Ryan and his great article on <a href="http://www.knowdotnet.com/articles/datasetmerge.html">"DataSet.Merge and Transferring Data"</a>. The way to get this to work is very simple, after you have set up your adapter and before you fill your dataset you need to set the AcceptChangesDuringFill property to false. The reason you set it to false is to get each row in the dataset to be marked as added. Then when you update it all the rows will be added. <br /><br />I hope this helps some one out and big thanks to William for a great write up.Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-240181408795373631.post-49373255319306074562008-07-09T08:56:00.000-07:002008-07-09T10:08:00.432-07:00So many tools so little time.I am still reading through the test-driven development book and am amazed by the number of tools/utilities that are available for Java. I am able to find some of these for C# but many don't have a counterpart in C#. I am starting to realize how serious of an undertaking practicing TDD is going to be for me. Just going through a mock/stub by hand is not easy, especially when you are just starting to create them. I do think it is a great exercise to improve your understanding of exactly what you are doing but I would not like doing it long term. <br /><br />So far I am going have to learn, MbUnit, Rhino.Mock, Nester, NCover, and ReSharper, when I buy it. That is a lot to learn but in the end I will be much better off than where I started.Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-240181408795373631.post-36801335270807940982008-07-08T14:54:00.000-07:002008-07-08T15:04:35.031-07:00Testdriven.NET and Ad Hoc testingSince I am fairly new to C# I still make a lot of syntactical mistakes. One of the features I love about Testdriven.NET is the ability to run Ad Hoc tests on a newly created method to make sure it will actually run. This is by no means a replacement for proper Unit Tests but it does at least tell me if I made a mistake with the code that would prevent it from building without going through the entire process of actually building it.<br /><br />To run an Ad Hoc test add MbUnit as a reference to your current project.<br />Then create a method. Once the method is "complete" right click anywhere inside the method and select Run Test(s).<br /><br />I am using the default setup for Visual Studio and Testdriven.NET. This will allow Testdriven.NET to show the output in the "output" pane.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-240181408795373631.post-29302954344947988142008-07-08T08:02:00.000-07:002008-07-08T09:24:17.701-07:003 months inI have been teaching myself C# for about the last 3 months now. My background was in C and Assembly and sometime last year I picked up Python. Python was a lot of fun. I didn't need to understand much about OOP to get started and was still able to be functional from day 1. <br /><br />C# hasn't been so easy. I purchased 2 books on learning C# from Apress, "Beginning C# 2008" and "Beginning Visual C# Express 2005". Knowing what I do now they are great books, however, coming from a C/Assembly background they did not allow me to learn the language. I feel the reason for this is limited exposure to OOP in these books. One of the books had 1 chapter on OOP while the other had 2. After reading both books I was frustrated, lost and thinking about ditching C# all together. That was when I decided to try a different approach.<br /><br />I went out and purchased "The Object-Oriented Thought Process" by Matt Weisfeld. I have to say that this was the best thing I could have ever done to get a grasp on C# and OOP in general. Most of the code samples were in Java but C# is similar enough that I was able to follow along without getting lost. I learned a lot from this book and plan to reread it several more times to get a better grounding in OOP. It also opened up some new areas I didn't know about, UML for instance. For anyone coming from a procedural background I can't tell you how invaluable this book is.<br /><br />I then went back and reread my previous 2 purchases and have been happy with the content. The Visual Studio book got me started on creating UIs for my apps, something I have never had a need for. The 2008 book taught me about writing tests for the code that you are writing. This was something new and after trying it out I felt it added alot to my learning ability. I even picked up a new book "Pro C# 2008 and the .NET Platform. This was definitely the next step in C# books for me. It was around this time that I began speaking with a co-worker of mine, <a href="http://adronbhall.com">Adron</a>, about some of what I was working on. Talk about opening a can of worms.<br /><br />Adron is one of those guys that if he couldn't do it he would be teaching. I am not talking about the boring lecture types but the one that gives real world concrete examples. He also has a ton of knowledge on process that I never had any exposure to. He starts throwing out terms like "Agile Programming", "Unit Testing", "Refactoring", "Design Patterns". I am just looking at him like he is speaking a foreign language, because he is. That was when he did something I hadn't expected, he gave a 5 minute brain dump of it all. Not everything mind you but enough to wet my appetite and show me why they were important. Now I was hungry again and off to the bookstore to find out what I could on these "new" processes.<br /><br />So I take a look at all the books they have to offer and realize I am not going to dump $300 on the books I want so I prioritize the list of processes and Test Driven Development rises to the top. I felt that at this point I was going to get the most out of TDD. For some reason I couldn't find anything on TDD in C# but I did find the next best thing, TDD in Java using jUnit. Again Java is close enough to C# that I can follow along and jUnit is close enough to mbUnit as well. I purchased "test-driven development A Practical Guide" by David Astels. So far it has been an exceptional book. It has some minor coverage on refactoring and design patterns already in it. This is another highly recommended book.<br /><br />The frustrations have been hard but the rewards are starting to pay off. <br /><br />Some things that I would really like to see change is an improvement in the documentation surrounding mbUnit. I end up using the nUnit documentation to figure out where to start from then fill in the blanks. I suppose it is pretty smart to have another project providing your documentation but until Adron told me to look at the nUnit documentation I didn't even know the project existed. Here is a perfect example. Perform a google search on mbunit and exception assert. I didn't find an mbUnit page until the 44th entry. With nUnit it was the first entry returned.Unknownnoreply@blogger.com0