Tuesday, September 8, 2009

Anatomy of an ASP.NET MVC Control

One of the great things about ASP.NET WebForms was that it wasy very easy to creat reuseable custom controls and components, but with appearance of ASP.NET MVC and lots of developers moving towards it – which is a good thing – what happens to component oriented development? Is is possible to create custom controls in MVC? Can we port our existing controls to MVC? ASP.NET MVC while may not be as good as WebForms when it comes to drag-and-drop style of using components, but it is fairly easy to use and to create custom controls in MVC! Let’s see how.

To create a control in WebForms world, you’d extend the existing “WebControl” class and override Render method which takes a HtmlTextWriter that you can use to output the desired HTML code to the browser. A control rendering “Hello World” on the screen would be as simple as this:

public class HelloWorldControl : WebControl
{
    protected override void Render(HtmlTextWriter writer)
    {
        base.Render(writer);

        writer.Write("<span>HelloWorld</span>");
    }
}
You’d put this on your web page and you’re all set. But what’s the best approach in MVC controls? There’s no WebControl or Control classes inside Mvc assemblies, so can either use any existing class you have as a base class or it from scratch.
public class WebControl
{
    /// <summary>
    /// Renders the control by writing the html code into the text writer.
    /// </summary>
    /// <param name="textWriter"></param>
    public virtual void Render(TextWriter textWriter)
    {
    }

    /// <summary>
    /// Renders the control and outputs the generated HTML code.
    /// </summary>
    /// <returns></returns>
    public string OnRender()
    {
        var tw = new StringWriter();

        Render(tw);

        return tw.ToString();
    }
}
With this, you have a ready to use base class for your controls. You need to override the Render method and construct the right HTML code. The code would look almost identical:
public class HelloWorldControl : WebControl
{
    public override void Render(TextWriter writer)
    {
        base.Render(writer);

        writer.Write("<span>Hello World!</span>");
    }
}
Note: There’s a catch here. We’d use existing methods on HtmlTextWriter in WebForms, which emitted correct HTML code per Browser. If you’re writing the HTML code manually (as I did in this example) you’d be careful in case you need to support different browsers.

The only thing remaining is, how do we use this in an MVC application? The way to do this, as it is already done in the MVC framework with other controls such as TextBox, CheckBox, etc. is to create an extension method on HtmlHelper class. HtmlHelper is just there as a waypoint for extension method and has no other uses:
public static class HelloWorldControlExtensions
{
    public static string HelloWorld(this HtmlHelper helper)
    {
        var control = new HelloWorldControl();

        return control.OnRender();
    }
}
Now you can add this controls to your views, as easy as other controls such as TextBoxes:
<%= Html.HelloWorld() %>

That’s almost it. The only thing remaining here is to implement control specific logic of your components and that part is left to you.
Submit this story to DotNetKicks Shout it

Wednesday, September 2, 2009

Caliburn = Less Code?

Caliburn is an application framework for WPF / Silverlight. If you’re developing applications for these platforms, there are many reasons why you definitely need to be using this framework, but today, I noticed how using this framework resulted writing less code while doing more. Let’s see how writing a small WPF application using MVVM pattern is different when using Caliburn.
Note: There are many other ways to skin a cat. This is how I do things, there may be other, better ways to do the same thing.

Application Startup
When creating an application using MVVM and “ViewModel First” development, you’d create the root View and VM, bind them through DataContext and show the main window of the application.

///
/// Interaction logic for App.xaml
///
public partial class App : Application
{
   protected override void OnStartup(StartupEventArgs e)
   {
      base.OnStartup(e);

      var container = new WindsorContainer();
      var rootView = new RootView();
      var rootModel = new RootViewModel();

      rootView.DataContext = rootModel;
      this.MainWindow = rootView;
      this.MainWindow.Show();
   }
}
With caliburn, all you need to do is to create the root VM. There’s no trace of any View creation and binding the DataContext to VM. All this is done automatically by Caliburn. To do this, use “CaliburnApplication” as your base application class which will configure Caliburn framework upon startup. There are other ways to do the configuration but let’s stick to this simple configuration scenario that installs default implementations of Calburn “Components”.
///
/// Interaction logic for App.xaml
///
public partial class App : CaliburnApplication
{
   protected override IServiceLocator CreateContainer()
   {
      var container = new WindsorContainer();
      var adapter = new WindsorAdapter(container);

      return adapter;
   }

   protected override object CreateRootModel()
   {
      return new RootViewModel();
   }
}
One thing a little different is that Caliburn uses IServiceLocator insterface (from Common Service Locator) and has no direct dependency on a vendor specific IoC Container, which is a good thing. This means, you can choose various IoC containers and adapters for major IoC containers like Windsor, Ninject, Autofac, etc. are already included in Caliburn bits. If you're not a fan of IoC containers and won't be using one in your application (now, come on!), Caliburn uses a lightweight built-in container, in case you don't specify any other.

Actions and Commands
Should you bind an action to a ICommand instance on the VM, in pure MVVM application you would bind the Command property to an ICommand instance on the VM. You can specify the condition on which the command will be executable and you’ll also implement the action execute by the command.
<Button Command="{Binding ExitCommand}" Content="Exit Application">

public class RootViewModel : BaseViewModel
{
   private ICommand _exitCommand;
   public ICommand ExitCommand
   {
      get
      {
         if (_exitCommand == null)
           _exitCommand = new RelayCommand(this.Exit, this.CanExit);

         return _exitCommand;
      }
   }

   public bool CanExit()
   {
      return true;
   }

   public void Exit()
   {
      Application.Current.Shutdown();
   }
}
Notice there are other “hidden” code here too. You’ll need to create a new Command, or use RelayCommand (kudos to Josh) and you probably need a common layer supertype that implements INotifyPropertyChanged interface. Using Caliburn you'd bind the action directly to the VM and there's no dependency to ICommand instances. The good thing is, you’re not limited to Command property anymore and you can bind various other events such as Click, MouseOver, etc. to actions on your VM.
<Button cal:Message.Attach="[Event Click] = [Action Exit]" Content="Exit Application">

public class RootViewModel : Presenter
{
   public bool CanExit()
   {
      return true;
   }

   public void Exit()
   {
      Application.Current.Shutdown();
   }
}
There are lots of existing boilerplate functionalities already available in Caliburn, so you can drop BaseViewModel and use Presenter class (IPresenter implementation).

Displaying Views
To display other views in the RootView (e.g. Shell), we’d constructed a new VM and set it to a Content property of a ContentControl. This will actually pick up the view specified in the DataTemplate from Application Resources, and display it on the UI. You have to maintain a mapping between your Views and your VMs in a resource dictionary and as your application grows this gets harder to maintain.
<Application.Resources>
   <DataTemplate DataType="{x:Type vm:CustomerViewModel}">
      <view:CustomerView />
   </DataTemplate>
</Application.Resources>

<ContentControl Content="{Binding Path=CurrentView}"/>

public class RootViewModel : BaseViewModel
{
   public void ShowCustomer()
   {
      CurrentView = IoC.Resolve<Customerviewmodel>();
   }

   private BaseViewModel _currentView;
   public BaseViewModel CurrentView
   {
      get { return _currentView; }
      set
      {
         _currentView = value;
         RaisePropertyChanged("CurrentView");
      }
   }
}
Let’s see how we can do this using Caliburn. First off, we do not need to maintain any ViewModel mapping if we name our Views and ViewModels according to the Caliburn Conventions that is, your view names should ending in View, presenters / VMs ending in “ViewModel” or “Presenter” and each should be in a separate namespace, namingly “Views” and “ViewModels” or “Presenters”. This is just by convention and you can always override if you need to. Caliburn will automatically create the view for you, set the “CurrentPresenter” property on the main window (i.e. IPresenterHost) and do any required bindings. Did I mention you don’t need the whole mapping of View <-> DataTemplate in your Application / Form resource?
<ContentControl x:Name="CurrentPresenter" >

[Singleton("RootViewModel")]
public class RootViewModel : PresenterManager
{
   public void ShowCustomer()
   {
      var presenter = ServiceLocator.Current.GetInstance<Customerviewmodel>();
      this.Open(presenter);
   }
}
Conclusion
What’s the catch? How does Caliburn do this? Caliburn uses “Convention over Configuration” pattern, so if you do things according to the convention you’ll end up saving a lot of code. There’s always the possibility to change the default behavior too. By complying to these conventions, clearly you’ll end up writing less code, but more importantly the code you do write is cleaner, more robust and probably with better testabilty. With the help of “Binding Tests” utilities existing in Caliburn, you can test your bindings the easy way, which is some thought for later posts.
Submit this story to DotNetKicks Shout it

Thursday, August 20, 2009

Windsor Registration : Service Interface

Sometimes when registering classes on Windsor container, that extend an existing base class with an interface, using auto registration and FirstInterface method is useless, because first interface finds the interface implemented by base class:

[TestFixture]
public class RegistrationFixture : ContainerTest
{
[Test]
public void Can_Find_Service_Using_Interface()
{
var service = TryResolve<IService>();

Assert.That(service, Is.Not.Null);
}

protected override void OnSetup()
{
base.OnSetup();

Container.Register(AllTypes.From(typeof(ServiceImpl))
.Where(null)
.Configure(x => x.LifeStyle.Is(LifestyleType.Transient))
.WithService.FirstInterface());
}

private interface IBaseService
{
}

private interface IService
{
}

private class BaseService : IBaseService
{
}

private class ServiceImpl : BaseService, IService
{
}
}
If you run the test, it will fail, because ServiceImpl is registered with IBaseService interface, which is the first interface on the class hierarchy. But that is not what I intended to do. I wanted the to register it using the first interface on the same type, e.g. IService. Extension methods come to the rescue:
public static class ContainerExtensions
{
public static BasedOnDescriptor FirstInterfaceOnClass(this ServiceDescriptor serviceDescriptor)
{
return serviceDescriptor.Select((t, bt) =>
{
var baseInterfaces = t.BaseType.GetInterfaces();
var interfaces = t.GetInterfaces().Except(baseInterfaces);

return interfaces.Count() != 0 ? new[] {interfaces.First()} : null;
});
}
}
Changing the registration to this would pass the failing test:
Container.Register(AllTypes.From(typeof(ServiceImpl))
.Where(null)
.Configure(x => x.LifeStyle.Is(LifestyleType.Transient))
.WithService.FirstInterfaceOfClass());


Submit this story to DotNetKicks Shout it

Thursday, July 30, 2009

LOB Application in WPF

I’ve been working on a small LoB application to manage sales of a small sales office. I thought it’d be a good idea to put to use my WPF knowledge and use WPF to create this application. The reason is obvious : Programming in WPF is as easy as it gets, more testable (as in Unit Testing and Acceptance Testing) and more end-user friendly.

Following applicaiton components and patterns were used:

  • NHibernate
  • NHibernate Validator to validate both entities and ViewModels
  • FarsiLibrary (globalizing Dates, DatePickers, etc.)
  • MVVM pattern

One part that took more effort than expected was localization and globalization of the application. In general, there are three things you need to check to achieve full localization, if you provide both Left-To-Right reading order languages (English) as well as Right-To-Left (Farsi, Arabic) :

Flow Direction

Thanks to WPF engine, most of the calculation of LTR reading order to RTL for Forms, UserControls and even Custom Controls is done automagically, although in custom controls, you might need to add some triggers to switch things like shadows, etc. and if you use a 3rd party custom control or library, you need to make sure component vendor has take care of issue like that.

Texts

WPF uses LocaBaml to extract localizable properties’ values to an excel file and after translation (e.g. assigning values for other languages), puts them in a satelite assembly. This approach looks rough to maintain but there are lots of libraries on Codeplex that will help you do this with xml files or .resx files. My suggestion is to use WPF Localization Extension which supports localizing FlowDirection, Brush, Texts, Images, etc.

Dates

Not eveyone use Gregorian Calendar available in english language cultures. For example in Arabic language HijriCalendar is used and for Farsi, PersianCalendar is used and sometimes just setting thread’s culture to the language (e.g. Farsi) would not be enough. If you use dates in your applications (who doesn’t?) you need to use date controls that work fluently with various languages and cultures. I used my own FarsiLibrary control for WPF which allows you to work with PersianCalendar, HijriCalendar and GregorianCalendar seamlessly.

System Messages

With all the efforts and steps mentioned above, one part of the application still remains in native language of the Windows Installation. That is when using Windows’s MessageBox to alert user and display messages. Fortunately, I already have my Expression Clone styles which come with a Expression style messagebox that come with localizable icons / button texts.

Waring_English_MsgBox Warning_Persian_MsgBox

Styling

No doubt one of the features that comes with WPF is the ability to style everything that makes sense to provide a better UX. I used my Expression styles which you can download here to style your WPF applications very easily to make it look like Expression series.

Before StylingBefore Styling

After StylingUsing Expression Styles

Submit this story to DotNetKicks Shout it

Wednesday, July 22, 2009

XamDataGrid Validation with NHibernate Validator

One of the good grid controls in WPF world belongs to Infragistics. With all the bells and whistles, there are still some limitation, some are WPF engine limitation and some are not. One thing that is very limiting is validation of data prior them being added to datasource. This is rather a broad subject, but I intended to use NHibernate entities (POCO objects) decorated with NHiberante validator attributes to do the validation for me.

NHibernate Validator

NHibernate Validator is a subproject in NHibernate Contrib which allows you validate plain business classes by using predefined set of validation attributes. The good thing is, as good as NHibernate uses POCO (Plain Old CLR Object) objects you can also validate any kind of simple classes using NHibernate validator. There are other validation frameworks out there but I didn’t wanted to clutter my object with the validation mechanism and I also didn’t want to write unnecessary properties on my domain objects (e.g. IsValid, etc.) so NHibernate Validator was a right choice for me. Let’s see how a POCO entity along with validation looks like:

public class Product
{
public Product()
{
}

public long ProductId
{
get;
private set;
}

[NotNullNotEmpty]
public string Title
{
get; set;
}

[NotNull]
public Category Category
{
get; set;
}

public string Description
{
get; set;
}

[Min(0)]
public long Quantity
{
get; set;
}
}

Binding To XamDataGrid

XamDataGrid supports binding to IEnumerable interface, so an IList<Product> would work. Also, XamDataGrid needs a public parameterless constructor if you’re going to add to that collection from the grid control. If this requirement is not met, grid control will silently ignore the NewLine setting value. Here’s the xaml snippet to display a grid with predefined fields (columns) and a NewLine row:

<igdp:XamDataGrid DataSource="{Binding ProductList}">
<
igdp:XamDataGrid.FieldLayouts>
<
igdp:FieldLayout>
<
igdp:FieldLayout.Settings>
<
igdp:FieldLayoutSettings AddNewRecordLocation="OnTopFixed" AllowDelete="False"
AllowAddNew="True" ExpansionIndicatorDisplayMode="Never"
/>
</
igdp:FieldLayout.Settings>
<
igdp:FieldLayout.Fields>
<
igdp:Field Name="Title" Label="Product Name" />
<
igdp:Field Name="Category" Label="Category" />
<
igdp:Field Name="Description" Label="Comment"/>
<
igdp:Field Name="Quantity" Label="Qtty" />
<
igdp:Field Name="ProductId" Visibility="Collapsed"/>
</
igdp:FieldLayout.Fields>
</
igdp:FieldLayout>
</
igdp:XamDataGrid.FieldLayouts>
</
igdp:XamDataGrid>
Now when you run the application and add a new Product object to the datasource, there’s no way to check if all the predefined validation rules are okay. So, how do we change the behavior of the grid control to:
  • Validate the product object PRIOR being added to the datasource so if an object is not validate, it won’t get added to the data source.

  • No redundant validation code should be written. We need to use NHibernate Validator infrastructure we already have in place.

  • A reusable mechanism. Our application might end up with lots of grid controls.

One way would be to subclass the grid control which although might work, is a heavy handed solution to our rather little problem. It is not right to put the code in our ViewModel (I’m using MVVM pattern), which introduces coupling betwee UI and ViewModel. Fortunately, this grid control exposes good events we can tap into and change the default validation behavior and we can do this by creating a new Attached Behavior.

Validation Attached Behavior

Attaching a behavior to an object, as the name puts it, means making the object do something that it would not do by default. According to Josh Smith:

“The idea is that you set an attached property on an element so that you can gain access to the element from the class that exposes the attached property. Once that class has access to the element, it can hook events on it and, in response to those events firing, make the element do things that it normally would not do. It is a very convenient alternative to creating and using subclasses, and is very XAML-friendly.”

…and that’s exactly what we’re going to do. We’re going to listen to one event in particular : “RecordUpdating” which fires when the user had edited an item and the control wants to submit the changes back to the data source. Here’s the part that does the validation:

private static void OnRecordUpdating(object sender, RoutedEventArgs e)
{
var arg = (RecordUpdatingEventArgs)e;
var dataobject = arg.Record.DataItem;
var rules = GetAllInvalidRules(dataobject);
var grid = (XamDataGrid)sender;

if (rules != null && rules.Count > 0)
{
var propertyName = rules[0].PropertyPath;
var propertyTitle = grid.DefaultFieldLayout.Fields[propertyName].Label;

arg.Action = RecordUpdatingAction.CancelUpdateRetainChanges;
arg.Record.Tag = string.Format("Check Field : {0}", propertyTitle);
}
else
{
arg.Record.Tag = null;
}

e.Handled = true;
}

Note : We only display one error at a time. If you need to display all of them at once, you can do so by changing the code a little bit.

We place the error information on the Record object’s Tag information. In our little RecordSelector style, we’ll display an error icon in case Tag property is set to some error information:
<Style TargetType="{x:Type igdp:RecordSelector}">
<
Setter Property="Template">
<
Setter.Value>
<
ControlTemplate TargetType="{x:Type igdp:RecordSelector}">
<
Image x:Name="ErrorIcon" Source="pack://application:,,,/GridValidation;component/Images/FieldError.png"
Width="16" Height="16" Margin="4,0,0,0" Visibility="Collapsed" ToolTip="{Binding Tag}" />
<
ControlTemplate.Triggers>
<
DataTrigger Binding="{Binding Path=Tag, Converter={StaticResource DefaultNullConverter}}" Value="False">
<
Setter TargetName="ErrorIcon" Property="Visibility" Value="Visible" />
</
DataTrigger>
</
ControlTemplate.Triggers>
</
ControlTemplate>
</
Setter.Value>
</
Setter>
</
Style>
One last thing that is remaining, is to connect our attached behavior to our xamDataGrid control. The great thing about the attached behaviors (one of them, at least) is that you can use them from XAML code directly and no code-behind is required at all. So back to our xamDataGrid code, here’s how to do the trick:
<igdp:XamDataGrid DataSource="{Binding ProductList}" bhv:DataGridValidationBehavior.HasRowValidation="true">

Conclusion

The final application looks like this picture. If you try to enter something wrong, either when creating a new item or editing one, validation mechanism will automagically kick in and does the work for you. The very important point is that data is retained in the new line but is it not added to the datasource, because the data is not validated.



xamGrid-Validation

You can download the source code from here. In order to fully compile and run the application, you need to install Infragistics WPF components which you can download here.


Submit this story to DotNetKicks Shout it

Monday, July 13, 2009

Infragistics WPF Reporting

I’ve been looking for flexible Reporting components for the WPF application I’m working on, and strangely enough, there are just a few. I think WPF component in general is still a work in progress, and even if you have the chance to find a working component, there ALL have a lot of short comings and lack design-mode features, developer-friendliness, etc. and when it comes down to reporting component, there is Infragistics with very basic feature set, ComponentOne with years of background in reporting tools and Stimulsoft with complete reporting set for WinForm, WPF and Web.

So, I start evaluating each one. Stimusoft WPF reporting looked very promising with all bells and whistles like end-user WPF designer and the whole UI (designer and preview) were in WPF, but If I’m going to buy a component I need more that just a reporting tool, how about having bunch of other controls as well? I skipped to ComponentOne and after downloading their package (around 100 MB download), the damn installation did not work and I was staring at the installation error message that had to do something with packaging. So in reality, I had only one more choice : Infragistics.

Infragistics Reporting

With very basic feature, Infragistics reporting is also easy to use. Since there is no designer (yet?) you have to code your report and create various report sections (Header, Footer, etc.) and add related stuff into that sections, all in code. The great thing about this reporting control (also a feature of ComponentOne) is that you can print any kind of UIElement, this means you can print your whole UserControl or Form which comes in handy.

Infragistics-Reporting

The real power of Infragistics reporting is when combined with their “Data Presenter” or “XamDataGrid” control. End-user can apply filtering, grouping, sorting, etc. and just print the result, easy as that.

RightToLeft Issue

When evaluating my application which is a multi-lingual application that supports RightToLeft and LeftToRight reading ordered languages, I came across a problem when printing controls with RightToLeft flow direction. The problem was that the whole control is “Mirrored”. Not that this mirroring is an issue, but all the texts and values printed are also mirrored which makes the whole report useless.

Mirrorred Report

Workaround

The workaround is, of course, not to print the control in RightToLeft and use LeftToRight for the time being until the bug is fixed. As easy as this sounds, it is not very easy to do for some reasons:

  • RightToLeft is usually set on the parent (Form), and controls just “inherit” the setting from their parent.
  • If you do change parent’s RightToLeft end-user will see the effect.

But you can always clone the object and change the behavior, right? But you can not do so with Visual Elements. There’s no Copy / Clone method on Visual elements in WPF, so how do we “clone” the control, change the FlowDirection, and hand it to the reporting?

Fortunately, WPF comes with two neglected classes : “XamlWriter” and “XamlReader” each of which do as exactly as the name puts it. Using “XamlWriter” you can write a Visual object (UIElement) into a string, then use “XamlReader” ton construct it back. This is just about the UI, so you’ll have to re-attach the “DataSource” and “DataContext” you might have. Here’s the snippet to do the trick:

public XamDataGrid Clone(XamDataGrid printable)
{
//Clone the grid control
var o = XamlWriter.Save(printable);
var sr = new StringReader(o);
var reader = XmlReader.Create(sr, new XmlReaderSettings());
var result = (XamDataGrid)XamlReader.Load(reader);

//It's a clone, need to reassign data source
result.DataSource = printable.DataSource;

//Set flow direction to LTR
result.FlowDirection = FlowDirection.LeftToRight;

return result;
}
You can download the whole sample that shows the issue and the workaround. To compile and run it you need to have Infragistics 2009.1 installed. You can download Infragistics package here.
Submit this story to DotNetKicks Shout it

Sunday, July 5, 2009

Additional CallContext information in WCF

Yeah, this might be a little old…but someone asked me how to send context information from client to the service with WCF.

Note: In general, you should not rely on client provided information about security, authentication, licensing, etc. Use this code and sample as an idea on how to implement your custom security. If you’re trying to send sensitive information over the network, use at your own risk.

WCF client and services might be (and probably are) in two separate AppDomain or even on separate machines across the network, so how do we send extra information from the client to the service when the service call is made? Fortunately, WCF provides enough extensibility points for us to participate in the action and change the default behavior. It is pretty much easy to add context information to the message header on the client side, and the on the server side extract the custom data from the message header. Added data to the message header can be a DataContract / Serialized class.

[DataContract]
public class MessageInfo
{
public MessageInfo(Guid sessionId, CultureInfo culture, DateTime requestDate)
{
this.sessionId = sessionId;
this.culture = culture;
this.requestDate = requestDate;
}

[DataMember]
public DateTime RequestDate
{
get;
set;
}

[DataMember]
public Guid SessionId
{
get;
set;
}

[DataMember]
public CultureInfo Culture
{
get;
set;
}
}
Client uses IClientMessageInspector to add context data before the message is handed over to WCF for the delivery.
/// <summary>
///
Flows the client's MessageInfo to the service.
/// </summary>
public class ClientMessageInfoInspector : IClientMessageInspector
{
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
request.Headers.Add(MessageHeader.CreateHeader(MessageHeaderKeys.MessageInfoKey, string.Empty, GetInfo()));
return null;
}

public void AfterReceiveReply(ref Message reply, object correlationState)
{
}

private MessageInfo GetInfo()
{
return new MessageInfo(Guid.NewGuid(), Thread.CurrentThread.CurrentUICulture, DateTime.Now);
}
}
On the other hand, the service side uses IDispatchMessageInspector interface to extract the data from message header.
/// <summary>
///
Reads the MessageInfo of client and updates the service.
/// </summary>
public class ServiceMessageInfoInspector : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
int headerIndex = request.Headers.FindHeader(MessageHeaderKeys.MessageInfoKey, string.Empty);
if (headerIndex != -1)
{
MessageInfo ui = request.Headers.GetHeader<MessageInfo>(headerIndex);

Thread.CurrentThread.CurrentUICulture = ui.Culture;
Thread.CurrentThread.CurrentCulture = ui.Culture;
            Console.WriteLine("Request recieved on {0}", ui.RequestDate);
}

return null;
}

public void BeforeSendReply(ref Message reply, object correlationState)
{
}
}

To wire things up, you also need to create a new behavior by implementing IEndpointBehavior and registering it with your endpoint, either by code, or configuration. Should you use a single behavior for both client and server, here’s how to do it:

public class MessageInfoBehavior : IEndpointBehavior
{
public void Validate(ServiceEndpoint endpoint)
{
}

public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}

public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
ServiceMessageInfoInspector inspector = new ServiceMessageInfoInspector();
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
}

public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
ClientMessageInfoInspector inspector = new ClientMessageInfoInspector();
clientRuntime.MessageInspectors.Add(inspector);
}
}

Hope this helps.


Submit this story to DotNetKicks Shout it