Checkout the upcoming F# Firestarter in Nashville, TN on 11/14/2009. It's going to be a great day of learning, exploring, hacking, and socializing.
We would very much like to launch a functional programming user's group out of this event, so come on out and share your thoughts and insights. You won't want to miss it.
You can register for the event at http://fsharpfirestarter.eventbrite.com/.
More information can be found at http://fsharpfirestarter.blogspot.com/.
Monday, November 9, 2009
Thursday, October 1, 2009
Development Principles and Standards
Several months ago I was asked to lead a fairly large development project that involved efforts from multiple consultant and offshore development groups. One of the first things that I did was draft a development principles and standards document to ensure that all groups were on the same page. The following is a slightly revised version of that document. This information is not new or extremly profound; however, I thought it might be beneficial to some.
Development Principles and Standards
There are several core principles and standards that are essential to the development of any solution. These principles and standards are necessary to ensure maintainability of the solution as well as successful, cost effective implementations of future customers that wish to take advantage of the product offering.
Reusability
Reusability is of prime importance as it relates to the development of the different aspects of a solution. The expectation is that all system functionality should be constructed so that new customers can be setup within the solution with no development. In addition, all functionality should be constructed in a manner that allows other systems to be able to interact with the solution with no internal system development.
Extensibility and Maintainability
There are multiple principles that should be followed to increase the extensibility and maintainability of the solution.
• Separation of Concerns (SoC) - This generally implies separation of UI, service, domain, and data access/persistence layers as well as abstraction of contracts/interfaces from implementation specifics. This allows for clear delineation of functionality and ensures that any type of updates to the solution can be accomplished quickly and with little to no unexpected ramifications.
• Single Responsibility Principle (SRP) – This principle states that each component, class, method, and/or function should only be responsible for a single piece of functionality. Another way to state this is that each distinct code block should only have a single reason to change. This reduces the potential for accidently causing an unexpected consequence when modifying a particular feature or piece of functionality.
• Don’t Repeat Yourself (DRY) – In order to make a solution extensible and maintainable, code and/or logic should not be duplicated. Failure to adhere to this principle increases both development time and the likelihood of errors.
• Self Documented Code – In order for a solution to be maintainable, it must be very easy to determine the intent of any specific piece of code. One of the best ways to accomplish this goal is to ensure that all code is as descriptive as possible by using identifier, method, function, and class names that clearly define intent.
Automated Tests and Testability
Functionality should be wrapped in automated tests. Ideally the solution would be developed using a test-first approach; however, it is acceptable to utilize a test-after approach as long as the majority of functionality is under test by the time of delivery. In addition to the “unit tests” (tests around each individual method), functional tests should be written to ensure that the overall behavior works as expected. Finally, all tests should be maintained during future development endeavors and run before “check-in” and before each deployment. These tests accomplish multiple goals:
1. They provide a form of documentation that shows the intent of the functionality and/or specific class/method.
2. They provide a quick regression testing strategy that allows confidence that any future code changes do not have unexpected, adverse ramifications.
3. A test-first approach has a general side-effect of a loosely coupled, highly cohesive, maintainable, and testable solution that greatly increases agility and significantly decreases bugs.
Consistency and Unity
The code should be consistent and unified. It should appear as though a single mind developed each bounded context. This can be accomplished by following various coding standards. It is important to point out that this relates to each bounded context and not the project as a whole. For example, any UI development should have a unified and consistent coding style. Likewise, any service/domain development should have a unified and consistent coding style (even if this style differs slightly from the UI development coding style). Conventions that promote consistency pertain to the standardization of layering, naming conventions, and consistent use of idioms. One great way to help ensure that these agreed upon standards are followed is to utilize a tool such as FxCop during development.
Versioning and Service Contract Management
In order for a system to be extensible, while continuing to support existing customers and functionality, a service contract versioning strategy must be followed. It is critical that unaffected consumers of the exposed services are not required to update/deploy changes to their systems every time that a modification/addition is implemented. This means that existing service contracts should only be modified when a non-breaking change is implemented (such as the addition of a new operation). It also implies that changes at the domain level should not automatically be propagated to the service layer (note: One strategy to prevent this issue is through the use of the DTO pattern). In the event of a required breaking-change, the service contract should be versioned using an agreed upon versioning strategy, while keeping everything as agnostic, reusable, and maintainable as possible.
Composability
The functionality exposed in the solution should be composable and expressive of agnostic logic. This means that the web services should be built as general services, which allow current business requirements to be met while allowing reusability for future consumers and/or business needs. This indicates that web services should rarely, if ever, be designed to support only a single client, consumer, or application.
Atomicity
The solution’s web services and functionality should be atomic. This means that all activity that occurs during the lifecycle of a service operation should be rolled back in the event of a failure. This ensures that the outcome of the operation is consistent with either a cancellation in conjunction with an error or a successful outcome with the expected response.
Fine-Granularity versus Course-Granularity
The solution should implement course-grained web services that act as a thin wrapper around a fine-grained domain model. The high level of abstraction provided by the web service interfaces allow consumers to depend on the exposed contract and receive maximum performance benefits associated with the course-grained services. The fine-grained domain model allows the solution to change whenever the business requires by providing maximum flexibility, while limiting chage to the interface(s) on which the consumers depend.
Logging and Error Handling
A logging strategy should be consistently utilized throughout the development of the overall solution. At a minimum, this strategy should include the logging of any user initiated action. Additionally, the ideal strategy should including logging at a method/function level indicating entry and exit of each specific method/function. An ideal approach to accomplishing this functionality, while still adhering to the DRY principle, is to utilize an Aspect Oriented Programming (AOP) approach (Note: A great example of a framework to help with this approach for C# development is PostSharp.) Finally, the verbosity of the logged information must be configurable during run-time. A collection of possible error codes and associated descriptions should be documented and made available for delivery to consumers. In addition, all errors should be logged in a persistent and searchable data store.
Development Principles and Standards
There are several core principles and standards that are essential to the development of any solution. These principles and standards are necessary to ensure maintainability of the solution as well as successful, cost effective implementations of future customers that wish to take advantage of the product offering.
Reusability
Reusability is of prime importance as it relates to the development of the different aspects of a solution. The expectation is that all system functionality should be constructed so that new customers can be setup within the solution with no development. In addition, all functionality should be constructed in a manner that allows other systems to be able to interact with the solution with no internal system development.
Extensibility and Maintainability
There are multiple principles that should be followed to increase the extensibility and maintainability of the solution.
• Separation of Concerns (SoC) - This generally implies separation of UI, service, domain, and data access/persistence layers as well as abstraction of contracts/interfaces from implementation specifics. This allows for clear delineation of functionality and ensures that any type of updates to the solution can be accomplished quickly and with little to no unexpected ramifications.
• Single Responsibility Principle (SRP) – This principle states that each component, class, method, and/or function should only be responsible for a single piece of functionality. Another way to state this is that each distinct code block should only have a single reason to change. This reduces the potential for accidently causing an unexpected consequence when modifying a particular feature or piece of functionality.
• Don’t Repeat Yourself (DRY) – In order to make a solution extensible and maintainable, code and/or logic should not be duplicated. Failure to adhere to this principle increases both development time and the likelihood of errors.
• Self Documented Code – In order for a solution to be maintainable, it must be very easy to determine the intent of any specific piece of code. One of the best ways to accomplish this goal is to ensure that all code is as descriptive as possible by using identifier, method, function, and class names that clearly define intent.
Automated Tests and Testability
Functionality should be wrapped in automated tests. Ideally the solution would be developed using a test-first approach; however, it is acceptable to utilize a test-after approach as long as the majority of functionality is under test by the time of delivery. In addition to the “unit tests” (tests around each individual method), functional tests should be written to ensure that the overall behavior works as expected. Finally, all tests should be maintained during future development endeavors and run before “check-in” and before each deployment. These tests accomplish multiple goals:
1. They provide a form of documentation that shows the intent of the functionality and/or specific class/method.
2. They provide a quick regression testing strategy that allows confidence that any future code changes do not have unexpected, adverse ramifications.
3. A test-first approach has a general side-effect of a loosely coupled, highly cohesive, maintainable, and testable solution that greatly increases agility and significantly decreases bugs.
Consistency and Unity
The code should be consistent and unified. It should appear as though a single mind developed each bounded context. This can be accomplished by following various coding standards. It is important to point out that this relates to each bounded context and not the project as a whole. For example, any UI development should have a unified and consistent coding style. Likewise, any service/domain development should have a unified and consistent coding style (even if this style differs slightly from the UI development coding style). Conventions that promote consistency pertain to the standardization of layering, naming conventions, and consistent use of idioms. One great way to help ensure that these agreed upon standards are followed is to utilize a tool such as FxCop during development.
Versioning and Service Contract Management
In order for a system to be extensible, while continuing to support existing customers and functionality, a service contract versioning strategy must be followed. It is critical that unaffected consumers of the exposed services are not required to update/deploy changes to their systems every time that a modification/addition is implemented. This means that existing service contracts should only be modified when a non-breaking change is implemented (such as the addition of a new operation). It also implies that changes at the domain level should not automatically be propagated to the service layer (note: One strategy to prevent this issue is through the use of the DTO pattern). In the event of a required breaking-change, the service contract should be versioned using an agreed upon versioning strategy, while keeping everything as agnostic, reusable, and maintainable as possible.
Composability
The functionality exposed in the solution should be composable and expressive of agnostic logic. This means that the web services should be built as general services, which allow current business requirements to be met while allowing reusability for future consumers and/or business needs. This indicates that web services should rarely, if ever, be designed to support only a single client, consumer, or application.
Atomicity
The solution’s web services and functionality should be atomic. This means that all activity that occurs during the lifecycle of a service operation should be rolled back in the event of a failure. This ensures that the outcome of the operation is consistent with either a cancellation in conjunction with an error or a successful outcome with the expected response.
Fine-Granularity versus Course-Granularity
The solution should implement course-grained web services that act as a thin wrapper around a fine-grained domain model. The high level of abstraction provided by the web service interfaces allow consumers to depend on the exposed contract and receive maximum performance benefits associated with the course-grained services. The fine-grained domain model allows the solution to change whenever the business requires by providing maximum flexibility, while limiting chage to the interface(s) on which the consumers depend.
Logging and Error Handling
A logging strategy should be consistently utilized throughout the development of the overall solution. At a minimum, this strategy should include the logging of any user initiated action. Additionally, the ideal strategy should including logging at a method/function level indicating entry and exit of each specific method/function. An ideal approach to accomplishing this functionality, while still adhering to the DRY principle, is to utilize an Aspect Oriented Programming (AOP) approach (Note: A great example of a framework to help with this approach for C# development is PostSharp.) Finally, the verbosity of the logged information must be configurable during run-time. A collection of possible error codes and associated descriptions should be documented and made available for delivery to consumers. In addition, all errors should be logged in a persistent and searchable data store.
Labels:
Architecture,
Development,
Principles and Standards
Sunday, August 30, 2009
F# - Asynchronous Directory.GetFiles and File.Copy
The Problem:
My wife recently decided to take on the task of ordering family photo albums. This primarily involved wading through the deluge of digital photos that have been piling up over the last three years, selecting the photos that were worthy to be placed in the album, uploading those photos to a certain web site, organizing the photos in the albums, and finally making the purchase. The particular imaging software, that was used to import/organize/modify the photos, stores the images in a directory structure that looks something like this ..\<Main Directory>\<Year>\<Month>\<Day>. While this would not normally be an issue, it made the task of uploading the images to the photo album creation site quite arduous.
This of course is a simple problem to solve in most programming languages. The following examples show how it could be solved with F# both synchronously and asynchronously. While this is definitely not production ready, it provides a few samples of how asynchronous workflows can be used in the wild.
The Synchronous Way:
(Note: A sleep statement has been added to emphasize the speed difference between the synchronous/asynchronous approaches.)
(Note: A sleep statement has been added to emphasize the speed difference between the synchronous/asynchronous approaches.)
My wife recently decided to take on the task of ordering family photo albums. This primarily involved wading through the deluge of digital photos that have been piling up over the last three years, selecting the photos that were worthy to be placed in the album, uploading those photos to a certain web site, organizing the photos in the albums, and finally making the purchase. The particular imaging software, that was used to import/organize/modify the photos, stores the images in a directory structure that looks something like this ..\<Main Directory>\<Year>\<Month>\<Day>. While this would not normally be an issue, it made the task of uploading the images to the photo album creation site quite arduous.
This of course is a simple problem to solve in most programming languages. The following examples show how it could be solved with F# both synchronously and asynchronously. While this is definitely not production ready, it provides a few samples of how asynchronous workflows can be used in the wild.
The Synchronous Way:
(Note: A sleep statement has been added to emphasize the speed difference between the synchronous/asynchronous approaches.)
open System.IO let destinationDirectory = @"C:\temp\picDest\" let sourceDirectoryRoot = @"C:\temp\pic" let searchPattern = @"*.jpg"; let getFileName sourceFile = FileInfo(sourceFile).Name let getSourceImages = Directory.GetFiles(sourceDirectoryRoot, searchPattern, SearchOption.AllDirectories) let getDestinationFileName sourceFile destinationDirectory = destinationDirectory + getFileName sourceFile let copyImage sourceFile destinationDirectory = File.Copy(sourceFile, getDestinationFileName sourceFile destinationDirectory, true) |> ignore do printfn "Starting the image consolidation process with base directory: %s" sourceDirectoryRoot for image in getSourceImages do System.Threading.Thread.Sleep(5000) do printfn "[.NET Thread %d] %s" System.Threading.Thread.CurrentThread.ManagedThreadId image copyImage image destinationDirectory do printfn "The images have been consolidated into directory %s." destinationDirectory do printfn "Press [Enter] close this command prompt." System.Console.ReadKey() |> ignoreThe Asynchronous Way:
(Note: A sleep statement has been added to emphasize the speed difference between the synchronous/asynchronous approaches.)
open System open System.IO type Directory with static member AsyncGetFiles(path:string, searchPattern:string, searchOption:SearchOption) = let fn = new Func <string * string * SearchOption, string[]>(Directory.GetFiles) Async.BuildPrimitive((path, searchPattern, searchOption), fn.BeginInvoke, fn.EndInvoke) type File with static member AsyncCopy(sourceFile:string, destinationFile:string, overwrite:bool) = let fn = new Func<string * string * bool, unit>(File.Copy) Async.BuildPrimitive((sourceFile, destinationFile, overwrite), fn.BeginInvoke, fn.EndInvoke) let destinationDirectory = @"C:\temp\picDest\" let sourceDirectoryRoot = @"C:\temp\pic" let searchPattern = @"*.jpg"; let getFileName sourceFile = FileInfo(sourceFile).Name let getSourceImages imageDirectory searchPattern searchOption = async { return! Directory.AsyncGetFiles(imageDirectory, searchPattern, searchOption) } let getDestinationFileName sourceFile destinationDirectory = destinationDirectory + getFileName sourceFile let copyImage sourceFile destinationDirectory overwrite = async { System.Threading.Thread.Sleep(5000) do printfn "[.NET Thread %d] %s" Threading.Thread.CurrentThread.ManagedThreadId sourceFile return! File.AsyncCopy(sourceFile, getDestinationFileName sourceFile destinationDirectory, overwrite) } do printfn "Starting the image consolidation process with base directory: %s" sourceDirectoryRoot let sourceImages = getSourceImages sourceDirectoryRoot searchPattern SearchOption.AllDirectories |> Async.RunSynchronously for image in sourceImages do copyImage image destinationDirectory true |> Async.Start do printfn "The images will be consolidated into the following directory: %s" destinationDirectory System.Console.ReadKey() |> ignore
Friday, June 26, 2009
CodeStock 2009 - The C# Developer's Guide to F#
Thanks to all who came out to my session today at CodeStock 2009. The slide deck and code samples are provided below:
- Slide Deck
- F# Survey Provider Sample
- F# Script Samples
- Slide Deck
- F# Survey Provider Sample
- F# Script Samples
Sunday, May 17, 2009
CodeStock 2009 Session: The C# Developers Guide to F#
Tuesday, March 24, 2009
Upcoming Developer Events/Conferences
There are several upcoming developer events/conferences of which I want to make sure that everyone is aware.
April 11 (tentative) - F# Fire Starter - Nashville, TN
This is going to be a great event full of presentations, demonstrations, pair programming, and open spaces. It's open to all levels of developers with all levels of F# experience. I'll be providing more information as it becomes available.
June 26-27 - CodeStock 2009 - Knoxvillle, TN
This is a great event where Open Spaces are mixed with a traditional conference. The cost is just $25 and registration will open on or after March 31st.
August 13-15 - devLink 2009 - Nashville, TN
DevLink features over 75 sessions of technical content intended to make you more knowledgeable and marketable. Registration opens April 1st and the early bird cost is $75. Note: This conference sells out every year, so get your ticket early!
April 11 (tentative) - F# Fire Starter - Nashville, TN
This is going to be a great event full of presentations, demonstrations, pair programming, and open spaces. It's open to all levels of developers with all levels of F# experience. I'll be providing more information as it becomes available.
June 26-27 - CodeStock 2009 - Knoxvillle, TN
This is a great event where Open Spaces are mixed with a traditional conference. The cost is just $25 and registration will open on or after March 31st.
August 13-15 - devLink 2009 - Nashville, TN
DevLink features over 75 sessions of technical content intended to make you more knowledgeable and marketable. Registration opens April 1st and the early bird cost is $75. Note: This conference sells out every year, so get your ticket early!
Friday, March 20, 2009
Presentation: An Introduction to F# - Slides and Sample Code
Thanks to all who came out to the Nashville .NET User Group last night. As promised, here are the slides and examples.
Click here for a zipped file containing the slides and sample script.
Click here for a zipped file containing the source code of the sample application.
Click here for a zipped file containing the slides and sample script.
Click here for a zipped file containing the source code of the sample application.
Tuesday, March 17, 2009
Sample F# Application - A Simple Quiz Provider
One of the things that we will be discussing at the Nashville .NET User Group Tomorrow night, March 19, 2009, is a sample application that has a service layer built in F#. To access the sample code click here.
A few notes:
- The code is broken out into two main layers: Service and Presentation.
- The service layer is built in F# and the presentation layer is build in C# with ASP.NET MVC RC1.
- The tests are written in C# (even in the service layer) to provide examples of language interoperability.
- To keep things as simple as possible, the data is stored in an XML file rather than a database. All interaction with the data is through Linq to XML.
- The intent of this example is to help existing object-oriented developers ease into the language. Because of this, many functional programming approaches are not utilized to the full extent.
- This uses the F# Sept. 2008 CTP.
A few notes:
- The code is broken out into two main layers: Service and Presentation.
- The service layer is built in F# and the presentation layer is build in C# with ASP.NET MVC RC1.
- The tests are written in C# (even in the service layer) to provide examples of language interoperability.
- To keep things as simple as possible, the data is stored in an XML file rather than a database. All interaction with the data is through Linq to XML.
- The intent of this example is to help existing object-oriented developers ease into the language. Because of this, many functional programming approaches are not utilized to the full extent.
- This uses the F# Sept. 2008 CTP.
Labels:
F#,
F# Sample Application,
Nashville .NET User Group
Monday, March 16, 2009
F# Presentation at the Nashville .NET User Group
I will be providing a presentation at the Nashville .NET User Group this Thursday, March 19, 2009. Here's the information:
Presentation: "An Introduction to F#"
Abstract :
What is F#? Why should you care? What advantages can F# provide for real world developers?
In this presentation we will answer these questions, cover the basic syntax of F#, and explore a sample F# line-of-business application.
Presentation: "An Introduction to F#"
Abstract :
What is F#? Why should you care? What advantages can F# provide for real world developers?
In this presentation we will answer these questions, cover the basic syntax of F#, and explore a sample F# line-of-business application.
Sunday, January 18, 2009
Building a RESTful Service with WCF and F#
There has been a lot of discussion recently, centered on the idea of making services RESTful. REST (Representational State Transfer) "is a key design idiom that embraces a stateless client-server
architecture in which the web services are viewed as resources and can
be identified by their URLs." (1) This post will provide a simple example of creating a RESTful service with WCF and F#.
Creating the project:
The first step in building our example is to create a new F# Library project. I chose to name this project "FSharpWCF". The next step is to add references to System.Runtime.Serialization, System.ServiceModel, and System.ServiceModel.Web.
Building the contracts:
The code looks only slightly different than an equivalent in a language such as C#, though there are a couple of key things that should be pointed out. First, System.ServiceModel.Web has been opened. This is the namespace that allows us to use the WebGet attribute. The WebGet attribute allows us to set a UriTemplate that will be used for navigation to our service. Our UriTemplate is set to "temp/{value}", which indicates that navigating to the base URL/temp/{value} will return the result of the service. {value} associates directly with the parameter named value in our GetData operation. The last important thing to notice is the assignment of the name "value" to the request argument of the GetData operation (i.e. abstract GetData : value:string -> string). For more information on this, see this post by Ted Neward.
Adding an app.config file:
Since an F# library doesn't have App.config as an option when adding a new item, you will need to create the file in the project directory manually, then add it as an existing item. The main thing to notice is the addition of the endpointBehaviors section and the association of this behaviorConfiguration to the endpoint.
Testing the service:
To test your new service, do the following:
1. Right click on the FSharpWCF project and select properties.
2. Navigate to the Debug tab, change the start action to "Start external program:" and locate the WcfSvcHost.exe on your development machine (i.e. C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\WcfSvcHost.exe).
3. Add the following "command line arguments:" /service:FSharpWCF.dll /config:FSharpWCF.dll.config
4. Set "Working directory:" to the directory of these DLLs.
You should now be able to launch the service by running the project from Visual Studio. This will host your service with WcfSvcHost and allow you to access your service from a browser. (Note: WcfSvcHost should only be used for testing purposes. You should never use this as a production host.)
To use the service, open a browser and navigate to http://localhost:8080/FSharpWCF/GetDataService/temp/2 and you should receive <string>You entered: 2</string> as a result.
Conclusion:
That's all there is to it. The service can now be viewed as a resource that can be identified by it's URL.
Resources:
1. http://java.sun.com/developer/technicalArticles/WebServices/restful/
Creating the project:
The first step in building our example is to create a new F# Library project. I chose to name this project "FSharpWCF". The next step is to add references to System.Runtime.Serialization, System.ServiceModel, and System.ServiceModel.Web.
Building the contracts:
The code looks only slightly different than an equivalent in a language such as C#, though there are a couple of key things that should be pointed out. First, System.ServiceModel.Web has been opened. This is the namespace that allows us to use the WebGet attribute. The WebGet attribute allows us to set a UriTemplate that will be used for navigation to our service. Our UriTemplate is set to "temp/{value}", which indicates that navigating to the base URL/temp/{value} will return the result of the service. {value} associates directly with the parameter named value in our GetData operation. The last important thing to notice is the assignment of the name "value" to the request argument of the GetData operation (i.e. abstract GetData : value:string -> string). For more information on this, see this post by Ted Neward.
#light namespace FSharpWCF open System open System.Runtime.Serialization open System.ServiceModel open System.ServiceModel.Web [<ServiceContract>] type IGetDataService = interface [<WebGet(UriTemplate="temp/{value}")>] [<OperationContract>] abstract GetData : value:string -> string end type GetDataService() = interface IGetDataService with member this.GetData value = sprintf "You entered: %s" value
Adding an app.config file:
Since an F# library doesn't have App.config as an option when adding a new item, you will need to create the file in the project directory manually, then add it as an existing item. The main thing to notice is the addition of the endpointBehaviors section and the association of this behaviorConfiguration to the endpoint.
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <services> <service name="FSharpWCF.GetDataService" behaviorConfiguration="FSharpWCF.GetDataServiceBehavior"> <host> <baseAddresses> <add baseAddress = "http://localhost:8080/FSharpWCF/GetDataService/" /> </baseAddresses> </host> <endpoint binding="webHttpBinding" contract="FSharpWCF.IGetDataService" behaviorConfiguration="Web"> <identity> <dns value="localhost"/> </identity> </endpoint> </service> </services> <behaviors> <serviceBehaviors> <behavior name="FSharpWCF.GetDataServiceBehavior"> <serviceMetadata httpGetEnabled="True"/> <serviceDebug includeExceptionDetailInFaults="False" /> </behavior> </serviceBehaviors> <endpointBehaviors> <behavior name="Web"> <webHttp/> </behavior> </endpointBehaviors> </behaviors> </system.serviceModel> </configuration>
Testing the service:
To test your new service, do the following:
1. Right click on the FSharpWCF project and select properties.
2. Navigate to the Debug tab, change the start action to "Start external program:" and locate the WcfSvcHost.exe on your development machine (i.e. C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\WcfSvcHost.exe).
3. Add the following "command line arguments:" /service:FSharpWCF.dll /config:FSharpWCF.dll.config
4. Set "Working directory:" to the directory of these DLLs.
You should now be able to launch the service by running the project from Visual Studio. This will host your service with WcfSvcHost and allow you to access your service from a browser. (Note: WcfSvcHost should only be used for testing purposes. You should never use this as a production host.)
To use the service, open a browser and navigate to http://localhost:8080/FSharpWCF/GetDataService/temp/2 and you should receive <string>You entered: 2</string> as a result.
Conclusion:
That's all there is to it. The service can now be viewed as a resource that can be identified by it's URL.
Resources:
1. http://java.sun.com/developer/technicalArticles/WebServices/restful/
Subscribe to:
Posts (Atom)