Welcome to Manicprogrammer Sign in | Join | Help

WCF Service Extreme Make-over - Part 3

IMPORTANT: It's really important that you read part 1 and part 2 before reading Part 3. I'll assume you did, so a lot might not make any sense unless you've read it.

Introduction

So in the previous two posts, we've established how we wanted to use and host our WCF Services, and how we actually hosted them.

Just some things to remember:

  1. Our Service should be usable by it's URL alone, which is configured using an AppSettings value with Key of "IMathServiceUrl".
  2. We want to access this service using var mathService = ServiceResolver.Resolve<IMathService>();

So, without further ado, let's have our service working. Oh, wait... Almost forgot I work for ThoughtWorks now. So let's have a failing test.

The very beginning - Our Failing Test

Let's have a test that calls on our Math Service, like this one:

[TestFixture]
public class TestServiceCall
{
    protected IMathService mathService;
 
    [TestFixtureSetUp]
    public void TestFixtureSetUp()
    {
        mathService = ServiceResolver.Resolve<IMathService>();
    }
 
    [Test]
    public void ShouldCallAdd()
    {
        Assert.That(mathService.Add(1, 2), Is.EqualTo(3));
    }
}

As you can see we initialize an instance of IMathService in our Fixture SetUp, and then just use it whenever we want it. Let's check the config file for the Test Project, just to make sure we are not using any WCF sorcery:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="IMathServiceUrl" value="http://localhost/MathService/MathService.svc" />
  </appSettings>
</configuration>

As promised we are just setting the Url for that service's endpoint. Let's run our test and check that it fails.

The actual Service Resolver

Cool, it doesn't even build, since it doesn't know any ServiceResolver classes. So let's change that by adding a ServiceResolver class to the ServiceInfrastructure project, like this one:

using System.ServiceModel;
 
namespace Stormwind.EasyWcf.ServiceInfrastructure
{
    public class ServiceResolver
    {
        public static T Resolve<T>()
        {
            return ChannelFactory<T>.CreateChannel(
                new BasicHttpBinding(),
                new EndpointAddress(UrlHelper.GetUrlFor<T>()));
        }
    }
}

What? That's it? I'm sure you must be mistaken!

Not at all my dear friend, and you can thank the WCF Team for that. They made it very easy to create a client-side proxy using code, instead of a Service Reference.

Now, let's run our test again, and who could foresee it! GREEN!

Conclusion

That's all there is to it, though. Even though I would like to keep rambling on and on about how hard it is, it wasn't even hard. I just had a hard time finding resources that explained the whole process. That's why I decided on writing a comprehensive post on it.

I really hope that these three posts have helped you grasp how to use WCF in a more developer-friendly way. I'll post next on how to do secure bindings and stuff like that using this approach, which is quite good to ENFORCE security, since the client and host cannot mess with the security settings. Once again, it has drawbacks on flexibility.

The full code for Stormwind.EasyWcf is available through our Subversion server at: http://svn.stormwindproject.org/svn/Personal/Heynemann/Stormwind.EasyWcf.

Cheers.

Published Wednesday, July 16, 2008 1:08 PM by heynemann
Filed under ,

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# while(availableTime>0) { : WCF Service Extreme Make-over - Part 2

# re: WCF Service Extreme Make-over - Part 3

Wednesday, July 16, 2008 11:39 AM by Maethorin

GREAT!!!!

You never stop dude??? :D... Thanks God for this...

To implement new end points type, like net.tcp, its seemed to be easy too.

Just add another appSettings <add key="IMathServiceTcp"...

and an overload to public static T Resolve<T>(BindindType bindindType)...

Is that right???

# re: WCF Service Extreme Make-over - Part 3

Wednesday, July 16, 2008 11:51 AM by heynemann

Yeah.

You would have to change both ServiceResolver and ServiceHostFactory in order to succeed in that. But it is pretty easy, yes.

Cheers,

Bernardo Heynemann

# re: WCF Service Extreme Make-over - Part 3

Tuesday, November 18, 2008 4:30 PM by Trace

Hello

Great Post, but i get always errors with the Solution.

1. No protocol binding matches the given address

2. When changing the Url to the development server port, so i get always an bad request error.

Can you give me please more informations about running the sample?

Many thanks

# re: WCF Service Extreme Make-over - Part 3

Wednesday, November 19, 2008 3:56 AM by Trace

I have found a solution that works fore me.

1. Add the baseAddresses to the service host.

2. set the HttpGetEnabled to true

public override ServiceHostBase CreateServiceHost(string service, Uri[] baseAddresses)

       {

           var implementationType = Type.GetType(service);

           var contractType = GetContractFrom(implementationType);

           var serviceHost = new ServiceHost(implementationType, baseAddresses);

           serviceHost.AddServiceEndpoint(contractType,

                                          new BasicHttpBinding(), UrlHelper.GetUrlFor(contractType));

           ServiceMetadataBehavior metadataBehavior = new ServiceMetadataBehavior();

           metadataBehavior.HttpGetEnabled = true;

           serviceHost.Description.Behaviors.Add(metadataBehavior);

           return serviceHost;

       }

# re: WCF Service Extreme Make-over - Part 3

Wednesday, November 19, 2008 7:20 AM by heynemann

Nice Job!

Cheers,

Bernardo Heynemann

# re: WCF Service Extreme Make-over - Part 3

Wednesday, November 19, 2008 4:01 PM by Trace

Here is another solution, if you want to use the service as webservice and script service (JSON)

1. Derive from WebScriptServiceHostFactory

2. Get the ServiceHost from the base class "base.CreateServiceHost"

3. set up the ws-endpoint

public class DefaultServiceHostFactory : WebScriptServiceHostFactory

   {

       public override ServiceHostBase CreateServiceHost(string service, Uri[] baseAddresses)

       {

           var implementationType = Type.GetType(service);

           var contractType = GetContractFrom(implementationType);

           var serviceHost = base.CreateServiceHost(implementationType, baseAddresses);

           serviceHost.AddServiceEndpoint(contractType, BindingHelper.GetWSHttpBinding(), "ws");

           ServiceMetadataBehavior metadataBehavior = new ServiceMetadataBehavior();

           metadataBehavior.HttpGetEnabled = true;

           serviceHost.Description.Behaviors.Add(metadataBehavior);

#if DEBUG

           ServiceDebugBehavior debugBehavior = (ServiceDebugBehavior)serviceHost.Description.Behaviors[typeof(ServiceDebugBehavior)];

           debugBehavior.IncludeExceptionDetailInFaults = true;

#endif

           return serviceHost;

       }

       private static Type GetContractFrom(Type serviceType)

       {

           var contract = serviceType.GetInterfaces().Where(type => type.IsServiceContract()).SingleOrDefault();

           if (contract != null)

               return contract;

           throw new InvalidOperationException(string.Format("The type {0} is not a service. Try using the ServiceContractAttribute.", serviceType));

       }

   }

Here an example for the binding helper:

public static class BindingHelper

   {

       public static WSHttpBinding GetWSHttpBinding()

       {

           WSHttpBinding wsHttpBinding = new WSHttpBinding();

           wsHttpBinding.MaxReceivedMessageSize = int.MaxValue;

           wsHttpBinding.MaxBufferPoolSize = int.MaxValue;

           wsHttpBinding.ReaderQuotas.MaxArrayLength = int.MaxValue;

           wsHttpBinding.ReaderQuotas.MaxStringContentLength = int.MaxValue;

           return wsHttpBinding;

       }

   }

In the client configuration you can now use the webservice

http://localhost/MathService/MathService.svc/ws

for Ajax clients you can get the javascript proxy with following url:

http://localhost/MathService/MathService.svc/js

# re: WCF Service Extreme Make-over - Part 3

Thursday, November 20, 2008 6:09 AM by heynemann

Cool as well! Thanks for the comments!

Cheers,

Bernardo Heynemann

# re: WCF Service Extreme Make-over - Part 3

Thursday, November 20, 2008 6:14 AM by heynemann

Just thought I'd mention. You guys know that we have a project called EasyWcf in Stormwind that needs some love, right?

You both seem very knowledgeable of WCF. Wouldn't you like to contribute?

Just let me know if you do and we can talk further.

Cheers!

Bernardo Heynemann


Enter the text you see in the image:

Leave a Comment

(required) 
required 
(required)