Solving Caching problem of IE for WCF REST service

Objective

This article will explain; how to solve the caching problem in IE while making call to for REST enabled WCF service. Client might be a SILVERLIGHT client or AJAX client.

Background

Read my other articles on WCF REST service for better understanding of this article.

Is REST service and a web page is same?

Theory says YES, these two are almost the same entity exist on web. Calling a REST service is exactly the same as of browsing the web page on the web.

REST is architecture to create service not a specification. And it works on the HTTP verbs.

REST stands for Representational state transfer where each operation in a service is uniquely identified. Each operation has their, own unique URI and can be accessed via this URL all across the web. Each operation in service definition is attributed with the HTTP verbs they are going to work with. So if URL of a REST service is browsed from the browser, it will return response from the service in form of either JSON or XML base on the service definition.

So, the below link can be browsed in browser.

http://localhost:80/Service1.Svc/GetName?deptId=9

Temporary Internet Files and History Settings

There are four options for cache settings in Internet Explorer


 

Every Time I visit the Web Page

On returning of the page which has been viewed previously, IE checks on the server whether viewed page has been changed. If viewed page has been changed, IE will display the new changed page else it will display the cached page.

Note: If this setting is selected in browser there is no need of handle the caching through code. There is no caching for this option.

Every Time I Start Internet Explorer

In this option IE will download the newer version from the server only when browser got reopened or refreshed [F5]. Else each time IE will show the cached page.

Automatically

In this option IE download the new page from the server based on certain algorithm. This is default setting of the browser.

Never

In this option IE never go to server to download the page. Always browser shows the cached page.

Bottom Line is, since
browsing web page and REST Service call is exactly the same so browser setting applies to calling REST service also. So caching problem does apply to REST service call also.

How to solve caching problem?

There are two ways to solve the caching problem of REST service call.

  1. Through work around
  2. Through JQuery

Through Work Around

Let us suppose service is

[WebGet(ResponseFormat = WebMessageFormat.Json)]

[OperationContract]


List<string> GetNames(string deptId);

 

Service is hosted somewhere and service is being called by,

AJAX cleint

$.getJSON(‘Service1.svc/ GetNames,

{ deptId: ids },

function(data,status){}

 

Silver Light Client

HttpClient proxyClient = new
HttpClient();

proxyClient.TransportSettings.Credentials = CredentialCache.DefaultCredentials;

string targetURI = string.Format(“/Service1.svc?deptId={0}”,deptId);

HttpResponseMessage response = proxyClient.Get(targetURI);

 

Now, if service is being called with the deptId=9; then URL of calling service will be

http://localhost:80/Service1.Svc/GetName?deptId=9

And a response will get cached at the client browser.

Problem Statement

Now consider and scenario, when for the deptId =9 database has been changed at the service side. If browser is set as the default (Automatic) and for the next service call with same dept id, browser will call the URL http://localhost:80/Service1.Svc/GetName?deptId=9 , and response for this URL has been cached at the browser, so at the client side changed database won’t be reflected.

Solution

This is a work around solution; just add an extra parameter of type DateTime in service and each time at calling the service pass current date time from the client. So each time there will be a unique URL and that won’t be cached. So each time browser will download the latest response from the server regardless of the browser setting.

Modify service as

[WebGet(ResponseFormat = WebMessageFormat.Json)]

[OperationContract]


List<string> GetNames(string currentDateTime, string deptId);

 

So now at time of calling the service just pass the current date time and it will modify the Service URL each time. So browser will get the response from the service each time.

http://localhost:80/Service1.Svc/GetName?currentDateTime=12-12-2009:10.00.00,deptId=9

After 1 sec the service call will get modify with the URL and this is new URL .

http://localhost:80/Service1.Svc/GetName?currentDateTime=12-12-2009:10.00.01,deptId=9

Through JQuery

This solution is only applicable for the AJAX client.

  1. Call $.ajaxSetup({ cache: false }); before making the service call.
  2. Call $.ajaxSetup({ cache: true }); after making the service call.
$.ajaxSetup({ cache: false });

$.getJSON(‘Service1.svc/ GetNames,

{ deptId: ids },

function(data,status){}

$.ajaxSetup({ cache: true });


Conclusion

This article explained about working with cache problem in IE while making call to REST enabled WCF service. Thanks for reading.

NTLM and Windows Authentication on WCF service

Objective

This document will explain various combinations of IIS and WCF Ntlm/Windows authentication settings.

What is difference between NTLM and WINDOWS authentication in WCF?

Windows authentication = authentication in NTLM + authentication in Active Directory

NTLM authentication = authentication in only NTLM

IIS configuration

For all scenario IIS is configured for Windows authentication. What I mean is Windows Authentication is enabled and all other authentication is disabled. Navigate to below path to open ApplicationHost.Config file of IIS.

C:\Windows\System32\inetsrv\config\applicationHost.config

Binding used in WCF service

For all scenario basicHttpBinding being used for WCF service.

Scenario #1

Default setting for IIS Applicationhost.Config is

<windowsAuthentication enabled=false>

<providers>

<add value=Negotiate />
<add value=NTLM />
</providers>
</windowsAuthentication>

If IIS APP.Config file is having default setting, then we can have any authentication for WCF service corresponding IIS configured; WCF service will run as expected without any error.

Note: SharePoint is running as expected

Browsers Behavior with default settings

  1. IE 7.0 is not asking for authentication
  2. Fire Fox 3.5.6 is asking user to authenticate
  3. Safari 4.0.4 is asking user to authenticate

Scenario #2

If IIS Applicationhost.Config File setting has been modified as below, where forcefully Windows authentication is enabled for Kerberos then we have to modify service with Windows authentication.

<windowsAuthentication enabled=true><providers>
<add value=Negotiate />
<!–<add value=”NTLM” />–>
</providers>
</windowsAuthentication>

WCF configuration setting for Windows authentication should be

<basicHttpBinding>

<binding name=BasicHttpBinding>
<security mode =TransportCredentialOnly>
<transport lientCredentialType =Windows/>
</security>
</binding>
</basicHttpBinding>

 

Note: SharePoint is running as expected

Browsers Behavior with default settings

  1. IE 7.0 is not asking for authentication
  2. Fire Fox 3.5.6 is asking user to authenticate
  3. Safari 4.0.4 is asking user to authenticate

Scenario #3

If IIS Applicationhost.Config File setting has been modified as below, where forcefully Windows authentication is enabled for NTLM

<windowsAuthentication enabled=true>

<providers>

<!–<add value=”Negotiate” />–>

<add value=NTLM />
</providers>
</windowsAuthentication>

 And we go with Windows authentication for the service, we will get below error

<basicHttpBinding>

<binding name=BasicHttpBinding>

<security mode =TransportCredentialOnly>

<transport clientCredentialType =Windows/>

</security>

</binding>

</basicHttpBinding>

So to remove above error, WCF configuration setting for should be modified for the NTLM authentication.

<basicHttpBinding>

<binding name=BasicHttpBinding>

<security mode =TransportCredentialOnly>

<transport clientCredentialType =Ntlm/>

</security>

</binding>

</basicHttpBinding>

 

Note: SharePoint is running as expected

Browsers Behavior with default settings

  1. IE 7.0 is not asking for authentication
  2. Fire Fox 3.5.6 is asking user to authenticate
  3. Safari 4.0.4 is asking user to authenticate

Summary

Sl No

IIS (Applicationhost.Config ) setting

WCF (Web.config) setting

1 Default Ntlm and Windows Binding behavior
2 Windowauthentication = true and Value = Negotiate Windows authenticated Bidding behavior
3 Windowauthentication = true and Value = Ntlm Ntlm authenticated Binding behavior

So,

  1. If we have ApplicationHost.Config of IIS configured as default, we can have either of Ntlm or Windows authentications for WCF service.
  2. If we have ApplicationHost.Config of IIS configured as Ntlm, we can have only Ntlm authentication for WCF service.

If we have ApplicationHost.Config of IIS configured as Windows, we can have only Windows authentication for WCF service.

Step by Step walkthrough to host WCF service in Windows Azure

Objective

This article will give step by step walkthrough of hosting a WCF service in windows azure.

Note: Before reading through this walkthrough see this http://djoncloud.cloudapp.net/DjService.svc . We are going to host this service in this walkthrough.

Prerequisite

VS 2010 Beta

Windows AZURE SDK should be installed on the system.

Step 1

Open Visual Studio 2010 as an administrator. Select File -> New -> Cloud Service. Click on Windows Azure cloud service template. Give name of the cloud service. After creating the cloud service select the type of role. There are many roles to choose from. For our purpose, we will choose ASP.Net Web Role. After creating ; Now examine the solution explorer. There should be 2 projects. Called WebRole1 and CloudServices1. These names may different basis of the name you given at time of creation of cloud service project in step1.

Step 2

Creating the WCF Service

Right click on WebRole1 project and add new item then select WCF service from the WEB project template.

Modify contract and service implementation as per you. For my purpose , I am making it simple service as below.

Contract

 [ServiceContract]
public interface IDjService
 {
[OperationContract]
string GetMyName(string name);
}

 Service Implementation

public class DjService : IDjService{
public string GetMyName(string name){
return “helllo “ + name + “to my service hosted in Azure”;
} }

 Change the Binding to basicHttpBinding. Make sure to do this.

Note : make sure you have set WebRole1 as startup project .

Step 3

Running on Local Development Fabric (Press F5)

Run the application. This will run on the local development fabric. When we install azure SDK, local development fabric got installed. And when we run the cloud service local development fabric get started and host the application. This provides exactly the same environment as of azure in the cloud. This local development fabric could be used to debug the application before hosting into the cloud.

Running the application on local development fabric

See the URL in address bar of browser, in my case this is

http://localhost:49863/DjService.svc

Step 4

Publishing to cloud (azure)

Right Click on Cloud Service 1 project and select Publish. And publish to azure. See my other articles for details.

Now when you open the URL after publishing , you will get the same page as output you got on the local development fabric. And now you successfully hotsed in cloud.

WCF service hosted in Azure

http://djoncloud.cloudapp.net/DjService.svc

Step 4

Consuming the service hosted in Windows Azure

Create a console application to consume the service. There is a known bug with Azure where a proxy cannot be created from the Azure hosted service. So to as a workaround to create proxy

  1. While adding service reference first adds URL of the service hosted on local development fabric. Copy the URL from Step 3 and right click on Console application and select Add service reference. In service URL paste the URL from step 3.

Call the service hosted in local development fabric like below,

using testingWcfAzureclient.ServiceReference1;
namespace testingWcfAzureclient
{class Program{
static void Main(string[] args)
{
DjServiceClient proxy = new DjServiceClient();
Console.WriteLine(proxy.GetMyName(“Dhananjay “));
Console.Read();
}}}

Output


Open the App.config and modify the address to address of service in azure.

<client><endpoint
address=http://djoncloud.cloudapp.net/DjService.svc
binding=basicHttpBinding
bindingConfiguration=BasicHttpBinding_IDjServicecontract=ServiceReference1.IDjServicename=BasicHttpBinding_IDjService /></client>

Again run the application and you will get the same output.

Step by Step walkthrough to create first application for cloud (Windows Azure)

Step 1

Open Visual Studio 2010 as an administrator. Select File -> New -> Cloud Service. Click on Windows Azure cloud service template. Give name of the cloud service. After creating the cloud service select the type of role. There are many roles to choose from. For our purpose, we will choose ASP.Net Web Role.

Now examine the solution explorer. There should be 2 projects. Called WebRole1 and CloudServices1. These names may different basis of the name you given at time of creation of cloud service project in step1.

CloudService1 project is having two service configuration file.

ServiceDefinition.csdef

This is definition file for the cloud service. This file contains setting like connection string, Endpoints etc.

ServiceConfiguration.csfg

This is configuration file for the cloud service. This contains setting for the roles. This file contains information for number of instance for the service. If we want to increase number of instance for the role only this configuration need to be amend to accommodate the change.

WebRole1 project

This is a simple ASP.Net project. Where we could do whatever we want and could do on an ASP.Net project.

Step 2

Creating the web project

For all our demo purpose, I have modified the aspx page with two buttons and one label and one image control.

Div section of Default.aspx

<div>

<asp:Image ID=”Image1″ runat=”server” ImageUrl=”~/Image0406.jpg”Width=”200px” Height=”300px” />
<asp:Label ID=”lblDisplay” runat=”server” ForeColor=”#FF1166″ Height=”45px” Width=”709px” Font-Bold=”True” Font-Size=”XX-Large”
></asp:Label>
<br/>
<br/>
<asp:Label ID=”lblImageMsg” runat=”server” ForeColor=”Black” Height=”64px” Width=”350pxFont-Bold=”True”>
am I looking good ?!!! LOL
</asp:Label><br/><br/>
<asp:Button ID=”btnClose” runat=”server” ForeColor=”#FF0066″ Height=”64px” Text=”Close my Image”Width=”150px”
onclick=”btnClose_Click”/>
<asp:Button ID=”btnCloud” runat=”server” ForeColor=”#FF0066″ Height=”64px” Text=”Button on Cloud, Hite ” Width=”190px” onclick=”btnCloud_Click”/>
</div>

Default.aspx.cs

namespace WebRole1{

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e){}
protected void btnCloud_Click(object sender, EventArgs e)
{
lblDisplay.Text = ” Hey I have created my first application on Azure ! long to Go!”;
}
protected void btnClose_Click(object sender, EventArgs e)
{
if(string.Equals(btnClose.Text,“Close my Image”,StringComparison.InvariantCultureIgnoreCase)){
Image1.Visible = false;

lblImageMsg.Visible = false;
btnClose.Text =“Show my Image”;
}
else{
Image1.Visible = true;
lblImageMsg.Visible = true;
btnClose.Text =“Close my Image”;
} }}}

Step 3

Running on Local Development Fabric

Run the application. This will run on the local development fabric. When we install azure SDK, local development fabric got installed. And when we run the cloud service local development fabric get started and host the application. This provides exactly the same environment as of azure in the cloud. This local development fabric could be used to debug the application before hosting into the cloud.

Running the application on local development fabric

On clicking at task tray; Local Development Fabric icon would be there. Right click on the icon will give below options as of below diagram.

Click on, Show Development Fabric UI. It will open the UI. This UI will show state of all the instances running for the different types of roles.

Since now only one instance of our application is running, so there is one instance showing in the UI. Let us go back to ServiceConfiguration.csfg
and open this file. Increase number of instance from 1 to 4.

ServiceConfiguration.csfg

<?xml
version=1.0?>

<ServiceConfiguration
serviceName=CloudService1
xmlns=http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration>

<Role
name=WebRole1>


<
Instances
count=4 />

<ConfigurationSettings>

<Setting
name=DiagnosticsConnectionString
value=UseDevelopmentStorage=true />

</ConfigurationSettings>

</Role>

</ServiceConfiguration>

 

Now again open the Development Fabric UI from the tray icon. We can see on clicking of WebRole1, there are 4 instances are running. We could individually manage all the instances of the Web Role.

Step 4

Publishing to cloud (azure)

Right Click on Cloud Service 1 project and select Publish.


It will open the azure site and ask for the login.

If first time, you are login to azure site for publishing browse to account section to redeem your token.

Now either create a project for windows azure or select existing project. I have already a project created with the name of DJProject . I am selecting that.

Since, I have already hosted in the project before. So I am getting the upgrade option. First time, you won’t get upgrade option. First time on creation of Windows azure project it will ask you to give an URL for your project . Just give an URL, which you will use to access your application across.

Click on upgrade option . It will ask for the package file and config file. Browse to CloudService1\bin\publish folder. CloudService1 is name of the application. It may be different in your case , depending on what name you have given in step1.

After uploading package and configuration file , give a label name and click on deploy.

It will take some time for deployment. After successfully deployment you will see a green sign against Web Role saying it is in ready state. You could directly click on Web site URL to test your application on cloud.

Now when you open the URL , you will get the same page as output you got on the local development fabric. And now you successfully hotsed in cloud.

WINDOWS authentication on REST enabled WCF service

Enabling windows authentication on a REST enabled service is relatively easier task than it’s appear. To test that windows authentication is enabled successfully or not use other browser than Internet explorer because IE will automatically do an NTLM negotiation with domain credentials. So when REST service is running in IE, it is not prompting for user credentials.

Service

 A very simple contract as REST service, I am going to use.
Contract

namespace RestserviceWindows{

[ServiceContract]

public interface IService1{
[OperationContract]
[WebGet()]
string GetData();
}}

 Service implementation

namespace RestserviceWindows{

public classService1 : IService1
{
public string GetData(){
return “Testing Windows Authentication with REST service”;
}}}

Configuring the Service

Method #1 Using Factory class

  1. Create a simple REST service. To create a REST service navigates to File->New->Project->Web and select WCF Service Application project template.
  2. WCF will create default endpoints inside System.ServiceModel. Delete both the default endpoints. Delete below end points.
<endpoint address=“” binding=wsHttpBindingcontract=RestserviceWindows.IService1>

<identity>
<dns value=localhost/>
</identity>
</endpoint>
<endpoint address=mexbinding=mexHttpBindingcontract=IMetadataExchange/>

 

  1. Right click on .SVC file. If your service name is Service1 then right click on Service1.svc. After right clicking select View Markup. Add Factory here
<%@
ServiceHost
Language=”C#”
Debug=”true”
Service=”RestserviceWindows.Service1″
CodeBehind=”Service1.svc.cs”
Factory=”System.ServiceModel.Activation.WebServiceHostFactory
%>

 

  1. Host the service in IIS. To host right click on service and Publish in IIS.
  2. Configure IIS for windows authentication.

The above 5 steps are required to host a REST service in IIS with windows authentication.

Method #2 Configuring End Point without Meta Data

  1. Create a simple REST service. To create a REST service navigates to File->New->Project->Web and select WCF Service Application project template.
  2. Delete endpoint address for MEX and binding mexHttpBinding
  3. Configure EndPoint to enable REST service.
  4. Configure EndPoint to enable windows authentication on the service.
  5. Configure End Point behavior.
  6. Make sure, there is no factory class provided for the service in markup of .svc

     

<%@
ServiceHost
Language=”C#”
Debug=”true”
Service=”RestserviceWindows.Service1″
CodeBehind=”Service1.svc.cs” %>

 

  1. Host the service in IIS. To host right click on service and Publish in IIS.
  2. Configure IIS for windows authentication.
<system.serviceModel>

<services>

<service
name=RestserviceWindows.Service1
behaviorConfiguration=RestserviceWindows.Service1Behavior>            

<endpoint
address=“”
binding=webHttpBinding
contract=RestserviceWindows.IService1
bindingConfiguration =RESTBINDING
behaviorConfiguration =REST>

<identity>

<dns
value=localhost/>

</identity>

</endpoint>

</service>

</services>

<behaviors>

<serviceBehaviors>

<behavior
name=RestserviceWindows.Service1Behavior>                    

<serviceMetadata
httpGetEnabled=true/>                    

<serviceDebug
includeExceptionDetailInFaults=false/>

</behavior>

</serviceBehaviors>


<
endpointBehaviors>

<behavior
name =REST>

<webHttp/>

</behavior>

</endpointBehaviors>

</behaviors>


<
bindings>

<webHttpBinding>

<binding
name =RESTBINDING>

<security
mode =TransportCredentialOnly>

<transport
clientCredentialType =Windows/>

</security>

</binding>


</
webHttpBinding>

</bindings>

    </system.serviceModel>

 

Method # 3 Configuring End Point with Meta Data

So far in above two methods, Meta Data is not getting exposed. Because mexHttpBinding only supports anonymous binding. So to enable windows authentication on mexHttpBinding , we need to configure IMetaDataContract with some other binding like basicHttpBinding or webHttpBinding.

  1. Create a simple REST service. To create a REST service navigates to File->New->Project->Web and select WCF Service Application project template.
  2. Configure EndPoint to enable REST service.
  3. Configure EndPoint to enable windows authentication on the service.
  4. Configure End Point behavior for both End Points.
  5. Make sure, there is no factory class provided for the service in markup of .svc
<%@
ServiceHost
Language=”C#”
Debug=”true”
Service=”RestserviceWindows.Service1″
CodeBehind=”Service1.svc.cs” %>

 

  1. Host the service in IIS. To host right click on service and Publish in IIS.
  2. Configure IIS for windows authentication.
<system.serviceModel>

        <services>

            <service
name=RestserviceWindows.Service1
behaviorConfiguration=RestserviceWindows.Service1Behavior>                

                <endpoint
address=“”
binding=webHttpBinding
contract=RestserviceWindows.IService1
bindingConfiguration =RESTBINDING
behaviorConfiguration =REST>

                <identity>

<dns
value=localhost/>

</identity>

</endpoint>

                <endpoint
address=mex
binding=webHttpBinding
contract=IMetadataExchange
bindingConfiguration =RESTBINDING/>

            </service>

        </services>

        <behaviors>

            <serviceBehaviors>

                <behavior
name=RestserviceWindows.Service1Behavior>                    

                    <serviceMetadata
httpGetEnabled=true/>                    

                    <serviceDebug
includeExceptionDetailInFaults=false/>

                </behavior>

            </serviceBehaviors>


<
endpointBehaviors>

<behavior
name =REST>

<webHttp/>

</behavior>

</endpointBehaviors>

        </behaviors>

<bindings>

<webHttpBinding>

<binding
name =RESTBINDING>

<security
mode =TransportCredentialOnly>

<transport
clientCredentialType =Windows/>

</security>

</binding>

</webHttpBinding>

</bindings>

    </system.serviceModel>

 

Note: Binding for IMetaDataExchange contract is webHttpBinding.

Consuming the Service

To enable a client to consume a windows authenticated WCF service, client has to pass domain credentials . If HttpClient is used by the client to consume the service then client has to set the credential like

clt.TransportSettings.Credentials=System.Net.CredentialCache.DefaultCredentials;

where clt is instance of HttpClient .

  1. Add Microsoft.Http and System.RunTime.Serlization assembly at refernece
  2. Add namespace of Microsoft.Http and System.Runtime.Serlization
  3. Create insatnce of HttpClint
  4. Set the default credential from the cache.
  5. Perfrom HTTP operation.

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Microsoft.Http;

using System.Runtime.Serialization;

using System.Net;

namespace ConsoleApplication1

{

class Program

{
static void Main(string[] args)
{
string url = http://localhost/RESTTESTING/Service1.svc/GetData;

HttpClient clt = new HttpClient();

clt.TransportSettings.Credentials = System.Net.CredentialCache.DefaultCredentials;
HttpResponseMessage msg = clt.Get(url);

string str = msg.Content.ReadAsDataContract<string>();

Console.WriteLine(str);

Console.Read();
}}}