Hey there! :)
In this article we'll be taking a brief look at how to set up a very simple WCF client and server. We're actually going to let Visual Studio generate the server, and see how we can interact with it. WCF allows us to create applications that communicate remotely with one another - for instance, a client can call a method on a remote server and obtain the result. To follow along, you'll need a version of Visual Studio from 2008 onwards. Sadly, you can't do this in SharpDevelop.
To start off, set up a new WCF Service Library:
You'll notice that Visual Studio has generated some files for us, but let's worry about those later. For now, press F5. When you do that, this program comes up:
This WCF Test Client is actually a program that is communicating with our service (the one autogenerated by Visual Studio). We can see that there is this service at a particular URL on localhost:8733. This service is exposing a couple of methods, one of which is GetData(). Both methods are part of an interface (called a contract) called IService1. If you double-click on GetData(), you can see a Request section at the top, which shows the input parameters it can take.
Let's change the Value of the value parameter from 0 to 35, and then hit the Invoke button. If you get the following security warning, just click OK:
Once you click Invoke, the Response section at the bottom shows the return value, and echoes your input:
Let us now take a look at how this works. Our service exposes the two methods we have seen via the IService1 interface, and the Service1 class which implements it:
Notice how the IService1 interface is adorned with the ServiceContract attribute, and its methods are adorned with the OperationContract. That's how a WCF service exposes its functionality; a client will talk to the server through this interface. We'll see that in a moment. But first, let's take a look at how the service is configured. If you open the App.config file, you'll notice there is quite a bit of configuration in there:
The important things to notice at this stage are the base address and the endpoints. The base address shows the URL where the service is being hosted, and it's the same URL that clients will connect to. The endpoints, on the other hand, define how clients will connect to the service. In this case we have two endpoints: a basic HTTP binding which is used when a client connects to the base address, and which uses the IService1 interface as a contract. If you read more about WCF, you'll find these endpoints referred to as ABC (address, binding, contract). The other endpoint, mex, is a metadata exchange feature by which clients can discover what a server has to offer - that's how the WCF Test Client we used earlier manages to discover the functionality offered by our service.
If you are thinking that the configuration file looks complicated, that's understandable. Fortunately, however, you don't have to edit it by hand. If you right click on App.config, and select Edit WCF Configuration...
...then you can use this handy editor to set things up as you like:
When you press F5 and run the service, it's actually being hosted inside this WCF Service Host, that you can access from the System Tray:
The WCF Test Client, on the other hand, is being invoked via a command line argument. You can see this if you right click on the project, select Properties, and then select the Debug tab, you'll see the following:
Now, let's see how we can actually communicate with our service without using the WCF Test Client. First, copy the service URL (by default it's http://localhost:8733/Design_Time_Addresses/CsWcfMinimal/Service1/). Add a new project (Console Application) to the solution; this project will act as the client. Once that is done, right click on References and select Add Service Reference...:
Enter the service URL in the Address field and hit Go:
Notice the Namespace field is set to ServiceReference1 by default - we'll use this in a minute to identify the service from the client code. Press OK. This generates a bunch of code in the background that makes life easier for the client. In fact, let us now write some code in the client's Main() method to use the service. We start off by creating a client using the code generated by the service reference:
ServiceReference1.IService1 service = new ServiceReference1.Service1Client();
If you click on Service1Client() and press F12 (Go to Definition), you'll be able to see the service reference code that was so conveniently generated for you:
...and if you open the client's App.config file, you'll see that the endpoint has been set up for us:
Let's get back to the code. All we have left to do is use the methods we want to use. Here's the full code for the client's Main() method:
static void Main(string[] args)
{
ServiceReference1.IService1 service = new ServiceReference1.Service1Client();
String response = service.GetData(5);
Console.WriteLine(response);
Console.ReadLine();
}
Now, since the service is still your startup project, press Ctrl+F5 to run it without debugging. Once that is up and running, start the client either via the appropriate context menu option (see screenshot below), or by setting it up as the startup project and then pressing F5.
Rejoice, for it works:
Lovely! :) In this article, we explored the sample WCF Service Library project that is provided when you start a new project of that type. We saw how it is hosted in the WCF Service Host, and how we can interact with it via the WCF Test Client, which is launched by means of a command line argument. We also learned how to consume it from a client program, by first adding a service reference based on the service URL, and then using the handy autogenerated code to invoke the methods on the service.
We didn't actually make any funky server functionality though - we simply used that provided in the project. If you want to try your hand at writing your own service, Mahak Gupta's "A Simple Example of WCF Service" is a great article showing how you can make a simple WCF calculator service.
Showing posts with label visual studio 2012. Show all posts
Showing posts with label visual studio 2012. Show all posts
Monday, November 25, 2013
Saturday, November 16, 2013
C# EF: Setting Connection Strings at Runtime with Entity Framework 5.0, Database First, VS2012
Hi everyone! :)
This article deals with how to solve the problem of building and setting an Entity Framework connection string at runtime, based on a database-first approach (i.e. you have generated an Entity Data Model based on an existing database). You are expected to be familiar with ADO .NET and the Entity Framework. The first part of the article deals with setting up an Entity Data Model and simple interactions with it; this should appeal to all readers. The second part deals with the custom connection string issue, and will be helpful only to those who have actually run into that problem.
We're going to be using Visual Studio 2012, and Entity Framework 5.0. Start a new Console Application so that you can follow along.
Since SQLCE works with just a file, we can create a basic connection string using just the name of the file we're working with.
The following code actually creates the database and a single table called person.
try
{
// create database if it doesn't exist already
if (!File.Exists(filename))
{
// create the actual database file
using (SqlCeEngine engine = new SqlCeEngine(connStr))
{
engine.CreateDatabase();
}
// create the table schema
using (SqlCeConnection conn = new SqlCeConnection(connStr))
{
conn.Open();
String sql = @"create table person(
id int identity not null primary key,
name nvarchar(20),
surname nvarchar(30)
);";
using (SqlCeCommand command = new SqlCeCommand())
{
command.CommandText = sql;
command.Connection = conn;
int result = command.ExecuteNonQuery();
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
We first use SqlCeEngine to create the database file. Then we use ADO .NET to create the person table. Each row will have an auto-incrementing id (primary key), as well as a name and surname. Note that SQLCE does not support the varchar type, so we have to use nvarchar (Unicode) instead.
If you now build and run the application, you should find a people.sdf file in the bin\Debug folder. We'll use that to create an Entity Data Model for the Entity Framework.
Right click on the project and select Add -> New Item...:
From the Data category, select ADO.NET Entity Data Model. You can choose a name for it, or just leave it as the default Model1.edmx; it doesn't really matter.
Click The Add button. This brings up the Entity Data Model Wizard.
The "Generate from database" option is the default selection, so just click Next.
Hit the New Connection... button to bring up the Connection Properties window.
If SQL Server Compact 4.0 is not already selected as the Data source, click the Change... button and select it from the Change Data Source window:
Back in the Connection Properties window, click the Browse... button and locate the people.sdf file in your bin\Debug folder that we generated in the previous section. Leave the Password field empty, and click Test Connection. If all is well, you'll get a message box saying that the test succeeded.
Once you click OK, the Entity Data Model Wizard should become populated with a connection string and a default name for the model:
When you click Next, you'll get the following message:
Just click Yes and get on with it. In the next step, import the person table into your model by ticking the checkbox next to it:
Click Finish. The files for your model are added to the project. You may also get the following warning:
You don't have to worry about it. Just click OK. If you click Cancel instead, you won't have the necessary autogenerated code that you need for this project.
After the database-creation code from the first section, and before the end of the try scope, add the following code:
// interact with the database
using (peopleEntities db = new peopleEntities())
{
db.people.Add(new person() { name = "John", surname = "Smith" });
db.SaveChanges();
foreach (person p in db.people)
{
Console.WriteLine("{0} {1} {2}", p.id, p.name, p.surname);
}
}
Here, we create an instance of our entity context (peopleEntities) and then use it to interact with the database. We add a new row to the person table, and then commit the change via db.SaveChanges(). Finally, We retrieve all rows from the table and display them.
Also, add the following at the end of the Main() method so that we can see the output:
Console.ReadLine();
Run the program by pressing F5. The output shows that a row was indeed added:
The Entity Framework knows where to find the database because it has a connection string in the App.config file:
<connectionStrings>
<add name="peopleEntities" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlServerCe.4.0;provider connection string="data source=|DataDirectory|\people.sdf"" providerName="System.Data.EntityClient" />
</connectionStrings>
This might be good enough in some situations, but other times, we might want to build such connection string in code and ask the Entity Framework to work with it. A reason for this might be because the connection string contains a password, and you want to obtain it from an encrypted source. The following two sections illustrate how this is done.
Let's start out by commenting out the connection string in the App.config file:
<connectionStrings>
<!--
<add name="peopleEntities" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlServerCe.4.0;provider connection string="data source=|DataDirectory|\people.sdf"" providerName="System.Data.EntityClient" />
-->
</connectionStrings>
If you try running the program now, you'll get a nice exception.
Now, what we want to do is add the connection string into our code and pass it to the entity context (the peopleEntities). So before our Entity Framework code (which starts with using (peopleEntities...), add the following:
String entityConnStr = @"metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlServerCe.4.0;provider connection string="data source=|DataDirectory|\people.sdf"";
If you now try to pass this connection string to the peopleEntities constructor, you'll realise that you can't. You can see why if you expand Model1.edmx and then Model1.Context.tt in Solution Explorer, and finally open the Model1.Context.cs file:
The peopleEntities class has only a parameterless constructor, and it calls the constructor of DbContext with the connection string name defined in App.config. The DbContext constructor may accept a connection string instead, but we have no way of passing it through peopleEntities directly.
While you could add another constructor to peopleEntities, it is never a good idea to modify autogenerated code. If you regenerate the model, any code you add would be lost. Fortunately, however, peopleEntities is a partial class, which means we can add implementation to it in a separate file (see this question and this other question on Stack Overflow).
Add a new class and name it peopleEntities. Add the following at the top:
using System.Data.Entity;
Implement the class as follows:
public partial class peopleEntities : DbContext
{
public peopleEntities(String connectionString)
: base(connectionString)
{
}
}
We can now modify our instantiation of peopleEntities to use our connection string as defined in code:
using (peopleEntities db = new peopleEntities(entityConnStr))
Since we are using a partial class defined in a separate file, any changes to the model will cause the autogenerated peopleEntities to be recreated, but will not touch the code we added in peopleEntities.cs.
When we run the program, we now get a very nice exception (though different from what we got right after commenting out the connection string in App.config):
Apparently this happens because of the " values, which are necessary in XML files but cause problems when supplied in a String literal in code. We can replace them with single quotes instead, as follows:
String entityConnStr = @"metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlServerCe.4.0;provider connection string='data source=|DataDirectory|\people.sdf'";
If we run the program now, it works fine, and a new row is added and retrieved:
You'll notice that the connection string we've been using is made up of three parts: metadata, provider, and the provider connection string that we normally use with ADO.NET.
We can use a class called EntityConnectionStringBuilder to provide these values separately and build a connection string. Using this approach avoids the problem with quotes illustrated at the end of the previous section.
First, remove or comment out the entityConnStr variable we have been using so far.
Then add the following near the top of Program.cs:
using System.Data.EntityClient;
Finally, add the following code instead of the connection string code we just removed:
EntityConnectionStringBuilder csb = new EntityConnectionStringBuilder();
csb.Metadata = "res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl";
csb.Provider = "System.Data.SqlServerCe.4.0";
csb.ProviderConnectionString = "data source=people.sdf";
String entityConnStr = csb.ToString();
When you run the program, it should work just as well:
I hope you found this useful. Feel free to leave any feedback in the comments below. Check back for more articles! :)
This article deals with how to solve the problem of building and setting an Entity Framework connection string at runtime, based on a database-first approach (i.e. you have generated an Entity Data Model based on an existing database). You are expected to be familiar with ADO .NET and the Entity Framework. The first part of the article deals with setting up an Entity Data Model and simple interactions with it; this should appeal to all readers. The second part deals with the custom connection string issue, and will be helpful only to those who have actually run into that problem.
We're going to be using Visual Studio 2012, and Entity Framework 5.0. Start a new Console Application so that you can follow along.
Setting up the database
You can use whatever database you want, but in my case I'm using SQL Server Compact edition (SQLCE). If you're using something else and already have a database, you can just skip over this section.
Unlike many of the more popular databases such as SQL Server and MySQL, SQLCE is not a server and stores its data in a file with .sdf extension. This file can be queried and updated using regular SQL, but is not designed to handle things like concurrent users - something which isn't a problem in our case. Such file-based databases are called embedded databases.
If you have Visual Studio, then you most likely already have SQLCE installed. Look for it in "C:\Program Files (x86)\Microsoft SQL Server Compact Edition\v4.0". Under the Desktop or Private folders you'll find a file called System.Data.SqlServerCe.dll which we need to interact with SQLCE. Add a reference to it from your Console Application.
Now, we're going to create the database and a simple one-table schema. We'll use good old ADO.NET for that. We'll create the database only if it doesn't exist already. First, add the following usings at the top of Program.cs:
using System.IO;
using System.Data.SqlServerCe;
In Main(), add the following:
String filename = "people.sdf";
String connStr = "Data Source=" + filename;
Since SQLCE works with just a file, we can create a basic connection string using just the name of the file we're working with.
The following code actually creates the database and a single table called person.
try
{
// create database if it doesn't exist already
if (!File.Exists(filename))
{
// create the actual database file
using (SqlCeEngine engine = new SqlCeEngine(connStr))
{
engine.CreateDatabase();
}
// create the table schema
using (SqlCeConnection conn = new SqlCeConnection(connStr))
{
conn.Open();
String sql = @"create table person(
id int identity not null primary key,
name nvarchar(20),
surname nvarchar(30)
);";
using (SqlCeCommand command = new SqlCeCommand())
{
command.CommandText = sql;
command.Connection = conn;
int result = command.ExecuteNonQuery();
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
We first use SqlCeEngine to create the database file. Then we use ADO .NET to create the person table. Each row will have an auto-incrementing id (primary key), as well as a name and surname. Note that SQLCE does not support the varchar type, so we have to use nvarchar (Unicode) instead.
If you now build and run the application, you should find a people.sdf file in the bin\Debug folder. We'll use that to create an Entity Data Model for the Entity Framework.
Creating the Data Model
From the Data category, select ADO.NET Entity Data Model. You can choose a name for it, or just leave it as the default Model1.edmx; it doesn't really matter.
Click The Add button. This brings up the Entity Data Model Wizard.
The "Generate from database" option is the default selection, so just click Next.
Hit the New Connection... button to bring up the Connection Properties window.
If SQL Server Compact 4.0 is not already selected as the Data source, click the Change... button and select it from the Change Data Source window:
Back in the Connection Properties window, click the Browse... button and locate the people.sdf file in your bin\Debug folder that we generated in the previous section. Leave the Password field empty, and click Test Connection. If all is well, you'll get a message box saying that the test succeeded.
Once you click OK, the Entity Data Model Wizard should become populated with a connection string and a default name for the model:
When you click Next, you'll get the following message:
Just click Yes and get on with it. In the next step, import the person table into your model by ticking the checkbox next to it:
Click Finish. The files for your model are added to the project. You may also get the following warning:
You don't have to worry about it. Just click OK. If you click Cancel instead, you won't have the necessary autogenerated code that you need for this project.
Interacting with the database using the Entity Framework
// interact with the database
using (peopleEntities db = new peopleEntities())
{
db.people.Add(new person() { name = "John", surname = "Smith" });
db.SaveChanges();
foreach (person p in db.people)
{
Console.WriteLine("{0} {1} {2}", p.id, p.name, p.surname);
}
}
Here, we create an instance of our entity context (peopleEntities) and then use it to interact with the database. We add a new row to the person table, and then commit the change via db.SaveChanges(). Finally, We retrieve all rows from the table and display them.
Also, add the following at the end of the Main() method so that we can see the output:
Console.ReadLine();
Run the program by pressing F5. The output shows that a row was indeed added:
The Entity Framework knows where to find the database because it has a connection string in the App.config file:
<connectionStrings>
<add name="peopleEntities" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlServerCe.4.0;provider connection string="data source=|DataDirectory|\people.sdf"" providerName="System.Data.EntityClient" />
</connectionStrings>
This might be good enough in some situations, but other times, we might want to build such connection string in code and ask the Entity Framework to work with it. A reason for this might be because the connection string contains a password, and you want to obtain it from an encrypted source. The following two sections illustrate how this is done.
Building a raw Entity Framework connection string
<connectionStrings>
<!--
<add name="peopleEntities" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlServerCe.4.0;provider connection string="data source=|DataDirectory|\people.sdf"" providerName="System.Data.EntityClient" />
-->
</connectionStrings>
If you try running the program now, you'll get a nice exception.
Now, what we want to do is add the connection string into our code and pass it to the entity context (the peopleEntities). So before our Entity Framework code (which starts with using (peopleEntities...), add the following:
String entityConnStr = @"metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlServerCe.4.0;provider connection string="data source=|DataDirectory|\people.sdf"";
If you now try to pass this connection string to the peopleEntities constructor, you'll realise that you can't. You can see why if you expand Model1.edmx and then Model1.Context.tt in Solution Explorer, and finally open the Model1.Context.cs file:
The peopleEntities class has only a parameterless constructor, and it calls the constructor of DbContext with the connection string name defined in App.config. The DbContext constructor may accept a connection string instead, but we have no way of passing it through peopleEntities directly.
While you could add another constructor to peopleEntities, it is never a good idea to modify autogenerated code. If you regenerate the model, any code you add would be lost. Fortunately, however, peopleEntities is a partial class, which means we can add implementation to it in a separate file (see this question and this other question on Stack Overflow).
Add a new class and name it peopleEntities. Add the following at the top:
using System.Data.Entity;
Implement the class as follows:
public partial class peopleEntities : DbContext
{
public peopleEntities(String connectionString)
: base(connectionString)
{
}
}
We can now modify our instantiation of peopleEntities to use our connection string as defined in code:
using (peopleEntities db = new peopleEntities(entityConnStr))
Since we are using a partial class defined in a separate file, any changes to the model will cause the autogenerated peopleEntities to be recreated, but will not touch the code we added in peopleEntities.cs.
When we run the program, we now get a very nice exception (though different from what we got right after commenting out the connection string in App.config):
Apparently this happens because of the " values, which are necessary in XML files but cause problems when supplied in a String literal in code. We can replace them with single quotes instead, as follows:
String entityConnStr = @"metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlServerCe.4.0;provider connection string='data source=|DataDirectory|\people.sdf'";
If we run the program now, it works fine, and a new row is added and retrieved:
Using EntityConnectionStringBuilder
We can use a class called EntityConnectionStringBuilder to provide these values separately and build a connection string. Using this approach avoids the problem with quotes illustrated at the end of the previous section.
First, remove or comment out the entityConnStr variable we have been using so far.
Then add the following near the top of Program.cs:
using System.Data.EntityClient;
Finally, add the following code instead of the connection string code we just removed:
EntityConnectionStringBuilder csb = new EntityConnectionStringBuilder();
csb.Metadata = "res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl";
csb.Provider = "System.Data.SqlServerCe.4.0";
csb.ProviderConnectionString = "data source=people.sdf";
String entityConnStr = csb.ToString();
When you run the program, it should work just as well:
Summary
This article covered quite a bit of ground:
- We first used the SqlceEngine and ADO .NET to create a SQL Server Compact database.
- When then created an Entity Data Model for this database.
- We added some code to add rows and retrieve data using the Entity Framework.
- We provided the Entity Framework with a raw connection string in code. To do this, we used a partial class to add a new constructor to the entity context class that can pass the connection string to the parent DbContext. We also observed a problem with using " in the connection string, and solved it by using single quotes instead.
- We used EntityConnectionStringBuilder to build a connection string from its constituent parts, and in doing so completely avoided the " problem.
Monday, October 28, 2013
Unit Tests, The Visual Studio Way
Hi! :)
Last month I wrote a couple of articles on unit testing: "C#: Unit Testing with SharpDevelop and NUnit" and "C#: Mocking and Dependency Injection for Unit Testing a File Sorting Program". These articles gave an introduction to unit testing using SharpDevelop and NUnit. If you're a Visual Studio user, however, you might prefer to use Visual Studio's own unit testing framework, known as MSTest. Visual Studio makes it really easy to run and debug tests directly from within the IDE, however writing the tests is slightly different.
In order to follow along, you'll need a version of Visual Studio from 2010 onwards, and one that includes unit testing (that doesn't include the Express editions, sorry). To demonstrate how to to write unit tests in Visual Studio, we're going to write a little program that tells us whether a year is a leap year or not.
First, let's create a new Console Application in Visual Studio 2010. You can do this by clicking on the "New Project..." link on the Start Page, or through the File Menu.
Above your Main() method, add a public static method called IsLeapYear():
public static bool IsLeapYear(int year)
{
return false; // TODO
}
We can now implement the logic that will decide whether the year is a leap year or not. We can use the leap year algorithm on Wikipedia. The leap year calculation, although not quite complex, might seem oddly contrived if you're looking at it for the first time. If you're curious about why there are so many conditions, you might want to check out this question on StackOverflow.
So the method ends up looking like this:
public static bool IsLeapYear(int year)
{
if (year % 400 == 0)
return true;
else if (year % 100 == 0)
return false;
else if (year % 4 == 0)
return true;
else
return false;
}
The % is called a modulus operator - it performs a division but returns the remainder, not the result. So you know that year is divisible by 4 because the remainder is zero.
Right, now let's create some unit tests for our shiny new method. Before you run off and start belching out code, Visual Studio has this really neat feature where you can just right click somewhere empty and select "Create Unit Tests...":
In the screen that pops up, you can select the methods and properties for which you want to create unit tests. In our case it's just one method, but this is really useful if you have lots of code and want to generate a bunch of skeleton unit tests quickly.
In the "Output project" option at the bottom, you can choose whether to create a new test project or use an existing one. Again, in our case we can just create a new one, but if you already have a test project and want to add to it, you can just select it from the drop-down list. Anyway, hit "OK", name your unit tests project, and hit "Create". By convention, tests projects are usually named as [ProjectName].Tests .
Now, when you're done, you might get this message about InternalsVisibleTo:
See, this is because our Program class is not public, and that makes it internal by default. This means that the test project can't see it. Visual Studio allows projects to access non-public classes anyway by using this thing called InternalsVisibleTo, but in most cases I wouldn't recommend it. Just hit "No".
So now Visual Studio created a new project and some code for us:
In the test project, you'll notice that there's a reference to our LeapYearVs2010 project (because the tests need to use our actual code), and there's also a reference to this Microsoft.VisualStudio.QualityTools.UnitTestFramework thing (try fitting that in a business card) - that's needed for unit tests projects.
You'll also notice a bunch of code was generated. It's mostly full of crap, so let's just take out the bull and leave the beef:
using LeapYearVs2010;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
namespace LeapYearVs2010.Tests
{
[TestClass()]
public class ProgramTest
{
[TestMethod()]
[DeploymentItem("LeapYearVs2010.exe")]
public void IsLeapYearTest()
{
int year = 0; // TODO: Initialize to an appropriate value
bool expected = false; // TODO: Initialize to an appropriate value
bool actual;
actual = Program_Accessor.IsLeapYear(year);
Assert.AreEqual(expected, actual);
Assert.Inconclusive("Verify the correctness of this test method.");
}
}
}
Before we can write any proper unit test code, we'll need to make our Program class (in the LeapYearVs2010 project) public:
public class Program
We can now write our first unit test. At times you might find the autogenerated skeleton code for unit tests useful, but in our case you can just throw it out and replace it with this:
[TestMethod()]
public void IsLeapYearTest()
{
int year = 2001;
bool expected = false;
bool actual = Program.IsLeapYear(year);
Assert.AreEqual(expected, actual, "2001 shouldn't be a leap year!");
}
You can now run the unit tests via the Test menu, -> Run -> All Tests in Solution, or else by right clicking on a TestClass or TestMethod and selecting "Run Tests". This right click option is context sensitive, so if you Run Tests on a TestMethod it will run that unit test; if you Run Tests on a TestClass it will run all unit tests for that class.
Right, now at this point, if you also have Visual Studio 2012 installed, you might run into this bug where the tests will just kinda get stuck, like this:
Apparently this is a known issue and you'll need to install Service Pack 1 for Visual Studio 2010 to get things working. When they do, you'll see a nice green tick mark next to your test:
Let us now add another test:
[TestMethod()]
public void IsLeapYearTest2()
{
int year = 1900;
bool expected = true;
bool actual = Program.IsLeapYear(year);
Assert.AreEqual(expected, actual);
}
Run it as before, and...
Whoops! Our second test failed. You can right click the test in the Test Results window and select "View Test Results Details" to obtain additional information including a stack trace (see screenshot above). If you need to, you can put a breakpoint in your test and then from the Test menu go to Debug -> Tests in Current Context while your cursor is in the unit test you want to debug. You can then debug the test as you would with normal code.
In our case, it's pretty clear that 1900 can't be a leap year because it's divisible by 100 but not by 400. So we need only update the expected value as follows:
bool expected = false;
Finally, let's take a look at how to create unit tests in Visual Studio 2012 and 2013. I'm going to create a new Console Application in this dark-themed VS2013 which looks like it came out of a chimney:
I'm going to set up Program just as I did in VS2010: make the class public, and add the method as before:
public static bool IsLeapYear(int year)
{
if (year % 400 == 0)
return true;
else if (year % 100 == 0)
return false;
else if (year % 4 == 0)
return true;
else
return false;
}
Now, let's create the unit tests. Right click in some empty space and...
Uhhhh... crap. Apparently the "Create Unit Tests..." option was removed in Visual Studio 2012, much to people's frustration. Fortunately, there are workarounds that can bring it back. If you don't want to do those, however, you're just going to have to create the test project and unit tests manually. To do this, right click on the solution, then Add -> New Project..., and from the Test category on the left, select "Unit Test Project". Give it a name and hit "OK".
This generates empty test code, and you can take off writing your unit tests from here. With VS2012, it's the same procedure.
Wow, this was long. Well, I hope it helped you learn about some of the unit testing tools that Visual Studio has to offer. It's very convenient because you can run and debug tests directly from within Visual Studio, and in Visual Studio 2010 there is the "Create Unit Tests" option which can be used to quickly generate skeleton code for unit tests of existing code. Sadly, this option is no longer there by default as from Visual Studio 2012, but there are ways of getting it back.
Check back for more programming goodness at Programmer's Ranch! :)
Last month I wrote a couple of articles on unit testing: "C#: Unit Testing with SharpDevelop and NUnit" and "C#: Mocking and Dependency Injection for Unit Testing a File Sorting Program". These articles gave an introduction to unit testing using SharpDevelop and NUnit. If you're a Visual Studio user, however, you might prefer to use Visual Studio's own unit testing framework, known as MSTest. Visual Studio makes it really easy to run and debug tests directly from within the IDE, however writing the tests is slightly different.
In order to follow along, you'll need a version of Visual Studio from 2010 onwards, and one that includes unit testing (that doesn't include the Express editions, sorry). To demonstrate how to to write unit tests in Visual Studio, we're going to write a little program that tells us whether a year is a leap year or not.
First, let's create a new Console Application in Visual Studio 2010. You can do this by clicking on the "New Project..." link on the Start Page, or through the File Menu.
Above your Main() method, add a public static method called IsLeapYear():
public static bool IsLeapYear(int year)
{
return false; // TODO
}
We can now implement the logic that will decide whether the year is a leap year or not. We can use the leap year algorithm on Wikipedia. The leap year calculation, although not quite complex, might seem oddly contrived if you're looking at it for the first time. If you're curious about why there are so many conditions, you might want to check out this question on StackOverflow.
So the method ends up looking like this:
public static bool IsLeapYear(int year)
{
if (year % 400 == 0)
return true;
else if (year % 100 == 0)
return false;
else if (year % 4 == 0)
return true;
else
return false;
}
The % is called a modulus operator - it performs a division but returns the remainder, not the result. So you know that year is divisible by 4 because the remainder is zero.
Right, now let's create some unit tests for our shiny new method. Before you run off and start belching out code, Visual Studio has this really neat feature where you can just right click somewhere empty and select "Create Unit Tests...":
In the screen that pops up, you can select the methods and properties for which you want to create unit tests. In our case it's just one method, but this is really useful if you have lots of code and want to generate a bunch of skeleton unit tests quickly.
In the "Output project" option at the bottom, you can choose whether to create a new test project or use an existing one. Again, in our case we can just create a new one, but if you already have a test project and want to add to it, you can just select it from the drop-down list. Anyway, hit "OK", name your unit tests project, and hit "Create". By convention, tests projects are usually named as [ProjectName].Tests .
Now, when you're done, you might get this message about InternalsVisibleTo:
See, this is because our Program class is not public, and that makes it internal by default. This means that the test project can't see it. Visual Studio allows projects to access non-public classes anyway by using this thing called InternalsVisibleTo, but in most cases I wouldn't recommend it. Just hit "No".
So now Visual Studio created a new project and some code for us:
In the test project, you'll notice that there's a reference to our LeapYearVs2010 project (because the tests need to use our actual code), and there's also a reference to this Microsoft.VisualStudio.QualityTools.UnitTestFramework thing (try fitting that in a business card) - that's needed for unit tests projects.
You'll also notice a bunch of code was generated. It's mostly full of crap, so let's just take out the bull and leave the beef:
using LeapYearVs2010;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
namespace LeapYearVs2010.Tests
{
[TestClass()]
public class ProgramTest
{
[TestMethod()]
[DeploymentItem("LeapYearVs2010.exe")]
public void IsLeapYearTest()
{
int year = 0; // TODO: Initialize to an appropriate value
bool expected = false; // TODO: Initialize to an appropriate value
bool actual;
actual = Program_Accessor.IsLeapYear(year);
Assert.AreEqual(expected, actual);
Assert.Inconclusive("Verify the correctness of this test method.");
}
}
}
So, our usings include our LeapYearVs2010 project, and also a namespace for MSTest unit testing. Other than that, it's pretty straightforward: you have a test class (aptly marked with the [TestClass()] attribute, and it contains one or more unit tests (marked with the [TestMethod()] attribute). I know we haven't quite talked about attributes so far, but just stick them in the right places and don't worry about them.
Before we can write any proper unit test code, we'll need to make our Program class (in the LeapYearVs2010 project) public:
public class Program
We can now write our first unit test. At times you might find the autogenerated skeleton code for unit tests useful, but in our case you can just throw it out and replace it with this:
[TestMethod()]
public void IsLeapYearTest()
{
int year = 2001;
bool expected = false;
bool actual = Program.IsLeapYear(year);
Assert.AreEqual(expected, actual, "2001 shouldn't be a leap year!");
}
You can now run the unit tests via the Test menu, -> Run -> All Tests in Solution, or else by right clicking on a TestClass or TestMethod and selecting "Run Tests". This right click option is context sensitive, so if you Run Tests on a TestMethod it will run that unit test; if you Run Tests on a TestClass it will run all unit tests for that class.
Right, now at this point, if you also have Visual Studio 2012 installed, you might run into this bug where the tests will just kinda get stuck, like this:
Apparently this is a known issue and you'll need to install Service Pack 1 for Visual Studio 2010 to get things working. When they do, you'll see a nice green tick mark next to your test:
Let us now add another test:
[TestMethod()]
public void IsLeapYearTest2()
{
int year = 1900;
bool expected = true;
bool actual = Program.IsLeapYear(year);
Assert.AreEqual(expected, actual);
}
Run it as before, and...
Whoops! Our second test failed. You can right click the test in the Test Results window and select "View Test Results Details" to obtain additional information including a stack trace (see screenshot above). If you need to, you can put a breakpoint in your test and then from the Test menu go to Debug -> Tests in Current Context while your cursor is in the unit test you want to debug. You can then debug the test as you would with normal code.
In our case, it's pretty clear that 1900 can't be a leap year because it's divisible by 100 but not by 400. So we need only update the expected value as follows:
bool expected = false;
Finally, let's take a look at how to create unit tests in Visual Studio 2012 and 2013. I'm going to create a new Console Application in this dark-themed VS2013 which looks like it came out of a chimney:
I'm going to set up Program just as I did in VS2010: make the class public, and add the method as before:
public static bool IsLeapYear(int year)
{
if (year % 400 == 0)
return true;
else if (year % 100 == 0)
return false;
else if (year % 4 == 0)
return true;
else
return false;
}
Now, let's create the unit tests. Right click in some empty space and...
Uhhhh... crap. Apparently the "Create Unit Tests..." option was removed in Visual Studio 2012, much to people's frustration. Fortunately, there are workarounds that can bring it back. If you don't want to do those, however, you're just going to have to create the test project and unit tests manually. To do this, right click on the solution, then Add -> New Project..., and from the Test category on the left, select "Unit Test Project". Give it a name and hit "OK".
This generates empty test code, and you can take off writing your unit tests from here. With VS2012, it's the same procedure.
Wow, this was long. Well, I hope it helped you learn about some of the unit testing tools that Visual Studio has to offer. It's very convenient because you can run and debug tests directly from within Visual Studio, and in Visual Studio 2010 there is the "Create Unit Tests" option which can be used to quickly generate skeleton code for unit tests of existing code. Sadly, this option is no longer there by default as from Visual Studio 2012, but there are ways of getting it back.
Check back for more programming goodness at Programmer's Ranch! :)
Sunday, September 8, 2013
C# WPF: Styling buttons in a window
Hi! :)
In this article we'll take a look at WPF styles, which allow us to manage the properties of many controls in one place. If you've used HTML and CSS in the past, this is a bit like how CSS allows you to customise the layout of HTML elements, leaving HTML to focus on the structure of the document.
To see how styling works, we'll create a Tic Tac Toe application (just the buttons... the logic is beyond the scope of the article). Start off by creating a new WPF application (I'm using Visual Studio 2012, but you may just as well use SharpDevelop or some other version of Visual Studio):
In MainWindow.xaml, you get some default XAML code. In VS2012, it looks like this:
<Window x:Class="CsWpfStyleButtons.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
</Grid>
</Window>
Here we define a style that works on elements of type Button. We can remove all the attributes from our buttons and into setters in this style, as above. If you run the application, you'll see that it just works:
Styles are quite powerful, and allow us to separate structure and style to a certain extent, much in the way we use HTML to control the structure of a webpage and CSS to style it. Styles allow us to apply the same properties to all controls of a particular type, as we have done here. They also allow us to affect particular elements of our choice, by setting an x:Key attribute instead of a TargetType, much in the manner of CSS classes.
In this article we'll take a look at WPF styles, which allow us to manage the properties of many controls in one place. If you've used HTML and CSS in the past, this is a bit like how CSS allows you to customise the layout of HTML elements, leaving HTML to focus on the structure of the document.
To see how styling works, we'll create a Tic Tac Toe application (just the buttons... the logic is beyond the scope of the article). Start off by creating a new WPF application (I'm using Visual Studio 2012, but you may just as well use SharpDevelop or some other version of Visual Studio):
In MainWindow.xaml, you get some default XAML code. In VS2012, it looks like this:
<Window x:Class="CsWpfStyleButtons.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
</Grid>
</Window>
A WPF UniformGrid gives us an easy way to make an nxn grid, and in Tic Tac Toe we want a 3x3 grid, so UniformGrid is perfect for the job. Change the XAML as follows (I've also edited some properties of the window):
<Window x:Class="CsWpfStyleButtons.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Tic Tac Toe" Height="200" Width="200">
<UniformGrid>
<Button>X</Button>
<Button></Button>
<Button>O</Button>
<Button></Button>
<Button></Button>
<Button>X</Button>
<Button></Button>
<Button>O</Button>
<Button></Button>
</UniformGrid>
</Window>
At this point, we get this:
Right, so what if we want to customise it? We might want a bigger font, for instance, but that would require setting the same attributes on each and every button. If we add a few more properties, the XAML quickly becomes a nightmare to maintain:
To make our life much easier, we can use styles. We define styles in a Window.Resources section, that goes just after the <Window> declaration and before the <UniformGrid>:
<Window.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="FontSize" Value="24" />
<Setter Property="Foreground" Value="DarkGreen" />
<Setter Property="Margin" Value="3" />
<Setter Property="FontFamily" Value="Verdana" />
<Setter Property="BorderBrush" Value="AliceBlue" />
</Style>
</Window.Resources>
Here we define a style that works on elements of type Button. We can remove all the attributes from our buttons and into setters in this style, as above. If you run the application, you'll see that it just works:
Styles are quite powerful, and allow us to separate structure and style to a certain extent, much in the way we use HTML to control the structure of a webpage and CSS to style it. Styles allow us to apply the same properties to all controls of a particular type, as we have done here. They also allow us to affect particular elements of our choice, by setting an x:Key attribute instead of a TargetType, much in the manner of CSS classes.
Subscribe to:
Posts (Atom)