I've been staring at the computer for a few minutes now and I honestly don't know what to write. First I thought of writing about myself, where I was born, where I studied, where I am now... but that seems shallow. Now that I thought about it. I'd rather not talk about who I am because it seems irrelevant right now. What I really want to say is..
I'm sad. Been like this for quite some time now.
Nobody knows I'm sad.
I tried telling my wife but I guess she didn't think it was serious. We were having a fight when I told her so she probably thought I was just making up an excuse for my behavior.
I'm not sad every single day. Some days I'm perfectly fine. I actually have no idea when I'd feel sad. It just happens. I'd wake up cheerful and then before I go to bed I already feel depressed. I have no idea what triggers it. On the bed, I'd turn my back to my wife, curl up into a fetal position and start sobbing silently. Awful.
Maybe you're wondering now what's the cause of all this.
My grandma passed away and I haven't completely come to terms with that fact. I long to see her, talk to her and hold her... but I can't do that anymore because she's gone. I will never be able to hear her voice and feel her touch again. To make matters worse, the only person whom I wish would stay beside me whenever I'm feeling miserable and dejected is never around. She's either working late or out with her friends. Such is my life at the moment. I doubt it will improve anytime soon.
REST services has been steadily gaining popularity over the past
years. While SOAP web services are still being used, (and will not go
away), it is no longer the preferred method of providing an online API
(application programming interface) to web sites and/or services.
Google for example have stopped supporting their SOAP-based API and is
almost exclusively using REST based services. Several companies like ,
especially startups (or previous startups) such as Reddit, Imgur only
provide REST APIs
With this tutorial I'd like to show you how easy it is to test REST services using a tool called WCFStorm.REST. With just 2 clicks you can already start interacting with your service
Before we begin
WCFStorm.REST can be downloaded here at http://www.wcfstorm.com, or directly from here.
If you go into the web site, you probably noticed that WCFStorm.REST is
a commercial tool. But don't worry a LITE version of it is available
for free and has enough features especially for developers who just
needs to simply call REST services. The FULL version is aimed mainly at
Software Testers who needs to prepare test cases, compare actual and
expected responses, etc.
So now go download WCFStorm.Rest. The
first time you run it, it will open in 15-day trial mode. That is OK.
After the trial period is over it will convert to LITE mode and you'll
still be able to use the tool.
Note: You can use discount code RESTPROMO to get a 30% off on WcfStorm.Rest
In order to get the content of the programming subreddit, we need to use this url, http://www.reddit.com/r/programming.json.
Notice that it ends with ".json"? That's because that URL returns
JSON. If you want to get back an XML instead, just change the ".json"
Reddit's full API is described here http://www.reddit.com/dev/api
Let's get started
you've already downloaded the tool, go double click on
WcfStorm.Rest.exe to open it up. You'll get the screen below. It's a
welcome screen. It shows you the operations/functionalities of the
Click #1 : Click on the QuickTest Tab
Or you can also click on the "Test" tile. It doesn't matter you will still get the window below. Enter the text "http://www.reddit.com/r/programming.json" on the url textbox. Reddit expects an HTTP GET request on that URL, so leave the "Verb" dropdown
list unchanged. By default, the it should have the "GET" option selected.
Click #2: Click the Send button. Done.
the send button (the one with the Green Play icon) to send the HTTP GET
request to reddit's service. Wait a second or two and if all goes well
you'll get back the response below. The HTTP headers are displayed on
the upper right while the response body is shown below it. Notice that
the JSON response has syntax highlighting ( a nice little touch, if I
may say so)
there you go. All it took was 2 clicks. And finally, as the JSON
response says, the top submission is about a security vulnerability in
internet explorer, titled "Any page loaded in IE can track your mouse movements, anywhere, any time",". Not a very comforting thought.
Points to consider
runs on .NET 4.0 so you need to install the 4.0 framework if you want
to use this tool. If you only have .NET 4.5, you have to delete
WcfStorm.Rest.exe.config so that it will run, otherwise it will crash.
For some reason the config points to the 4.0 Fsharp assemblies.
Deleting the config file, forces it to use the 4.5 assemblies.
One of the benefits of using WCF is that you're not required to host it in IIS. Most people create console hosts during development and then just use windows service in production. This is a quick and very easy way of hosting WCF services especially if you just have 2 or 3 services. However, when the number of wcf services gets too high, controlling them using the mmc snap-in (services.msc) can get a bit tedious (maybe not if your powershell or WMI kung fu skills are quite good).
However, if you're tired of writing these repetetive console/windows service hosts and is looking for another way of managing WCF services, then try out WcfStormHost. It will let you dynamically host WCF Services without ever writing a single code. Each WCF service is hosted in its own AppDomain so you wont have to worry about wcf services interfering with each other.
Here's a quick rundown of its features
- Auto-discover and host WCF services
- WcfStormHost can read a folder containing assemblies (*.dll and *.exe) and *.config and automatically determine the service type to host.
- It monitors changes in the *.dll and *.config files. If it detects changes, it automatically re-hosts the service! You won't have to manually restart the service, unlike a windows service host. It doesnt lock the assembly file which means deployment is much simplified. You just simple need to copy over the dll or config file.
During development this is also very useful because you can setup WcfStormHost to host a service located in your $Project/bin/Debug folder. This means that everytime you make a code change and recompile, the service automatically gets re-hosted.
- It has a simple, intuitive UI for managing services. WcfStormHost (specifically the system tray host) can be started as an application that sits on your system stray (as in the screenshot above) which means it is easy to find. If you need to do something on a wcf service, just click on the system tray icon and the main UI will popup over it.
- It can auto-load wcf services. WcfStormHost has an optional config file called Host.config. This file can be created by clicking the "Save" icon in the menu. The host.config file can contain a list of WCF services which are automatically loaded at startup. Shown below is a sample service configured to be auto-started. The assembly files + the config file (<ConfigFile>WcfService.dll.config</ConfigFile>) are located in the value specified by the <Path> node.
<WcfService id="MySvc" type="WcfService.MyTestSvc, WcfService">
- For quick debugging, it allows you to trace WCF messages being sent and received by the hosted wcf service. Just select a service and then click on the "Trace" button on the right-hand side. Shown below is the trace window.
- It creates log files for each of the hosted services. The log files are created daily and can be configured not to exceed a certain size. By default a log file can not exceed 0.5 MB. Old log files and log files that exceed the size limit are moved into the "archive" folder.
Try it out and see for yourself. Get Started
Download WcfStormHost (blue download icon on the right hand-side)
These are the current features of WcfStormHost and of course suggestions for more features are most welcome! Please post it in the comments or send a mail to email@example.com
One of the more common design patterns used in object oriented languages like C# is the Composite Pattern. The main benefit of using this pattern is that it allows us to treat individual objects and composite of objects in the same way. In the UML below, the type Component is abstract and defines the operations (method1 and method2) which are implemented by the concrete types Leaf and Composite. The type Composite contains a collection of Component objects. Due to the fact that it inherits from Component we can write code that invokes method1 and method2 without knowing the specific type.
For example, suppose we work at a fast food chain and we'd like to write code for computing the price of fries, burger, coke or a combo meal. Following the composite pattern, we could create an abstract class called Product which has the GetPrice() method and then one class each for Burger, Fries, Coke and ComboMeal.
Component --- maps to --> Product
Leaf --- maps to --> Burger, Fries, Coke
Composite --- maps to ---> ComboMeal
Our C# code would look like
public abstract class Product
public abstract double GetPrice();
public class Fries : Product
public override double GetPrice()
public class Burger : Product
public override double GetPrice()
public class Coke : Product
public override double GetPrice()
public class ComboMeal : Product
List<Product> _products = new List<Product>();
public void Add(Product p)
public override double GetPrice()
var sum = 0.0;
foreach (var p in _products)
sum += p.GetPrice();
we can then write a helper method that Computes a price. This method does not need to know whether its computing the price of a single item (Fries, Burger ) or that of a combo meal.
public static double ComputePrice(Product p)
Suppose, someone ordered 1 fries and 1 Burger separately, our code will be,
var totalFriesAndBurger = ComputePrice(new Fries()) + ComputePrice(new Burger());
Now if another one ordered a Combo meal (Fries + Coke + Burger), our code will be
var combo = new ComboMeal();
var totalCombo = ComputePrice(combo);
For our C# implementation (not counting the helper method ComputePrice() ), we have 5 classes and approximately 40 lines of code.
Now lets see how we can implement the same pattern in F#.
Knowing that the types Fries, Burger, Coke and ComboMeal are just different representations of the Product type, we can model this relationship cleanly in F# using discriminated unions. To represent the the combo meal, we make it into a tupleof 2 products. An item of this tuple can be a single product (Coke, Fries or Burger) or any combination (i.e a combo)
type Product =
| Fries of double
| Coke of double
| Burger of double
| Combo of Product * Product
And how about the GetPrice method, you'd ask? That's easy enough; F# allows us to add methods to union types. Implementing that, our code now looks like this. Notice the "with member w.GetPrice()" part?
type Product =
| Fries of double
| Coke of double
| Burger of double
| Combo of Product * Product
member w.GetPrice() =
match w with
| Fries(p) | Coke(p) | Burger(p)-> p
| Combo(p1,p2) -> p1.GetPrice() + p2.GetPrice()
Again, if someone ordered a combo meal our code will look like
let combomeal = Combo(fries, Combo(burger, coke))
Console.WriteLine("Combo meal Total = " + combomeal.GetPrice().ToString())
That's just cool isn't it? With F# we ony 1 Union type and about 10 lines of code
I bought myself an early christmas gift and purchased the book "Functional Programming in the Real World" by Tomas Petricek. The book is available through Manning's early access program. I've been drooling over this book for a long time and finally I have it now! (cue music: Jingle bells, jingle bells jingle all the way..)
Sadly though I have an exam coming (I'm taking my masters in Software Engineering) in 2 weeks time and now I need to force myself to study the lecture notes and not read Tomas's book. Arrgh.
P.S I was able to buy the book using donations from Storm. Thanks guys!
A few months ago I've promised that version 1.1 will be released in July. Today I make good on that promise and am happy to announce that version 1.1 is ready for download!
A very big thanks goes out to those who not only have purchased WCFStorm but also provided valuable feedback in terms of feature requests and bug reports. Thank you very much guys.
Below are the main features of version 1.1
- Loading of existing client App.config files into WCFStorm
- One-click execution of all functional test cases under a method or of the whole WCF service.
- A plugin interface for custom validations of functional test cases.
- A plugin interface for randomizing requests or re-using the previous response as input to the next request.
- A plugin interface for programmatically modifying the ServiceEndpoint instance
- A plugin interface to support Duplex services
Here's the full list of what's new in 1.1
If you're not yet familiar on how to add a service and invoke a method, please see Getting Started
The short video below shows how to create and execute a functional test case in WCFStorm. Towards the end of the video, it shows one of the main features of functional testing with WCFStorm - which is the ability to visually view the difference between the expected and actual responses in a test.
If you're not yet familiar on how to add a service and invoke a method, please see Getting Started
The video below shows the steps on how to create and run performance test cases. When a performance test case is executed, WCFStorm captures the responses and displays a graph in real-time the actual and average response times as well the rate at which the service is responding the method invocations.
The following are the performance test parameters
- Number of agents
- This is the number of background workers that will repeatedly invoke the service method until the test is stopped or the test duration has completed.
- This is the interval in seconds at which the agents are created. For example, if the rampup value is "1", every second, WCFStorm will create an agent until it has reached the specified number of agents
- Test duration
- This is the test duration in seconds
- Invoke interval
- This is the interval in milliseconds at which an agent repeatedly invokes a service method
Sample Perf Test setup
- Constant Load
- This can be achieved by setting the "Rampup" value to zero
- Incrementing number of users
- Set "Rampup" and "Number of Agents" to a non-zero value.
In order for WCFStorm to invoke a service having a netTcp endpoint, the service must be configured to expose the WSDL via http. A sample config for the WCF service will be,
In above configuration, the service is using 3 bindings. mexHttpBindings is used to expose the WSDL, while netTcpBinding and wsHttpBinding are for the actual methods calls. To test the serivice using WCFStorm, use the mexHttpBinding url to add the service.
As can be seen from the log, the tool detected both the netTcpBinding and WsHttpBindings. If we select a method and invoke it ( (please see getting started on the steps to invoke a method) , the tool will select the endpoint that was declared first (which is NetTcpBinding). If you'd like to use the other endoint, wsHttpBinding, right-click the service and select "ModifyEndpoint"
This will bring up a form which lets you choose the binding that you'd like to use. Click on the dropdown to select a new binding. You can also specify a new endpoint address in this form.
Click OK to use the selected binding. This will trigger WCFStorm to regenerate a proxy class that uses the new binding. All subsequent method invocations will now use the new proxy (and hence the new binding).
EDIT : Please visit www.wcfstorm.com for th updated tutorials.
This is a first in a series for post describing the tasks and the features available inWCF Storm.
1. Getting Started
2. Invoking a service having multiple endpoints.
3. How to create and run a performance test
4. How to create and execute a functional test
Ok, so lets get started....
Getting Started : (Invoking a method of a WCF/Web service)
Add a service.
This can be done by either clicking "File --> Service --> Add" or by clicking the Add button in the menu bar.
This will bring up a form where you can type in the metadata exchange endpoint (i.e. WSDL endpoint). WcfStorm will then read the wsdl, generate the client code and compile it. If all goes well, the service and its method will be displayed on the left hand side.
Now go ahead and select on method
2. Select a method
If a method is selected, its parameters will be read and displayed in the "RequestPane'. In the screenshot below I've selected the method "GetDataUsingContract" which takes parameter of type "CompositeType"
The structure of CompositeType is shown below. As you can see, what's displayed in the request pane matches exactly the defined type.
Now, select a field of the composite type parameter.
3. Edit a field in the parameter
This will bring up the Object Editor which will let you edit the field. If the type is not primitive, the "Set to null' checkbox will be enabled. If the tye of the selected field is polymorphic, the object editor will display the subtypes that can be assigned to the field.
Here I've selected the string field.
Clicking OK will assign the value "my string" to the StringValue field of the CompositeType parameter.
Now Click Send (Green arrow)
4. Invoking the service method
Click on send to invoke the web method. The test service we are invoking merely echoes back the input parameters it has received ( a convenient way of checking that the object editor in the previous step worked). This is shown in the screenshot below
Looking at the log, we can see that WCFStorm used the NetTcpBinding endpoint. Recall that when we added the service, we used http://localhost:8080/httpEndpoint?wsdl - obvoiusly an endpoint that uses http. So how come the tool is now using NetTcpBinding? In this case, the service that we are using declared 3 endpoints in its config. An http endpoint for the metadata exchange (to expose the wsdl) a NetTcpBinding and a WsHttpBinding endpoint for the actual method calls. By default WCFStorm uses 1st endpoint that was declared by the service (which was the NetTcpBinding.)
That's it! we have now successfully invoked the WCF service.
During the last few months I've been working on a commercial tool for testing WCF services. The knowledge I learned building STORM really helped alot in building this tool. So here it is my fellow coders, WCF Storm. It has more features than its open source cousin, STORM and the best part is it works on both WCF and Web services!
EDIT : www.wcfstorm.com is up! Please visit the site for updates and to purchase WCFStorm online
- .NET Framework 3.0 or higher.
Features at a glance:
- Dynamically invoke and test WCF Services
- Dynamically invoke and test Web services written in any language
- Save your opened service and its test cases into a "project" which can be reloaded anytime
- Dynamically invoke service methods even those containing complex data types
- UI-based, dynamic editing of complex data types
- Test multiple WCF and Web services within a single UI.
- Multiple-tabbed interface
- Basic and windows authentication
- Test services sitting behind a proxy
- Dynamically modify the URL endpoint of a WCF or Web service.
- Dynamically edit the service binding.
- Create functional test cases and save it as part of a project
- Create and save functional test cases containing Expected results.
- Graphically compare (side-by-side) the expected results with the actual response of a service.
- Create performance test cases and save it as part of a project
- Graphically display charts in real-time as the performance test progresses.
- Configurable test parameters (# of Agents, Test duration, interval etc.). You can stress out your service as much as you want.
What all these features mean is that testing WCF/Web services becomes a breeze and you'll have plenty of time to spend on writing the logic of your service (which is what you should be really doing).
Performance testing screenshot:
Functional testing screenshot:
Check out the gallery for more screenshots.
Try it out! Download the trial version below.
So how much does it cost?
Short answer is ... Not so much! I've priced the tool for the budget conscious. Consider this, I used to work for a company that bought a license for a soap testing tool that costs almost 700 USD (that's right7 hundred!) annually per seat. It was a great tool. It had tons of features but the problem was, we rarely used them. We mainly used it to invoke web service methods and verify that the results are correct. All the other features that the company paid (dearly) for, were rarely or sometimes never used. Why pay so much for unused features?
So how much does WCF Storm cost?
- Personal Edition : 14.99 USD only (annually/seat )
- Enterprise Edition : 49.99 USD only (annually for 10 seats!)
(EDIT : I've finalized the pricing structure for WCFStorm. Please visit http://www.wcfstorm.com/wcf/buynow.aspx to view the offers)
Not bad, huh? :) For such a low price not only can you test WCF services, it even works on Web services. if you buy now and be part of the first 100 to purchase WCF Storm, I'd extend your license for 2 years!
However, if you think that the price is expensive, drop me an email and we can discuss the price we're both comfortable with.
I love the price, but why didn't you just open source it like STORM?
I think these words are sufficient to answer that question:
This recession that we all are experiencing right now has also affected myself and my family. I still have my job but I can't tell whether next month I'd still have it. Some people had already been let go and management has been awfully quiet on when the next round of layoffs will be. I have a wife and a lovely 5 year-old daughter to care for. I also have a mortgage and credit card bills to pay. My job, which is our main source of income is in an unstable state right now.
My wife is 2 months pregnant. During our last visit to the doctor, we found out our baby is about 9 mm in length already. In programmer-speak, our baby is in the Alpha or Beta state right now. But he/she has already achieved a major project milestone- he/she has a heartbeat! Oh I am the happiest person in the world right now! We can't wait for him/her to come join us in November later this year.
I had a DONATE button on the codeplex site of STORM and even added it to the Storm application itself. Its been there for more than 6 months and inspite of the 6000+ downloads, I have yet to receive a single donation. I know, you'd say, open source doesn't work like that. One cannot expect donations on open source projects. It's the spirit of giving and sharing code that matters. Yes, that is true, I believe that as well.
But as you can see, I simply can't afford to give out WCF Storm for free right now. If my family is to weather this difficult time we need to have another source of income. I hope people understand.
Simulate a class using the Record type
How we'll do this
Create a tool that can translate a number into another format. In particular, we'll convert a number into
- Roman Numerals or
- multiply it by 10
Why are you doing this?
No particular reason. I was just curious. I was just thinking that if F# did not support OOP, how can I still achieve the same things I was used to doing in C#?
Ok so here we go..
F# record types are simple named types. We can pattern match over it and it is also constructed quite easily. For example
The record Person contains 2 named fields, which are both strings. Most of the time records are used to hold data but since F# is an FP language, we can also have the fields of the record carry a function. For example, we can modify the Person record type to instead of having the "LastName" as a string, we'll turn it into a function that computes the last name. Something like,
As you can see we have changed the signature of LastName from "string" to "unit->string". The function "fun -> Guid.NewGuid().ToString() " matches this new signature. (Side note: as a C# coder, this was a big mind shift for me)
Going back to our example, lets define a Converter record type as
this type holds a string field "x" and "ToNewFormat" field with the signature unit->string. The function does not take any parameter because we'll have it use the value assigned to "x" i.e. it will convert the value in "x" into a different format. If we were using a class, our code (C#) will be something like
and to use it we'd write
So how do we contsruct our F# Converter record so that it would behave essentially like the C# Converter class?
We create a converter function that takes 2 parameters, "numStr" and "myConverterFunction". NumStr gets assigned to the field "x" while the myconverterFunction is wrapped inside the "intToNewFormat" function which has the signature unit->string.
MyConverterFunction was wrapped inside intToNewFormat function because we want this function to work on the value of field "x". Well actually myConverter function uses the value of "positiveNum" (an int) which was derived from the string value of temp.x. The "temp" value is of course of type Converter.
The important part here is that in order for us to acces the instance value of "x" we need add the "rec" keyword in the definition of the value temp. If we didn't do that we won't be able to access temp.x!
To call this createConverter function, all we need to do is pass a string and a function that has the signature int->string
In the code above, we create a romanConverter function that takes a string and creates the instance of the Converter record by passing the string and "RomanConverterFunction.romanConverter" function. The "RomanConverterFunction.romanConverter" function takes an integer and converts it to Roman numerals. For example, if you pass it "1980" it will output "MCMLXXX"
That's it! whenever we call, romanNumeralConverter.ToNewFormat(), it is converting its instance value of "x" into roman numerals exactly the same way the C# Converter class is working.
Note that because we are passing around functions we can easily create different kinds converters. In the above code we created another converter, "multiplier10converter" which merely multiplies a number by 10 (yes, this example is not very good. :-p ). If we needed a different converter all we need to do is write the code for that converter and pass the new conversion function to "createConverter". Simple. If we had to do this in OO, we have to through the inheritance-override route.
Here's the tool in action
F# is an awesome language. I'd choose to write F# code any day over any language if my work allows it. The way you are able to concisely and cleanly write code with it is what brought me over. Sure there is an initial overhead (if you we are an OO programmer) in learning all the functional constructs but in the end its all worth it. Even though you might not be able to use it at work (read : management only wants C#/VB.NET), the way you are writing OO code will definitely be improved. I for example have come to appreciate Generics and delegates more because of F#.
Microsoft Research has done such a great job with it and I'm quite sure they will continue to do so.
There is no question that "F# as a language" is great. People do however have a gripe about "F# as a Microsoft product". It is not open source nor is it standard like C#. There is a technology-lockin which I presume some fear will later on will translate into a vendor-lockin.
F# targets mainly the research and financial institutions. I can not say much about financial companies but research instituions and technology companies are big Linux users. There is very high likelihood that these people are also open-source advocates. It will be in their best interest to ensure that the language works perfectly on both Windows and non-windows systems. This is both a win for the users and for Microsoft. It would also propel the language forward at a much quicker pace.
It might be too early to ask this given that the F# CTP was only recently released, but should Microsoft open source F# and get the community involved?
One of the commonly used design pattern is the Observer Pattern because its just so easy to use and implement. The classic OO way of implementing it is to have a Subject class having the methods "Attach", "Detach" and "Notify". The Subject class usually stores the observers in an ArrayList and then when it needs to update the observers then iterates on the list and invokes the "Update" method of each observer. See diagram below.
In C#, a more elegant way of implementing this is with Events and Delegates. Here's a nice sample implementation. By using using events and delegates, the code became a lot shorter and straight-forward
In F#, implementation of the observer pattern became even more concise and elegant. How come? Take a look at the code below.
line 11 : A clean and simple (one-liner!) way of creating events and triggers. A call to IEvent.create is all it takes
lines 16 & 17 : calling "trigger" and passing the correct parameters notifies all listeners of the changeEvent. We don't even need to check if there are listeners attached. If this is in C# we need to make changeEvent != null otherwise a NullReferenceException will be raised.
lines 28 & 30. In F# Events are first-class values , that means we can pass it around and more importantly we can do all sorts of wonderful things with it using the IEvent module. For example, in line 28, we filtered the event, basically saying that we are only interested in events of the Remove operation. Now imagine if the Operation type (an enum actually, lines 5-7 ) contains more items such as Update, Delete, AddedThenRemoved, AddedThenUpdated, RemovedAddedAgainThenFinallyUpdated ... (you get what I mean). If we want to a handle only the Remove operation then we'd have no choice but to break it down using an if-elseif-else or switch-case construct. It would work but its not going to be pretty. And this is where IEvent.filter shines. With just a single line of code (line 28, please ignore the comment above it.), we were able to filter out the event that we are only interested in. Apart from filtering, IEvent also allows us to map, partition, fold, split etc. events.
lines 25 & 30 : 2 ways of attaching to an Event. I'm not very sure what's the difference between these 2. (TODO : Investigate)
Here's the output! Notice that the "observerForRemove" printed out only the message related to the Remove operation even though the Subject class raised 2 events (one for Add, another one for Remove) in the Notify() method at line 15. Sweet.
To everyone who've either sent me an email or posted a comment asking whether SoapBits
can be made into an open source project, well here I am pleased to let you all know that finally it has happened!
SoapBits is now open source and is available at codeplex!
In line with this change, it have given it a new name,STORM
. (I meant "STORM" to be an acronym but I can only come up with S
esting for "ST" . The "ORM" part I have yet to figure out, so please do suggest if you think of a clever meaning. ;) ) Another major change is that the tool is now written mostly
, a language which I believe is a lot more expressive and powerful than C# because of the ease with which it has combined Object Oriented and Functional programming. The user interface part though is still written in C# mainly because F# is not yet fully integrated into Visual Studio.
STORM site : http://codeplex.com/storm
As you all can see below, the UI has also changed a bit but the old functionalities are still there
Enjoy the tool everyone! And don't forget to give back and contribute to the project.