Sunday, 5 May 2013

Accessing WCF service that is REST-enabled in a web browser

Developers using WCF most often will expose and consume these services in intranet business applications. But sometimes, it is desired to expose services through a web browser.

To expose a WCF service to a web browser, it is possible to do this using the WCF web programming model, based upon the ideas of REST (Representational State Transfer). This article will show how this can be achieved in WCF, using some easy adjustments. Make note that it is possible to allow both a traditional access and web based access, it boils down to activating and adding the necessary endpoints.

First off, let us take the default WCF Service Library template as a starter point.


    public class Service1 : IService1
    {

        [WebGet(UriTemplate="GetData?value={value}")] 
        public string GetData(int value)
        {
            return string.Format("You entered: {0}", value);
        }

        ..

    }

The difference between the code above and the one in the template, is that the service method implementation class Service1 is attributed with the WebGet attribute. In addition, an UriTemplate is added. The WebGet attribute is used to support HTTP GET operations. To use the POST, PUT or DELETE operation in HTTP, use the HttpInvoke attribute. To be able to use this WCF HTTP Programming model you not only have to add a reference to the System.ServiceModel assembly, but also System.ServiceModel.Web assembly. In addition, add the following using statement:
using System.ServiceModel.Web;
Next, some changes must be done in the configuration files for the project where WCF service is located. Open the web.config (or app.config) of the project containing the WCF service. Check that you have the following in the system.servicemodel section:

<system.serviceModel>
    <services>
      <service name="HelloWorldWCFService.Service1">
        <host>
          <baseAddresses>
            <add baseAddress = "http://localhost:8734/Service1/" />
          </baseAddresses>
        </host>
        <!-- Service Endpoints -->
        <!-- Unless fully qualified, address is relative to base address supplied above -->
        <endpoint address="" binding="basicHttpBinding" contract="HelloWorldWCFService.IService1">
          <!-- 
              Upon deployment, the following identity element should be removed or replaced to reflect the 
              identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity 
              automatically.
          -->
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <endpoint address="http://localhost:8733/Service1/mex" binding="mexHttpBinding" contract="IMetadataExchange"  /> 
        <endpoint address="net.tcp://localhost:8080/Service1" binding="netTcpBinding" contract="HelloWorldWCFService.IService1" />
       
        <endpoint address="http://localhost:8734/Service1/Web/" binding="webHttpBinding" contract="HelloWorldWCFService.IService1" behaviorConfiguration="webBehaviorConfig" />
        
        <!-- Metadata Endpoints -->
        <!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. --> 
        <!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        
       
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="webBehaviorConfig">
          <webHttp />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>

        <behavior>
          <!-- To avoid disclosing metadata information, 
          set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
          <!-- To receive exception details in faults for debugging purposes, 
          set the value below to true.  Set to false before deployment 
          to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>


That was a lot of config. In fact what is key to note here is just that we add an endpoint that has the webHttpBinding endpoint. The address is the URL that will be used to access the service, as the prefix combined with the UriTemplate of each WCF operation that is exposed. In addition, the endpointBehaviors element is added with a behavior where we give it a name and add the webHttp element. Also, note that the attributes httpGetEnabled and httpsGetEnabled is set on the serviceMetadata element. To access the web-enabled WCF service in this example, open a web browser and enter the following URL:
http://localhost:8734/Service1/Web/GetData?value=42


The returned data is in the form of an XML, which is the default output format. It is possible to change the output format into JSON for example, to integrate the data returned with Javascript and Ajax in modern web browsers.
This will give you a start to test out accessing the WCF service through a web browser. Of course, when exposing WCF service on the web, security considerations should be taken. Most often, it comes down to what should be done when a new attack vector is made available. Obviously, more often than not, you will want to limit which users can access the web service. In addition, the service should not expose sensitive data, without security considerations. There are also limits in which data can be passed in an URL. When you use the WebInvoke attribute, more complex objects can be passed into a service, but still, the object being passed in must be serializable into an XML.

Also note that the UriTemplate must match the naming of the parameters to the WCF method. There are limitations to which data types can be passed in a query string. An explanation of the format one must follow when it is required to pass, say a DateTime, check out the following MSDN article:
WCF Web HTTP Programming Model Overview

It is easy to change the output from XML to JSON.

We will now look at calling the same WCF Method used above through jQuery and its $.ajax method. First, change the signature of the WCF service:
        [WebInvoke(ResponseFormat=WebMessageFormat.Json, BodyStyle=WebMessageBodyStyle.Wrapped)] 
        public string GetData(int value)
        {
            return string.Format("You entered: {0}", value);
        }
Note that we do not specify the Method property of WebInvoke, which defaults to POST verb of HTTP. We have also changed from WebGet to WebInvoke. Next, adding a MVC 4 application to act as a client, add the following code to your global.asax code behind file (Global.asax.cs) in this project:
     
        protected void Application_BeginRequest(object sender, EventArgs e)
        {

            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "http://localhost:*/");

            if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
            {
                HttpContext.Current.Response.AddHeader("Cache-Control", "no-cache");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
                HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
                HttpContext.Current.Response.End();
            }
        }

The code above is to added to fix compability issues in Chrome and Firefox to allow Ajax calls to the WCF service (IE did not need this fix). Add the following content to the Index.cshtml file of the added MVC Project:
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>

    <script type="text/javascript">

        function testPosting() {

            jQuery.support.cors = true;

            var enteredValue = $("#txtValue").val();
            var data = { value: enteredValue };

            var payload = JSON.stringify(data);

            $.ajax({
                type: 'POST',
                url: 'http://localhost:8734/Service1/Web/GetData',
                contentType: 'application/json',
                dataType: 'text',
                data: payload,
                error: function (request, status, error) {
                    alert(request.responseText + " " + status + " " + error);
                },
                success: function (msg) {
                    var result = JSON.parse(msg);
                    console.log(result);
                    $("#results").append(result.GetDataResult + "<br />");
                }
            });

        }

    </script> 
Adding jquery above is not necessary, since the MVC template has already added this. Next, a method called testPosting is added. Here, a call to the $.ajax method is added. The $.ajax metod specifies the url of the WCF service. Also note that the service should be on the same server and preferably the same port to avoid security issues. Of course, your service can access remote servers in its code. This means that the Web Application and the WCF Service preferably should be installed on the same server. Cross-domain scripts are usually disallowed in web browsers today. But the option for your WCF services to access remote servers is of course not affected by this limitation. The dataType is set to 'text', but it could be 'json'. Instead, the json is parsed in the success callback. Further on, the name of the argument of your WCF method must match the constructed json object being passed into the method.


We need a simple GUI also to test the combination of WCF, REST, Ajax and JSON (GUI below is just a mockup in Google Blogger):
 

Enter an integer:



The code in the Global.asax.cs file was obtained by reading this article: Method 405 fix for WCF

This shows that WCF services can provide XML, JSON, Ajax and REST capabilities and not just be an intranet web services provider, as its typical use. Of course, often WCF will feel a bit heavy weight when all you want is to expose web services to your Clients. But again, often you want to create Intranet style web applications too, where you want some of your services and their methods provide web access. This will make it easier to use existing WCF services hosted in IIS through for example WAS to be utilized by mobile clients. The information which these methods of your WCF services will usually be services that are not sensitive, or else one has to provide security mechanisms around the web access. One possible way of adding security is to provide a token or similar information in the JSON payload being sent over to the server. If the WCF service verfies the token sent in, the information will then be sent back again to the client. For example, the client could log in to a web application which uses a Security Token Service or similar to log in. If WIF is used, the client will get a FedAuthCookie as a certification of a valid user. The user can then relay the necessary information over to the WCF Rest-enabled service to inspect the users claims or similar. One could use a digital signature or similar. I will look at WCF REST security tokens and related topics in the near future. The level of security will be lower than what is possible in many other types of bindings being used in WCF such as wsFederationBinding or similar.

This article shows that WCF can be used in many web scenarios. I have not touched the topics of WebServiceHost and calling the REST-enabled services through code and not JavaScript. If you want a web-enabled WCF service, chances are higher that you want to reach the WCF service through jQuery + Ajax or similar using JSON as information interchange format. There are a multitude of topics to cover here and the developer should be aware that it is a learning curve to start using WCF for the web.

Friday, 5 April 2013

Stopping a process with Powershell and the Out-GridView

Powershell can display a nice menu where the user can select e.g. a single or a multiple element in an arbitrary gridview, with the cmdlet Out-GridView. Let's see how this can be done to support stopping a single process of which the user chooses to stop. Of course, this is already available in Task Manager, but it is always nice to see that Powershell can give us a dedicated way of doing this also.

Here is the script for doing this, in the function Stop-SelectedProcess:

            
function Stop-SelectedProcess(){            
            
    Write-Host Select the process to stop ...            
    Start-Sleep 2            
                
    $selectedProcess = $null             
    Get-Process | Out-GridView -OutputMode Single -Outvariable selectedProcess            
                
    if ($selectedProcess -eq $null -or $selectedProcess.Count -eq 0)             
    {            
        return;            
    }             
            
    Stop-Process $selectedProcess            
            
}            
            
Stop-SelectedProcess
Make note how the Out-GridView cmdlet which we pipe the result from Get-Process to is specified to have an -OutputMode of single (i.e. choose one item at a time)and a -OutVariable also set, also note the missing $-sign after -OutVariable, this is correct. This shows how we can present the user with a nice menu to choose for while running the command. This is easier than asking the user to select a process to stop by e.g. PID or #-line number.

This is just another example of how modern as a scripting language Powershell really is.

Word of caution at the end - never stop a process you are not sure of what runs. I stopped the process smss process the other day, because I thought it was Sql Management Studio. Needless to say, I experienced my first BSOD in Windows 8 ..

Screenshot of the action:

Thursday, 4 April 2013

Dynamic modules in Powershell as objects

This article will show how dynamic modules can act as objects for Powershell. With this technique, it is possible to create object definitions in Powershell if you want more object orientation for your scripts. Let's first look at the Manifest file for the dynamic module. The file modasobj.psd1 contains the following:

#Module manifest for module 'modasobj            
#Generated by: Tore Aurstad            
            
@{            
ModuleVersion = '1.0'            
Guid = 'C9B7488B-507C-470C-B93E-6B040A5EF2AC'            
Author='Tore Aurstad'            
Description='Demonstrates use of modules as objects'            
            
ScriptsToProcess = @('modasobj.ps1')            
            
}
The manifest file will always have the name MODULENAME.psd1, where MODULENAME is the folder name under one of your $env:psmodulepath folders. As we see, we define the Guid, Author, Description and ModuleVersion. For non-dynamic modules, we specify more properties in the hashtable of our manifest .psd1 file for our Powershell modules. An overview of the manifest properties to set is here:

How to write a module manifest
We define our module as objects definitions in the other file, modasobj.ps1
function New-Address {            
            
 New-Module -AsCustomObject -Name Address {            
    $House = $null            
    $Street = $null            
    $Town = $null            
    $County = $null            
    $Country = $null            
    $PostCode = $null             
            
    Export-ModuleMember -Variable *            
            
 }            
            
}            
            
function New-Person {            
 New-Module -AsCustomObject -Name Person {            
    $Name = $null            
    $Address = $null            
    $Occupation = $null             
    $Age = $null            
    $NiNo = $null              
            
    Export-ModuleMember -Variable *            
            
  }            
            
}
Here we see the use of New-Module cmdlet, followed by the flag -AsCustomObject and the -Name flag followed by the name of the custom object we want to create. To play around with this object, we can just create a new Person object and set its address to be an Address object. Some output of this follows.


PS C:\users> import-module modasobj -verbose -force
VERBOSE: Loading module from path 'C:\Users\Tore Aurstad\Documents\WindowsPowerShell\Modules\modasobj\modasobj.psd1'.
VERBOSE: Loading module from path 'C:\Users\Tore Aurstad\Documents\WindowsPowerShell\Modules\modasobj\modasobj.ps1'.
VERBOSE: Dot-sourcing the script file 'C:\Users\Tore
Aurstad\Documents\WindowsPowerShell\Modules\modasobj\modasobj.ps1'.
PS C:\users> $me = New-Person
PS C:\users> $me


Address    :
Age        :
Name       :
NiNo       :
Occupation :

PS C:\users> $me.Age = 34
PS C:\users> $me.Name = 'Tore Aurstad'
PS C:\users> $me.Occupation = 'System Developer'
PS C:\users> $me.Occupation = 'Systems Developer'
PS C:\users> $me.Address = 'Kyavegen 1 7045 Trondheim'
PS C:\users> $me.Address.Country = 'Norway'
Property 'Country' cannot be found on this object; make sure it exists and is settable.
At line:1 char:1
+ $me.Address.Country = 'Norway'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyAssignmentException

PS C:\users> $me.Address.County = 'Sør-Trøndelag'
Property 'County' cannot be found on this object; make sure it exists and is settable.
At line:1 char:1
+ $me.Address.County = 'Sør-Trøndelag'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyAssignmentException

PS C:\users> $address = New-Address
PS C:\users> $me.Address = $address
PS C:\users> $address.Country = 'Norway'
PS C:\users> $me


Address    : @{Country=Norway; County=; House=; PostCode=; Street=; Town=}
Age        : 34
Name       : Tore Aurstad
NiNo       :
Occupation : Systems Developer

PS C:\users> $address.County = 'Sør-Trøndelag'
PS C:\users> $address.House = '1'
PS C:\users> $address.PostCode = '7045'
PS C:\users> $address.Street = 'Kyavegen'
PS C:\users> $address.Town = 'Trondheim'
PS C:\users> $me

Address    : @{Country=Norway; County=Sør-Trøndelag; House=1; PostCode=7045; Street=Kyavegen; Town=Trondheim}
Age        : 34
Name       : Tore Aurstad
NiNo       :
Occupation : Systems Developer

PS C:\users>

PS C:\users> $me.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    PSCustomObject                           System.Object


PS C:\users> $address.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    PSCustomObject                           System.Object


PS C:\users> $me | Get-Member


   TypeName: System.Management.Automation.PSCustomObject

Name        MemberType   Definition
----        ----------   ----------
Equals      Method       bool Equals(System.Object obj)
GetHashCode Method       int GetHashCode()
GetType     Method       type GetType()
ToString    Method       string ToString()
Address     NoteProperty System.Management.Automation.PSCustomObject Address=@{Country=Norway; County=Sør-Trøndelag...
Age         NoteProperty System.Int32 Age=34
Name        NoteProperty System.String Name=Tore Aurstad
NiNo        NoteProperty  NiNo=null
Occupation  NoteProperty System.String Occupation=Systems Developer


PS C:\users>

As you can see, I had to adjust above the way I was setting $me.Address properties by having to declare a new address object $address and set its properties to see the changes reflected in the parent object $me. Both objects are of type PSCustomObject. As we can see, when we pipe our object variable to the cmdlet Get-Member, we get a nice listing of our members and derived members. This shows how custom objects can be made inline in Powershell. Of course, Powershell can create objects easily with the New-Object cmdlet and by specifying a library object either in .NET or created by you, but this shows how you don't have to recompile and create an object specification or class, you can have Powershell create for you, with dynamic modules and the -AsCustomObject and -Name flags set inside the function. In addition, you need to use the cmdlet Export-ModuleMember-Property *, such that your properties are visible for consumers of the dynamic module.

If you want to remove the module again, use:
remove-module modasobj*

Modules are a huge topic and this article shows one of their many ways of being created.