Introduction

Hello everyone! This is my first blog on WCF and I hope that you like it.

Today, I will talk about how to implement heart beat mechanism in WCF, so that whenever client is not alive, our WCF service detects it and kills its long running process and saves the server resources for other clients.

Background

Basic knowledge of WCF is required.

Using the Code

IMHO, I think there is no easy way to detect client has been closed or client is abruptly killed somehow.

Now, I am presenting one scenario and the problem in it and at last, the solution for it.

Scenario

Suppose there is one service which takes lots of time to complete, say 1 hour. And in-between, the client of WCF service gets killed.

Problem

Then the WCF service will continue to run till the whole method completes its execution, it means full 1 hour. WCF service does not have mechanism to stop its execution when client is no longer active or alive. It will waste huge server resource and will keep server busy in case resource is scarce on server side.

Solution

Suppose we have a method called “DoWork” that will take 1 hour to complete its execution.

Hide   Copy Code
[ServiceContract]
public interface ILongRunningService
{
[OperationContract]
Output DoWork();
}

Now to resolve the problem statement, we have to refactor this method into the below code snippet.

Hide   Copy Code
[ServiceContract]
public interface ILongRunningServiceV2
{
[OperationContract]
void StartDoWork(); [OperationContract]
Status ContinueWorkAndGetStatusFromServer(); [OperationContract]
Output GetFinalDoWork();
}

Now the method “DoWork” is divided into two parts, one is “StartDoWork” and the second is “GetFinalDoWork”.

The client will now call the first method “StartDoWork” and return immediately, “StartDoWork” will spawn a thread for its execution.

Then client will call “ContinueWorkAndGetStatusFromServer” continuously in while loop with wait (Thread.Sleep) of 1 second. This is required because it will keep the server informed that client is still connected to WCF Service and “DoWork” method execution should not stop. In case client does not call this method “ContinueWorkAndGetStatusFromServer”, then service after few elapsed seconds will stop the execution of “DoWork”.

In case client keeps calling this method and method “DoWork” completes its execution, then the client will call “GetFinalDoWork” to fetch the result from the service.

This implementation is also called heart beat implementation.

Now you can see the code snippet below and download the source code.

And this is the original implementation of method “DoWork”.

Hide   Copy Code
public class LongRunningService : ILongRunningService
{
public Output DoWork()
{
var builder = new StringBuilder();
for (int count = 0; count < 10; count++)
{
builder.Append("Count: " + count);
Thread.Sleep(1000);
}
return new Output(builder.ToString());
}
}

Now, we have created one SessionManger class for managing the session of active client.

Whenever any client connects to our service, it will go through the SessionManager class which will maintain the object of ServiceProvider.

ServiceProvider is our new refactored implementation of method “DoWork”.

Hide   Shrink   Copy Code
public class ServiceProvider
{
private Output _resourceOutput;
private readonly Status _status;
private volatile bool _shouldDisconnect = false;
private Timer _timer;
private DateTime _clientDateTime; public ServiceProvider()
{
this._status = new Status()
{
Message = "Initialized",
OperationStatus = OperationStatus.None
};
} public void StartDoWork()
{
TimerCallback timerCallback = StopActivity;
_clientDateTime = DateTime.Now;
_timer = new Timer(timerCallback, null, 2000, 2000);
Task.Factory.StartNew(this.RunActivity);
} public Status ContinueProcessingAndGetStatus()
{
_clientDateTime = DateTime.Now;
return this._status;
} public Output GetFinalDoWork()
{
if (this._status.OperationStatus == OperationStatus.Ready)
{
return this._resourceOutput;
}
else
{
throw new Exception("Exception");
}
} private void RunActivity()
{
this._status.OperationStatus = OperationStatus.Working; var builder = new StringBuilder(); for (int count = 0; count < 10; count++)
{
if (_shouldDisconnect)
break;
builder.Append("Count: " + count);
Thread.Sleep(1000);
Debug.WriteLine(count);
this._status.Message = count.ToString();
} this._status.OperationStatus = OperationStatus.Ready;
_resourceOutput = new Output(builder.ToString());
} private void StopActivity(object state)
{
TimeSpan span = DateTime.Now - _clientDateTime;
if (span > new TimeSpan(0, 0, 7))
{
this._timer.Dispose();
_shouldDisconnect = true;
}
}
}

This is a SessionManager class.

Hide   Shrink   Copy Code
public static class SessionManager<TSessionHandler> where TSessionHandler
: new()
{
private static readonly ConcurrentDictionary<string, TSessionHandler>
SessionHandlers = new ConcurrentDictionary<string, TSessionHandler>(); private static readonly object SyncObject = new object(); public static TSessionHandler GetSession()
{
var sessionId = OperationContext.Current.SessionId;
if (SessionHandlers.ContainsKey(sessionId))
{
return SessionHandlers[sessionId];
}
else
{
lock (SyncObject)
{
TSessionHandler handler = new TSessionHandler();
SessionHandlers.TryAdd(sessionId, handler);
return handler;
}
}
}
}

This is client code, the method “WithNormalService” is an old way of calling and method “WithVersion2Service” is a new way of calling service.

Hide   Shrink   Copy Code
static void WithNormalService()
{
LongRunningServiceClient client = new LongRunningServiceClient();
var result = client.DoWork();
Console.WriteLine(result.FinalValue);
} static void WithVersion2Service()
{
LongRunningServiceV2Client client = new LongRunningServiceV2Client();
client.StartDoWork();
string serviceMsg = string.Empty;
Status status = client.ContinueWorkAndGetStatusFromServer(); Console.WriteLine(status.OperationStatus);
do
{
if (!string.IsNullOrEmpty(status.Message))
{
if (!serviceMsg.Equals(status.Message))
{
serviceMsg = status.Message;
Console.Out.WriteLine(status.Message);
}
} Thread.Sleep(500); status = client.ContinueWorkAndGetStatusFromServer(); } while (status.OperationStatus != OperationStatus.Ready); ServiceReferenceV2.Output image = client.GetFinalDoWork(); Console.WriteLine(image.FinalValue);
}

Earlier, this was the flow of calling between client and service.

Client ---> DoWork

Now after the implementation of Heartbeat in WCF Service, this is the new way of calling WCF Service.

Client ---> StartDoWork

Client ---> ContinueWorkAndGetStatusFromServer in a while loop till it get Operation Status Ready, then it will call GetFinalDoWork.

Client ---> GetFinalDoWork

Point of Interest

One improvement point in this code is to remove the dead client references from the dictionary in SessionManager class.

Detecting Client Connection in WCF Long Running Service (Heartbeat Implementation) z的更多相关文章

  1. wcf和web service的区别

    1.WebService:严格来说是行业标准,不是技术,使用XML扩展标记语言来表示数据(这个是夸语言和平台的关键).微软的Web服务实现称为ASP.NET Web Service.它使用Soap简单 ...

  2. WCF和Web Service的 区(guan)别(xi)

    参考文献:http://social.microsoft.com/Forums/zh-CN/c06420d1-69ba-4aa6-abe5-242e3213b68f/wcf-webservice 之前 ...

  3. ORA-12518,TNS:listener could not hand off client connection

    前几天在启动应用的时候,在控制台抛出了此异常信息!很明显是数据库方面的问题,不过具体是什么问题哪?百度了一下,网上关于此问题的信息还是有比较多,从异常的提示中我们也能看到是具体是和客户端的连接相关的问 ...

  4. 本地运行项目成功 ,但在服务器运行程序就会报Failed to establish a new connection: [Errno -2] Name or service not known

    equests.exceptions.ConnectionError: HTTPSConnectionPool(host=): Max retries exceeded with url: /appa ...

  5. 扩展Wcf call security service, 手动添加 Soap Security Head.

    有次我们有个项目需要Call 一个 Java 的 web service, Soap包中需要一个 Security Head <soapenv:Header> <wsse:Secur ...

  6. Entity Framework + WCF REST JSON Service

    利用EF 和WCF 建立一个REST JSON Service. 首先我们要下载一个Visual Studio 的Template 叫 "ADO.NET C# POCO Entity Gen ...

  7. WCF - Versus Web Service

    There are some major differences that exist between WCF and a Web service which are listed below. 这里 ...

  8. WCF: Retry when service is in fault state.

    Service Host: using System; using System.Configuration; using System.ServiceModel; using System.Serv ...

  9. WCF宿主Window Service Demo

    尝试了下将服务寄宿在window 服务上.具体步骤如下 整个解决方案截图 一.创建window 服务 Wcf.WinService namespace Wcf.WinService { public ...

随机推荐

  1. SQL端通过脚本判断文件夹是否存在 并创建

    做数据库备份作业的时候..想按日期建立文件夹.. 首先要判断文件夹是否存在 ) --路径 ) --日期 例如: 20171011 SET @DATE=CAST(DATEPART(YYYY,GETDAT ...

  2. 对接京东jos遇到的坑 记录一下。方便查询

    坑很多,有一些忘记了.文档乱的很,有问题可以私信我一下我看能不能想起来. 坑一.添加商品接口. {"error_response": {"code":" ...

  3. ViewData与ViewBag的区别

    本文导读:在asp.net mvc程序设计中,传递数据常常会用到viewdata.viewbag.ViewData是一个字典集合,通过key值读取对应的value:ViewBag是动态类型,作用和Vi ...

  4. ie8兼容总结

    ie兼容总结 1.页面必须编写规范 doctype 必须申明,否则会让浏览器出现怪异模式呈现,我记得一次是页面没有写doctype,样式的继承也会有问题,明明body里面写了字体样式12px,页面ta ...

  5. SQL Cookbook—字符串

    1.遍历字符串2.计算字符在字符串中出现的次数3.从字符串中删除不需要的字符4.将字符和数字数据分离5.判别字符串是不是字母数字型的6.提取姓名的大写首字母缩写7.按字符串中的部分内容排序8.按字符串 ...

  6. 【百度之星2014~复赛)解题报告】The Query on the Tree

    声明 笔者最近意外的发现 笔者的个人网站http://tiankonguse.com/ 的很多文章被其它网站转载,但是转载时未声明文章来源或参考自 http://tiankonguse.com/ 网站 ...

  7. leetcode简单题目两道(1)

    Problem: You are playing the following Nim Game with your friend: There is a heap of stones on the t ...

  8. JavaScript中的异步 macrotask 和 microtask

    看过很多setTimeout.Promise执行顺序的面试题,一直不明白为啥都是异步操作,Promise就牛×些呢?直到了解了macrotask和micromask才恍然大悟... 先来一道面试题助助 ...

  9. Opencv中图像的遍历与像素操作

    Opencv中图像的遍历与像素操作 OpenCV中表示图像的数据结构是cv::Mat,Mat对象本质上是一个由数值组成的矩阵.矩阵的每一个元素代表一个像素,对于灰度图像,像素是由8位无符号数来表示(0 ...

  10. js打印去掉页眉页脚

    <style type="text/css" media="print"> @page /* 实现代码 */ { size: auto; /* au ...