Jun 29, 2007

WCF Callback Port for WSDualHttpBinding

When using a callback contract and the WSDualHttpBinding WCF binding then port 80 is assigned per default. As this produces an obvious problem when IIS is installed, you have to configure another port for your callback service on the client side.

// set callback port for dual HTTP binding as another channel is required. Not for npipe, tcpip.

WSDualHttpBinding binding = cf.Endpoint.Binding as WSDualHttpBinding;

if (binding != null)

{

    int port = int.Parse((string)ConfigurationManager.AppSettings["DeviceServerCallbackPort"]);

    binding.ClientBaseAddress = new Uri(cf.Endpoint.Address.Uri.Scheme + "://"

        + System.Environment.MachineName + ":" + port + "/" + typeof(IDeviceServerService).Name);

}

Jun 26, 2007

WCF Message Copying

A WCF Message can only be read once. The Message class contains a "State" property indicating if this was already done before. So quite often you need to copy a Message object:

// a Message can only be read once, so create a copy

MessageBuffer mb = orgMessage.CreateBufferedCopy(int.MaxValue);

System.ServiceModel.Channels.Message copyMessage = mb.CreateMessage();


There is an extensive article about the WCF Message type at MSDN.

Jun 18, 2007

Spring.NET framework

Spring.NET framework 1.1 M1 recently got ready for download.

For all of you who don't know what Spring is (as myself a week ago):
"Spring.NET is an open source application framework that makes building enterprise .NET applications easier. Providing components based on proven design patterns that can be integrated into all tiers of your application architecture, Spring helps increase development productivity and improve application quality and performance."

I was especially interested in the IoC/DI (Inversion of Control, Dependency Injection) and Expression Evaluation areas.

First I defined a contract:

public interface IModulePlugin : IDisposable

{

    void Initialize();

    void Execute();

 

    string Name { get; set; }

    int Value { get; set; }

    DateTime Date { get; set; }

}


and did two interface implementations (you may imagine the code). I then wrote some code to instantiate my loosely coupled modules:

// use spring

IApplicationContext ctx = ContextRegistry.GetContext();

 

// get "a" loosely coupled (DI/IoC) module

using (IModulePlugin aModule = (IModulePlugin)ctx.GetObject("aModule"))

{

    aModule.Execute();

}

 

// get "another" loosely coupled (DI/IoC) module

using (IModulePlugin aModule = (IModulePlugin)ctx.GetObject("anotherModule"))

{

    aModule.Execute();

}

 

// try exprission features

TimeSpan t = (TimeSpan)ExpressionEvaluator.GetValue(null, "DateTime.Today - date('13/02/1970 06:10:00')");

Console.WriteLine("My age is " + t.ToString() + " [days]");


that is configured in the app.config as follows:

<objects xmlns="http://www.springframework.net">

 

  <object name="anotherModule" type="Spring.Modules.ModulePlugin, Spring.Modules" singleton="false" init-method="Initialize">

    <property name="Name" value="Leder" />

    <property name="Value" value="14" />

    <property name="Date" value="13.02.1970" />

  </object>

 

  <object name="aModule" type="Spring.Modules.AnotherModulePlugin, Spring.Modules" singleton="false"  init-method="Initialize" destroy-method="Dispose">

    <property name="Name" value="Markus" />

    <property name="Value" value="13" />

    <property name="Date" value="15.06.2007" />

  </object>

 

</objects>


Nice and no dependencies...

Jun 15, 2007

SQL notifications do not work with SqlDependency

Maybe somebody can hint me why I do net get update change notifications from my SQL Server 2005:


private void SetDependancy()

{

    SqlClientPermission perm = new SqlClientPermission(PermissionState.Unrestricted);

    perm.Demand();

 

    bool result = SqlDependency.Start(this.ConnectionString);

 

    SqlConnection sqlConn = this.CreateWriterConnection();

    SqlCommand cmd = new SqlCommand("SELECT [ID], [CorrelationID], [Sender], [Receiver], [Message], [TimeStamp] FROM [dbo].[tWcfDatabaseChannel]", sqlConn);

    dependency = new SqlDependency(cmd);

    dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);

 

    try

    {

        sqlConn.Open();

        object res = cmd.ExecuteScalar();

    }

    catch

    {

        // ...

    }

    finally

    {

        sqlConn.Close();

    }

}

 

void dependency_OnChange(object sender, SqlNotificationEventArgs e)

{

    // bubble up this event

    if (this.OnChange != null)

        this.OnChange(sender, e);

 

    SetDependancy();

}



With the following database:

-- Creating a database
CREATE DATABASE [Test]
GO

-- Ensuring that Service Broker is enabled
ALTER DATABASE [Test] SET ENABLE_BROKER
GO

-- Switching to our database
use [Test]

/****** Object: Table [dbo].[tWcfDatabaseChannel] Script Date: 06/15/2007 09:06:50 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[tWcfDatabaseChannel](
[ID] [uniqueidentifier] NOT NULL,
[CorrelationID] [uniqueidentifier] NULL,
[Sender] [nvarchar](200) COLLATE Latin1_General_CI_AS NULL,
[Receiver] [nvarchar](200) COLLATE Latin1_General_CI_AS NULL,
[Message] [ntext] COLLATE Latin1_General_CI_AS NULL,
[TimeStamp] [datetime] NOT NULL,
CONSTRAINT [PK_tWcfDatabaseChannel] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

WCF database transport custom binding

Based on articles of Nicholas Allen I started to create an implementation of a database transport WCF binding, including C# code for:

- DatabaseChannelAdapter (SQL 2005 database adapter)
- DatabaseChannelBase (read/write from/to database table, sql notification)
- DatabaseRequestChannel (derived from DatabaseChannelBase)
- DatabaseRequestContext (derived from DatabaseChannelBase)
- DatabaseReplyChannel
- DatabaseRequestChannelFactory
- DatabaseReplyChannelListener
- DatabaseTransportBindingElement
- DatabaseTransportBinding

Unfortunately it does not work yet, because I do not get SQL notifications. More to come on this one soon.

Jun 11, 2007

Deadlock with Callbacks

Per default the callback service operation invoked by the service "arrives" in the user interface thread. In a case where the callback service implementation is within the Form class this is bad news concerning deadlocks.

Responsible for this behaviour is the so-called SynchronizationContext (modified since .NET 2.0 ?).

So maybe you better disable this

[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Single, UseSynchronizationContext = false)]

public partial class ClientForm : Form, IDeviceView, IMasterCallbackService

{

    ...

}


and synchronize back into the UI thread yourself manually.

OneWay Callback Service Invocation Pattern?

As shown in an earlier post WCF allows callback service contracts to be of a request/response pattern. Where in p2p situation this might be great and simple, I was questioning this design in a C/S distributed application and opted for a OneWay pattern:

[ServiceContract(Namespace = "http://www.mleder.blogspot.com/CallbackService/2007/05")]

public interface IMasterCallbackService

{

    [OperationContract(IsOneWay = true)]

    void RaiseEvent(Message eventToRaise);

}


If you think OneWay prevents dead-locks, then you are wrong, because the request still needs to synchronize with the thread of the client.

Jun 6, 2007

Passing callback service implementation to create channel (factory)

I don't like "Add Service Reference", preferring ChannelFactory. The following sample shows how to pass a WCF callback service implementation to DuplexChannelFactory to create a service proxy:


// create the callback endpoint object (client-side service endpoint)

IDeviceServerCallbackService callback = new DeviceServerCallbackService();

InstanceContext context = new InstanceContext(callback);

 

// create duplex channel

cf = new DuplexChannelFactory<IDeviceServerService>(context, "MasterEndpointDualHttp");

proxy = cf.CreateChannel();

Jun 5, 2007

WCF callback service

This is a simple WCF service contract with a callback contract:


[ServiceContract(Namespace = "http://www.mleder.blogspot.com/WCF/Service"

, CallbackContract=typeof(IDeviceServerCallbackService))]

public interface IDeviceServerService

{

[OperationContract]

[FaultContract(typeof(ServiceOperationFault))]

DoWorkResponse DoWork(DoWorkRequest myValue);

[OperationContract]

Role[] GetRoles();

}

Please note that:

  • even as the callback contract interface is implemented on the client side, the semantical naming is related to the service name
  • DoWork is a generic web operation that concentrates all service calls and routes requests to the corresponding business object

Jun 4, 2007

New blog for my .NET

This blog went online today to share ideas, problems and knowledge with others in the area of .NET software development.

It is knowingly almost entirely technical and does not provide information not available thousandfold on the WWW. Please note the links to the information sources given.

I stick to the following considerations.