Posts for the tag: WCF

Jun
7
2010

Microsoft TechEd 2010 - Its All About the Cloud

I had the chance to see the Microsoft Teched Keynote today mainly presented by Bob Muglia, and unlike previous TechEd keynotes I have attended--actually I have only attended one in 2007--it was all business and no fluff. No side celebrities to some lame skit this time around. There were no earth shattering announcements made today although today they made a major push to go to the cloud which I thought was pretty interesting.

The main drive of the keynote was all about cloud computing. It was the overall theme that pretty much drove the whole keynote address. Each topic that was presented somehow tied back to the cloud. As a matter of fact, one of the demos was of an application that allowed user to be authenticated and recognized by a website via Active Directory profiles without that user actually having to be on the premises where that website is hosted. This was done by hosting the Activity Directory profiles in the cloud via Azure. Seems a pretty scary thing to do, but Muglia emphases as one of his points that the emphasis of this drive was that it was secure.

Muglia announced today that Visual Studio 2010, will now have the capabilities to develop applications specifically for Azure. From within Visual Studio you can specify things like how big your virtual environment will be, and you will be able to deploy directly to Azure with tracing of the deployment provided.

Other announcements that were made that:

  • The AppFabric plug in for IIS 7 is now available in RTM. This will allow IT to better manage deployments, diagnose and monitor WCF services, and provide a more flexible and scalable caching alternative to the current ASP.Net caching.
  • Windows Server R2 SP1 and Windows 7 SP1 will be available in July.
  • A new version of Windows Communicator will be available which will provide better conferencing (including video) as well as a "big brother" function that will analyze a user mail and other data and determine what skill-sets they have so someone in the company can search on that skill-set and give you a ring if you have it.  Sounds a bit scary to me.
  • Full development capability for the Windows 7 Phone will be able to be done in Visual Studio 2010 and Silverlight. This is a good sign that Microsoft still wants to be in the phone market although I think they still have a ways to go if they want catch up to the iPhone. Seems they are going after the business phone market.
  • Windows 9 will have full support of HTML 5 and have graphics acceleration for faster graphics rendering of a web page.
  • The new version of Web Expressions was released to day and it includes a Super Preview to compare what you design pages in to different browser versions such as IE 6, 7, 8, Firefox, and new with this release is Safari on the Mac. Yes you can now test Mac versions of Safari with needing a Mac. By they way, you can also do it on Spoon.net. http://spoon.net/browsers/

There a few other announcement but those were the ones as a web developer that interested me. I will try and update the blog with other stuff I learn through out this week so stay in touched.

 

Feb
24
2010

Build a REST Web Application with WCF and jQuery

Introduction

So at my work, we started on a new web application, and mainly because a lot of guys working on it were going to be new and also because it is somewhat a visible project; we figured we would keep the risk low and use the traditional web forms ASP.Net application.

On the other hand we still wanted the separation of concerns you get from a MVC style application, and because we were also planming on using designers for the web pages who were very proficient with jQuery but who did not know much about ASP.net. As a matter of fact, most of these guys write jQuery and HTML with a simple text editor…show offs :)

Also, for performance reasons and the fact the web designers were very familiar with the protocol, we wanted to pass JSON objects back and forth from the client to the server and vice versa.

Another goal is we want to keep as little as code as possible in the web project and place it in a different “Core” assembly. This would make deployments for us easier.

The Solution Layout

The solution looks like this:

The EventList.aspx page will be the page I will use for this demo. I deleted the associated code-behind files with and also removed the references of the code-behind from the page deplaration.

When I added the EventService.svc WCF Service into the project, Visual Studio added the EventService.svc.cs file and the IEventService service contract interface. I moved them to the Core project and changed the namespaces.

I also added a folder for the Unity service factory build up. You can see how I did it in a previous post.

The Service

Since I moved the associated files that were added when I added the WCF Service, I have to go in and change the declarations so they point to the proper place.

   1: <%@ ServiceHost 
   2:     Language="C#" 
   3:     Debug="true" 
   4:     Service="RestSample.Core.ServiceContracts.EventsService" 
   5:     Factory="RestSample.Core.ServiceContrainer.UnityServiceHostFactory" 
   6: %>

 

Also the code behind reference was moved and Factory attribute was added to point to my custom Unity Service Host Factory.

The Service Contract

The Service contract needs to be decorated with the ServiceContract attrubute; but I also need to specify that this message will take “POST” requests, and that the protocal will be JSON.

   1: using System.ServiceModel;
   2: using System.ServiceModel.Web;
   3: using RestSample.Core.DataContracts;
   4:  
   5: namespace RestSample.Core.ServiceContracts
   6: {
   7:     [ServiceContract]
   8:     public interface IEventsService
   9:     {
  10:         [OperationContract]
  11:         [WebInvoke(Method = "POST",
  12:             ResponseFormat = WebMessageFormat.Json,
  13:             BodyStyle = WebMessageBodyStyle.Bare)]
  14:         EventList GetLatestEvents();
  15:     }
  16: }

 

The implantation of this contract is injected with my controller where my response will be built up.

Here is the service contract implementation:

   1: using RestSample.Core.Controllers;
   2: using RestSample.Core.DataContracts;
   3:  
   4: namespace RestSample.Core.ServiceContracts
   5: {
   6:     public class EventsService : IEventsService
   7:     {
   8:         private readonly IEventController _eventController;
   9:  
  10:         public EventsService(IEventController eventController)
  11:         {
  12:             _eventController = eventController;
  13:         }
  14:  
  15:         #region IEventsService Members
  16:  
  17:         public EventList GetLatestEvents()
  18:         {
  19:             return _eventController.GetLatestEvents();
  20:         }
  21:  
  22:         #endregion
  23:     }
  24: }

 

Here is the controller class implementation:

   1: using System;
   2: using System.Collections.Generic;
   3: using RestSample.Core.DataContracts;
   4:  
   5: namespace RestSample.Core.Controllers
   6: {
   7:     public class EventController : IEventController
   8:     {
   9:         #region IEventController Members
  10:  
  11:         public EventList GetLatestEvents()
  12:         {
  13:             var list = new EventList {Items = new List<EventItem>()};
  14:             const int upper = 5;
  15:             for (int i = 0; i < upper; i++)
  16:             {
  17:                 list.Items.Add(new EventItem
  18:                                    {
  19:                                        EventCode = i.ToString(),
  20:                                        EventDate = DateTime.Today.AddDays(-1*i).ToLongDateString(),
  21:                                        EventName = string.Format("Name {0}", i)
  22:                                    });
  23:             }
  24:  
  25:             return list;
  26:         }
  27:  
  28:         #endregion
  29:     }
  30: }

Obviously I am just returning back trash, but you get the point. Here are the data contracts:

   1: using System.Runtime.Serialization;
   2:  
   3: namespace RestSample.Core.DataContracts
   4: {
   5:     [DataContract]
   6:     public class EventItem
   7:     {
   8:         [DataMember]
   9:         public string EventCode { get; set; }
  10:         [DataMember]
  11:         public string EventName { get; set; }
  12:         [DataMember]
  13:         public string EventDate { get; set; }
  14:     }
  15: }

 

   1: using System.Collections.Generic;
   2: using System.Runtime.Serialization;
   3:  
   4: namespace RestSample.Core.DataContracts
   5: {
   6:     [DataContract]
   7:     public class EventList
   8:     {
   9:         [DataMember]
  10:         public IList<EventItem> Items { get; set; }
  11:     }
  12: }

 

The web.config Set Up.

Because I want to return JSON, and because I moved the service files; I need to make some changes to the System.ServiceModel section of the web.config.

   1: <system.serviceModel>
   2:     <behaviors>
   3:         <serviceBehaviors>
   4:             <behavior name="RestSample.Core.ServiceContracts.EventsServiceBehavior">
   5:                 <serviceMetadata httpGetEnabled="true"/>
   6:                 <serviceDebug includeExceptionDetailInFaults="false"/>
   7:             </behavior>
   8:         </serviceBehaviors>
   9:   <endpointBehaviors>
  10:     <behavior name="WebHttpBehavior">
  11:       <webHttp />
  12:     </behavior>
  13:   </endpointBehaviors>
  14:     </behaviors>
  15:     <services>
  16:         <service behaviorConfiguration="RestSample.Core.ServiceContracts.EventsServiceBehavior" name="RestSample.Core.ServiceContracts.EventsService">
  17:             <endpoint address="" binding="webHttpBinding" contract="RestSample.Core.ServiceContracts.IEventsService" behaviorConfiguration="WebHttpBehavior">
  18:                 <identity>
  19:                     <dns value="localhost"/>
  20:                 </identity>
  21:             </endpoint>
  22:             <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
  23:         </service>
  24:     </services>
  25: </system.serviceModel>

I added an Endpoint Behavior and specified webHttp and then referenced it in the endpoint. This enables the “web programming model” for WCF which makes the service RESTful.

I also changed the name and contract location of the service so it points to new location in my solution.

Now my service is ready and if I run the service file at this point I get the standard service page to come up to show the everything is configured properly.

The Client

Now that the service is working I am just going to write some jQuery to make a call to the service when a button is click.

Here is the aspx page.

   1: <%@ Page Title="" Language="C#" MasterPageFile="~/Shared/Main.Master" %>
   2: <asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
   3:     <script src="../Scripts/json2.js" type="text/javascript"></script>
   4:     <script src="../Scripts/restsample.js" type="text/javascript"></script>
   5: </asp:Content>
   6: <asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
   7:     
   8:     <input type="button" value="Make Call" id="restCall" />
   9: </asp:Content>

Here is the jQuery

   1:  
   2: $(document).ready(function() {
   3:     setInputFunction();
   4: });
   5:  
   6: function setInputFunction() {
   7:     $('input').click(function() {
   8:         makeEventCall();
   9:     });
  10: }
  11:  
  12: function makeEventCall() {
  13:     $.ajax({
  14:         url: 'http://localhost:56296/Services/EventsService.svc/GetLatestEvents',
  15:         type: "POST",
  16:         processData: false,
  17:         contentType: "application/json",
  18:         timeout: 10000,
  19:         dataType: "text",  // not "json" we'll parse
  20:         success: function(data) {
  21:             loadSuccessful(data);
  22:         }
  23:     });
  24: }
  25:  
  26: function loadSuccessful(data) {
  27:     var result = JSON.parse(data);
  28:     console.log('result', result);
  29: }
  30:  
  31:  

So the jQuery code above makes a call to the service when the button is clicked. Here are some things to notice about this jQuery code.

  • First off, you cannot see it here but I have a script reference to the jQuery 1.4.1 file located on the Microsoft CDN. More on that here.
  • The url is the a combination of the service url and the function GetLatestEvents.
  • I need to specify “POST” as the type because that is what I specified on my ServiceContract.
  • I am going to return back text and then parse it using Douglas Crockford's json2.js.
  • For this demo, I am just going to log the response to the Firebug console using the console.log feature. (Note: remember to take this out later because you will get a JavaScript error in other browsers).

So with I am done and now when I bring up that web page and click the button I get this JSON response back.

{"Items":[{"EventCode":"0","EventDate":"Saturday, February 20, 2010","EventName":"Name 0"},
{"EventCode":"1","EventDate":"Friday, February 19, 2010","EventName":"Name 1"},
{"EventCode":"2","EventDate":"Thursday, February 18, 2010","EventName":"Name 2"},
{"EventCode":"3","EventDate":"Wednesday, February 17, 2010","EventName":"Name 3"},
{"EventCode":"4","EventDate":"Tuesday, February 16, 2010","EventName":"Name 4"}]}

The response in Firebug looks like this:

response

 

Hope that helps :)

Dec
15
2009

Syndicating RSS in an ASP.Net MVC app using WCF

About a month back Rob Conery mentioned that he was going to create a blogging application using MVC, which caused me to think to myself: “SELF! why don’t you try something like that and see what you can come up with?”  So in my spare time when I am not doing real work or at home shuttling kids around, I’ve been playing around with this idea.  I am really happy with my BlogEngine.Net set up and probably will continue to use it even if I were to finish this app but I figure this would be an opportunity to just do something different than I have been doing lately and learn some new things that I have not had a chance to work with as of yet.

So with that in mind, one of the first things I decided to tackle was going about syndicating an RSS feed and as it turns out it is not too terribly difficult to do; although, there are some things I did struggle with—uhhh---but I am getting ahead of myself.

 

Build you own ActionResult

I mention in my previous post that ASP.Net come with several different controller actions, and the one that I used in the that example was the JsonResult.  Well JsonResult really is just a class that is derived from the abstract class ActionResult.  I can write my own class that derives from ActionResult to return back to the view an RSS feed which is what I am going to do in this example.

 

   1: using System.ServiceModel.Syndication;
   2: using System.Web.Mvc;
   3: using System.Xml;
   4:  
   5: namespace Aviblog.Core.ActionResults
   6: {
   7:     public class RssResult : ActionResult
   8:     {
   9:         private readonly SyndicationFeed _feed;
  10:  
  11:         public RssResult(SyndicationFeed feed)
  12:         {
  13:             _feed = feed;
  14:         }
  15:  
  16:         public override void ExecuteResult(ControllerContext context)
  17:         {
  18:             context.HttpContext.Response.ContentType = "application/rss+xml";
  19:             var formatter = new Rss20FeedFormatter(_feed);
  20:  
  21:             using (XmlWriter writer = XmlWriter.Create(context.HttpContext.Response.Output))
  22:                 if (writer != null) formatter.WriteTo(writer);
  23:         }
  24:     }
  25: }

So in my custom RssResult that inherits from ActionResult, I need to then override the ExecuteResult method.  Inside that method I then need to set the response type to “application/rss+xml” so it can be rendered as RSS.  The next thing to notice is that in my constructor I am passing in an object of type SyndicationFeed which is a part of WCF.  It is in the System.ServiceModel.Syndication namespace.  You can find it by referencing the System.ServiceModel.Web assembly.  I can then use the Rss20FeedFormatter to generate XML which is RSS compliant.

Building the SyndicationFeed

Building the SyndicationFeed object is where I had the most trouble. If you just want a simple compliant RSS feed, this guy works great; however, as you can see just from looking at my own RSS feed there many other elements you can extend to an RSS feed and adding those to the SyndicationFeed element is a bit tricky.

   1: public SyndicationFeed Buildfeed()
   2:         {
   3:             var settingQry = _settingsRepository.GetSettings();
   4:             const string nameKey = "name";
   5:             const string nameDescription = "description";
   6:             const string link = "link";
   7:             string blogTitle = _settingsService.GetValue(settingQry, nameKey);
   8:             string blogDescription = _settingsService.GetValue(settingQry, nameDescription);
   9:             Uri blogUrl = _settingsService.GetUri(settingQry, link);
  10:  
  11:             var feed = new SyndicationFeed(blogTitle, blogDescription, blogUrl);
  12:  
  13:             foreach (var element in _feedRepository.GetFeedElements())
  14:                 feed.ElementExtensions.Add(BuildXmlElement(element));
  15:  
  16:             feed.Items = LoadPosts(_postService.GetMostRecentPosts());
  17:             return feed;
  18:         }
  19:  
  20:         private static XmlElement BuildXmlElement(FeedElementDto element)
  21:         {
  22:             var doc = new XmlDocument();
  23:             XmlElement feedElement = doc.CreateElement(element.Prefix, element.Element, element.Namespace);
  24:             feedElement.InnerText = element.InnerText;
  25:             return feedElement;
  26:         }

 

From the code you can see that when I am instantiating the SyndicationFeed object I am passing in the title of the blog, the blog description, and the URL.  Where it got a bit hairy, was adding other elements that prefixed a common namespace.  I could add the namespace for each element (as seen in the code) but there does not seem to be a way to put the common namespaces in say the channel element and then just use the prefix to those namespaces later. I ended up having to repeat the same namespaces over again.  But that being said, it is still pretty easy to build the feed.

Once the feed object is ready I then could add each of the posts by mapping them to a SyndicationItem object and then add those collection of objects to the items collection in the feed.

   1: private static IEnumerable<SyndicationItem> LoadPosts(IEnumerable<PostDto> posts)
   2:         {
   3:             IList<SyndicationItem> items = new List<SyndicationItem>();
   4:             foreach (var post in posts)
   5:             {
   6:                 var item = new SyndicationItem();
   7:                 item.Title = new TextSyndicationContent(post.Title);
   8:                 item.Authors.Add(new SyndicationPerson(post.Author));
   9:                 item.Content = SyndicationContent.CreateHtmlContent(post.PostContent);
  10:                 items.Add(item);
  11:             }
  12:             return items;
  13:         }

 

 

 

The Controller Class

Now that I have my RssResult and my functionality to build the SyndicationFeed object, I can then create an action inside my controller class that puts the two together.

   1: public class SyndicationController : Controller
   2:     {
   3:         private readonly IRss20SyndicationService _rss20SyndicationService;
   4:  
   5:         public SyndicationController(IRss20SyndicationService rss20SyndicationService)
   6:         {
   7:             _rss20SyndicationService = rss20SyndicationService;
   8:         }
   9:  
  10:         public RssResult Rss()
  11:         {
  12:  
  13:             return new RssResult(_rss20SyndicationService.Buildfeed());
  14:         }
  15:     }

 

 

The Result

So when I browse to domain/controller/action in this case http://localhost:64533/Syndication/Rss I get the following RSS sample:

 

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
   3:   <channel>
   4:     <title>Steve Moseley</title>
   5:     <link>http://www.test.com/</link>
   6:     <description>Trying my best to apprehend all these dev changes.</description>
   7:     <blogChannel:blogRoll xmlns:blogChannel="http://backend.userland.com/blogChannelModule">http://www.avingtonsolutions.com/blog/opml.axd</blogChannel:blogRoll>
   8:     <blogChannel:blink xmlns:blogChannel="http://backend.userland.com/blogChannelModule">http://www.dotnetblogengine.net/syndication.axd</blogChannel:blink>
   9:     <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Steve Moseley</dc:creator>
  10:     <dc:title xmlns:dc="http://purl.org/dc/elements/1.1/">Steve Moseley</dc:title>
  11:     <geo:lat xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">0.000000</geo:lat>
  12:     <geo:long xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">0.000000</geo:long>
  13:     <item>
  14:       <author>Steve</author>
  15:       <title />
  16:       <description>
  17:        blah, blah, blah
  18:       </description>
  19:     </item>
  20:   </channel>
  21: </rss>

 

Looks pretty good, although, if you look at my actual RSS feed and this one, you will notice that the name spaces are repeated verses being listed at the top as they probably should be.  I need to play around with it some more but this gets the job done and I did not have to write all that much code, which is nice.

Jun
15
2009

Creating a Custom Trace Listener for WCF

Introduction

We have been using WCF to consume a lot of 3rd party web services, and one of things we depend on when testing is being able to see the actual request and response that is being sent to and from the host.  This is expecially inportant in 3rd party services, because the service is essentially a black box in which there is no way to know what is going on except that you send it a request and you get a response back.  I posted how, out of the box, you can configure WCF to write the message to a trace xml file, but one of things about writing to a file is that if you or your testers do not have access to the web server where the file is being written then this is not going to work.

Solution

The way around this problem is to create a custom trace listener that catches the messages and does what ever you want.  Here is a simple sample.

Create a class that inherits from the TraceListiner class.

    1 using System.Diagnostics;

    2 

    3 namespace WcfTrace.Trace

    4 {

    5     public class WebTraceListener : TraceListener

    6     {

    7         public override void Write(string message)

    8         {

    9             //write you custom code here

   10             Debug.WriteLine(message);

   11         }

   12 

   13 

   14         public override void WriteLine(string message)

   15         {

   16             //write your custom code here

   17             Debug.WriteLine(message);

   18         }

   19     }

   20 }

The next thing to do is to wire up the custom class in the web.config (or app.config) so that when messages are created ,they caught by the custom trace listener class.  The config below is telling source messages to use the sharedListener named xml which the custom trace listener listed above.

  108   <system.diagnostics>

  109     <sources>

  110       <source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true">

  111         <listeners>

  112           <add name="xml" />

  113         </listeners>

  114       </source>

  115       <source name="System.ServiceModel.MessageLogging">

  116         <listeners>

  117           <add name="xml" />

  118         </listeners>

  119       </source>

  120     </sources>

  121     <sharedListeners>

  122       <add name="xml" type="WcfTrace.Trace.WebTraceListener,WcfTrace.Trace" />

  123     </sharedListeners>

  124   </system.diagnostics>

  125 

  126   <system.serviceModel>

  127     <diagnostics>

  128       <messageLogging

  129           logEntireMessage="true"

  130           logMalformedMessages="false"

  131           logMessagesAtServiceLevel="true"

  132           logMessagesAtTransportLevel="false"

  133           maxMessagesToLog="300000"

  134           maxSizeOfMessageToLog="200000"/>

  135     </diagnostics>

That's it.  Now when ever a web service call is made, the custom trace listener class is executed, passing it the trace messages.

Aug
7
2008

Usng Unity with a WCF Service

Introduction

In a provious blog post, I talked about using Unity in a multi-layer web application.  You could see in that example, the Application_OnStart event worked out as a very nice place to configure the Unity Container so it could be used throughout the application.  But what do you do if you have a WCF Service project, and you want to configure your service to access the same container?  In this case, you do not have access to any application events, nor is there a web context you pull from.

Oran Dennison has a nice example of accomplishing this task using Spring.Net, and it turns out there is not much to change if you want to use it with Unity also.

Step 1 - Creating an custom InstanceProvider that resolves the service.

The IInstanceProvider controls the creating and recycling of the service when it is requested.  We can impliment this interface and pass in a UnityContainer and resolve the service that is being requested.

 

    1 using System;

    2 

    3 using System.ServiceModel;

    4 using System.ServiceModel.Channels;

    5 using System.ServiceModel.Dispatcher;

    6 

    7 using Microsoft.Practices.Unity;

    8 

    9 namespace UnitySample

   10 {

   11     public class UnityInstanceProvider : IInstanceProvider

   12     {

   13         public UnityContainer Container { set; get; }

   14         public Type ServiceType { set; get; }

   15 

   16         public UnityInstanceProvider()

   17             : this(null)

   18         {

   19         }

   20 

   21         public UnityInstanceProvider(Type type)

   22         {

   23             ServiceType = type;

   24             Container = new UnityContainer();

   25         }

   26 

   27         #region IInstanceProvider Members

   28 

   29         public object GetInstance(InstanceContext instanceContext, Message message)

   30         {

   31             return Container.Resolve(ServiceType);

   32         }

   33 

   34         public object GetInstance(InstanceContext instanceContext)

   35         {

   36             return GetInstance(instanceContext, null);

   37         }

   38         public void ReleaseInstance(InstanceContext instanceContext, object instance)

   39         {

   40         }

   41 

   42         #endregion

 You can see above when the GetInstance is evoked by a service, the service's type is passed into the contructor and resolved by the UnityContainer.

 Step 2 - Create a custom ServiceBehavior object to plug in our InstanceProvider

Now that we have a cutom instance provider we need to way to insert this new provider at run time, and it is IServiceProvider that is going to provide this for us.  When the ApplyDispatchBehaviour is evoked, the code will loop through the collection of EndPoints in our project and pass the corresponding service type to the instance provider.

    1 using System.ServiceModel;

    2 using System.ServiceModel.Channels;

    3 using System.ServiceModel.Description;

    4 using System.ServiceModel.Dispatcher;

    5 

    6 using Microsoft.Practices.Unity;

    7 using System.Collections.ObjectModel;

    8 

    9 namespace UnitySample

   10 {

   11     public class UnityServiceBehavior : IServiceBehavior

   12     {

   13         public UnityInstanceProvider InstanceProvider

   14         { get; set; }

   15 

   16         private ServiceHost serviceHost = null;

   17 

   18         public UnityServiceBehavior()

   19         {

   20             InstanceProvider = new UnityInstanceProvider();

   21         }

   22         public UnityServiceBehavior(UnityContainer unity)

   23         {

   24             InstanceProvider = new UnityInstanceProvider();

   25             InstanceProvider.Container = unity;

   26         }

   27         public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)

   28         {

   29             foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)

   30             {

   31                 ChannelDispatcher cd = cdb as ChannelDispatcher;

   32                 if (cd != null)

   33                 {

   34                     foreach (EndpointDispatcher ed in cd.Endpoints)

   35                     {

   36                         InstanceProvider.ServiceType = serviceDescription.ServiceType;

   37                         ed.DispatchRuntime.InstanceProvider = InstanceProvider;

   38 

   39                     }

   40                 }

   41             }

   42         }

   43 

   44 

   45         public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { }

   46 

   47 

   48         public void AddBindingParameters(

   49             ServiceDescription serviceDescription,

   50             ServiceHostBase serviceHostBase,

   51             Collection<ServiceEndpoint> endpoints,

   52             BindingParameterCollection bindingParameters)

   53         {

   54         }

   55 

   56     }

   57 }

 Step 3 - Create a Custom Service Host that will add the new behavior

The ServiceHost object basically provides the mechamism to "load a service, configure endpoints, apply security settings, and start listeners to handle incoming requests."  We can derive a custom ServiceHost class that in our case that will also add the functionality of adding our custom Service Behavior to it.

    1 using System;

    2 using System.ServiceModel;

    3 

    4 using Microsoft.Practices.Unity;

    5 

    6 namespace UnitySample

    7 {

    8     public class UnityServiceHost : ServiceHost

    9     {

   10         public UnityContainer Container { set; get; }

   11 

   12         public UnityServiceHost()

   13             : base()

   14         {

   15             Container = new UnityContainer();

   16         }

   17 

   18         public UnityServiceHost(Type serviceType, params Uri[] baseAddresses)

   19             : base(serviceType, baseAddresses)

   20         {

   21             Container = new UnityContainer();

   22         }

   23 

   24         protected override void OnOpening()

   25         {

   26             if (this.Description.Behaviors.Find<UnitySample.UnityServiceBehavior>() == null)

   27                 this.Description.Behaviors.Add(new UnityServiceBehavior(Container));

   28 

   29             base.OnOpening();

   30         }

   31 

   32 

   33 

   34     }

   35 }

 When the service host starts it will check to see if the custom ServiceBehaviour has already been added and if it has not, then it will be added to Behavior collection.

Step 4 - Creating the Custom ServiceHostFactory

In IIS our Host will be created dynamically, so we need to use the ServiceHostFactory which uses the Factory Pattern behind the scenes to return the custom Service Host we need.

    1 using System;

    2 using System.ServiceModel;

    3 using System.ServiceModel.Activation;

    4 using Microsoft.Practices.Unity;

    5 using Microsoft.Practices.Unity.Configuration;

    6 using System.Configuration;

    7 

    8 namespace UnitySample

    9 {

   10     public class UnityServiceHostFactory : ServiceHostFactory

   11     {

   12         protected override ServiceHost CreateServiceHost(

   13                                           Type serviceType, Uri[] baseAddresses)

   14         {

   15             UnityServiceHost serviceHost = new UnityServiceHost(serviceType, baseAddresses);

   16             UnityContainer container = new UnityContainer();

   17             serviceHost.Container = container;

   18 

   19             //configure container

   20             UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");

   21             section.Containers.Default.Configure(serviceHost.Container);

   22 

   23             return serviceHost;

   24         }

   25     }

   26 }

Note that I am using the same Unity Configuration from my previous post.

Step 5 - Add a Reference to ServiceHostFactory in the *.svc file

    1 <%@ ServiceHost Language="C#" Debug="true" Service="UnitySampleService" CodeBehind="~/App_Code/UnitySampleService.cs"

    2     Factory="UnitySample.UnityServiceHostFactory" %>

Step 6 - Inject Your Objects on the Service

    1 using System;

    2 using System.Collections.Generic;

    3 using System.Linq;

    4 using System.Runtime.Serialization;

    5 using System.ServiceModel;

    6 using System.Text;

    7 using UnitySamples.Core.Controllers;

    8 using UnitySamples.Core.Dto;

    9 

   10 // NOTE: If you change the class name "UnitySampleService" here, you must also update the reference to "UnitySampleService" in Web.config.

   11 public class UnitySampleService : IUnitySampleService

   12 {

   13     private IProcessUserController controller;

   14 

   15     public UnitySampleService(IProcessUserController controller)

   16     {

   17         this.controller = controller;

   18     }

   19 

   20     public void DoWork(User user)

   21     {

   22         controller.RegisterUser(user);

   23     }

   24 

   25 }

 

 

 

Aug
2
2008

Tracing SOAP Messages in WCF

This is a nice feature that comes with WCF (Windows Communication Foundation) with regards to debugging SOAP messages.  With VS 2005, out of the box there is no way to trace message when your message is not well formed and cannot be parsed.  You have to download WSE 3 or another third party tool like Contract First to assist in debugging.

 

WCF in VS 2008 comes with a neat tool out of the box called SvcTraceViewer.exe.  To use it, you configure your service to log events when a message is made.  To do that you use the following configuration:

 

<system.serviceModel>
    <!-- add trace logging -->
    <diagnostics wmiProviderEnabled="true">
      <messageLogging
           logEntireMessage="true"
           logMalformedMessages="true"
           logMessagesAtServiceLevel="true"
           logMessagesAtTransportLevel="true"
           maxMessagesToLog="3000"
       />

    </diagnostics>     
  </system.serviceModel>
  <!-- define trace logging -->
  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel"
              switchValue="Information, ActivityTracing"
              propagateActivity="true" >
        <listeners>
          <add name="xml"/>
        </listeners>
      </source>
      <source name="System.ServiceModel.MessageLogging">
        <listeners>
          <add name="xml"/>
        </listeners>
      </source>
    </sources>
    <sharedListeners>
      <add name="xml"
           type="System.Diagnostics.XmlWriterTraceListener"
           initializeData="C:\logs\CommandLineSTS.svclog" />
    </sharedListeners>

  </system.diagnostics>

 

Once your service is configured to log messages you can then use the tool to see the SOAP message and whatever exception were captured.  Below is a sample SOAP call to the QuickSell message logged.