This may be something that everyone else knows already, but since this tripped me up for a little while, I figured I might as well post a blog about it.
Today, as I was tweaking one of our DataTemplates that was being used in a DataForm in Silverlight 4, I was running into a problem related to the IsEditable property. I had a ComboBox in my template, and I tried everything I could to get it to be read-only (I needed it to be read-only only some of the time - depending on what was set in a different property). After eventually thinking maybe my binding was broken, even though I saw it call the get of my property, I tried hard coding IsEnabled to false. Still to no avail - it kept being editable (much to my chagrin). Eventually, after reading about how DataForms worked, I came up with an idea - I put the IsEnabled binding on the DataField tag instead of on the ComboBox itself. Sure enough, poof! it instantly started working and my ComboBox was enabled or disabled depending on the value that my DataField was bound to.
Hopefully this helps someone who runs into a similar problem. As a sidenote, I also discovered during my testing that you can set something inside a DataForm to be read only by changing the Editable attribute on the property that is being bound to. This wouldn't work in my situation, however, since whether the value was read only or not was dependent on the value of another property, so it made the attribute route more tricky.
Wednesday, December 15, 2010
Tuesday, November 2, 2010
New Blog
Just for those of you that are interested, I have created a new blog at the following link: http://jedwards14thegamer.blogspot.com This will be a personal (non-technical) blog. One of my primary hobbies is playing board games, and so I will be reviewing games that I play on that blog. If you are interested in board games, feel free to follow that one, too!
Friday, October 15, 2010
Asynchronous Silverlight Unit Tests
So, after beginning to do some unit testing of View Models in Silverlight, I discovered that there have not been that many articles written about how to do this. Fortunately, I did find http://www.jeff.wilcox.name/2009/03/asynchronous-testing/ but other than that, most of what I have learned has been by trial and error. Therefore, here are my findings. Hopefully this will help someone else.
1. "Asynchronous" is a bit of a misnomer. Think of all of the "Enqueue" commands as "Do this later". In traditional asynchronous processing, if you fire off something like an "EnqueueConditional" command, it will fire off a new thread that will begin executing immediately. This is not the case with the Silverlight unit tests. Here is what I did as an example:
Now, what I would expect would be that method2 would be called before method1. After all, x == 1 as soon as the 2nd condition is enqueued. However, as I said earlier "Enqueue" should be thought of as "do this later". Therefore, what actually will happen is that method1 will be called (because at the end of the method's synchronous processing x == 2), and method2 will never be called (because x != 1 ever again in the method - also, this will never get to the TestComplete, and so will be an infinite test, just so you're warned).
2. "EnqueueConditional" basically means "wait until". This seems to be the most important piece of the processing. This is the key that will allow you to ensure that a condition is met. After this happens, all of the EnqueueCallbacks (including EnqueueTestComplete) are executed until the new "EnqueueConditional", which will then perform another wait until the condition is completed.
3. "EnqueueCallback" just allows code to be done later. The "later" is driven based off of the EnqueueConditionals. Consider the following code snippet:
In this situation, the EnqueueCallback has nothing that it has to wait on, but since it is an "EnqueueCallback", it will not execute until the end of the method. It will function the same as if I had written the code this way:
1. "Asynchronous" is a bit of a misnomer. Think of all of the "Enqueue" commands as "Do this later". In traditional asynchronous processing, if you fire off something like an "EnqueueConditional" command, it will fire off a new thread that will begin executing immediately. This is not the case with the Silverlight unit tests. Here is what I did as an example:
[TestMethod]
[Asynchronous]
[Description("Whatever")]
public void TestMethod()
{
int x = 0;
EnqueueConditional(() => x == 2);
EnqueueCallback(() => { method1(); });
x = 1;
EnqueueConditional(() => x == 1);
EnqueueCallback(() => { method2(); });
x = 2;
EnqueueTestComplete();
}
Now, what I would expect would be that method2 would be called before method1. After all, x == 1 as soon as the 2nd condition is enqueued. However, as I said earlier "Enqueue" should be thought of as "do this later". Therefore, what actually will happen is that method1 will be called (because at the end of the method's synchronous processing x == 2), and method2 will never be called (because x != 1 ever again in the method - also, this will never get to the TestComplete, and so will be an infinite test, just so you're warned).
2. "EnqueueConditional" basically means "wait until". This seems to be the most important piece of the processing. This is the key that will allow you to ensure that a condition is met. After this happens, all of the EnqueueCallbacks (including EnqueueTestComplete) are executed until the new "EnqueueConditional", which will then perform another wait until the condition is completed.
3. "EnqueueCallback" just allows code to be done later. The "later" is driven based off of the EnqueueConditionals. Consider the following code snippet:
[TestMethod]
[Asynchronous]
[Description("TestMethod2")]
public void TestMethod2()
{
int x = 0;
EnqueueCallback(() => x = 2);
x = 1;
EnqueueConditional(() => x == 2);
EnqueueTestComplete();
}
In this situation, the EnqueueCallback has nothing that it has to wait on, but since it is an "EnqueueCallback", it will not execute until the end of the method. It will function the same as if I had written the code this way:
[TestMethod]
[Asynchronous]
[Description("TestMethod2")]
public void TestMethod2()
{
int x = 0;
x = 1;
EnqueueConditional(() => x == 2);
EnqueueTestComplete();
x = 2;
}
Labels:
.NET,
asynchronous,
EnqueueCallback,
EnqueueConditional,
silverlight,
test,
unit test
Wednesday, September 1, 2010
The Importance of Unit Testing
So, a while back, a friend and I started working on developing a game in a new language, mainly as a means of learning that language. Because of this, it didn't really matter how well the code was written, or if we tested it all that thoroughly. However, once our code seemed pretty stable, we decided to go ahead and open it up to the Open Source community. At this point, we started getting reports of some weird errors that we had never seen.
As it turns out, we had tested our game within the confines of what "normally" happens in a game, and in those situations, everything worked out fine. What we did not test is what happens when something "abnormal" happens, ie, the game runs out of money, the game is especially high scoring, etc. Now, of course, these do not often happen - in fact, we did not even think about them. Also, since we simply had a stack trace, it was at first confusing to try to hunt these bugs down, as the piece of code looked correct. Had we written unit tests to test both positive and negative test conditions, then theoretically, we would have caught this and our users wouldn't have had to report it. Realistically, however, you can't catch everything. Needless to say, there are unit tests for these conditions now.
As it turns out, we had tested our game within the confines of what "normally" happens in a game, and in those situations, everything worked out fine. What we did not test is what happens when something "abnormal" happens, ie, the game runs out of money, the game is especially high scoring, etc. Now, of course, these do not often happen - in fact, we did not even think about them. Also, since we simply had a stack trace, it was at first confusing to try to hunt these bugs down, as the piece of code looked correct. Had we written unit tests to test both positive and negative test conditions, then theoretically, we would have caught this and our users wouldn't have had to report it. Realistically, however, you can't catch everything. Needless to say, there are unit tests for these conditions now.
Friday, July 30, 2010
REST Services in WCF and ASP.NET MVC
So, recently my team has started a project with a large base of legacy code, causing us to switch from the Java world, in which we have a large amount of experience to the .NET world in which we are much more limited. In doing this, one of the first things we needed to determine was how we were going to create Web Services, and if they were going to be in REST or SOAP. After some banter about SOAP and REST, we decided to use REST for now, delivering the responses in JSON. The next obvious question was, how are we going to implement the REST services. Here are the two ways that we have gotten them implemented so far:
ASP.NET MVC:
To do this, we simply created a new ASP.NET MVC 2 Application. From here, it was a simple matter of adding a Controller to the Controllers folder, and viola, we had a REST Service. The next thing we had to do was to make it return the response in JSON. This was another fairly simple matter, and eventually, we had a method returning an "ActionResult" and ending with this line:
We were disappointed that result had to be an actual object instead of a dynamic object, however (unless we just haven't figured out how to get around that).
We did run into a couple of lessons on this, though:
1. This works great with IIS 7 (and much less great with anything before it). To get around this, we have used wildcard extensions for now. If you are getting 404 errors when trying to hit your Controllers in IIS, but everything works while debugging, Google this, as it will help.
2. Our controller's method really likes being called "Index". I'm sure there's a configuration where we can change this, but we have realized that configurations can be hard to find in .NET.
3. When deploying, there seem to be a large number of files that are always necessary, instead of neatly bundling into a single artifact.
WCF:
To create a service in WCF is just as simple as creating one in MVC. Just create a new WCF project, and *poof* you have a Web Service. Unfortunately, it's SOAP. To get around this, you have to perform some configuration of your Web.config file. I don't understand all of it, but in the end, this is what I came up with that worked for ours (note that this is just the Services and Behavior tags inside of the system.serviceModel tag - this is not the whole file):
Also, we had to mark our services with an extra line:
We had some observations about this one, too:
1. The Web.config is a pain to figure out the first time.
2. You have to maintain both an Interface and an implementation of each Service.
3. You seem to have to type the .svc to navigate to the service instead of having the freedom to name your service whatever you want.
4. An interesting thing we noticed is that the return of JSON is smarter than I thought. I had a problem here where my method signature returned a string, and so I was converting things to Json to return. This caused them to all return the quotes as \". Instead, I should have just let the method "do it's thing" and return the original object - it converts it to Json for me.
Anyway, now we have the tough decision to make - which one are we going to use? I have no idea....
ASP.NET MVC:
To do this, we simply created a new ASP.NET MVC 2 Application. From here, it was a simple matter of adding a Controller to the Controllers folder, and viola, we had a REST Service. The next thing we had to do was to make it return the response in JSON. This was another fairly simple matter, and eventually, we had a method returning an "ActionResult" and ending with this line:
return Json(result, JsonRequestBehavior.AllowGet);
We were disappointed that result had to be an actual object instead of a dynamic object, however (unless we just haven't figured out how to get around that).
We did run into a couple of lessons on this, though:
1. This works great with IIS 7 (and much less great with anything before it). To get around this, we have used wildcard extensions for now. If you are getting 404 errors when trying to hit your Controllers in IIS, but everything works while debugging, Google this, as it will help.
2. Our controller's method really likes being called "Index". I'm sure there's a configuration where we can change this, but we have realized that configurations can be hard to find in .NET.
3. When deploying, there seem to be a large number of files that are always necessary, instead of neatly bundling into a single artifact.
WCF:
To create a service in WCF is just as simple as creating one in MVC. Just create a new WCF project, and *poof* you have a Web Service. Unfortunately, it's SOAP. To get around this, you have to perform some configuration of your Web.config file. I don't understand all of it, but in the end, this is what I came up with that worked for ours (note that this is just the Services and Behavior tags inside of the system.serviceModel tag - this is not the whole file):
<services>
<service name="RestLayerInWCF.Service1">
<endpoint
behaviorConfiguration="webby" binding="webHttpBinding" bindingConfiguration=""
name="Rest" contract="RestLayerInWCF.IService1" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="webby">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
Also, we had to mark our services with an extra line:
[WebGet(UriTemplate = "/", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = System.ServiceModel.Web.WebMessageFormat.Json)]
We had some observations about this one, too:
1. The Web.config is a pain to figure out the first time.
2. You have to maintain both an Interface and an implementation of each Service.
3. You seem to have to type the .svc to navigate to the service instead of having the freedom to name your service whatever you want.
4. An interesting thing we noticed is that the return of JSON is smarter than I thought. I had a problem here where my method signature returned a string, and so I was converting things to Json to return. This caused them to all return the quotes as \". Instead, I should have just let the method "do it's thing" and return the original object - it converts it to Json for me.
Anyway, now we have the tough decision to make - which one are we going to use? I have no idea....
Subscribe to:
Posts (Atom)