Dennis van der Stelt

The most votes generally drown out the best votes

Community

News

  • Meet me at PDC08

Email Notifications

I read...

I Use...

Tags

Recent Posts

Archives

Who is actually using LINQ or LINQ to SQL?

Microsoft UK sends out these MSDN Flash newsletters once in a while. Every one of them has this poll with some .NET related question and the results come in the next letter. I got the latest today and last time the poll was about the following:

What really amazes me is the high number of LINQ to SQL and especially LINQ to Entities projects starting on January 1 2009. From what we hear at Class-A from every contact we've got, very, very few people are using LINQ, let alone LINQ to SQL. Entity Framework isn't even something people think about using for production code.

So my question to you is

  • are you using LINQ, LINQ to SQL or any other flavor in production code and what are your experiences?
  • Are you using .NET Framework 3.5 anyway? Are you still on .NET Framework 2.0?
PDC 2008 : Sessions & hard drive

I just got a question from Dries which sessions I intend to visit during the PDC. Although there isn't a final list yet and especially tracks and times are still missing, I do have some favorites. I'll post the list below for no reason at all, just that PDC is going through my mind like 24 hours a day right now. Besides LittleBigPlanet by the way, although they are hard to match together. Anyway, the list is quite large and I hope I don't have to choose between 3 or 4 sessions held at once.

I'm extremely interested in Oslo and the new programming bits, .NET 4.0 and especially the CLR and type advances and of course the next version of WCF with the new modeling extensions presented at PDC. I'm also interested in Visual Studio and Team Foundation Server and Velocity, Pex and some other stuff, but I won't hesitate to drop those against the previously mentioned stuff. I'm looking forward to sessions from Don Box, Justin Smith, Nicholas Allen and of course Anders Hejlsberg on the future of C#.

Also, the 'goods' (as in demos, whitepapers, vpc images, etc) is an ridiculous amount to put on DVDs so they're giving every attendee a 160GB external drive which is black and PDC08 branded. Awesome!

The list below is alphabetically, like on the site

  • "Oslo": Customizing and Extending the Visual Design Experience
  • "Oslo": The Language
  • "Rosario": A Sprint with the Next Version of Microsoft Visual Studio Team System
  • "Zermatt": Deep Dive
  • A Lap around "Oslo"
  • A Lap around Building Block Services
  • Access Control across the Building Block Services
  • Architecture without Big Design Up Front
  • Deep Dive: Building an Optimized, Graphics-Intensive Application in Microsoft Silverlight
  • Entity Framework Futures
  • FAST: Building Search-Driven Portals with Microsoft Office SharePoint Server 2007 and Microsoft Silverlight
  • Hosting Workflows and Services
  • Microsoft .NET Framework: CLR Futures
  • Microsoft .NET Framework: Declarative Programming Using XAML
  • Microsoft .NET Framework: Developing RESTful Services
  • Microsoft Silverlight, WPF and the Microsoft .NET Framework: Sharing Skills and Code
  • Parallel Programming for Managed Developers with the Next Version of Microsoft Visual Studio
  • Project Velocity: Under the Hood
  • Securing Your Service Using the Federated Identity Services
  • Service Bus Building Blocks: Connectivity, Messaging, Events, and Discovery
  • SharePoint: Microsoft Visual Studio 2008 Extensions
  • Team Foundation Server: Cool New Features
  • The Future of C#
  • The Future of Programming Languages
  • Under the Hood: Advances in the .NET Type System
  • WCF 4.0: Building WCF Services with WF in Microsoft .NET 4.0
  • WCF: Tips and Tricks for Performance and Scale
  • WF 4.0: A First Look
Typemock Isolator : Getting internal variables

Sometimes you execute some method and the method returns void. But it still does some complicated stuff and you want to check if everything worked. But you can't access the internal variable that was created. You can mock everything away and make sure you set the proper return values. But there's also another way to achieve about the same result.

Imagine we have a customer class.

public class Customer

{

  public string Name { get; set; }

  public int Age { get; set; }

}

We're also having a class that internally creates a customer and works with it a little.

public class ClassToTest

{

  public void Somemethod()

  {

    int[] ages = new int[] { 33, 34, 35 };

 

    Customer c = new Customer();

    c.Name = "Dennis van der Stelt";

    c.Age = ages.SkipWhile(i => i < 34).First();

  }

}

As you can see, normally it'd be impossible to test what happened to the customer object. Unless you're using TypeMock Isolator. Here's how.

    1 [TestMethod]

    2 public void TestExample()

    3 {

    4   MockManager.Init();

    5   Mock mockedCustomer = MockManager.Mock<Customer>(Constructor.NotMocked);

    6 

    7   ClassToTest ctt = new ClassToTest();

    8   ctt.Somemethod();

    9 

   10   Customer c = mockedCustomer.MockedInstance as Customer;

   11   Assert.AreEqual<string>("Dennis van der Stelt", c.Name);

   12   Assert.AreEqual<int>(34, c.Age);

   13 }

In line 5 we're telling Isolator to mock the object, but we're not setting any expectations. Therefor nothing is hidden or mocked away. We're even telling the constructor to be executed normally. In lines 7 & 8 we execute the method. In line 10 we're getting the instance that was created inside our tested method and after that, we can assert its values in line 11 and 12.

Now image that the age.SkipWhile() method was some call to another class or even the database. We'd definitely want to mock that out. But we're already using reflective mocks. Although more powerful, it's so much easier to work with natural mocks. Here's how.

    1 [TestMethod]

    2 public void TestExample2()

    3 {

    4   MockManager.Init();

    5   Mock mockedCustomer = MockManager.Mock<Customer>();

    6 

    7   int[] someArray = new int[] { 1, 2, 3 };

    8   using (RecordExpectations recorder = RecorderManager.StartRecording())

    9   {

   10     someArray.SkipWhile(i => i < 2).First();

   11     recorder.Return(5);

   12   }

   13 

   14   ClassToTest ctt = new ClassToTest();

   15   ctt.Somemethod();

   16 

   17   Customer c = mockedCustomer.MockedInstance as Customer;

   18   Assert.AreEqual<string>("Dennis van der Stelt", c.Name);

   19   Assert.AreEqual<int>(5, c.Age);

   20 }

As you can see in line 7 I'm creating a temporary integer array so I can use the SkipWhile extension method on it. It holds completely different values however. In line 11 I set the actual return value, again completely separated from anything else I've created before. I tell it to return the value 5 and that's what I'm asserting later in my test on line 19.

But what if more instances of the Customer class are created? That's also very easy, because the natural mocks work exactly like the real code it passes. As you can see in the example below on line 5 and 6 I expect two Customer classes to be created and set the resulting mocked object to different variables. In line 15 and 16 I retrieve the second Customer object and assert its values.

    1 [TestMethod]

    2 public void TestExample()

    3 {

    4   MockManager.Init();

    5   Mock mockedCustomer = MockManager.Mock<Customer>(Constructor.NotMocked);

    6   Mock mockedCustomer2 = MockManager.Mock<Customer>(Constructor.NotMocked);

    7 

    8   ClassToTest ctt = new ClassToTest();

    9   ctt.Somemethod();

   10 

   11   Customer c = mockedCustomer.MockedInstance as Customer;

   12   Assert.AreEqual<string>("Dennis van der Stelt", c.Name);

   13   Assert.AreEqual<int>(34, c.Age);

   14 

   15   Customer c2 = mockedCustomer2.MockedInstance as Customer;

   16   Assert.AreEqual<string>("Eli Lopian", c2.Name);

   17 }

Microsoft project “Velocity”

Thursday September the 4th I gave a presentation for DotNed about Velocity, the framework to enable distributed cache on the Windows platform. It was a fun evening for me with lots of great questions from the audience. You can download the slides from the site.

There were a few questions that I couldn’t answer though.

Regions 
I know assumptions are the mother of all censored, but I made the assumption that regions aren’t being replicated across hosts but stay in one host. It’s not entirely untrue, but it is a little more complex though.

When you specify a region in configuration or in the .Put() method calls, all objects in that region won’t get replicated or partitioned across hosts but will stay on a single host, also called a node. However if you don’t specify a region explicitly, the objects will get spread across nodes. However, Velocity will still create regions. And that’s what we were wondering about during the course where I explained I didn’t fully understood what was going on there. Well, the regions being created will (or might) hold a copy of your object and this way your object will get partitioned across hosts and preferably across machines.

What about security?
Velocity enabled caching on enterprise scale, resulting in a cache distributed over possible hundreds of machines, accessed by a great number of applications. In CTP1 there’s no way to secure your data, which is likely a problem for a number of scenarios. The team just posted that for version 1 of Velocity they’re going to implement application level security using token level security and/or take the applicationid/siteid from ASP.NET to use that to secure access. Read more in this thread on the forums.

Still only 38 days, 16 hours and 37 minutes to PDC, hope to hear more about Velocity there.

FinalBuilder : Action lists

As I’ve said before, years ago on some project I first got the opportunity to work with FinalBuilder. After years of silence I picked it up again at version 5 and recently switched to the latest version 6.

Have you ever had the feeling that some developer around you suffered from the NIH syndrome? Like myself on the pdf creation?! And that they’re wasting a humongous amount of time building it themselves instead of using some $300 tool?

If you still work with MSBuild, you’re suffering from the NIH syndrome

Setting up a FinalBuilder script can take some time, especially for the first time, but not as much as with MSBuild. And when you’re done, it so extremely easy to change the script real fast. Seriously, try it out. It’ll enhance your daily life.

But back to action lists. Today I found out about them. FinalBuilder is so chuck-full of actions and possibilities that you can’t learn them all at once. But that’s where the blogosphere comes to the rescue.

actionlist Ever noticed the two tabs “Main” and “OnFailure”? The first one is where your actions are and the second one is executed on failure. It’s awesome to use for sending an e-mail or creating TFS workitems when something went wrong.

But looking at the image on the right you might already noticed I’ve created a third and custom action list. This is like a subroutine you can execute, just like in your code. You can even provide it with a set of parameters that you can set from the “Run Action List” action, as shown in the image. Right-click the tab to rename it or specify the available parameters. I’ve added a “MessageBox_Message” parameter so I can show a MessageBox with a custom message.

actionlist2

After you’ve specified some parameters, you can set them within the mentioned “Run Action List” action, as shown below.

actionlist3

When I get back to work tomorrow, I really have to implement this in one of our most complex build scripts.

  1. It cleans up the “General” action list
  2. It takes parameters without having the need to specify extra project variables/properties.
Oslo, D and the PDC

There’s an article up at eweek about Oslo, the new initiative by Microsoft in create the tools and a language that’s more accessible to more people than just official developers. You’re supposed to create data and models to build an application, something where the business analyst can already do a lot of work, where he now transfers a large document over to the development team.

I’m really interested in hearing more about Oslo at the PDC next month, and Erwyn van der Meer keeps triggering me and others by telling (over chat and blogs) that we’ll like what we’re going to see at the PDC. I’ve already heard some stuff and I can’t wait.

I’m really curious however that if they’re going to make it more accessible to non-developers, how are ‘real’ developers going to like it. As far as I understand the new language ‘D’ is for those developers but how about the modeling tools? From day one that I got into computers people have told me that in the future you’d just put some blocks together, tweak a bit here and there in configuration and you’ll have some application. While that might sound interesting to a lot of people, I got into programming when I was 10 years old and haven’t stopped coding since. I do my work because I love coding. Will Oslo and ‘D’ change this?

We’ll see. According to the site, 47 days, 3 hours and 11 minutes to go. :-)

Internet Explorer 8 Beta 2 experiences

I just uninstalled Internet Explorer 8 Beta 2 because it constantly kept crashing. A good thing was that it was only crashing a single tab in IE8, but multiple tabs constantly kept crashing for no reason (to me at least).

A new nice feature is colored tabs. But the behavior also changed. Normally I could drag the icon of a website from the address bar to the active tab or drag a link from a page to the active tab. That has been taken away and I question why. Maybe because it’s beta, maybe because Microsoft doesn’t understand it. Since I can remember Firefox supports way more advanced tabs. I can drag URLs to any tab and open the website in that tab, without losing focus of the current active tab. I can also close inactive tabs without opening it first. I really missed those features in IE7 but IE8 seems to make it worse.

Anyway, I’ll keep on using IE7 and hope for the best in the future…

Gaming for students

We used to have an XBox at Class-A for students to play on. But the older it got, the less students were interested in playing with it. So we decided to have a new console and opted for either Nintendo Wii or PlayStation 3. I took an investigation upon me to see which was most interesting. Wii has of course great controllers, but PlayStation 3 way better graphics and more important, cooler games to play with multiple people. Wii can’t even beat that, as it can’t even handle splitscreen from a performance point of view!

Anyway, today Astrid and I connected a 40” TV and the PlayStation 3 together with Guitar Hero 3 and two guitars, Buzz!: Quiz TV with four buzzers and Call of Duty 4, because of the 4 player splitscreen multiplayer part. Motorstorm Pacific Rift and LittleBigPlanet (check out this video) are already on pre-order and we’ll see about other games.

Here’s me testing out Guitar Hero 3. After seeing the images I think I look much too sweet soft to be a Rock Legend, but I did enjoy playing the game though.

dennis_gh3_1 dennis_gh3_2

Don’t forget, when you visit us for a training, you _will_ be challenged to play a game! After my vacation I’ll create some .NET questions for Buzz! :-)

What’s a good library to create PDF documents?

For a customer I’m looking for a PDF library to create thousands of PDF document. I’ve tried two open source libraries, but didn’t quite like them. I’m not sure if it’s me, the library or just PDF because they didn’t feel right.

So I tried two commercial libraries. One just didn’t allow me to do what I wanted and I don’t even remember which one. The other one is from Syncfusion. It does work quite well, until you hit the details on changing tables, cells and other stuff. And it’s loaded with bugs. I’m not sure how long this has been under development, but I just kept running into ‘features’ to which the common reply was “We have logged this as a issue and our development team is currently working on this.”. They’ve fixed one issue so far and it’s released in next weeks developer build. But it still doesn’t gracefully draw tables on the next page and I can’t change the style of individual cells.

Now I am creating the PDF 100% by hand (or code actually) and perhaps it’s a better idea to create some other format first (html, Word, etc) and convert it to PDF afterwards.

What are your experiences with PDF libraries and/or creating PDF documents?

LINQ to SQL objects and doing in-memory queries over them

This is extremely easy and for most of you probably so obvious that you’ll start spamming me that this is time spend better on other things. But it has helped others and maybe it can help some of my visitors. I’ve used it when migrating data between two databases, where the data models were nothing alike.

When you’re using LINQ to SQL and are creating new objects that are defined in your LINQ to SQL classes (or .dbml) you can still query over them before committing them to the database. Here’s an example.

// Create root collection that we can query in our application.

List<Customer> customers = new List<Customer>(); 

 

Customer customer = new Customer();

customer.CompanyName = "Class-A";

customer.ContactName = "Dennis van der Stelt";

 

// Add this customer to our collection.

customers.Add(customer);

 

Product product = new Product();

product.ProductName = "i pwn n00bs t-shirt";

 

Order_Detail orderDetails = new Order_Detail();

orderDetails.Product = product;

 

Order order = new Order();

order.Customer = customer;

order.Order_Details.Add(orderDetails);

 

// Select all ordered products by Dennis

var query = from c in customers

            from o in c.Orders

            from d in o.Order_Details

            select d.Product;

As you can see I never used db.SubmitChanges() so it’s not in the database yet. I did however query over the in-memory collection(s) I’ve build. I’ve created a root collection customers which I’ll use in my application to start querying. You can pass around the list of customers if you’d like.

With this example I can go through all customers in one database and pass every product. Imagine that Alex Thissen had ordered the same t-shirt (which he didn’t btw, he ordered the übergamer t-shirt from the n00b store ;-) I’d be able to query the created products, see that it was already created and make a reference to that product, instead of (again) creating a new one.

Hope that last paragraph makes sense.

Waegis was launched

waegis Keyvan Nayyeri has launched his project today, something he calls “The Web Cleaner”. The official name is Waegis and it’s a service to filter out spam.

Alpha testing

BloggingAbout.NET joined the alpha process and we were extremely happy with the results of Waegis. To start with, installation is a breeze. This is also because of Community Server 2008 (CS2008), but you just have to copy two binaries onto the webserver and configure the Waegis spam blocker. Each CS2008 spam blocker rates every comment with some points and based on your own configuration decides if it’s possible spam or should be automatically deleted. During alpha we initially didn’t let Waegis rate comments too high, but after only a few weeks of testing we decided that if Waegis thought it was spam, it should be auto deleted.

I just installed the latest version and am keeping a close eye on what Waegis does, but if everything goes as smooth as it did, Waegis is going to change the lives (or at least the mail inbox) of our bloggers.

API

You can download ‘custom’ clients for multiple Community Server versions and GraffitiCMS. But there’s also an API available on CodePlex to code against. This way you could write spam blockers for every other blog engine or even Exchange server and/or Outlook.

Conclusion

We tried Akismet before but weren’t too happy about the results. Comments that were obviously spam weren’t rate by Akismet that way, but Waegis seems to do it’s job perfectly. We’ll see what the future brings, but for now Waegis is definitely worth looking into if you have any problems with (comment) spam.

TypeMock Isolator and LINQ

I’m doing some work with TypeMock and I start to love it more and more. For example, how about removing your database completely from your continuous tests? Sure you can do some database testing during the nightly build, but please keep the tests as fast as possible.

A little story about a build
tableJust a few days ago on a Friday my colleague Alex Thissen and I were planning to leave the building. Unfortunately after checking in some code, a few unit tests failed in Alex’s project. It were some really minor changes, but as it was 20:00 hours already, we weren’t as sharp anymore. After 4 trial-and-error sessions getting the test to work, we could go home. The code changes took only a few seconds, running the build took much, much longer. Mainly because Visual Studio 2008 for DB Professionals was deploying the database every time. What if we only needed that during the nightly build and actually had the continuous build running much faster?

Imagine a nice little table like the one on the right. Just some Class-A trainers in there. Imagine some code retrieving the trainers.

public List<MyTrainer> GetTrainers()

{

  List<MyTrainer> trainers = new List<MyTrainer>();

 

  using (SqlConnection con = new SqlConnection())

  {

    con.ConnectionString = @"Server=.\sqlexpress;database=courses;integrated security=sspi;";

    con.Open();

 

    SqlCommand cmd = new SqlCommand();

    cmd.Connection = con;

    cmd.CommandText = "select * from trainers";

 

    SqlDataReader rdr = cmd.ExecuteReader();

    while (rdr.Read())

    {

      MyTrainer t = new MyTrainer();

      t.Name = rdr["Name"].ToString();

      trainers.Add(t);

    }

  }

 

  return trainers;

}

Normal ADO.NET code for retrieving trainers and adding them to a collection of MyTrainer objects. We could just test this with a special test database so that we always get the same results. We could create a very easy test where we just execute the GetTrainers method and see what data it returns. But as this accesses the database you might want to do this in a nightly batch. To be a little more sure you don’t break the build at night, you can always run these tests from your local machine.

[TestMethod]

public void GetTrainers_DBAccessed_Return7Trainers()

{

  DAL dal = new DAL();

  List<MyTrainer> trainers = dal.GetTrainers();

 

  Assert.IsNotNull(trainers);

  Assert.AreEqual(7, trainers.Count());

  Assert.AreEqual("Anko Duizer", trainers[0].Name);

}

But we really want to test the code without actually connecting to the database. You could stub out a lot, but that’s a lot of work. Especially because the datareader is very hard to stub out. I’ve once used a datareader that was running on a dataset with one ore more tables in it. Pretty nice, but still took a whole lot of code to fill the datareader initially.

When we want to use a mocking framework like TypeMock, it still requires some code. We need to actually mock out three objects and create expectations for them. Here’s the code.

[TestMethod, VerifyMocks]

public void GetTrainers_NoDBAccess_Return2Trainers()

{

  using (RecordExpectations rec = RecorderManager.StartRecording())

  {

    using (SqlConnection con = new SqlConnection())

    {

      con.ConnectionString = "";

      con.Open();

 

      SqlCommand cmd = new SqlCommand();

      cmd.Connection = con;

      cmd.CommandText = "";

 

      SqlDataReader fakeReader = RecorderManager.CreateMockedObject<SqlDataReader>();

      rec.ExpectAndReturn(cmd.ExecuteReader(), fakeReader);

      rec.ExpectAndReturn(fakeReader.Read(), true).Repeat(2);

      rec.ExpectAndReturn(fakeReader["name"].ToString(), "Dennis van der Stelt");

      rec.ExpectAndReturn(fakeReader["name"].ToString(), "Alex Thissen");

    }

  }

 

  DAL dal = new DAL();

  List<MyTrainer> trainers = dal.GetTrainers();

 

  Assert.AreEqual("Dennis van der Stelt", trainers[0].Name);

  Assert.AreEqual("Alex Thissen", trainers[1].Name);

}

As you can see we set up a recorder and created expectations for the values that should be returned. The reader.Read method should return true twice so we can fill two MyTrainer objects with data. We then set expectations for the two times the name column is accessed using the reader. When finished recording, we actually execute the code we’re testing and mocking. Of course this is a very simple implementation, but it’s to show how to mock things out. For more advanced scenarios you should check the TypeMock manual.

Now let’s see how we would retrieve the same data with LINQ.

public List<Trainer> GetTrainersViaLINQ()

{

  CoursesDataContext db = new CoursesDataContext();

 

  var query = from t in db.Trainers

              select t;

 

  return query.ToList();

}

This is a lot less code. When we want to mock this out, we again use a recorder and just use the same code. However LINQ to SQL returns an IQueryable collection of Trainer objects. You can’t use recorder.Return(someList.AsQueryable()) inside the recording-block because then the AsQueryable would be mocked out as well. So we have to prepare the collection of trainers in advance.

[TestMethod, VerifyMocks]

public void GetTrainersViaLINQ_NoDBAccess_Return2Trainers()

{

  var fakeTrainers =

    (new [] {

      new Trainer() { Name = "Dennis van der Stelt" },

      new Trainer() { Name = "Alex Thissen" } }

    ).AsQueryable();

 

  using (RecordExpectations rec = RecorderManager.StartRecording())

  {

    CoursesDataContext db = new CoursesDataContext();

 

    var query = from t in db.Trainers

                select t;

 

    rec.Return(fakeTrainers);

  }

 

  DAL dal = new DAL();

  IEnumerable<Trainer> trainers = dal.GetTrainersViaLINQ();

 

  Assert.AreEqual(2, trainers.Count());

  Assert.AreEqual("Dennis van der Stelt", trainers.ElementAt(0).Name);

  Assert.AreEqual("Alex Thissen", trainers.ElementAt(1).Name);

}

You can see I prepared the fakeTrainers collection in advance, start recording and set the return value to the prepared collection. I then actually execute the code inside my tested class and assert that everything’s as expected.

The new pc

napkin1 napkin2How about this, a pc in/on a napkin to use, read, write, collaborate with and more…

As you see in the picture on the left, there are enough in the holder and you can grab one to work with. Or each member of the team grabs one and start drawing out ideas and exchange napkins to share ideas and work them out more.

When you combine napkins you can create larger surfaces and present something to the team. The idea sounds awesome and I can only hope something like this will become reality. For now, it’s just an idea from a contest. Unfortunately.

PDC08 : Meet me in Los Angeles

pdc_registration

Unit tests are for functionality, not code!

Marco mailed me this morning with the following sentence

Unit tests are meant to test functionality, NOT code! That means if you write your unit tests after the fact, you’re probably not focusing on the functionality.

This comes from two weblogs that have some unit testing comments. Jason Young posted the sentence and he refers to Obishawn who also has something to say. Why I’m writing this post is for two reasons. Or three actually. The first reason is that I liked the quote. The second reason is that Obishawn tries to prove that you should even test properties, something not many people do. But his argument is that it can grow to something that you definitely would want to test, so you should have a test in place to test the functionality. He also states that you should not trust your framework and although he’s probably right, I wouldn’t test my properties because I don’t trust the framework. If that’d be the case, it’d probably be enough to test a single property because with that I’d have tested them all. I know the .NET Framework has its bugs, but I hope to find these when writing tests that target my own code functionality.

Anyway, Obishawn also provides a few lines of code to prove you should test properties. I have written a small piece of code to expands on this a bit. There are three errors in it and maybe you can spot them. Although these are extremely simple (once you know which ones I mean) it’s an example of why you should seriously consider writing tests for all your code functionality.

public class CoD4 : Game

{

  private List<string> _redPlayers;

  private List<string> _bluePlayers;

  private string _name;

 

  public CoD4()

  {

    this.Name = "Call of Duty 4";

  }

 

  public List<string> BluePlayerCount

  {

    get { return BluePlayers.Count(); }

  }

 

  public string Name

  {

    get { return Name; }

  }

 

  public void AddPlayer(string name)

  {

    base.AddPlayer(name);

 

    if (_redPlayers.Count <= _bluePlayers.Count)

      _bluePlayers.Add(name);

    else

      _redPlayers.Add(name);

  }

}

More Posts Next page »