July 2007 - Posts
One of the nifty features in Windows Communication Foundation is duplex requests. To define a duplex request you need to create two interfaces, both with their OperationContract marked with IsOneWay:=True. The request interface also contains a CallbackContract with the response interface.
<ServiceContract(CallbackContract:=GetType(IDuplexResponse))> _
Public
Interface IDuplexRequest
<OperationContract(IsOneWay:=True)> _
Sub SendRequest(ByVal data As
String)
End
Interface
<ServiceContract()> _
Public
Interface IDuplexResponse
<OperationContract(IsOneWay:=True)> _
Sub SendResponse(ByVal data As
String)
End
Interface
Now in the request implementation you can use the OperationContext to retrieve the callback interface using OperationContext.Current.GetCallbackChannel(Of IDuplexResponse)().
Public
Class DuplexRequest
Implements IDuplexRequest
Public
Sub SendRequest(ByVal data As
String) Implements IDuplexRequest.SendRequest
Dim responseChannel As IDuplexResponse = OperationContext.Current.GetCallbackChannel(Of IDuplexResponse)()
responseChannel.SendResponse(String.Format("I received '{0}'.", data))
End
Sub
End
Class
So far so good. Now with all the operations marked as one way and seem a perfect fit for a netMsmqBinding implementation. Unfortunately this doesn't seem to work though, or otherwise I could not figure out how to get this to work
. Even though all operations are one way the channel still needs to be a duplex channel and as the netMsmqBinding is a simple binding instead of a duplex binding this just doesn't work.
This is unfortunate because the sample Microsoft released showing duplex communication is very primitive and in fact strongly coupled to netMsmqBinding as it requires passing the address as a normal piece of data to the client. Because of this it doesn't seem to be in the "spirit" of WCF
. BTW you can find the Microsoft sample at: http://msdn2.microsoft.com/en-us/library/ms752264.aspx.
If anyone has OperationContext.Current.GetCallbackChannel() working with netMsmqBinding I would appreciate the information on how to do this.
Most of the time there isn't much of a problem when developing custom activities and workflow persistence. After all when an external system send a message, the service retrieves this, extracts the WorkflowInstanceId and queue name and signals the workflow. Everything's works just fine and if the workflow runtime restarts the message received will cause the workflow to be reloaded.
However there is a catch. Suppose the external service isn't passively waiting for an external event but must do so in a more active mode. An example of this is a service waiting for a particular file to be recreated. In this case the service needs to be aware of the file we are waiting for even after a restart of the workflow runtime. When the workflow starts and uses a SqlWorkflowPersistenceService each workflow waiting for a DelayActivity is actually reloaded if the delay timer has expired. When this happens an OnActivityExecutionContextLoad() function is called on the activity waiting. This activity can now signal the external service that it is waiting for the file. Adding a dummy timer subscription isn't all that hard.
Activity parent = this;
while (parent.Parent != null)
{
parent = parent.Parent;
}
TimerEventSubscriptionCollection timers = (TimerEventSubscriptionCollection)parent.GetValue(TimerEventSubscriptionCollection.TimerCollectionProperty);
TimerEventSubscription item = new
TimerEventSubscription(WorkflowInstanceId, DateTime.UtcNow);
timers.Add(item);
This code will prevent the requirements for an extra persistence service for use with the runtime service waiting for the file. Keep in mind though that this behavior depends on the internal, and undocumented, behavior of the DelayActivity and the SqlWorkflowPersistenceService so it could well change in the future.
Enjoy!
I am changing my blog to go through FeedBurner in the future. So if you are subscribing to the RSS feed of my blog please update it to point to http://feeds.feedburner.com/TheProblemSolver instead.
Caching can be a great way of increasing the performance of an application. I often use the HttpRuntime.Cache just for this purpose, even in WinForm applications as it is fast and easy to use. However as usual there is a tradeoff. In the case of caching the catch is memory consumption. Instead of querying or calculating some data again just keep all results around in the hope they are used again. But that uses up memory and while coding you probably have a fast machine with plenty of memory the case at runtime might be a little different.
One easy way to solve the problem is to the WeakReference object. Using this WeakReference you keep sort of a hold on an object but allow the .NET garbage collector to remove it from memory when required. The following code is a quick sample of how to do this. Keep in mind that this is a quick demo and not fully tested so use at your own risk
using System;
using System.Web;
namespace MesFileImporterShared.Utils
{
static
class
Cache
{
static
public
void Insert(string key, object value)
{
CacheItem item = GetCacheItem(key, value);
HttpRuntime.Cache[key] = item;
}
private
static
CacheItem GetCacheItem(string key, object value)
{
CacheItem result = new
CacheItem();
result.Key = key;
result.Value = new
WeakReference(value, false);
return result;
}
private
static
bool Exists(string key)
{
bool result = false;
CacheItem item = HttpRuntime.Cache[key] as
CacheItem;
if (item != null)
{
result = item.Value.IsAlive;
}
return result;
}
public
static
object Get(string key)
{
object result = null;
CacheItem item = HttpRuntime.Cache[key] as
CacheItem;
if (item != null)
if (item.Value.IsAlive)
result = item.Value.Target;
else
throw
new
NullReferenceException("Item is no longer alive");
return result;
}
public
static
bool TryGet(string key, out
object value)
{
bool result = false;
value = null;
CacheItem item = HttpRuntime.Cache[key] as
CacheItem;
if (item != null && item.Value.IsAlive)
{
value = item.Value.Target;
result = true;
}
return result;
}
private
class
CacheItem
{
public
string Key;
public
WeakReference Value;
}
}
}
Enjoy!
Dear Maurice de Beijer,
Congratulations! We are pleased to present you with the 2007 Microsoft® MVP Award!
The Microsoft MVP Award is our way of saying thank you and to honor and support the significant contributions you make to communities worldwide. As a recipient of Microsoft's Most Valuable Professional award, you join an elite group of technical community leaders from around the world who foster the free and objective exchange of knowledge by actively sharing your real world expertise with users and Microsoft. Microsoft salutes all MVPs for promoting the spirit of community and enhancing people's lives and the industry's success everyday. To learn more about the MVP Program, visit: www.microsoft.com/mvp.
Your extraordinary efforts in Visual Developer - Visual Basic technical communities during the past year are greatly appreciated.
Yes that is right, MVP for another year 