Showing posts with label WCF. Show all posts
Showing posts with label WCF. Show all posts

Thursday, January 3, 2013

WCF Service Optimization: An interesting technique to split your *.svc.cs file to have more manageable WCF service

Introduction

WCF (Windows communication foundation) is the service layer foundation and the base of SOA in Microsoft dot net, what will happen when you have a huge WCF service consisting of 5000 operation contract. This is not unreal at all, if you design a service bus for a large intranet application, where 1000 employee using your application and doing day to day operation and your WCF service hits per second is about 2000. You can do so many thing to optimize it, first of all you can cluster the service and then apply load balance. So horizontal scaling is a solution.

Now if you are given a task to optimize the operation and each time you need to look at the service you have to find it in a large class where you have about 5000 operation contract. How developers will maintain this huge code base?

Fortunately we have few solutions to that problem

Today we are going to see 1st of many solution

split your *.svc.cs file

This does not help in optimization of the service rather managing the file and the codebase. First of all I would split the svc file in to several pieces. Each will contain in about 100 methods, still we would have 20 files for the svc file, its kind of sounds different but, would help managing 2000 methods, each file will contain domain specific methods for the service.

How we do it?

We will add class with almost same name as the service, for instance if we have a WCF service named “myservice.svc” then the code behind file is  “myservice.svc.cs”. Off Course its not necessary to have svc.cs file with the wcf service we can have only the declaration.

Below a code example is given,This is how a real world service which is out of refactoring and maintain for a while looks like.

image

Figure: Log Class of 2000 method

In above screenshot If you carefully look at the scrollbar of the method dropdown of the visual studio, you will have an idea how much its doing.

So now we need to optimize this in perspective of code management. As we already discussed the technique. we will split this in to several pieces, luckily we have a partial class concept in c#, so we would split this in to several pieces according to class responsibility domain.

Naming convention for the partial class. “myservice.[responsibilityDomain].svc.cs” that’s the filename of the class. In practical case I have named on of my partial class as “ReliantDataConnect.CandidateOffer.svc.cs” I have moved all the methods related to CandidateOffer in this file.

Now Lets say we have added another partial class file name “ReliantDataConnect.Resource.svc.cs” using the following wizard window.

image

Figure: Add a new class

And after moving the related methods in the partial class the partial class may look like below screen shot.

image

Now problem is the partial class will be visible in solution explorer as a isolated file rather part of the WCF Service. Below how it looks like after adding the file.

image

Now if we can add this file as a dependent file of the ReliantDataConnect.svc file this will save us form watching isolated file, and make a combined file. Here is how we do it.

Make a file dependent on another file in visual studio

First of all we have to open the project file in note pad or text pad or note pad ++ which ever you like. Then find the file name that we added “ReliantDataConnect.Resource.svc.cs”, finally add DependentUpon Child node and specify the file name in our case its “RelaintDataConnect.svc” Now saved the file. Close it. If visual studio is open it should already warn you that file is been modified outside and reload is necessary. Reload to proceed.

image

After reload you will see that the file is now part of svc file.

image

Cool right?. Well for now you can go and browse other blog, I will get busy with creating 20 more class file for this project. Until next time.

Masudur Rahman is out.

Saturday, October 1, 2011

Using WCF Service with Silverlight

Introduction

In one of our products, we had to use WCF service with Silverlight. While working on Silverlight and WCF, I found out some very interesting things and I feel that those are worth sharing. Whenever we want to work with Silverlight and need some kind of service communication, we would encounter those common problems. In this article, we are going to discuss a few interesting findings about WCF and Silverlight Bridge.

For the purpose of demonstration, we are going to use a demo application with some simple class. Let's say we have an expense management application and we have a client build with Silverlight. And the client communicated to server via WCF. Let's take this example to fit our explanation process.

Using WCF with Silverlight

In this section, we will see how we can use WCF service with Silverlight. I am sure every reader has a nice grip on what is WCF and how we can use it in web applications. Some of the stuff is repeated and discussed again and may sound familiar. But as we need some parts as a subset, I am discussing it again. First, we would look at the basics and then we would see some other relevant tricks and information.

The WCF Basics

WCF has three basic building blocks. Those are called A,B,C of WCF. A stands for Address, B stands for Binding and C stands for contract. In a later section, we would see the most common knowledge that is necessary to work with WCF, of course communication with Silverlight context. WCF can be hosted in several ways. Most common ones are given below:

  • Hosting in Internet Information Services
  • Hosting in Windows Process Activation Service
  • Hosting in a Windows Service Application
  • Hosting in a Managed Application

We are not going to discuss about the above hosting options in this article as those need further study, and assumes to not be the focused area of the article. I would recommend that you spend some time on MSDN or Google to learn more about WCF hosting process.

The Service Contract and Operation Contract

I am sure we all know what a service contract is, but I am still discussing it as it is a beginner article. We make any class a service contract by adding one simple class attribute "[ServiceContract]" but it's better to declare an interface first and then apply class attribute to that interface and then implement class in a derived class. Now the methods that we would want to expose as part of the service need to be decorated with a method attribute named "[OperationContract]".

Below we have a code block with an interface that has been declared as a service contract and then we have implemented a derived class from the interface to define the methods that would be invoked via clients.

Service Contract

[ServiceContract]
public interface IMoneyService
{
[OperationContract]
ServiceResponse AddExpense(Expense expense);
[OperationContract]
ServiceResponse UpdateExpense(Expense expense);
[OperationContract]
ServiceResponse DeleteExpense(Expense expense);
[OperationContract]
ServiceResponse GetExpenseByID(int expenseId);
[OperationContract]
ServiceResponse AddCategory(Category category);
[OperationContract]
ServiceResponse UpdateCategory(Category category);
[OperationContract]
ServiceResponse DeleteCategory(Category category);
[OperationContract]
ServiceResponse GetCategoryByID(int categoryId);
}

Implementation of the Contract

[AspNetCompatibilityRequirements
(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MoneyService : IMoneyService
{
public ServiceResponse AddExpense(Expense expense)
{
var response = new ServiceResponse();
using (var manager = new ExpenseManager())
{
try
{
response.Result = manager.AddExpense(expense);
response.IsSuccess = true;
}
catch (Exception exception)
{
response.ServiceException = exception;
response.IsSuccess = false;
response.ErrorMessage = "Unable to add Expense";
}
}
return response;
}

///Other method's implementation.... goes bellow
///....
}

In the above example, we didn't put down all the implementation in one method to demonstrate the idea.


The Data Contract


If we want to transfer custom data via WCF from server to client, we have to apply "[DataContract]" class attribute on the custom data type. Besides, all primitive datatypes can be used as a transferable data. Below we have added a simple class that we have used as our custom type to transfer data from service to client.


You might need to use KnownType attribute in case you have nested custom type in your data contract.

[KnownType(<span style="COLOR: blue">typeof</span>(your-custom-type))]

Below, a sample Data contract implementation is given.

[DataContract]
public class ServiceResponse
{
private string _errorMessage;
[DataMember]
public string ErrorMessage
{
get { return _errorMessage; }
set { _errorMessage = value; }
}
private object _result;
[DataMember]
public object Result
{
get { return _result; }
set { _result = value; }
}
private bool _isSuccess;
[DataMember]
public bool IsSuccess
{
get { return _isSuccess; }
set { _isSuccess = value; }
}
private Exception _serviceException;
[DataMember]
public Exception ServiceException
{
get { return _serviceException; }
set { _serviceException = value; }
}
}

ASP.NET Compatibility


This particular scenario is very useful if we host the WCF service in the IIS environment. The idea is to share the same HttpContext in service methods and inner methods so that we can access session and application data of the web application where the WCF service is being exposed.

var context = HttpContext.Current;
var path = context.Server.MapPath("~/MyPics");

if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}

var userFolder = string.Format("{0}\\{1}", path, userId);

if (!Directory.Exists(userFolder))
{
Directory.CreateDirectory(userFolder);
}

In the above example, we want to find a folder name "MyPics" where the pictures of a particular user will be saved. So we need the httpContext where the service is running.


Below, the service configuration is given. The key stuff is the tag "serviceHostingEnvironment" we have to set the attribute aspNetCompatibilityEnabled="true".

    <system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="PEM.MoneyTrackingServiceAspNetAjaxBehavior">
<enableWebScript />

</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />

<services>
<service name="PEM.MoneyTrackingService">
<endpoint address=""
behaviorConfiguration="PEM.MoneyTrackingServiceAspNetAjaxBehavior"
binding="webHttpBinding" contract="PEM.MoneyTrackingService" />

</service>
</services>
</system.serviceModel>

After that, we have to put the AspNetCompatibilityRequirements class attribute with value RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed to the desired service contract implementation. Note that this attribute cannot be added before the interface which is the contract. We have to add it before the service contract implementation.

[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements
(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MoneyTrackingService
{
[OperationContract]
public void DoWork()
{
return;
}
}

Adding Service Reference to Silverlight


Alright. We have the basics on our finger tip, now it's time to make the service workable. Here are the steps we have to do.



  • Step 1: Define Data Contract that we want to transmit via service. Add "[DataContract]" class attribute to class and "[DataMember]" property attribute to properties. If we have any enum in the DataContract we have to apply EnumMember attribute.
  • Step 2: Define interface for ServiceContract with methods, add service contract attribute. mark each method that we want to expose to OperationContract.
  • Step 3: Define a derived class for ServiceContract implementation. Add the necessary class attribute if we need ASP.NET compatibility.
    In our case, we have defined those classes and interface in a separate project named MoneyTracking.Service.
  • Step 4: Add a reference to the project where we defined the classes. If we defined all the classes and interfaces in the web project, then no worries.
  • Step 5: Add a svc file. Get rid of the "cs" file. Modify the XML for the .svc file. put down the proper service name.
     <%@ ServiceHost Language="C#" Debug="true" 
    Service="full Qualified name goes here" %>

  • Step 6: Define proper service definition in service model tag of web.config. We have defined the XML in the previous section, we can also copy from there. Note that we should at mex binding as well.
  • Step 7: Browser the service to see if everything is working fine or not.
  • Step 8: Go to the Silverlight project where we want to consume the service, right click on the project's reference node and select add Service Reference, which will bring the configure add service reference wizard. Rest of the work is self explanatory in the wizard.

When you finished adding the service, you will have a service reference node where the service will be added. Visual Studio also adds lots of code behind the scenes, an also a ServiceReferences.ClientConfig file. We will see the uses in later sections.


ServiceReferences.ClientConfig

<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>

<binding name="BasicHttpBinding_IMoneyService" maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<security mode="None" />

</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/MoneyTrackingService.svc"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IMoneyService"

contract="MoneyTrackingServiceReference.IMoneyService"
name="BasicHttpBinding_IMoneyService" />
</client>
</system.serviceModel>
</configuration>

Using the Channel Factory


So far, we have three ways to use a WCF service in Silverlight:



  • Using a service reference
  • Using chanel Factory
  • Using Client base

Below, we have explained how the chanel factory can be used to define a WCF service in Silverlight side. Note that in this case, we don't have to use any sort of reference for the service. But how? Silverlight only allows asynchronous model of service method call, so we cannot use the same OperationContract. We can copy all the classes that are DataContract as a link and use in the Silverlight project, for the service contract we have to define a new class with ServiceContract attribute. Note that the methods need to have [OperationContract(AsyncPattern = true)] method attribute. For each method in the ServiceContract in server, we have to define two methods with pre-fix "Begin" and "End" so if we have a method named "AddExpense" in server, in the client class we have to define two methods named "BeginAddExpense" and "EndAddExpense". Below, a complete code has been given for the class IMoneyService of client.


Example of AnyncPattern Contract

namespace MoneyTracking.Service
{
[ServiceContract]
public interface IMoneyService
{
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginAddExpense
(Expense expense, AsyncCallback callback, object state);

[OperationContract(AsyncPattern = true)]
IAsyncResult BeginUpdateExpense
(Expense expense, AsyncCallback callback, object state);

[OperationContract(AsyncPattern = true)]
IAsyncResult BeginDeleteExpense
(Expense expense, AsyncCallback callback, object state);

[OperationContract(AsyncPattern = true)]
IAsyncResult BeginGetExpenseByID
(int expenseId, AsyncCallback callback, object state);

[OperationContract(AsyncPattern = true)]
IAsyncResult BeginAddCategory
(Category category, AsyncCallback callback, object state);

[OperationContract(AsyncPattern = true)]
IAsyncResult BeginUpdateCategory
(Category category, AsyncCallback callback, object state);

[OperationContract(AsyncPattern = true)]
IAsyncResult BeginDeleteCategory
(Category category, AsyncCallback callback, object state);

[OperationContract(AsyncPattern = true)]
IAsyncResult BeginGetCategoryByID
(int categoryId, AsyncCallback callback, object state);

ServiceResponse EndAddExpense(IAsyncResult result);

ServiceResponse EndUpdateExpense(IAsyncResult result);

ServiceResponse EndDeleteExpense(IAsyncResult result);

ServiceResponse EndGetExpenseByID(IAsyncResult result);

ServiceResponse EndAddCategory(IAsyncResult result);

ServiceResponse EndUpdateCategory(IAsyncResult result);

ServiceResponse EndDeleteCategory(IAsyncResult result);

ServiceResponse EndGetCategoryByID(IAsyncResult result);
}
}

Example of chanelFactory


Now we have defined the interface. It's time to build the service using ChanelFactory. Below a simple code is given to demonstrate how we can create a service client and invoke a method.

private void UsingChanelFactory(object sender, RoutedEventArgs e)
{
var basicHttpBinding = new BasicHttpBinding();
var endpointAddress = new EndpointAddress
("http://localhost/MoneyTrackingWeb/MoneyTrackingService.svc");
var moneyService = new ChannelFactory
<moneytracking.service.imoneyservice>

(basicHttpBinding, endpointAddress).CreateChannel();
moneyService.BeginAddCategory
(new MoneyTracking.Common.Category(), ASyncronousCallBack, moneyService);
}

private void ASyncronousCallBack(IAsyncResult ar)
{
if(ar.IsCompleted)
{
MoneyTracking.Common.ServiceResponse serviceResponse =
((MoneyTracking.Service.IMoneyService)ar.AsyncState).EndAddCategory(ar);
if(serviceResponse.IsSuccess)
{
//do your work here
}
}
}

Making Synchronous Call


By default, the methods that we have in service client in Silverlight are asynchronous method calls. A simple code is given below to demonstrate the idea. A Client has been initiated and then a completed event has been subscribed to and then call the asynchronous method.


Example of Asynchronous call

public void AddExpense()
{
var client = new MoneyServiceClient();
var category = new Category();
//fill category attributes here
client.AddCategoryCompleted += ClientAddCategoryCompleted;
client.AddCategoryAsync(category);
}

void ClientAddCategoryCompleted(object sender, AddCategoryCompletedEventArgs e)
{
ServiceResponse serviceResponse = e.Result;
if(serviceResponse.IsSuccess)
Categories.Add((Category) serviceResponse.Result);
}

Example of Synchronous Call


In some scenarios, we need to have a synchronous call, since Silverlight does not allow the synchronous call we can always bypass and use the same system in such a way so that we have a synchronous call, the idea is to stop the current code execution until the completed event is been fired.


We have defined a custom class AsyncCallStatus<T> a custom status which will be passed via Async Method. But the magic class which make all this possible is "AutoResetEvent", we have the current execution freeze using _autoResetEvent.WaitOne(). When in completed event, we get the result back we simply set the  _autoResetEvent.Set(); which again resumes the process.


Note that in Silverlight 4, we have to use ThreadPool.QueueUserWorkItem(MethodNameGoesHere); to start the process otherwise AutoResetEvent.WaitOne() will stop the current tread execution, and completed event won't fire at all, in fact call the server will never be invoked. Below, we have put down the complete listing of a method called synchronously.

private void SyncronousCall(object sender, RoutedEventArgs e)
{
ThreadPool.QueueUserWorkItem(AddExpenseInServer);

}

private void AddExpenseInServer(object state)
{
Expense addedExpense = AddExpense();
Dispatcher.BeginInvoke(() =>
{
StatusMessage.Content = "Expense is been Added";
Expenses.Add(addedExpense);
});
}

private Expense AddExpense()
{
var asyncCallStatus = new AsyncCallStatus<AddExpenseCompletedEventArgs>();
var client = new MoneyServiceClient();
client.AddExpenseCompleted += ClientAddExpenseCompleted;
client.AddExpenseAsync(new Expense(),asyncCallStatus);
_autoResetEvent.WaitOne();
if (asyncCallStatus.CompletedEventArgs.Error != null)
{
throw asyncCallStatus.CompletedEventArgs.Error;
}
var serviceResponse = asyncCallStatus.CompletedEventArgs.Result;
if (serviceResponse.IsSuccess)
{
return serviceResponse.Result as Expense;
}
else
return null;
}

void ClientAddExpenseCompleted(object sender, AddExpenseCompletedEventArgs e)
{
var status = e.UserState as AsyncCallStatus<AddExpenseCompletedEventArgs>;
if (status != null) status.CompletedEventArgs = e;
_autoResetEvent.Set();
}

private readonly AutoResetEvent _autoResetEvent = new AutoResetEvent(false);

public class AsyncCallStatus<T>

{
public T CompletedEventArgs { get; set; }
}

Cross Domain Service Call


By default, Silverlight can invoke any method from the originator site. So if the Silverlight component is invoked from "http://mytestside.com/silverlightTestPage.aspx", the component can call any WCF service hosted in "http://mytestside.com/testservice.svc". But let's say we want to call a WCF service which is hosted on "http://myotherside.com/otherservice.svc", we would encounter an error something like this:


The way to archive cross domain service call in Silverlight is pretty simple in fact. We have to put two XML files named "clientaccesspolicy.xml" and "crossdomain.xml" file in root folder of the service. So if we have a service named "http://mytestserver.com/myservice.svc", we need to put down those two files in "http://mytestserver.com/clientaccesspolicy.xml". Both the file and its content are given below.


clientaccesspolicy.xml

<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
<cross-domain-access>

<policy>
<allow-from http-request-headers="SOAPAction">
<domain uri="*"/>
</allow-from>
<grant-to>

<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>

</access-policy>

crossdomain.xml

<?xml version="1.0" ?>
<!DOCTYPE cross-domain-policy SYSTEM
"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-http-request-headers-from domain="*" headers="SOAPAction,Content-Type"/>

</cross-domain-policy>

You can simulate the crossdomain class in the local environment also. For this, modify the host file:

127.0.0.1 testserver.com 
127.0.0.1 testclient.com

Now you can run your project from testclient and service will be consumed from testserver.


Transfer Large Data


In this section, we would see how we can customize the WCF service so that we can transfer large amount of data. We often encounter an error while communicating that max limit of array size has been crossed or perhaps an exception that endpoint not found, it's simply because there could be a size issue. Note that the endpoint not found exception can occur for many reasons.


To overcome the limitation, we need to customize the basicHttpBinding. We have to define a bindings section under <system.servicemodel> and under that we would customize the basicHttpBinding. For this, we have to create another sub section under binding named "<basicHttpBinding>". Here we can put multiple bindings and of course we can set all the advanced attributes.


Below, we have put down both client and server configuration.


Service Configuration on Server

<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"
aspNetCompatibilityEnabled="true"/>

<bindings>
<basicHttpBinding>
<binding name="MoneyTrackingServiceBinding" maxBufferPoolSize="2147483647"
maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">

<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647">
</readerQuotas>

</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="MoneyTrackingServiceBehavior">

<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>

</behaviors>
<services>
<service name="MoneyTracking.Service.MoneyService"
behaviorConfiguration="MoneyTrackingServiceBehavior">
<endpoint address="" binding="basicHttpBinding"

bindingConfiguration="MoneyTrackingServiceBinding"
contract="MoneyTracking.Service.IMoneyService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>

</service>
</services>
</system.serviceModel>

Here under service, we have added behaviorConfiguration to "" in service and under that in endpoint section we have also set "bindingConfiguration" to our desired configuration name.


Client Side Configuration

<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="MoneyTrackingServiceBinding" maxBufferSize="2147483647"

maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" />
</basicHttpBinding>
</bindings>
<client>

<endpoint address="http://localhost/MoneyTrackingWeb/MoneyTrackingService.svc"
binding="basicHttpBinding"
bindingConfiguration="MoneyTrackingServiceBinding"
contract="MoneyTrackingServiceReference.IMoneyService"
name="BasicHttpBinding_IMoneyService" />

</client>
</system.serviceModel>
</configuration>

The above service configuration section is for the client, note that both server and client binding configuration name should match and the value should also match. In client service configuration fine we don't have to define the "readerQuotas", infact that would give you an exception. And we don't need behaviour configuration. You guys can also copy and paste the above configurations in your context, while doing so you have to fix the contract names and service names.


Summary


In this short article, we have seen the basics of WCF service. We have discussed only those parts that are necessary to build a simple WCF service that can be consumed by a Silverlight client. Then we have seen two ways of creating a client proxy for Silverlight. We can add service reference and also can use chanel factory to build client. Chanel factory gives more control over client proxy.


After that, we have seen how we can use some small policy XML files to extend the service so that it can be consumed via Silverlight components running in a different domain. Lastly, we have seen how we can customize the binding to support large amount of data transfer. There are lots of challenges in real life development regarding WCF and Silverlight. I hope to put together more content in a future article.


References



History



  • 29th September, 2011: Initial version

Monday, February 9, 2009

A Beginner's Guide for "Using WCF in JavaScript using Asp.net Ajax"

Contents

    1. Development Platform
    2. Introduction
    3. Using Ajax-Enabled WCF Service item template
    4. Using Service Interface defined in a class library
    5. Configure the Web Application To Use TODO Service
    6. Using Service In JavaScript
    7. Summery
    8. References

Development Platform

  • Visual Studio 2008 SP1
  • Dot.net Framework 3.5 SP1
  • Asp.net Ajax
  • IIS7 or VS Integrated Web Server [WCF and SVS file configured]
  • Windows Vista

Introduction

WCF (Windows communication foundation) added lot of new capability in Microsoft application development platform, particularly in case of how applications communicate to each other. In this article we are going to see how WCF can be used directly from clients JavaScript code. Its a very cool future provided by asp.net Ajax. In this article we are not going to cover every theory about WCF internals rather we only remained focused on how to use the service directly from JavaScript. So no behind the scene stuff of how asp.net or dot net runtime manage this feature.

To demonstrate the ideas and facts we are going create a demo solution with two projects. So with no time waste create a blank solution and save it. Now add a class library project to the solution. Name the class library as "ServiceLibrary". Now Add another web application project to the solution and name it as WEBUI. We are going to see two approach to add WCF service that can be consumed from JavaScript.

  1. Using Ajax-Enable WCF Service item template
  2. Using Service Interface defined in a class library

Using Ajax-Enabled WCF Service item template

Its a very strait forward way to use WCF service in JavaScript. Right Click on the web application project and select add new item. Select Ajax-Enabled WCF Service item template name it as "HelloWorldService.svc" and click ok. Wizard will add a HelloWorldService.svc file to solution as expected. This file have a code behind file as well. If you open the HelloWorldService.svc in xml file editor you will see a markup like this

<%@ ServiceHost Language="C#" Debug="true" Service="WebUI.HelloWorldService"

CodeBehind="HelloWorldService.svc.cs" %>










And if you open the code behind file you will se code some thing like this




namespace WebUI
{
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class HelloWorldService
{
// Add [WebGet] attribute to use HTTP GET
[OperationContract]
public void DoWork()
{
// Add your operation implementation here
return;
}

// Add more operations here and mark them with [OperationContract]
}
}



Visual Studio 2008 automatically add the necessary configuration for you in the web.config file so no need to configure any thing in web.config. Now go ahead and add a method like HelloWorld() which returns a string "HelloWorld" and add [OperationContract] method attribute to the method. we will explain what the attributes are for later in this article. Now add a page to web application project and name it as "HelloWorldTest.aspx". Drag drop a script manager item from visual studio tool box. Inside the ScriptManager tag add service reference of the service. Bellow a example code is give.




<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="~/HelloWorldService.svc" />
</Services>
</asp:ScriptManager>



Now add a button and a textbox to the page and on button click use a JavaScript function to call the service. when you will write the service call function Visual Studio 2008 Html Editor will provide intellisense to write necessary function call. Full code of html part is give bellow.




<form id="form1" runat="server">
<div>
<script language="javascript" type="text/javascript">
function GetValueFromServer() {
HelloWorldService.HelloWorld(onSuccess, onFailure);
}

function onSuccess(result) {
document.getElementById('txtValueContainer').value = result;
}

function onFailure(result) {
window.alert(result);
}
</script>
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="~/HelloWorldService.svc" />
</Services>
</asp:ScriptManager>
<input id="btnServiceCaller" type="button" value="Get Value" onclick="GetValueFromServer()"; />
<input id="txtValueContainer" type="text" value="" />
</div>
</form>



Note that when calling the service we have passed two method one is for callback and other one is for error callback. If we need to pass any parameters to the function parameters will go first and then the call back. So if we have a function name getvalue which take two string parameters as argument we are going to call the function as [NameSpaceName].[ServiceName].getvalue("value one","value two",on_success,on_error); where on_sucess and on_error are callback and error callback respectively.



Using Service Interface defined in a class library



So we have looked how to use a Ajax-Enabled WCF Service using item template. Now we are going to see more traditional WCF Service implementation and we are also going to see how we can expose this service for Asp.net Ajax. when we created the class library project by default its not added with the service model and runtime serialization support which is necessary to run WCF. So we got to add the necessary service references. so go ahead and right client on class library project and select add reference and then select the references.




  1. System.Runtime.Serialization


  2. System.ServiceModel





In this phase we are going to use a TODO Management example to demonstrate the whole idea. Add A Service Based Database and then create a TODO Table with ID,Description and Status Field. Now Add A LinkToSQL class file from item template. Drag Drop the table TODO from database to link to SQL Class File designer. Now Click on the designer surface and from property window change the Serialization Mode to Unidirectional. Now our designer generated Link to SQL classes are ready to use for WCF. If you want to use custom user defined types you must set [DataContract] class attribute to your class and you must add [DataMember] property attribute to each property of the class you want to expose to WCF.



Now we are going to add a service interface like this




namespace ServiceLibrary
{
[ServiceContract(Namespace = "ServiceLibrary")]
interface IToDoService
{
[OperationContract]
ToDo GetToDo(long ID);
[OperationContract]
ToDo AddToDo(ToDo toDo);
[OperationContract]
bool DeleteToDo(ToDo todo);
[OperationContract]
ToDo UpdateToDo(ToDo todo);
[OperationContract]
List<ToDo> GetAllToDo();
}
}



Note that we have mentioned a name space in side the ServiceContract interface Attribute. This is very important. we are going to use this name as the service name in side the JavaScript to access the services. Now we are going to add the implementation to this service interface the code is given bellow. Please note that in bellow code i have used [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] class attribute, this is must requirement for exposing the service as asp.net Ajax enabled WCF service.




namespace ServiceLibrary
{
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ToDoService : IToDoService
{
#region IToDoService Members
public ToDo GetToDo(long ID)
{
DataClasses1DataContext context = new DataClasses1DataContext();
var toDos = from p in context.ToDos
where p.ID == ID
select p;
List<ToDo> listTodos = toDos.ToList();
if (listTodos != null && listTodos.Count > 0)
{
return listTodos[0];
}
else
{
return null;
}
}

//all the methods is not shown

#endregion
}
}



Configure the Web Application To Use TODO Service



Now that we have defined all the necessary stuff to run our TODO Application its time to expose the service to the client as a asp.net Ajax enabled WCF service. For this we are going to add a Ajax-Enabled WCF Service .svc file. And we will get rid of the code behind file. or we can add a xml file or text file and then rename it to ToDoService.svc. Open it with xml editor and put directive like bellow



<%@ ServiceHost Language="C#" Debug="true" Service="ServiceLibrary.ToDoService" %>



Now we are going to put necessary configuration to run this service in web.config, the code is given bellow



 




<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="AspNetAjaxBehavior">
<enableWebScript />
</behavior>
<behavior name="WebUI.HelloWorldServiceAspNetAjaxBehavior">
<enableWebScript />
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<services>
</service>
<service name="ServiceLibrary.ToDoService">
<endpoint behaviorConfiguration="AspNetAjaxBehavior" binding="webHttpBinding"
contract="ServiceLibrary.IToDoService" />
</service>
<service name="WebUI.HelloWorldService">
<endpoint address="" behaviorConfiguration="WebUI.HelloWorldServiceAspNetAjaxBehavior"
binding="webHttpBinding" contract="WebUI.HelloWorldService" />
</service>
</services>
</system.serviceModel>



Now right click on the file and select view in browser to see the service is up and running well. Few things must be mentioned before moving to next phase. You must add serviceHostingEnvironment and set its aspNetCompatibilityEnabled="true" to be able to use wcf service in asp.net with its features like httpContext, Session etc.



Using Service In JavaScript



Now use the service just like HelloWorldService we have previously used. Bellow I have given few example code to make things clear. Bellow the ScriptManager Mark up is given. Note that we have added a clientServiceHelper.js file. We have put all the client to WCF communication JavaScript functions in that file.




<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Path="~/Script/ClientServiceHeler.js" />
</Scripts>
<Services>
<asp:ServiceReference Path="~/ToDoService.svc" />
</Services>
</asp:ScriptManager>



We have used asp.net Ajax client side object oriented model to write bellow JavaScript client code which are the part of clientServiceHelper.js.




Type.registerNamespace("ServiceClients");

ServiceClients.ToDoClient = function() {
}

ServiceClients.ToDoClient.prototype = {

AddToDo: function(todo, callback, errorCallBack) {
ServiceLibrary.IToDoService.AddToDo(todo, callback, errorCallBack);
},

DeleteToDo: function(todo, callback, errorCallBack) {
ServiceLibrary.IToDoService.DeleteToDo(todo, callback, errorCallBack);
},

UpdateToDo: function(todo, callback, errorCallBack) {
ServiceLibrary.IToDoService.UpdateToDo(todo, callback, errorCallBack);
},

GetAllToDo: function(callback, errorCallBack) {
ServiceLibrary.IToDoService.GetAllToDo(callback, errorCallBack);
},

dispose: function() {
//disposed
}
}

ServiceClients.ToDoClient.registerClass('ServiceClients.ToDoClient', null, Sys.IDisposable)

// Notify ScriptManager that this is the end of the script.
if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();



Summery



In this article we have seen how we can use Ajax-Enable WCF Service item template. The we have seen how we can use a service interface based wcf service. we have also seen how to configure web.config to use the services, last of all we have seen how we can add service reference in ScriptManager. Few things must be mentioned before ending this article we can also add service reference in c# code below a simple code example is given.




ScriptManager manager = ScriptManager.GetCurrent(Page);
ServiceReference reference = new ServiceReference("ToDoService.svc");
manager.Services.Add(reference);



If the beginners encounter problem of not understanding any particular portion of the article please drop a message. You can learn the ABC of WCF here. If you have any difficulty configuring WCF in IIS please see this article here.



References




  1. http://msdn.microsoft.com/en-us/library/aa480190.aspx [WCF - ABC]


  2. http://munna.shatkotha.com/Blog/post/2008/07/08/Install-WCF-Aspnet-in-IIS7.aspx [Configure WCF]


  3. http://msdn.microsoft.com/en-us/library/bb514961.aspx [Expose WCF to Client Script]


  4. http://msdn.microsoft.com/en-us/library/bb763177.aspx [Configure WCF in asp.net Environment]


  5. http://msdn.microsoft.com/en-us/library/bb398785.aspx [Web Service in asp.net]


  6. http://peterkellner.net/2008/09/14/wcf-web-service-json-vs2008/ [Article that discussed the same concept]

Thursday, July 17, 2008

A beginner's guide to WCF in XBAP

Contents

  1. Development Platform
  2. Introduction
  3. Prepare the stage
  4. Creating the projects and necessary files
  5. Configure the WCF for XBAP
  6. Consume WCF Service from XBAP
  7. Debugging WCF Service
  8. Deploying your solution
  9. Using the WsHttpBinding configuration
  10. A quick discussion on Data Transfer Limit
  11. Conclusion

Development Platform

  1. Visual Studio 2008
  2. Dot net framework 3.5
  3. IIS 5.1~7
  4. IE7/Firefox 2.x
  5. Asp.net 2.0
  6. Windows vista/xp

Introduction

Windows presentation foundation in short, wpf is Microsoft’s new user interface technology. Wpf introduced with the release of dot net framework 3.0. Wpf comes with lot of promises, for example, it can be used to show very rich graphics centric 2D and 3D models. WPF uses the client machines graphics capability to full extent. For more information about wpf please visit www.windowclient.net. In this article we will discuss about using wpf in web! It sounds a very strange wish to accomplish. But it’s true; wpf can be used in browser. This special browser centric package called WPF Browser Application. XBAP stands for XAML Browser Application which is the eventual output of WPF browser application. The main purpose of XBAP is to introduce a fat client application which runs on client side and provide the user an ease of desktop application in web. XBAP use the resources of client machine, that’s why .net framework must be installed in client machine to run WPF browser application. Even though XBAP uses client machine's resource and memory but it run in a sandbox environment, this mode of sandbox called the partial trust mode. XBAP in dot net 3.5 have few improvement over 3.0. Using WCF in partial trust mode is one of them. In this article we will see the implemention of WCF service in XBAP partial trust mode.

Prepare the stage

Learning by example is always a very good way of learning new things, that’s why we are going to develop a simple XAML browser application in which we will display a to-do list and notes of a user and of course going to use WCF to communicate with our data layer. Few things must be clear before jumped in to the stage. In partial trust mode XBAP can consume WCF service from the site of origin only. So we cannot use a cross domain WCF service from XBAP. Another restriction we have in case of WCF binding configuration, we can use only BasicHttpBinding and WSHttpBinding in partial trust mode. For retrieving, creating, deleting and updating tasks we will use BasicHttpBinding. On the other hand to retrieving, creating, deleting and updating notes we will use WsHttpBinding. Let’s go through the projects templates first. We will of course create a WPF Browser application Project, Next we are going to create a WCF Service Application Project and Finally we are going to develop a simple web site (web application project of vs2008) where our browser application will be hosted. We will use a SQL express edition database in data service layer that is a “tododata.mdf” we will construct our own user base and user validation. WPF browser application will forward all request to a WCF web service. WCF service will do business logic validation and retrieve data from data access layer. Bellow here is a simple diagram to presented how the application architecture will be.

XBAP-WCF.JPG

Creating the projects and necessary files

By now we already know that we are going to create three different projects. So let’s get started, we will start with creating a blank solution for our convenience. Go ahead and create a blank solution in vs2008 and save the solution to your convenient place with a convenient name. Now add a new WPF Browser application project to the solution. Then add a new WCF Service Application to the solution and lastly add a new web application project to the solution, that concludes the projects creation process. To save the data we will use sql express database, so let's go ahead and add a Sql server database file and name it to your convenient. Then create necessary tables for task, notes and users. Next we need a simple mechanism to retrieve, save and to modify data from the database, for this we are going to use LINQ. Add a dbml file to the wcf service project drag and drop the data tables from database explorer to the dbml. Next we have to define our service interfaces. We will have two services in the same wcf project one for notes (INoteService) and other one for tasks (ITaskService).

Projects.jpg

Configure the WCF for XBAP

If you are new to wcf I would like to suggest you to spend some time on msdn library learning wcf. So now we have our wcf service application “WcfService”. Now we are going to configure our wcf service so that our XBAP can consume this service. By default when users add a wcf service, visual studio automatically configure two end points for the service. We are going to modify the binding configuration for our service so that XBAP can communicate with it. Visual studio 2008 provides a nice tool to edit wcf service configurations, and the tool is “WCF Service Configuration Editor” we will edit service configurations with this tool, you can also modify the web.config manually to setup appropriate markup under service model section. By default when you right click on web.config of service no edit configuration tool is shown, to make it show first we have to run it from the tools menu of visual studio 2008. Click on the tools menu of the visual studio 2008 and click on wcf configuration menu. Now you can close the tool. Once you have opened the tool it will be available for the current session. Now right click on the web.config file of the wcf service project and select “Edit WCF configuration”. Configuration editor will pop up with the entire configuration that is defined in the web.config. In configuration editor on the left side you will find a tree with service information’s populated. Expand the services node and you will see a node named “Endpoints”. By default under endpoints node there are two pre-added endpoints, one endpoint configured with WsHttpBinding and another is configured with MaxHttpBinding. Now select the endpoint that is configured with WsHttpBinding. After selecting the endpoint, properties of that end point will be shown in property editor on the right side. Change the binding property to WsHttpBinding to BasicHttpBinding. Click on file and save and close the tool.

ServiceConfigurationEditor.jpg

Now it’s time to host the service to a location so that our application can consume it from a fixed location. When we added the wcf service application by default visual studio 2005/2008 configure the service to run on visual studio development server. We are going to modify this to run from IIS. For this right click on wcf service project and select properties. After project properties window popup, navigate to web tab and change the server configuration under servers section from “Use Visual Studio Development server” to “Use IIS Web server” after that you need to click on create virtual directory button to finish the process. Now save the project. And you are all done configuring the service for you xbap. If you are in windows vista you can encounter with few errors, to overcome the problems you must run visual studio with “run as administrator” mode.

Consume WCF Service from XBAP

The hard part is now over, just add a service reference like normal procedure i.e. right click on project select “add service reference “ after add service reference window popup, click on discover button. You will see the service will be found and URL will be added to the address textbox. Click okay and you are all done.
Because of the previous action that is performed appropriate mark up will be added in the app.config under service model configurations section. The markup that is added look like this


<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService1" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://munna.kaz.com.bd/TODO.SERVICE/Service1.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1"
contract="TodoServiceReference1.IService1" name="BasicHttpBinding_IService1" />
</client>
</system.serviceModel>


Debugging WCF Service



While developing XBAP sometimes developers need to debug the
application. Developer may needs to investigate what data is received
to the service and what data is transmitted from the service. Well,
since WCF works in XBAP only in partial trust mode it’s become a little
bit difficult, but not yet that much difficult. While debug from visual
studio 2008 we can set the “trust mode” to full trust. You can set
trust mode to full trust from security tab of project properties. This
will enable your WPF Project to debug in application in development
environment. But while deployment you must change trust mode back to
partial trust otherwise you will encounter with trust not granted error.


Deploying your solution



First of all developer needs to set XBAP’s security mode to partial
trust. In publish wizard first step is to specify where you want to
publish the binary. Browse and select a folder as convenience. Click
next will guide the user to select next option which is selection of
how the user will install the application. In this screen developer
needs to select “from a web site” option and specify the location of
the web site. Browse or put down the location of the web site. While
deploying your solution you must be careful about the deployment URL
and the URL or the WCF service that is defined in the app.confiq of the
XBAP. In app.config let’s say you have an end point with
http://localhost/wcfservice you should also put your XBAP deployment
URL as http://localhost/xbaphost. If you in app.config you have
localhost but you browse as http://{pcname}/xbaphost things won’t work
and you will end up with a code access security violation exception. So
you must remain consistent about the URL of WCF Service, XBAP Host, and
the URLS.



PublishWizard.jpg


Using the WsHttpBinding Configuration



You can also use WsHttpBinding to communicate with the wcf also, but
few things need to configure to ensure that you don’t suffer from code
access security exception. If you want to use WsHttpBinding you don’t
have to create any new binding. Visual studio 2008 by default creates
two end points for a wcf service application one is WsHttpBinding and
another is MaxHttpBinding. What developer needs to do is to configure a
new binding configuration. To accomplish this edit the web.config of
WCF Service application. In default window you will see first endpoint
is configured with WsHttpBinding and under the endpoint a default
binding is configured, it should say “(Default) Click to Create” just
click to create new binding configuration and configure it not to use
reliable session and security mode to None. Bellow the service mode
configuration is provided for better understanding; eventually WCF
Configuration Editor will generate this sort of markup.




<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="NewBinding0" messageEncoding="Text">
<reliableSession enabled="false"/>
<security mode="None">
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="TESTWCF.Service1Behavior" name="TESTWCF.Service1">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="NewBinding0"
contract="TESTWCF.IService1">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="TESTWCF.Service1Behavior">
<!-- To avoid disclosing metadata information, set the value below to false and remove


the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="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>



Make sure that you set enable reliable session to “false” and set
security mode to “none” in both client endpoint and service’s endpoint
binding configuration. Otherwise XBAP can suffer from code access
security exception.


A quick discussion on Data Transfer Limit



XBAP to WCF communication data transfer have few limitations in data
transfer size. If you are transferring huge list of objects that
exceeds the size specified in max buffer size and max receive size in
web.config application will cause receive limit exceed exception. You
can increase the size of the maxBufferSize and maxReceivedMessageSize
from web.config in binding configuration section of service, but
increasing its size will cause the application suffer from code access
permission exception. So a very straight forward way to escape from
this issue is to make your service in such a way so that you don’t
return data that exceed the size limit. And if you have huge data to
transfer, change the service contract in such a way, so that you can
transfer data in multiple requests, and in every request size limit
should remain under the maxBufferSize.


Conclusion



In few cases you will see that service is taking a little bit time
to respond to your request, and that can cause your application to
become irresponsive for few seconds. To escape from this problem you
can use background process to call the WCF service, and display a wait
screen to the user and hide the wait screen after the process finished
execution. That concludes a beginner introduction to xbap to wcf
communication.