Professional Documents
Culture Documents
Hi. This is Aaron Skonnard with Pluralsight. I'll be presenting this module on Introducing WCF, or
Windows Communication Foundation. As far as prerequisites are concerned, we assume you'll have
some familiarity with basic web service concepts. But we don't expect you to have any concrete
experience using WCF, or .NET 3.0. If you're brand new to these things, you're in the right
place. Well begin this module by providing you with a quick overview to the world of connected
systems. Along the way, we'll discuss some of the trends that've caused the industry to move
towards this new concept of services. We'll discuss service-orientation, a new design paradigm that
you adopt to buildservice-oriented architectures. After that brief introduction, we'll be prepared to
turn our attention to Windows Communication Foundation, a new programming model that's part
of .NET 3.0 for building these types of service-oriented solutions. We'll cover some of the basics
around how you write the WCF code to both implement, and consume services. And towards the
end of this module, we'll answer some of the most common questions that developers ask when
they're first presented with this new technology. Okay, with that in place, let's dive in.
on Windows. There are actually quite a few ways to build connected systems on
Windows. Microsoft has shipped numerous communication frameworks over the years for doing
this. I'm guessing that most of you will probably have experience with at least one, if not all of the
frameworks we're about to discuss. Back in the day, we had things like DCOM, and COM+, and
even when they shipped .NET 1.0 they released a wrapper for those things called Enterprise
Services. This gave us a very component-oriented approach for building connected systems, very
RPC-based in nature, where you could take your COM components and deploy them around the
network, and then invoke them remotely. One of the key characteristics of this technology was
distributed transactions, where you could have a logical transaction span the work being done by
multiple COM components throughout the network, which turned out to be very compelling in a lot of
scenarios. Now, in order to take advantage of this technology, it did require you to have the DCOM
infrastructure available on every node that would take part in that style of communication. With the
release of .NET, they also introduced a brand new distributed object technology known as .NET
Remoting. Very similar to DCOM in a lot of ways. It was also very component-oriented, and RPC in
style, but it was a solution for managed code, meaning that your components would execute
completely in a managed environment within the .NET CLR. As a result, .NET Remoting turned out
to be very simple, and highly extensible, but it still did depend on a key piece of infrastructure, in this
case, the .NET CLR. And then there's our good old friend MSMQ. Unlike the other two frameworks,
which are very focused on components and RPC, MSMQ is purely focused on messaging.
Meaning, it allows you to take a message and transmit it between two nodes in a connected system
in an asynchronous durable and reliable fashion. It has nothing to do with components, or method
calls. However, it does still require a key piece of infrastructure; that of MSMQ. If you're going to use
MSMQ throughout your system, you will have to have the MSMQ infrastructure installed on every
machine that will participate in that style of communication. So here we have three frameworks, all
focused on communication, and they each come with some key features, and characteristics that
we may want to employ in our connected systems. In fact, it's often the case where we may want to
employ all three of these frameworks at the same time. Well the problem with that is that each of
these frameworks comes with a unique programming model,meaning the way I write the code for
one framework is going to be very different from how I write it for another. This requires your
developers to become familiar with the intricacies of numerous programming models in order to
accomplish what are essentially similar goals. The other problem with these traditional
Microsoft frameworks is that they each restrict you to Windows everywhere throughout your
connected system. Each framework depends on key infrastructure, which, for all practical purposes,
is only available on Windows today, and in today's growing connected world, this restriction alone
turns out to be quite problematic indeed.
deal of energy has been invested throughout the industry in this line of service-oriented
thinking. And now today, there are two primary philosophies that one can adopt when
designing service-oriented solutions.
SOAP-based services
SOAP and WS-* based services build on a great deal of work that's been happening throughout the
industry to implement a completely new protocol stack for services. One of the primary design goals
for this new protocol stack was that of transport neutrality, meaning that any additional features, or
capabilities that we want to implement for our services, should be possible to implement in a
transport neutral way. And we'll accomplish that in this protocol stack by using an XML-based
messaging layer. Now, this is where SOAP comes into the picture. SOAP is a particular XML
vocabulary for packaging up messages that we need to transmit to our services. Let me bring up
Notepad now to illustrate what a SOAP message looks like. The SOAP message always contains a
root Envelope element from the SOAP namespace.I'm just going to type in ... for the SOAP
namespace identifier for now just because I don't want to type it all in. Now, a SOAP Envelope
contains two other elements. It contains a Header element, as well as a Body element. The SOAP
Body is where you'll actually place your Payload element. So if your service is dealing with invoices,
this is where your Invoice would go. (Typing) Now the SOAP Header section up here is where it gets
interesting. This is where you can place additional XML-based headers that have semantic meaning
around different types of capabilities. For example, this is where I can implement security, RM, and
transaction capabilities. The various WS-* protocols are implemented as SOAP Headers, and those
Headers would go right here. So this gives me a mechanism for implementing those types of
security, RM, and transaction features, completely in XML, within the XML SOAP message. And that
allows me to take advantage of those behaviors over any transport that I choose to use. Now,
jumping back to the slides, that's where these various WS-* specifications fit into the picture. They're
simply standard SOAP-based headers that revolve around security reliable messaging and
transaction capabilities. Now, if you happen to be using any of these advanced features, you'll also
need to provide your consumers with metadata that conveys to them the capabilities
and requirements of your services. This gives us a complete protocol stack for implementing a wide
variety of advanced services. The vendors usually implement this protocol stack within the context
of an RPC-based toolkit, meaning that you would write service contracts through method
signatures. Each method signature defines a service operation that you want to expose on the
service.This makes the code you end up writing feel an awful lot like the code you used to write
back in the days of COM+, only this time the functionality, and capabilities will be available to you in
a completely interoperable fashion, even at these more advanced levels of service functionality.
RESTful services
RESTful services are fundamentally different than SOAP-based services, because they don't
attempt to achieve transport neutrality. In fact, RESTful services typically embrace HTTP as the only
transport used throughout the system. The reason I say typically is because RESTful design doesn't
say anything about which implementation technologies you use; however, in practice, HTTP is the
only commonly used protocol. With REST, you model services as resources, and you give them
unique identifiers in the form of URIs. And then you interact with those resources through a standard
uniform interface, or service contract. In this case, it would be the methods defined by the HTTP
protocol; specifically GET, POST, PUT, DELETE, and HEAD. By standardizing on a uniform
interface, we can build infrastructure around the semantic meaning of each operation, and make
performance, and scalability improvements when possible. This turns out to be extremely
adventitious when building highly scalable web applications and services. Now, we also need to be
able to represent resources using a concrete representation, a message format, such as XML, RSS,
JSON, etc. So when we work with our resources, when we request them, or update them, or create
them, we're going to be passing a representation of that resource at a particular point in time. Let's
look at an example of what it might be like to interact with a RESTful service. So here I have a
RESTful service that deals with invoices, and let's say that I want to create an invoice. Well the way
I'll do that is I'll take a representation of my invoice, and I'll send a PUT message to the address
where I want that resource to live. So this address that you're looking at here is the identifier for the
resource that I'm about to create. So when I send that HTTP PUT message to the service at
that address, we will create an invoice with the ID of 123. Later on, someone can walk up to the
service and request that particular invoice by simply sending a GET request to the service at that
same address, asking for invoice 123, and that consumer will then get a representation of that
invoice back out, most likely in XML format. And then later on, if someone wants to delete that
invoice, they can simply send a DELETE message to the service at that address, causing that
particular resource to be deleted. Now, when you build services this way, the assumption is that
HTTP can provide you with all the necessary features that you need around security, and scalability,
and it has proven to be a very successful design pattern used throughout the web in a wide variety
of web applications, and highly scalable web services.
and WS-Trust, and they also introduced support for simple TCP-based services as well. Now you
could use WSE either standalone, or in conjunction with ASMX to add some of those behaviors
to your ASMX services. But in the end, both of these frameworks turned out to be quite limited in
several ways. In the area of SOAP-based services, they didn't provide much support for the wide
variety of WS-* specifications that we would hope to have. They also didn't provide much in the way
of transport neutrality, or, in other words, additional protocols, additional transport protocols that we
can could use to transmit our SOAP messages. They also didn't provide much in the way of building
RESTful services. So they were a good first step, but they didn't really come close to achieving the
full vision of either SOAP-based services, or RESTful services. The other problem with these two
frameworks is they each came with a new programming model. So, if you were building a
connected system that used some of those other Microsoft communication frameworks, like
COM+, .NET Remoting, and MSMQ, and then you also introduced one of these web service
frameworks, now you had even more programming models your developers had to deal with. The
good news is, Microsoft realized that this wasn't a good situation for their connected systems
developers to be in, and so they quickly started thinking about what an ideal communication
framework might look like.
as message formats. In some cases, I might want to use HTTP and XML for interoperability, or as in
other cases I might want to use TCP and binary messages for raw performance and efficiency. And
in some other cases, I might want to use HTTP and JSON to help accommodate AJAX style
applications. The point is, I should be able to pick and choose which transport, and message format
combination makes the most sense for a particular communication scenario. They also knew they'd
have to make it easy to pick and choose from the various WS-* protocols that you might choose to
use, if any. Microsoft realized that if they could provide a high degree of flexibility around the
transport,message format, and messaging protocols, that you would be able to take this framework
and adapt it to pretty much any communication scenario that you might face within a large
connected system. But even with that high degree of flexibility, Microsoft also realized that they
wouldn't be able to accommodate every scenario in V1 out of the box. So they also knew that they
would have to provide significant extensibility opportunities throughout the API, by providing
numerous extensibility points that would allow you to plug in your own transports, your own
message formats, or even your own messaging protocols when needed, or even your own
processing behaviors when the default WCF processing doesn't fit your precise needs. So after a lot
of careful analysis and design, this is what Microsoft concluded thattheir unified communications
model should look like on Windows moving forward, and the result was Windows Communication
Foundation.
Introducing WCF
So WCF is the new unified communications framework for Windows moving forward. To recap, it
takes all the best ideas from these existing communication frameworks we've had on Windows, and
it attempts to unify them into one logical model. This essentially greatly simplifies the
communications landscape on Windows, and makes WCF the default choice for connecting your
applications from this point on. Now, when you're faced with a particular communication scenario,
you no longer have to suffer from paralysis by analysis, thinking about all the different
communication frameworks you might choose to implement that actual scenario. Now, the choice is
clear. You simply use WCF to write the communication logic, and then you decide which of its many
features you wish to employ. Most of the WCF functionality is found within a single assembly called
System.ServiceModel.dll, which you will get once you install the .NET Framework 3.0. Now, let's
return to this connected systems scenario from before, and see what it will look like by using
WCF. Well we should point out at first that WCF is indeed a service-oriented programming
model. So the way we'll go about implementing this connected system is by writing, and deploying
what are called WCF services on each node. Now, there's just one way to write this code, so there's
only one programming model your developers will have to learn, regardless of how you might
choose to communicate with these services. In one case, you may decide to use a distributed object
style of communication, where you use TCP-based communications, and raw binary messages for
performance reasons. In another case, you may decide to use more of a SOAP style service, where
you use the SOAP-based message format on the wire, and use MSMQ to transmit those messages
in a secure, reliable, and asynchronous manner. And then in another scenario, you may choose to
use a RESTful style, where you actually embrace HTTP as the transport mechanism, and you
retrieve resources that may be represented using the RSS format. The point is, WCF supports all
these different communication styles, and many more not illustrated here. So, we have just one way
to write the code, but many ways to connect the dots between the services. This, in a nutshell, is the
value of WCF. Okay, time to get a little more specific. When we say there's just one way to write the
code, what do we really mean? Well, in WCF, we're going to write traditional .NET classes and
interfaces. The classes will represent the messages that we're going to send as part of a service
operation. And the interface definition defines the set of operations that we want to expose on
a particular service contract. And so we'll use traditional .NET code to layout the basic structure of
these things, and then we'll annotate them with some special WCF attributes. The combination of
these two things basically defines the communication contracts for our WCF services. We can then
go implement these contracts on a .NET class. Notice here below, I've got a class
called InvoiceService that derives from our service contract, IInvoiceService, and we simply
implement the method SubmitInvoice. This is where the business logic goes. Pretty much all the
services that you author with WCF will follow this basic model. So that's how you write the code.
Now, how about connecting the dots? Well, in WCF you do this by configuring what are called
endpoints on your service. Here I've got my InvoiceService configured with three different
endpoints. Each endpoint defines a different communication option for talking to the service. This
first endpoint uses REST over HTTP. The second endpoint uses SOAP and WS-* over MSMQ, and
it uses binary messages by default. And this third endpoint also uses SOAP and WS-*, but over
TCP, and it also uses binary messages for efficiency. So we've got a single service
implementation, but three wildly different communication endpoints for talking to the service, and we
were able to accomplish all of this strictly through configuration. We didn't have to touch the service
implementation code at all to accommodate these different options.
DataContract that red underscore appears allowing me to hit Ctrl+., then I can say let's add that
using statement for System.Runtime.Serialization, so that comes in. Then for each field that I wish
to expose, I type in DataMember. I'll need to do this down here with Last as well. And now we have
a type that I can use within my service operation. Now I'll define a public interface called
IHelloWorld. And IHelloWorld's going to have a single operation that returns a string called SayHello,
and this will take one of our Name objects, and we'll just call that person. Now in order to expose
this as a service contract, I also need to annotate the interface with the ServiceContract attribute.
Now, if I hit Ctrl+. here, that will allow me to bring in the System.ServiceModel namespace. And the
other attribute I need to apply here on the method is the OperationContract attribute. So that tells
WCF that this is a service-oriented contract that couldbe hosted within, that can be exposed through
a WCF service endpoint. Now to actually implement this ServiceContract, I'll come down here to this
class, which I'm going to make public, and I will simply derive it from IHelloWorld. And here I can
press Ctrl+. to automaticallyimplement that interface. And then down here within the implementation
of SayHello, I will simply return string.Format, passing in Hello, First, Last, and we'll pass in
person.First, person.Last. Okay, that'll be our implementation. Now notice I didn't have to annotate
this implementation class with any additional attributes. All of the contractual attributes are simply
inherited from the interface definition, and the class definitions that we're using in the operations. So
when we say there's one way to write the code, this is essentially what we're talking about. We're
talking about this programming model for adding attributes to classes and interfaces, and
implementing those on a concrete surface implementation class. Now we're ready to host this
service. At this point, we'd either have to write our own host application, or host this thing and deploy
it inside of IIS. But there is another way. Visual Studio 2008 comes with a test WCF service host
application, which will allow you to automatically host up your WCF service libraries without writing
any code. And so that's the approach I'm going to use. But we still have to tell that host application
what endpoints I want to expose on this service. So we'll do that over here inside of our App.config
file. So, let me bring that up. Okay, here I'm going to need to update this App.config file to tell it the
name of my service that I'm trying to expose. In our case, it was called HelloWorldService. And I'm
also going to change the baseAddress here to something a little simpler. I'll change the
baseAddress to 8080/helloworld. And then down here below is where I'll put all my endpoints.Now,
they put a bunch of stuff in here that I'm not going to need for this example, so I'm simply going
to remove them, and I'm going to change the contract on this first endpoint that it gave me to
IHelloWorld. Then I'm going to copy this endpoint and add a few different endpoints into the mix. So
the first endpoint will have a relative address of ws. So we'll have a baseAddress
oflocalhost:8080/helloworld/ws, and that's going to use the wsHttpBinding, and my contract is
IHelloWorld. If we jump back to the code just to confirm that's what our interface name was. And
then the second one is going to use the basicHttpBinding. So we'll have a relative address of
basic, the binding will be the basicHttpBinding, and it also exposes the IHelloWorld service
contact. And finally, we'll have a TCP-based endpoint. So we'll have a relative address of tcp. I'll
specify the netTcpBinding, and, actually I can't use a relative address of tcp, I'm going to use a
full address specifying net.tcp as the protocol scheme, localhost:8081/helloworld. So we'll actually
use a full address for the TCP endpoint. Now, with this in place, we're ready to host the service. All I
need to do is save this file, and then I can go ahead and press F5 to launch the WCF service host
application. You'll notice this little bubble shows up down in the system tray showing me that the
WCF service host did indeed launch, and you'll see this little icon show up down here in the
corner. If I double click on that, it brings up the Service Host application, and you'll notice that it
thinks it's indeed hosting our HelloWorldService. It shows the service as Started, and it shows the
Metadata Address where we can request metadata from this service. I didn't really mention that, but
if you look at the App.config file, this service was indeed configured to expose metadata. Then it
also launched this WCF Test Client application, which automatically requested the metadata from
our service running in that test host, and it downloaded all of the endpoints. It actually found three
endpoints that were available on that service, and this actually shows you the different endpoints
that we had. And then it gives us the ability to invoke any one of these different endpoints. I can just
double click on the operation, and then over here it gives me a little form to type in theinformation
that I want to send across as part of this operation name, as part of this service operation set of, this
service operation message, I should say, and then I can go ahead and press Invoke. That sends a
message to our service, and hopefully we'll get a response back here that says Hello Aaron
Skonnard. I can go ahead and press SayHello on a different endpoint, and now we'll invoke it using
TCP. So here we'll pass in Joe Bob, and press Invoke, and this went over the TCP-based
endpoint. So, there you have an example of building a simple WCF service. We wrote the code in
this one C# file. In fact, let me stop the debugger, so I can show you this in full screen. There was
one way to write this code, but there were many ways to talk to that code through these
three different endpoint definitions that we configured on the service.
Built-in bindings
Let's just spend a few more seconds discussing this idea around bindings. A binding is essentially a
recipe for how WCF will build the underlying communication channel. Now, WCF comes with a
whole bunch of built-in bindings for some common communication scenarios,and I've listed those
here. You can think of these as just a bunch of built-in recipes for how WCF will configure the
underlying channel stacks. As you can see here, the first three bindings all use HTTP. The transport
is actually implied within the binding name. The first one provides RESTful style communications,
whereas the following two provide SOAP style communications. The BasicHttpBinding gives you
simple SOAP support that conforms to the WS-I Basic Profile. That'll give you a high degree of
interoperability with other non-Microsoft SOAP-based toolkits. Whereas the WSHttpBinding will give
you access to the full range of WS-* protocols for those more advanced web services scenarios.
Now, since all three of these HTTP bindings are meant for interoperability, they all use XML
message formats on the wire. Now, the remaining four bindings shown in this table do not have a
goal around interoperability. In fact, they actually assume that you'll be using WCF on both sides of
the wire. That's why their names begin with Net, because the assumption is their going to be
used for .NET-to-.NET communication. The NetTcpBinding is used for cross-machine
communication over TCP, and the NetPeerTcpBinding is also used for cross-machine WCF
communication, where you want peer-to-peer semantics. The NetNamedPipesBinding gives you
same-machine communications in a very efficient manner. So, if your clients actually reside on the
same machine as the services, or perhaps even within the same process, or app domain, that
would be the binding you would want to use. And finally, we have the NetMsmqBinding, which
allows us to make WCF service calls over MSMQ as a transport. All of these Net bindings use
efficient binary messages on the wire, because, again, they aren't trying to accomplish
interoperability, and since we know we'll have WCF on both sides, they always optimize
for performance and efficiency. Now, typically you'll just be able to pick one of these bindings, the
one that best fits the communication scenario you're trying to tackle. But if you run into a scenario
that can't be satisfied with one of these built-in bindings, you can always write a custom binding, or a
custom recipe, that specifies your exact communication requirements.
Now, let me show you how to build a simple WCF service client that consumes the
HelloWorldService we just built. So, I'll start by pressing Ctrl+F5 to launch our HelloWorld service
into the WCF Service Host application, the test host that comes with Visual Studio 2008. Notice our
HelloWorldService is up and running now. We can right click, and select Copy Metadata Address to
grab the metadata address into our Clipboard. Now, I can return to Visual Studio and I want to build
a new client that can talk to that service, so I'm going to Add a New Project, and I'm going to add a
Console Application project, and I'll just call this thing Client. And then I'm ready to add a reference
to our HelloWorldService. Well, one of the new features in Visual Studio 2008 is the Add Service
Reference feature. So I can select that, and then Paste in the address to our metadata endpoint,
and press Enter. This contacts the service, and downloads the metadata, and shows me the service
contracts that are available, and the operations that are found on them. If I'm happy with that
service, I can go ahead and type in aname for my service reference. In this case, I'll call it
HelloWorldServiceReference, and press OK. That downloads the metadata, and generates a few
things for me. It adds in all the WCF assemblies that I'll need in the Client project, and it creates this
Service Reference node here, which basically is just a nice package for all the code it created, and it
also adds this app.config file, which will contain all of theclient side endpoint definitions for talking to
that service. If you right click on the Service References, and select View in Object Browser, you can
actually come over here and look at all the code that it generated for you on the client side. Notice
we have the Name class with our First and Last Name fields. It also created the IHelloWorld
interface with our SayHello operation, and it created a wrapper proxy class called HelloWorldClient.
That'll make it really easy to invoke our service from the client side through that IHelloWorld
interface. Okay, so that's what we're going to use. So, to begin writing our code, we just need to
come into our source file, and first add in a namespace, a using statement for our
HelloWorldServiceReference. Then I can come in here and instantiate a HelloWorldClient. Now,
when I instantiate this, the thing I need to pass in here is the endpoint name that I want to use. If we
jump back over here to our app.config file, and open it up, you'll see that it actually created three
endpoint definitions for me on the client side, and each one represents one of the endpoints that we
had configured originally on the service side. So, I just have to decide which one of these endpoints
I want to use. How about we'll use the NetTcp endpoint for this example? So, here's the endpoint
name. I'm going to grab that endpoint name and put it in my Clipboard, and then jump back here to
the source file, and Paste that endpoint name right here into my code. So, now when it constructs
this client proxy object, it'll actually build the underlying communication channel based on that
endpoint definition. Then, I'll need to generate a Name object, and I'll need to fill it up with some
data. We'll have the First field, let's pass in my name, along with the Last field, and then I can go
ahead and call client.SayHello, and pass in the person object. Now remember, SayHello returns a
string, so I could actually just print out to the Console Window the result of calling SayHello. That's
what I'll do. Let me go ahead and Build this, make sure it Builds. And now we're ready to test our
client. Now there's a few different ways we could test this client. We could just dropout to a Console
Window, and try invoking it directly, or we could tell Visual Studio 2008 to launch it for us. I'll do the
latter. So, I'm also going to add in just a little Console.ReadLine to hold this Window open after its
done executing. Then I'm going to come over here to my HelloWorldService, and I'm going to right
click on it, and go to Properties, and then in the Debug Window, notice here you can specify the
name of the client application you want it to execute. Well the name of our client application is
client.exe, and I need to specify the working directory, which is going to be Client, bin, Debug. So
that's the working directory where this client.exe lives, and client.exe is the name of the application.
So now, if I go ahead and Close this, I should be able to just press F5 to test both our service, and
our client at the same time together. So, I'll press F5. It launches the service within the service host,
and then notice it launched our Client Console application, and it printed the result of calling
SayHello to our Console window. So in this demo you saw how to build a client application by
walking up to a service, retrieving its metadata, and generating local endpoint definitions, and
service contract definitions that you can use to build a client side WCF channel for communicating
with that service.
many other frameworks are there in the world that WCF can interoperate with? Well, the answer to
this question is actually a function of the number of WS-* protocols you choose to use within your
services. And I basically plotted the answer here on this graph. Obviously, the more WS-* protocols
you use in your services, the fewer interoperable frameworks you'll find in the world, and the
converse is also true if you don't use hardly any WS-* protocols. Perhaps you're doing simple SOAP,
or REST, and you're not using any of them, you'll basically be able to interoperate with almost any
other framework in the world today. The reason for this is because it's reallydifficult to implement the
full range of WS-* protocols. Today, only four large vendors have been able to accomplish this
successfully. You have Microsoft, IBM, Oracle. There was also BEA, but it was recently acquired by
Oracle, and SAP. If you're using the full range of WS-* protocols in WCF, you're most likely only
going to be able to interoperate with one of the frameworks provided by one of these other
vendors. Now, again, if you don't use hardly anything in terms of the WS-* support, then it's pretty
much wide open. You'll be able to interoperate with almost any other framework on the planet. The
next question that people often ask is, what about all my existing communication code? Let's say I
have existing investments built with ASMX, or WSE, or .NET Remoting, or COM+. What about all
those things? What's my migration path forward? Well, first it's important to note that WCF does
integrate on the wire with some of those key Microsoft frameworks that we discussed earlier. For
example, WCF can integrate with COM+ Enterprise Services, as well as ASMX, and WSE 3.0, as
well as MSMQ. So, assuming you have investments around built with one of those different
communication stacks, you can plug your new WCF applications into those existing investments on
the wire. You can effectively bridge between those different communication components using some
of the features that WCF provides out of the box. Now, you can also fully migrate the code. If you
want to take that COM+, or ASMX, or MSMQ code and port it over to WCF, that's usually
pretty simple and mechanical. It's not going to require huge amounts of time and investments,
unless you used a lot of low level extensibility code. And the one thing I should note about this
picture is the one missing framework here, of course, is .NET Remoting. Wire-level interop with
.NET Remoting is not supported by WCF. Another key question is, what does WCF run on? The
answer to this is pretty simple. Basically, all of today's modern Windows platforms. WCF can run on
Windows XP SP2, Windows Server 2003, Windows Vista and Longhorn, and Windows Mobile, at
least a subset of WCF. And finally, the last question we need to answer is, why should I move
towards WCF? Well, there're actually lots of answers to this question, but probably the most
fundamental reason is that it's bound to increase your developer productivity. Thanks to WCF's
unified programming model, your developers now only have to worry about a single programming
model for writing all their communication logic. And that fact alone is bound to increase your
developer productivity results over time. Another reason is that if you move to WCF, you will
immediately increaseyour interoperability potential. Like we discussed, WCF is capable of doing
basic web services, and all the way up to advanced SOAP and WS-* communications, giving you a
wide range of communication options on the wire. WCF also provides increased flexibility. Not only
in terms of the communication, like we just talked about, but also in terms of being able to plug in
your own code. WCF is one of the most extensible frameworks I've ever worked with it. If you're not
happy with some of the built-in functionality that comes with WCF out of the box, you can always
inject your own behaviors, and communication protocols that address your precise needs. Plus, the
way WCF is designed to work, you don't actually have to move everything over to WCF
immediately. You can also choose to adopt WCF piecemeal, step-by-step. You may decide today
that you're just going to start building some of your new services with WCF, just to get your feet wet,
to get familiar with how it works, and understand the issues you're going to run in to. And, of course,
thanks to its interoperability potential, and the fact that it can integrate on the wire with some of
today's existing Microsoft frameworks, it's very easy to plug those new WCF services into your
existing connected systems. There's no reason why you have to decide to move your entire
connected system over to WCF at a single point in time. And the last, perhaps most practical reason
for moving towards WCF, is that all of Microsoft's future communications work is focused here. So, if
you want to benefit from all of Microsoft's future investments on the communications front, you'll
really need to move over to WCF at some point in time.
Summary
And that brings us to the end of this module. To summarize, WCF provides a unified programming
model with great flexibility around communications. It essentially replaces the need for all of the
preceding Microsoft Windows based communications frameworks, and it does so by bringing all the
key features, and capabilities from those frameworks into one unified runtime, that gives you your
choice of architectural style, transport, message format, and messaging protocols. This really is the
new DCOM for the next decade.
Programming Services
Overview
Hi. This is Aaron Skonnard with Pluralsight. I'll be presenting this module on programming WCF
services. In this module, we'll be diving further into the details of the WCF program model,
specifically around how you author WCF services. At this point, we assume that you have some
basic familiarity with WCF architecture, and terminology, but that's about it. We'll begin this module
by providing you with a quick review of the WCF service model architecture. After that, we'll cover
the steps involved in programming WCF services, specifically defining message structures, defining
service contracts, implementing those service contracts on service classes, and then finally, hosting
services in your own applications. Next, we'll cover how to configure services with both endpoints
and behaviors. We'll also discuss how to publish service metadata, and some different options
around how to do that, including WS-Metadata Exchange. And finally, we'll discuss some of
the important concepts around service exceptions. Let's just quickly review the WCF service model
architecture. In WCF, you write services that expose endpoints. So here we have a service that's
going to be hosted inside of some .NET 3.0 application. That service can then expose one or more
endpoints to the outside world. If this client wants to consume that service, it needs to walk up to the
service and request its metadata in the form of a WSDL definition. The client can then take that
WSDL definition and process it through what's called a metadata import tool on the client side to
produce some local endpoint definitions. The client can then pick one of those endpoint definitions
that it wants to invoke; in this case, the one that's highlighted in gray, and it can create what's called
a WCF channel based on that endpoint. With that channel in place, the client can then simply make
method calls through the channel to transmit messages to the service through that particular
endpoint. So, as illustrated in this picture, the service model architecture really revolves around this
concept of endpoints, both on the service side, as well as the client side, providing a symmetric
model on both sides of the wire. Now, in this particular module, we're going to be spending most of
our time talking about the experience on the service side, how you go about implementing those
services, exposing the endpoints, and hosting the service within a host application. Okay, so how do
you actually go about programming a WCF service? Well, typically when you program a
WCF service, you follow these steps. First, you spend some time defining the data contracts. A data
contract is essentially a piece of data that will become part of a message that you transmit to the
service. Then, you define your service contracts. A service contract is essentially a group of
operations that you want to support on the service. Then you implement the service, and you do this
by simply implementing some of the service contract types on your service class. Then, you're ready
to host the service, and there are quite a few options here for hosting. You can either host the
service in your own .NET 3.0 application, or you can host it inside of IIS, or WAS. And then finally,
you can configure the service with endpoints and behaviors. The endpoints control how you
communicate with the service, whereas the behaviors influence how the service executes locally
within the .NET app domain. Now, let's take a few seconds to discuss each of these steps in more
detail.
application code. So you do have a choice. So WCF supports both typed and untyped message
processing. With untyped message processing, you simply define your service operations in terms
of that generic message type we just discussed. If you want to use typed message processing, then
it's your job to define the .NET types that your messages will map into. Then at runtime, WCF will
provide what's called a serializer to actually perform the mapping between the messages and the
.NET objects. The serializer will take a message and deserialize it into an object, or it can take an
object and serialize it back out into a message. The way the serializer figures out to perform this
mapping is by looking at the .NET type definition for the target object your mapping to or from. In
WCF, this is often referred to as the data contract. So, how do you write one of these data
contracts? Well, the way you write a data contract is actuallydependent on the serializer you happen
to be using. WCF actually supports several serializers out of the box, but we're going to focus on the
default serializer in this module, called DataContractSerializer. The DataContractSerializer is
actually quite a bit different than the XML serializer used by ASMX. With the XML serializer, it would
take any public class and serialize out all of its public read/write fields and properties by default
without any specific annotation. The DataContractSerializer, on the other hand, requires you to
explicitly annotate your types, telling the serializer exactly what you want to include in the message.
You do this through some special mapping attributes that are found in the
System.Runtime.Serialization namespace. This is the one other namespace you're going to want to
keep in your head besides System.ServiceModel. And there are two core attributes that you'll use
quite a bit, DataContract, and DataMember. Let's take a look at an example of how you might use
these. So here we have an Invoice, and let's say that we want to make this is a DataContract
type. We can accomplish that by simply annotating Invoice with DataContract, and each field that
we want to include with DataMember. So we add DataContract to the type definition, the actual
class, and that essentially makes the class serializable through the DataContractSerializer.And we
annotate each field, or property that we want to include with DataMember to include that piece
of information in the message. Notice, we can do that to both public and private fields. And if I don't
annotate a field with DataMember, then that field is not included in the message. So, as you can
see, the concept of visibility at the message level is orthogonal to the concept of visibility within
the .NET language. Now, there are some other features and capabilities of these DataContract
attributes that we'll discuss later, but this basic introduction suffices for now.
Implementing services
Once you have your contracts in place, then you can implement the service. Implementing the
service is as simple as deriving from at least one service contract type. So you write a new class, in
this case we called it InvoiceService that derives from some service contract type. In our example, it
was called IInvoiceService. And then you simply implement all the methods on that interface to
define the business logic. It's important to note that a particular service implementation could choose
to implement multiple service contracts if you're going to want to expose multiple service contracts
to the outside world. Now, the implementation you're looking at here would suffice. You could take
this implementation, and host it without any additional attribution. All of the contractual attributes are
going to be inherited through that service contract type. So this creates a nice separation of
concerns between the contractual information, and the actual implementation logic. However, there
are some attributes you can choose to put on your service implementation classes, but these
attributes only impact the service behaviors. For example, here I'm annotating my service with a
couple of attributes; ServiceBehavior, and OperationBehavior. In this example, the ServiceBehavior
attribute is influencing the instancing mode for my service, and the concurrency mode, which affects
the threading model. And the OperationBehavior attribute is controlling a security-related
behavior. So, these things impact how our service executes, but they don't have any impact on what
the messages look like on the wire. We just mentioned a couple of service behaviors that are
actually quite fundamental, and important to understand when building your WCF services. They
have to do with service instancing and threading, and you configure both of these behaviors through
the ServiceBehavior attribute. The InstanceContextMode property of ServiceBehavior gives you
three options; PerCall, Single, and PerSession. PerCall means that every incoming message will get
a new instance of your service. Whereas Single means there will be a singleton instance that
handles all incoming messages. And PerSession means each unique client will get its own
dedicated service instance. ConcurrencyMode allows you to control the threading model of your
service, and there are three options here as well; Single, Multiple, and Reentrant. Single means only
a single thread at a time will be allowedinto your service instance. Whereas, Multiple means multiple
threads will be allowed into your service instance concurrently. And Reentrant is a special case of
Single, where only a single thread will be allowed in at a time, but when there's an outbound call
pending, it will allow in another incoming thread. Now, we do have an entire module coming up that
will dissect the ins and outs of these different behaviors, and how they work, and when to choose
one over the other, but I wanted to at least introduce these options upfront so you would know
what's available to you.
ServiceContract, I need to annotate this, the method with OperationContract to include that in the
ServiceContract definition. Okay, now we have an interface definition that we can implement as a
ServiceContract. So down here, I'm going to make this class public, and then I'm simply going to
derive it from IEvalService, and I'll use this nice feature to implement the interface, and now I've got
my implementation. At this point, I need to decide what instancing mode I want to use for my
service. In this case, I'm going to use a singleton. So, I'm going to add this ServiceBehavior attribute
to my Service class, and specify an InstanceContextMode of InstanceContextMode.Single. That
means that within this Service Host, we'll only have a single instance of the service running in
memory, and it will be used to service all of the incoming messages. That makes my implementation
here a little bit easier, because then I can just basically have a List of Evals in memory that I use, a
List of Eval objects, and I'll call this evals, and I'll instantiate this here. And then whenever
SubmitEval is called, I'll simply Add the eval into that list. And when GetEvals is called, we'll simply
return evals. Okay, so that's a pretty simple implementation, and now we're ready to Build this thing
and make sure it Builds okay. Oops. Let me Build that, and notice the Build did succeed. Okay, now
we're ready to actually test this thing in the Visual Studio 2008 WCF Service Host. So I need to go to
my App.config here, just to configure the service properly. Our service is now called EvalService,
and the contract that we're using for this thing is called IEvalService, so I need to change that on this
endpoint definition. Let me Save this file, and with that in place, I should be able to load up my little
service implementation here in that test tool that comes with Visual Studio 2008. So, let me press
F5. This is going to launch the WCF Service Host. You can see my EvalService is indeed loaded
and Started, and then it launched this Test Client that automatically connected to the Service Host,
and downloaded themetadata, and notice it's showing both of those operations on IEvalService,
SubmitEval and GetEvals. Well, let's test it out. We'll double click on SubmitEval, and we'll type in
some comments here, not sure about this, and for the Submitter, we'll type in Bob, and then we'll
press Invoke, and we should see some kind of response back here. It should just be an empty
message, as you can see. Let's go ahead and Invoke that a couple more times. Now, let's go over
here to GetEvals, double click on it. Notice, we don't have to pass anything into this one, and let's
press Invoke. And notice, we got three evals back in the response. They all contain the same data,
because I didn't change it each time I invoked the service. So we can see that we have a simple
service called EvalService that's ready to be hosted. We just hosted it in this case in our WCF
Service Host Test application that comes with Visual Studio, but here in a few minutes, we'll see how
to host it in our own application.
Hosting services
Once you have the service implementation in place, you're ready to host the service, and there're
actually quite a few options for hosting in WCF. First, you can choose to host your services inside of
any .NET application that supports the .NET Framework 3.0, or above. There is a special class
called ServiceHost that's basically your API for hosting a service. If you want to host a service, you
can simply create aninstance of the ServiceHost class, and you manage the lifetime of that instance
yourself. So, this approach is often referred to as self-hosting, because you're the one who has to
deal with the hosting logic. Now, you can also take your WCF services and deploy them to IIS or
WAS, and host them inside of that managed environment. So this is often referred to as a managed
hosting solution, because, in this case, you don't have to touch the ServiceHost instance yourself
directly. Both of these approaches can be useful depending on the scenario. So to summarize, we
could take a WCF service and host it inside of a Windows service, or perhaps inside of a client-side
WPF application, and we can also of course deploy it to IIS or WAS, and host it inside of
the ASP.NET app domain. Let me show you some code to illustrate how this hosting stuff
works. Let's start with the self-hosting example. Here I've got a Console app where I'm trying to host
the InvoiceService. And if you look here, the first thing I'm doing in this application is I create an
instance of ServiceHost, and specify InvoiceService in the constructor.Then, after that line of code is
where I'd actually configure the host with endpoints and behaviors, and I'm just leaving that code out
for now. Then, once I'm ready to open my ServiceHost, I call host.Open, and that's the magic line of
code that will actually go off and create all of the underlying communication components. Now, I
want to make sure my host application doesn't Close down immediately, which is what it would do
by default in this Console application case, so I'm calling Console.ReadLine, just to pin the Console
application Open until someone presses Enter. Then, once I know you're ready to shut down the
host application, we call host.Close, which does a clean, graceful shutdown of all those
communication components. Now, in the case of an exception, notice I'm calling host.Abort. That's
different than Close in that it does an ungraceful teardown of all those communication components
that were created behind the scenes in the call to Open. So this code shows you the basic model for
how you manage the lifetime of your ServiceHost instance. The process would be very similar,
whether you're hosting inside of a Console app, a Windows service, or perhaps even a WPF
application on the client side. If you want to host this service inside of IIS, the process is actually
quite a bit different, and much simpler, I might add. Because, in this case, you no longer have to
deal with the ServiceHost instance directly. Instead, we're going to let ASP.NET take care of that for
us. The way it works is this. You write what's called an SVC file that basically just tells the WCF
infrastructure what service type you want it to host on your behalf. Then, when the first request
comes in for this SVC endpoint, the infrastructure will automatically instantiate a ServiceHost
instance for that type, and it takes care of managing the lifetime of that ServiceHost behind the
scenes. So, this is a much simpler proposition forhosting when you're able to take advantage of this
type of managed hosting environment. But that won't fit every particular WCF use case, so it's still
important to understand the basics around how ServiceHost works.
System.ServiceModel, and that's where you'll configure all your WCF service options. For example,
that's where you can define your WCF service endpoints, as well as behavior configurations, etc.
Now, if you don't want to deal with this configuration section directly, you can also take advantage of
a tool that comes with WCF, called SvcConfigEditor.exe, which gives you a nice, graphical interface
for modifying the WCF configuration section.First, let's see how to configure the service with
endpoints, and we'll do this in code. The way you do this is by calling AddServiceEndpoint on the
ServiceHost instance for each endpoint that you want to configure on the service. And for each one,
you'll specify the address, the binding, and the contract. Here's an example. So here, assuming
we've already created the host instance up above, we'll call AddServiceEndpoint for each endpoint
that we want to add in. And for each one we'll specify the address, the binding, and the contract. So
here, both of these endpoints are using the IInvoiceService contract, one's using the
BasicHttpBinding, while the other is using the NetTcpBinding, and each one is using an address that
makes sense for that binding. Now, one thing to note here is that the binding names are actually
PascalCase in code, and then once we've added in those endpoints, we can go ahead and call
host.Open.
endpoints. So, I'll say host.AddServiceEndpoint, and I'll add in an endpoint that uses our
IEvalService contract. I'll use the BasicHttpBinding for this one, and I'll specify an absolute address
of localhost:8080/evals, and I'll call this one basic. Now, let me actually Copy this, and let me Paste
it, and I'll use the same format here, only this time, I'll have another endpoint that uses the
WSHttpBinding, and the address will just differ at the very end. Now, I may want to add another
binding that uses TCP. So, here I'll change this to the NetTcpBinding, and I'll change the address to
net.tcp://localhost:8081/evals. And so that's how we can add three different endpoints into the mix.
Now, let me add a try statement here, and I'll go ahead and type in host.Open. That's the magic line
of code that will open up the WCF runtime, and create all the underlying communication
components for the endpoints that we've configured. Now, I need to make sure I can keep my
application, my Host application up and running, so I'm going to type in Console.ReadLine right
here, and then when you press Enter, and you want to close this thing down, we'll do a graceful
closedown by calling host.Close. Now in the case of an exception, what I'll do is first print out the
exception to the Console window, and then I will call host.Abort, which does a teardown of the
ServiceHost runtime. That's the basic model here for hosting our service inside of a Console
app. Let me actually set this as the Startup project, and then I'll come over here and press Ctrl+F5
to launch it. Now it looks like the Console application is running, looks like there were no exceptions
thrown, otherwise we would've seen a message printed out. If I press Enter, it shuts the program
down, and away it goes. So, it looks like our service was actually being hosted at that point in
time. Now, how about we do something to verify that. Let me add another method here to our class
called PrintServiceInfo, and it's going to take the ServiceHost coming in. And what it's going to do is
print out, first it'll print out the type name. It'll say, this service is up and running with these
endpoints. Okay. And then we'll pass in host.Description.ServiceType. And then we'll need to iterate
over each of the service endpoints, so I'll do ServiceEndpoint for each service endpoint in
host.Description.Endpoints. And I will just simply print out Console.WriteLine(se.Address); and I'll
just print out the endpoint address. Now, up here, I will then call PrintServiceInfo right after calling
host.Open. Now, let's do a Ctrl+F5 again, and see what happens. Now, it shows that EvalService is
up and running with these endpoints, and we see those three endpoints that are supposedly there.
Now, let's try something real quick. I'm going to open up a web browser. And let me just bring it
down a little bit so it's easier to see. And then I'm going to type in the address to one of our HTTP
endpoints. I'll type in localhost:8080/evals/basic, and see what we get back. Notice, we actually get
a SOAP Fault back out, and it actually shows us that, hey, the message that was sent in cannot be
processed at the receiver. So, you can definitely see that there's some piece of code on the other
side that's being hosted by WCF that's responding to that Get message that I just sent it. But
obviously here we can't actually invoke the operation, because we haven't built a full-fledged WCF
client yet.
comment out these endpoints that we've currently added this way, so we can see those are no
longer going to be taking effect. Then I'm going to come back to my ConsoleHost, right click, and
Add a New Item, and the item I want to add is going to be an App.config file. Now, within this
App.config file, I can simply just start typing to start using this WCF configuration section. The
element name is system.serviceModel, and notice, you will get IntelliSense, which makes it pretty
easy to just type this stuff in. So, here I'm going to configure my service called
EvalServiceLibrary.EvalService. And within this element, I can then just start specifying my
endpoints. So, I'll have one endpoint that uses an address of http://localhost:8080/evals/basic, and
for the binding we'll use the basicHttpBinding, and notice the camelCase. And then here for the
contract, I'll specify EvalServiceLibrary.IEvalService. Now, let me Save that, and let me just come
back up here and Copy and Paste all these guys. We're going to add both endpoints back in. This
one's going to be the WS endpoint, or the wsHttpBinding, and it'll use the same contract. And then
this next one is going to use the TCP binding, so we'll say net.tcp, change the port number to
8081, and we'll just end that in evals, and then here, I need to specify the netTcpBinding. Okay. So,
let me Save that now, and let me just press Ctrl+F5 to Run my host again. And notice that the Host
looks exactly the same this time, the three endpoints are showing up from our PrintServiceInfo
method, just like before when we added those endpoints in via code, only now these endpoints are
being done completely in configuration. Let's just add another one, just to verify what's going on
here. Let me add, in fact, let's add one more down here at the end that uses named pipes. So, for
this one we'll say net.pipe://localhost/evals, and it's the netNamedPipeBinding, same contract. Save,
Ctrl+F5, and notice we now have a fourth endpoint. So, we could do that without evenrecompiling
the application. We can simply add new endpoints in on the fly through the config file. Now, you
may, or may not like the idea of editing this application configuration file by hand, like I've been
doing. Because of the IntelliSense, it's actually pretty easy to get this stuff right, but you still have to
know the binding names, and there're a few things that are fairly easy to mess up. So, you may
want to use that service configuration editor tool that we talked about. The way you can do that from
within Visual Studio is by right clicking on the App.config file, and selecting Edit WCF
Configuration. That brings up this window. And here, you basically get a graphical user interface for
editing that WCF configuration section in your config file. Notice here, it's showing all the endpoints
that are currently configured on our EvalService. If you drop this down over here in the window,
you'll see all of the different endpoints that are listed here, and you can go and configure each one
of them. And notice, it you want to specify a binding, it actually gives you a dropdown with all the
binding names, which is kind of nice. Let me just show you how to add a new endpoint using this
technique. Here I can right click and say, give me a New Service Endpoint. I can then come down
here and specify the Address I want to use. Let's just add another one for HTTP. We'll just call that
one onemore. We'll use the basicHttpBinding, and then down here for the Contract, notice we can
actually go and select the assembly that contains our contract, and there's our IEvalService. Well
select that guy. And we'll go ahead and Save this file right here; I'll just select Save, or press
Ctrl+S. Close that out, and then notice it updated my App.config file. So if I reload that you'll see that
this new endpoint showed up at the end. There's the one we just added with onemore at the end of
the address. Now, if I press Ctrl+F5, we should see that new endpoint show up at the end of our list.
assuming your host application has been configured with a base address. Now, on to bindings. A
binding is essentially a recipe that specifies three key communication details. The binding specifies
the transport, the message format, and the suite of messaging protocols you wish to use, if any. So
each endpoint is configured with a binding, and the binding tells the underlying runtime how to
configure the communication components. It tells it which transport to use, which message format
to use, and which, if any, messaging protocols to use. Now, you can create your own binding recipes
from scratch if you like, but to make it easier for you as a developer, WCF comes with a whole suite
of built-in bindings that address some of today's most common communication scenarios. This table
describes some of the common built-in bindings that ship with WCF today. Each one of these
bindings, like we talked about on the previous slides, specifies a transport, a message format, and a
suite of additional protocols that are going to be used. Now, we already talked about the general use
case for each of these bindings in the previous module, so we won't take time to do that here again.
But you'll notice that there's also this new binding at the end of the table, called CustomBinding. This
is the one you would use when you want to define a completely new binding from scratch, where
you specify your own transport, message format, and suite of additional protocols. But usually you
don't have to go quite that far. For most communication scenarios, you can simply pick one of these
built-in binding names that we've listed here in the table, and then you can configure it, or tweak it to
fit your precise needs.
Binding configurations
Now let's look at an example of how we can take one of the built-in bindings, and tailor it to fit our
precise needs. In this example, we're going to take the BasicHttpBinding, and configure it to use
SSL, and basic authentication. The way we do that is we construct an instance of the
BasicHttpBinding. Then we use the properties it provides to configure it. We're going to change its
Security Mode to use the Transport Security Mode, which implies SSL, and we're going to change
its ClientCredentialType to be Basic, which implies basic authentication. Now, if I want to use that
particular binding configuration, I simply take that binding instance, and pass it in when I call
AddServiceEndpoint. We can also accomplish the same thing purely in configuration. Check out this
configuration file. Let's assume that we want to configure the BasicHttpBinding just like we did in the
previous code example. Well, the way you do this is you add the bindings element to the WCF
configuration section, and then you specify which binding you want to configure. So here, I want to
configure the basicHttpBinding. And then within that element, you specify the name of your binding
configuration, so you use the binding element, and the name attribute, and you give your
configuration a name. In this case, I've called mine MyBindingConfiguration. Then, within that
element you can essentiallycustomize the binding, and configure it however you'd like to. In this
case, I'm changing the security mode to Transport, and the clientCredentialType to Basic. Then, up
above in my endpoint definition, I can simply specify that bindingConfiguration name to be used in
conjunction with the basicHttpBinding, and that lines everything up. By doing it this way in
configuration, I now have more opportunities to change the binding configuration down the road
without having to recompile my code.
Messaging. You'll notice that there's this ReliableSession Properties section down here, and I want
to change Enabled to True on this one. So by simply doing that, I now have a binding configuration
for this particular binding that turns off message-based security, and turns on reliable messaging
semantics at the SOAP level. And notice, there's a whole bunch of other things that I can configure
here on this binding. Now, I simply need to apply this binding configuration to my endpoint that uses
the wsHttpBinding. So I'll come over to my Service, and expand my list of Endpoints, and find the
one that uses the wsHttpBinding, and this is it right here. Then in my BindingConfiguration section, I
can drop this down and find my NoSecurityPlusRM configuration. Select that. Save it. And now
we've effectively configured that endpoint to use that custom binding configuration. Let me Close
this out, and see what it changed over here in our file. Notice it added this bindings section inside of
system.serviceModel, and it added a configuration for the wsHttpBinding. We called that
NoSecurityPlusRM, and notice it just added this reliableSession element with enabled=true, security
mode=equals None. And then down here, if we look at that endpoint, this one right here, we should
see that it added the bindingConfiguration to that endpoint definition. So that's essentially all it did in
our config file. Now, let me go ahead and press Ctrl+F5 to Run our Host, and notice that endpoint
still loads up just like before, but if you actually tried to call it, it would no longer expect to use
message-based security, and it would expect to use WS Reliable Messaging.
Service behaviors
Now let's turn our attention to behaviors. Let's start by seeing how we can add behaviors in via
code. Well, you've already seen a few ways to do this. We saw an example earlier where we applied
some behaviors to our service logic. We used the service behavior, and operation behavior
attributes, and that was one way to configure a service with a behavior. You can also configure
behaviors on a service through theServiceHost class, or through the configuration file. Let's start by
looking at how to do this in code via the ServiceHost class. Here's an example where I've created
my ServiceHost, and then I decide that I want to apply a particular behavior to my service, so I'll
instantiate the behavior that I want to use. In this case, I'm going to use the
ServiceMetadataBehavior, and then I configure that behavior. Here I'm saying that I want to enable
HTTP GET request for the metadata. Then I can simply add that behavior into my ServiceHost by
adding it to the Behaviors collection on the Description property. And then when I call Open on that
ServiceHost, it'll apply that behavior to the actual WCF runtime, thereby enabling metadata on my
service in this case. There're actually quite a few different types of behaviors that you can apply this
way. We're just showing you one example for now. As we move through the rest of the course, we'll
cover numerous other behaviors that are useful in different situations. Remember how we said that
everything we can do in code, we can also do in config? Well, here's an example of applying that
same service behavior purely in configuration. So, here in this example, I've defined that
serviceBehavior down here below within this behaviors element. So before we were using the
bindings element to create custom binding configurations. Here, I'm using the behaviors element to
define a specific type of behavior configuration. Here I'm going to create a serviceBehavior, and
inside of this I specify the behavior configuration name. Then within that behavior element, I can
specify which behaviors I want to apply. Here I'm applying the serviceMetadata behavior, and I'm
specifying that I want to Enable HTTP GET request. So the exact same thing I did in the previous
example. Then to apply this behavior, I go up to my service within the services section, and I simply
use the behaviorConfiguration attribute specifying my behavior name defined down below. And that
will cause the same thing to happen when we open our ServiceHost.
we'll go ahead and enable this serviceMetadata behavior on our service. So we called this thing
Metadata. So if I come back to my Service, I then need to apply that behavior configuration to my
Service right here. Now if I Save this and Close this out, and jump back to my config file, you can
see what changes it made. Notice it added this behavior section up here at the top with a new
behavior called Metadata. It's using the serviceMetadata element with httpGetEnabled=true,
specifying the exact URL where we want that metadata to reside. Then we simply associated that
behavior with our EvalService. So, now if we press Ctrl+F5 to Run our Host,we should see that our
ServiceHost comes up, and it shows those same five endpoints. And now, if we bring up a web
browser, and we navigate to http://localhost:8080/eval/meta. Oops, I typed it in wrong. It needs to be
evals/meta, so if I fix the URL and press Enter again, it should contact our service and request the
metadata. And now notice that our service is indeed serving up metadata in response to that
request. We have this nice big WSDL file that our clients can now consume to figure out how to
integrate with our service. With this configuration in place, a client can now easily generate client
side code from that WSDL definition. In WCF, we do that through a tool called SvcUtil.exe. So let me
move into my Demo's directory, and I'll show you how to use this. So, if I type in SvcUtil.exe, and I
type in the address to our metadata endpoint, we have localhost:8080/evals/meta, it'll actually issue
a GET request to download that metadata, and then generate some client-side code and
configuration. Notice it generated a file called EvalService.cs, as well as output.config. Now, a WCF
client could use those two artifacts to successfully build a client capable of talking to this service.
service. Now, there's also another technique for retrieving metadata known as WSMetadataExchange, or MEX for short. MEX defines a standard service contract for retrieving
metadata, and by doing that it would then be possible to retrieve that metadata over a variety of
different transports. Instead of having to retrieve it over HTTP, we could also retrieve metadata over
TCP, or named pipes, for example. Now WCF makes it easy to expose a MEX endpoint on your
service. They provide a built-in service contract called IMetadataExchange, which implements the
MEX protocol, and they also provide some built-in bindings for doing MEX over HTTP, TCP, or
named pipes. This example shows you how to expose an endpoint for MEX. In this case, we're
exposing a MEX endpoint over TCP. We're using the mexTcpBinding, and we've
specifiedIMetadataExchange for the service contract. Now, the cool thing about this is, I didn't have
to implement IMetadataExchange on my service class. Instead, all I do is I enable the
MetadataBehavior on my service, just like we showed you in the last example, and that behavior will
take care of adding the implementation for IMetadataExchange.
output.config file for the configuration element. So that indeed worked. Now, let's try it again, and
this time we'll actually provide the TCP-based address, localhost:8081/evals/mex, and we'll see
what happens this time. Notice, same results. So, by adding MEX endpoints to my service, I'm now
able to retrieve metadata over multiple protocols.
Service exceptions
The last general concept we need to discuss on programming services is that of exceptions. How
are exceptions propagated from your service back down to clients? Well, exceptions are very
technology specific. So, by definition, they should not cross the service boundaryunless you
explicitly specify how that should happen. So by default, WCF automatically translates all unhandled
exceptions into some generic SOAP faults. They simply create a generic message that doesn't
tell the client all that much about what really happened, and that's what gets transmitted down to the
client. This is what it looks like. It's basically just an internal service faultcode with a description that
saysthe server was unable to process the request due to an internal error. So, again, not much help
to the client. But, it's also good for security reasons, because now we're not exposing unnecessary
details, and stuff that we didn't mean to have transmitted back down to the client,like a call stack, for
example, that could help the client figure out how to tamper with our service. Sometimes though this
can be more of a nuisance than a help. While you're developing, and testing a service, it's often very
common to want those exception details to travel down to the client so you can figure out what went
wrong. If you want to configure your service to allow that to happen, you can use either
theServiceBehavior attribute, or the serviceDebug behavior element, in your configuration file, to
enable those exceptions to travel down to the client. So again, not something you'd want to do in
production, but very helpful during testing and debugging. So, here's how you would do this in a
configuration file. We created a behavior here called Default. We added the serviceDebug element,
and we specifiedincludeExceptionDetailInFaults, and we set it to true. And that basically allows our
service to transmit those exception details in the fault messages. And so as long as we associate
this behavior with our service, we're good to go. Now, if you actually want to throw a fault to the
client, and have it travel down there safely so the client can catch it, you need to throw what's called
a FaultException. A FaultException is a class that represents an explicit SOAP fault. When you
throw a FaultException, you can specify all the SOAP fault details. Then on the client side, our WCF
clients can simply catch the FaultException to handle the error. Here's what it would look like in
code. So, here on the server side I simply throw a new FaultException, and here with this string I'm
specifying the fault reason. There's other stuff I could also specify there if I wanted to. Now, there's
also a whole bunch of support around typed faults, where on the server side I could throw an actual
typed fault, and on the client, catch that same typed fault. But we'll come back to these more
advanced fault scenarios in a future module.
Summary
And that brings us to the end of this module. We've seen how the service model architecture clearly
revolves around endpoint definitions, and we've taken some time to walk through the various steps
involved in programming WCF services. We've seen how to define message structures with data
contracts, how to define our service contracts, how to implement those services, and how to host
the service. We've also seen how to configure services with endpoints, and behaviors, and one of
those behaviors that we spent some time looking at was the one around publishing metadata to
expose WSDL definitions for our clients, or perhaps doing so through MEX endpoints. And finally,
we saw that WCF provides various options for dealing with server side exceptions.
Programming Clients
Overview
Hi. This is Aaron Skonnard with Pluralsight. I'll be presenting this module on programming WCF
clients. In this module, we'll dive into the details around how to consume services found in the world
using the WCF client-side programming model. At this point, we assume you have some exposure
to the WCF architecture, and basic terminology, but not much beyond that. Here are some of the
topics that we're going to look at in this module. We'll start by giving you a brief review of the WCF
client-side architecture, and then we'll dive into some of the specifics around the client-side
programming experience. With that foundation in place, we'll dive into some of the lower level details
around client-side programming, including things like channel lifetime management, and dealing
with exceptions, how to perform asynchronous invocations, how to share WCF contract assemblies
across projects, and finally, we'll show you the details around how to use WS-Metadata Exchange in
your client applications to make them more dynamic, and automatically configurable at runtime. By
the end of this module, you should have a clear understanding of how to use WCF to consume a
wide variety of services found throughout the world today. Okay, let's review what the WCF
architecture looks like with a focus on the client. So here we have a service, hosted inside of a .NET
application that exposes a few endpoints. This service is simply waiting for messages to arrive. And
over on the left, we have a client application that wants to consume that service. In order for this
client to consume that service, first it needs to retrieve the service's metadata. So the service will
expose that metadata typically in the form of a WSDL definition. The client will retrieve that WSDL
definition and then run it through a client-side metadata import tool. By doing that in WCF that will
produce client-side endpoint definitions that represent the information needed to communicate with
that service through one of its endpoints. The client, once it has those endpoint definitions, can then
choose an endpoint, in this case, the one highlighted in gray, and construct a channel based on that
endpoint. Once the client has constructed a channel based on an endpoint exposed by that service,
it can then begin sending messages to the service through that channel by simply making method
calls on the channel instance. So, when you use WCF on the client side, you create channels based
on endpoints.
and that tool will produce two artifacts, a .NET config file containing the client-side endpoint
definitions, and a .NET source file containing all of the .NET contract definitions. Those two artifacts
will need to be compiled into the client-side application, and then the programming modelbecomes
very symmetric to what it's like on the service side, and that's one of the nice things about the WCF
architecture in general.SvcUtil.exe is the primary metadata import tool provided by WCF. This is a
command line tool that you can run inside of any command prompt to basically do what we just
talked about, to retrieve a WSDL definition, and to generate those two artifacts, both the code and
the configuration needed for your client-side endpoints. This tool ships with Visual Studio 2008, as
well as the Windows Vista SDK, and it provides numerous command line options, and some nice
help, as you can see here in this image that I've provided you with. If you simply type in SvcUtil.exe,
you'll see the basic usage, and you can drill into that tool documentation to figure out all the fancy
things it's capable of doing. It's important to note that this tool's capable of retrieving metadata over
HTTP, or over TCP, and named pipes if the service happens to support WS-Metadata Exchange, or
MEX. With the release of Visual Studio 2008, they added a new feature called Add Service
Reference. This is a lot like the old Add Web Reference feature, but this one's designed specifically
for WCF. And it basically gives you access to the same capabilities as SvcUtil.exe, but it does so
directly within the context of a Visual Studio project. So here, you would right click on your project,
and select Add Service Reference, and it brings up this dialog you're looking at. Then you type in the
address to yourservice metadata, and then once you tell it to, it'll download that metadata, and
generate the code, and the configuration necessary for your client-side endpoints. Then it
automatically adds those artifacts into your project for you, and it will merge the configuration file
automatically when necessary. Then it will add a new thing to your project called A Service
Reference.
we actually Host the service. If you look at the config file for this Host, you'll notice that it
exposes multiple endpoints to the outside world. These first four are actual EvalService endpoints
that implement the IEvalService contract, and these last two are MEX endpoints. We actually
expose MEX over HTTP, as well as over TCP. If I press Ctrl+F5 right now, it'll launch the Host, and it
will show us that the service is up and running with all of these various endpoints. Those endpoints
are active, and ready to go. If I bring up Internet Explorer right now, and I navigate to
localhost:8080/evals/meta, you'll see that we can browse directly to the WSDL definition of that
service. And that is one way to go about generating these client-side endpoints. I can type in to
SvcUtil, this address right here. In fact, let me just Copy that into my Clipboard, and it will download
that, and generate the WSDL. Let me show you how that works. So, I'm going to come here to my
Start menu, and I'm going to open the Visual Studio 2008 Command Prompt. Let me show you how
to get to that through All Programs. If I come down here, All Programs, and then select Microsoft
Visual Studio 2008, and then go into Visual Studio Tools, you'll find the Visual Studio 2008
Command Prompt. Let's open that up. The reason you want to use this command prompt is
because it has SvcUtil.exe already configured in the path. So now I can just type in SvcUtil.exe, hit
Enter, and then notice it shows me all of the help information around the usage for this tool. So
notice there's a lot of options. A lot of different ways you can use this thing. For now, we're just going
to show you the basics around how to point it to a WSDL definition, and generate the client-side
endpoints. So, to do this, let me actually clear the screen, and move into my Demo's directory for
this particular project. I want to generate this stuff in my Client project, which right now is basically
just empty. So what I'll do is I'll type in SvcUtil.exe, along with the address to our metadata, which is
the one wejust typed into Internet Explorer a few seconds ago. If I go ahead and press Enter,
SvcUtil will download that metadata and generate these two files, EvalService.cs, and
Output.config. Let me open these up so you can see them. If I open up EvalService.cs, you'll notice
this just a C# file containing a bunch of .NET code. This is all the contractual code for our service.
So now we have that on the client-side. And if I open up Output.config, you'll notice that this is a
config file that I can then use in my client-side project. And if I scroll all the way down here, you'll
notice it contains a bunch of endpoint definitions. So that is how you go about downloading WSDL
via simple HTTP GET request using SvcUtil. Now, SvcUtil.exe is also capable of downloading
metadata over MEX, the MEX protocol. Let me illustrate that. So now what I'm going to do is I'm
going to type in SvcUtil.exe, and I'm going to pass in localhost:8080/evals/mex, which was the
HTTP address for our MEX endpoint, and notice that this is going to work the exact same way. I can
also do it over TCP. Let me type in my net.tcp address here,localhost:8081/evals/mex, and now
SvcUtil will communicate over TCP to the service, and do the same thing. So, you know, we have
various different ways through SvcUtil to contact the service, request the metadata, and once it gets
that metadata back, it produces those two artifacts for me that I need on the client-side, the code,
containing all the contract definitions, and the config, containing all the endpoint definitions. And
those are the two things that I need to add to my project. So, if I jump back over here to Visual
Studio, and go to my Client project, this is where I need to add those things. So I'll right click, and
select Add, Existing Item, and then notice here, I see EvalService andOutput.config, I'll Add those in.
And really to be able to use Output.config, I'll need to make this an app.config file, so I'll just change
the name myself, and then EvalService is that code file we looked at before in Notepad. Notice it's
got the Eval data contract now on the client side. We have our IEvalService, and we have a few
other types that we'll use to actually program against that service, which we'll come back to
later. Okay, now, if I try to Build this thing, you'll notice that the Build succeeded, but I did have to
add in some References here, to System.Runtime.Serialization and System.ServiceModel. In fact,
let me remove those just for a second so you can see what will happen if I try to Build now. Now, the
Build failed. I had already added those to the project ahead of time. So, this is one of the manual
things you'll have to do. You'll have to come in here and Add System.ServiceModel, along with
System.Runtime.Serialization into your client-side project,and once you've got those in there, then
you can Build this thing. And, at this point in time, I'm ready to start writing the code in my Program,
which is still empty, to consume this service. I now have all the types I need on the client side, and I
have the actual endpointdefinitions here in my config file. I've got four of them, to be precise, that I
can begin using to contact the service. I just have to pick one of these, and use it.
In this demo, I'll show you how to use the new Add Service Reference feature in Visual Studio
2008. Before this feature existed, you had to drop out to the command prompt to use SvcUtil.exe to
generate your client-side artifacts. For example, here I have my ServiceHost up and running with
several different endpoints, and I can come out here to a command prompt using SvcUtil to actually
generate a couple of things, a source file, and a config file. Then I have to take those files, and I
have to add them into my project over here manually. It requires me to merge the config file into my
current application config file. I have to add the source files in here, and manage those, and then I
also have to come in here and add a few References to the WCF assembly. So there're quite a few
things that you have to manually do when using SvcUtil.exe. So let me show you now how to do the
same thing using Add Service Reference. So I'm going to delete these two things out of my Clientside project. So we're going to start from scratch. And I'm also going to delete these two assembly
References, so we don't have any of the core WCF stuff in here by default. Now, my ServiceHost
should still be running. Let me just look at that. So my ServiceHost is indeed running, and I can use
any of these MEX endpoints that I want, even inside of the Add Service Reference feature. So here,
I can right click and select Add Service Reference. Now, when this comes up, I can point it to
various different addresses. I can point it to localhost:8080/evals/meta, that's the public address for
downloading the WSDL definition over a GET request. I can also point it to my MEX endpoints. So,
let me change this address to localhost:8080/evals/mex, and notice that it can now contact the
service via MEX, and download that as well. In fact, let's even try the net, sorry, I'm in the wrong
place. Let me try the net.tcp address, localhost:8081/evals/mex, and let's hit that one. So notice, the
Add Service Reference dialog is just like SvcUtil in that it can contact services in a variety of different
ways, either using simple HTTP GET request, or using the MEX protocol over a variety of different
transports. Once you've found the service that you want to communicate with, notice it gives you
this little display of the service itself, and the service contracts it exposes, and so you can kind
of see the operations that exist on it. Once you're ready to go ahead and add a Reference, you can
specify a local namespace for this thing. We're going to call ours in this case
EvalServiceReference. That's just going to be the .NET name used for this thing over here in the
Solution. There's also a bunch of advanced properties you can specify here as well. You can specify
the access level for the classes it's going to generate. Do you want to generate async operations?
There's a bunch of other more advanced things, and in fact, as we move through the rest of the
module, we'll come back and talk about a couple of these features you see here. But for now, we're
just going to keep it simple. So then when I'm ready to go, I just press OK. It downloads the
metadata. It generates those artifacts. It adds in the two assemblies I need in this case. I need the
System.Runtime.Serialization, and System.Service model, so it did that automatically. And it added
in this EvalServiceReference node underneath my Service References folder. And inside of here is
where the source code actually exists.And then notice my app.config file was also added. In fact, it
added that for me, because before it didn't exist. If you remember, I deleted that. And if you look
inside of this, you'll notice it downloaded all these endpoints again. So now I have my four endpoints
available to me on the client-side that I can begin using. So, it automated all those things that we
had to do before manually when using SvcUtil.exe. Now, once you have this Service Reference, it's
pretty easy to manage it, because you can right click on it, and say, Update Service Reference, and
that will download the WSDL again, and just Refresh everything, so, if the service changed it's as
simple as just right clicking and saying Update, and you'll get the current WSDL definition at that
point in time. If you want to see the code, like actually navigate into the contracts that are found
inside of this thing, you can select View in Object Browser. It brings it up over here, and then you
can see those different types, and all the things that are available on these types. So, that's typically
how you discover the code that's found inside of this thing. Now, if you actually want to see the
source code, you can click up here on Show All Files, and notice you can then navigate into this guy,
and then you'll find a file called Reference.cs, and that's where the actual source code lives for all
these things. So, they just try to make it easier for you and hide some of those gory details. So, you
can also right click, and select Configure if you want to change some of the details around
thisService Reference, or how the code is being generated. So you can always change those details
after the fact as well, and then regenerate things. If I Build the Solution at this point, it should
succeed, and now I'm in the exact same position I was before. I have the code that I need for my
service contracts, and I have the endpoints that I need inside my app.config file, so now I'm ready to
come in here to my Client and begin writing the code to actually consume the service.
Programming channels
Once you've retrieved the endpoints of interest, you're next job is to use the WCF client-side
programming model to build a channel capable of sending messages to the service. And this
consists of several steps. First, you need to create and configure a ChannelFactory based on one of
the endpoints exposed by the service. Then you actually create a channel instance through that
ChannelFactory. Once you have a channel, you can simply make method calls through the
channel via the service contract methods. And then finally, when you're done using the channel, you
need to either Close, or Abort it to do the necessary cleanup. Over the next several slides, we'll walk
through the details of these various steps. The first thing we need to discuss is how to create a
ChannelFactory based on a particular endpoint. The way you do this is through a special class
called ChannelFactory of T. This allows you to create a channel based on a specific service contract
type represented by T. When you construct ChannelFactory of T, you also supply the target endpoint
in its constructor. So here, we're showing some sample code. We're constructing a ChannelFactory
of type IInvoiceService. That's the service contract type. And we're supplying an endpoint object that
represents the target endpoint we want to communicate with. Once we've created this
ChannelFactory, we can use it to create channels of type IInvoiceService capable of communicating
with the endpoint that we provided in the constructor.
looks a lot like the server-side configuration of endpoints, only here inside of system.servicemodel,
there's a client element instead of services. And inside of client, we specify all of the client
endpoints. Now, one of the big differences here is that each of these things also has a name
attribute. We typically don't put a name on your service-side endpoints. We do this on the client-side
so we have something to refer to in our code. So this is the WCF client-side configuration section.
And these are the names that you'll refer to in your code when constructing your ChannelFactory,
like I just showed you. Now, you can also have binding, and behavior configurations in this clientside configuration file, just like you can have on the server side.
Channel lifecycle
Okay, now that we've seen how to create ChannelFactories, it's time to discuss the process of
creating channels, and how to manage their lifecycle. Well, you create a channel by calling the
CreateChannel method on the ChannelFactory. And that's one of those magic lines of code that
hides a whole bunch of gory details. Behind the scenes, when you call CreateChannel, WCF will
actually build the underlying WCF runtime for transmitting messages on the wire to the service. But
it's able to hide all that from you by simply returning you an object that implements your service
contract type. So, all you interface with is your service contract. You simply make method calls, and
those method calls will then translate into messages hitting the wire through that underlying channel
stack. Now, all channel instances will also implement another interface called IClientChannel. That's
a special interface for managing the lifecycle. It will provide both a Close, and an Abort method that
you can use when you need to shut things down. So let's look at a quick example here. Here I have
a ChannelFactory of type IInvoiceService, that's my service contract type, and it's targeting
an endpoint called tcpEndpoint found in my config file. Once I've created that ChannelFactory, I can
simply call CreateChannel to produce a channel object. Notice that it gives me an object back of
type IInvoiceService. Then when I want to actually send a message to the service, I can simply call
a method on that service contract type, in this case, SubmitInvoice, passing in my invoice
object. And when I'm doing using this channel, I can then cast the channel object to IClientChannel,
and then call Close. So what's the difference between Close and Abort? Close performs a graceful
shutdown of the client-side channel, which means it's going to wait for all in-progress calls to
complete before actually closing things down. So, if you have three or four different operations that
are still outstanding, and someone else comes along and calls Close on that channel, it's not
actually going to Close it until those other service operations actually complete. Now that can often
be a lengthy process, which is another reason why they provide an async version of Close. Once all
of the in-progress calls have completed, it'll then take care of closing all of the underlying networking
resources that were being used within that client-side channel. Now, there are a few types of
exceptions that Close can throw. It can throw CommunicationException, because it is interacting
with those underlying networking resources. It can also throw a TimeoutException if the overall
Close process takes too long. Now, Abort is much different, because it doesn't wait for anything to
happen.The assumption here is that you simply want to Abort all of the in-progress calls. You don't
want to wait for them to complete. And you want it to Close all of the channel infrastructure
immediately. You typically want to call Close at the end of your clean execution path, and you call
Abort in situations where something has gone wrong, and you just need to clean things up as
quickly as possible. Typically, you call Abort in cases where you have faulted channels. In fact, you
must call Abort on a faulted channel. If you try to call Close on a faulted channel, that'll actually
throw another exception. And we'll talk a little bit more about that stuff later. Remember that both
Close and Abort are found on the IClientChannel interface, and that interface will be available on all
channel objects returned by your ChannelFactory. But you will have to cast to IClientChannel in
order to call Close or Abort, which is pretty cumbersome. It'd be nice if there were a way around
that. When you generate your client-side code, you'll notice that the actual code definitions includes
another interface definition that derives from both your service contract type, as well as
IClientChannel. And if you use that special interface type with your ChannelFactory, it'll produce a
channel that immediately supports both of those interfaces, making it possible for you to call Close
and Abort directly on your channel. So here's what the interface would look like. We have an
interface called IInvoiceServiceChannel, which derives from IInvoiceService, which is our service
contract type, as well as IClientChannel. And if I pass that into my ChannelFactory, like I'm showing
you here, and actually create a channel based on that IInvoiceServiceChannel, I can then call the
methods on my service contract type, like SubmitInvoice, and I can also straightaway call Close
without having to cast.
operations found on that service contract type. So SubmitEval takes an Eval. I'll need to construct
one of these guys real quick, and I'll just fill it up with some data. We'll have a Submitter name, let's
use my name for that. And then we'll have a Timesent, which will just be DateTime.Now, and then
we'll have some Comments (Typing) I think I'm liking this. Okay. And then we can go ahead and
pass that in here to SubmitEval. And, in fact, why don't we call this thing a couple times. And then
after that, why don't we call channel.GetEvals and get a List of Evals back. And notice that in the
service, in the signature here, you can see that it returns an EvalArray. Now on the service side, we
used a List of Evals, but in theactual schema definition that's part of the WSDL, that's just going to
be represented as a sequence of elements, and so on the client side, the Client code generator has
to decide how to map that back into .NET code, and by default, they choose to use Arrays instead of
Lists.But I'll show you in a second how you can change that. So here we have an EvalArray, and
once we get that List of Evals back, let's just printout to the Console window, if I can type today,
number of evals, and we'll just printout evals.Length. So that's how we can make several different
service operation calls through this channel. So we've called SubmitEval twice, and then GetEvals
once. And then when I'm done using that channel, I need to Close it, and the way we do that again
is by calling Close on the channel. But notice, if I call, if I type in channel. there's no Close method,
because I only see the operations made available on IEvalService here. So, in order to get the
Close operation, we have to cast the channel to the IClientChannel interface. Remember, that all
channels returned by CreateChannel will automatically implement IClientChannel, as well as the
service contract type, so this is completely legal, and safe to do. So that's the basic model. We
construct the ChannelFactory, call CreateChannel, then we come down here and make a few calls
through that channel, and then when we're done with the channel we Close it. Let me Build. Build
succeeded. Okay, let's go ahead and execute it. Notice I've got the Client application set as the
Startup project, and I'll just go ahead and press Ctrl+F5 to let this thing Run. Notice, it prints out
Number of evals: 2, and that obviously must've worked because we passed in 2 evals, and then we
called GetEvals immediately. Now the service is implemented as a singleton, so it's just keeping all
those things in memory. If I Close this, and actually Run it again, we should see 4. And if we Close
that one down, and Run it again, we're up to 6. So it's definitely doing that, communicating with the
service, and doing so through these channels. Now, if I wanted to use a different endpoint to
communicate with the service, that's as simple as just picking a different endpoint name. So let's say
I want to use the WSHttpBinding instead. Let me grab that endpoint name, come back here, and
swap it in here, and then let me just press Ctrl+F5 to Build and Run it in this configuration. Notice it
works the same way, and now our counts up to 8. So the endpoint is basically just a piece of
configuration that completely drives the construction of the underlying channel stack, but as far as
your code is concerned, it has no impact. Now, let me show you a few other things that will make the
code look a little nicer. This was one thing that is a little problematic. If we want to work with a List of
Arrays, sorry, a List of Evals instead of an Array of Evals, I can do that by coming back here to my
Service Reference, and pressing Configure, and then notice here, I can specify what collection type
I want to use by default for sequences. Let's change that to Generic.List. Press OK. Now, notice
what magically happens. Now, the signature returns a List of Arrays, sorry, a List of Evals. So if I
come here now, I'll need to change my code to operate on a List of Eval, and I'll need to change
this over here to Count instead of Length. Let me go ahead and Run that, and ensure that that
works. So, that's one of those things that you can change in terms of how it generates the code
through the import tool. This is the other problematic thing. This is kind of yucky to have to cast to
IClientChannel every time we need to call a Close or Abort. So, instead of doing that, you'll
remember that we talked about this specialIClientChannel derived interface. If we go and View in
our Object Browser, all the types that exist over here, notice that in addition to IEvalService we also
have this IEvalServiceChannel. And if you look at the Base Types, you'll notice it derives from
IClientChannel, as well as IServiceChannel. So, if I use this with my ChannelFactory instead of
IEvalService, all of the methods on both of these interfaces will be available to me on that resulting
channel object. So, let me jump back here and change our code to use that one. So here I'll use
IEvalServiceChannel, same here, and I'll need to change this reference as well to an
IEvalServiceChannel, and now down here, I should be able to just write channel.Close. Notice that's
available now. So that cleans up the code. Let me go ahead and press Ctrl+F5 to Run it like this.
Notice it works the same way.
Avoiding ChannelFactory
And if you want to make things even easier on the client side, you might want to try avoiding
ChannelFactory of T altogether. The import tools will also generate what's called a proxy class that
completely shields you from the underlying ChannelFactory. So here I'm showing you the
InvoiceServiceClient proxy class. Notice it derives from the special base class, called ClientBase,
where we're passing in IInvoiceService as the service contract type, and then it also directly derives
from IInvoiceService as well. And then you'll notice I provided you with a few of the constructors
here. One of the constructors allows you to specify the endpoint that you want to target with
thisparticular proxy class. One thing that's interesting to note about this class is how it comes up with
the actual proxy class name. So here it's called InvoiceServiceClient. How did it come up with that
name? It basically takes the name of the service contract. In our case, it was called
IInvoiceService, and it removes the I at the beginning of that contract name, and then it tacks Client
onto the end of it. So if our service contract was called IInvoiceService, it took off the I in the
beginning, and then tacked Client on the end, hence the proxy class name is InvoiceServiceClient. If
our service contract was called IMef, as another example, then the client proxy class would simply
be MefClient. This proxy class greatly simplifies the client-side programming experience
because, again, it shields you entirely from the underlying ChannelFactory, and the channel
instances.
you'll notice that if I actually come here just so you can see and press . you'll see that indeed
SubmitInvoice is available on this thing, or sorry, SubmitEval, as well as GetEvals, and you'll also
notice that Abort, and Close are available on this thing. So, it's very easy to use. I don't really have
to change any of the other code down below. All we really changed here is the fact that we no
longer have to see, or deal with these ChannelFactories, and the actual channel instances
ourselves. Behind the scenes, when we actually construct this ServiceClient, and then start making
method calls, it'll take care of building the channels for us underneath. Let's go ahead and press
Ctrl+F5 to test this. And notice that it works just like before.
obviously this is one of those things that you would need to coordinate with the service. And then to
use this binding configuration on my client-side endpoint, I use the binding configurationattribute and
specify MyConfiguration. Now, there're obviously lots of things that you could configure this way.
This is just one example.Now, let's look at how to configure a client-side behavior. So here again, I
have my client-side application configuration file, and notice that underneath the client element, I
now have this behaviors element. And this is where I can define my client-side behaviors. Again, the
client-side behaviors are called endpoint behaviors, and I've got this new endpoint behavior that I've
defined called the viaBehavior. And within this element, I've added this child element called
clientVia, which represents a specific behavior that I want to take advantage of. This is the one that
does that special auto-routing for me. Notice, I specify a viaUri, which specifies the address that I
want the client-side, the outgoing messages to be routed through, and then I can apply this clientside behavior to my endpoint through the behavior configuration attribute. With this in place,
whenever I make calls through that client-side endpoint on a channel, it'll automatically perform that
routing functionality for me behind the scenes. Again, this is just one example, and there're various
other client-side behaviors that you can take advantage of this way. And as we move through the
rest of the course, we'll see some of this.
channel after one of these types of exceptions occurs. And so, I'll need to go ahead and fix these up
obviously. Let me do that real quick.CommunicationException handler, and then this will be called
ce, and this last one will be the TimeoutException handler, and this needs to be te. Okay, let's Build
that. So now we have a Client that's capable of handling three different types of exceptions that
could occur at runtime. So, let's see if we can make each of these different types of exceptions
occur. I've already updated the service code to help accommodate this. If you come in here to the
service again, you'll notice that inside of the SubmitEval operation I check to see if the Submitter's
name is Throw, and if it is, then I'll throw a new FaultException, and we'll see if that makes it down to
the client within that block. And then inside of GetEvals you'll notice I've caused my operation to
Sleep for 5 seconds, and we'll use that to test our Timeout capabilities. So let's go ahead and Run
the Host. Let me set this as the Startup project, and launch it. So now our new and improved Host is
up and running. And now let's go in and Run the Client a few times. So if I jump back to the Client
code, you'll see that right now we're passing in Aaron for the name, and let's see if we can make that
FaultException occur first. So I'll change this to Throw, and then we'll execute the Client. Now, notice
FaultException did indeed occur. So we entered our FaultException block, and that caused the
channel to shut down through the call to Abort. Now, if I change that back to Aaron, and Run it
again, this time it should block for 5 seconds, and then we can see that the number of evals is
2. Okay, so that was a successful Run. Now let's see if we can make the TimeoutException occur.
We can do that by adjusting our timeout threshold in the config file. Right now we're using the
WSHttpBinding, so if I come to the configuration for thatbinding, right here, and I change the
sendTimeout limit to say 2 seconds, and we Run the Client again, notice this time we got a
TimeoutException. And so that's how we can handle that is by simply putting our timeout to a more
reasonable value, and Run it again, and this time it should work just fine, after the delay for 5
seconds. Okay, there we are. Now the last exception we want to see is just other types of generic,
well, not generic, but other types of various WCF runtime exceptions that might occur. Probably the
easiest way to see one of these would be to go to our app.config file and mess something up at our
endpoint. So this is the endpoint that we're using. Why don't we put in a bad host name, or
something like that, so it can't even connect to the service. And now let's go ahead and Run the
Client again, and see what happens this time. Notice now we got, we went into our
CommunicationException handler, and the actual type of exception that was thrown was the
EndpointNotFoundException. That's just one example of a type of exception that can be thrown
within the WCF channel runtime when it's actually trying to communicate with the network. So, there
you have a simple example of building some exception handling logic into your WCF clients. Pretty
much every client needs to be prepared to deal with these three different types of
exceptions, FaultExceptions, CommunicationExceptions, and TimeoutExceptions.
automatically see this async model in place, assuming you've checked that you want to produce the
asynchronous operations.
will help me if I press Tab right now, by generating an event handler for me. So then down here
below, you see I have my channel_GetEvalsCompleted event handler, and that's now been
associated with that GetEvalsCompleted event. Okay, so I set that up right before I call
GetEvalsAsync, and that's basically all I have to do. And then I can harvest the result right down
here. So, instead of calling Console.WriteLine here, I'll want to do that down here. And now how do I
get that Evals List back? Well that's part of the GetEvalsCompletedEventArgs that's passed into
me. So here I'll say, e.Result, and then I can just simply .Count like I would've before, because
Result is the List of Evals. So that's how we do that. Now, before we test this, after we call
GetEvalsAsync, let's write something to the Console window so we can see we actually got passed
that call. We'll write out Waiting like this, and then we'll do a Console.ReadLine to make sure that
our ConsoleHost doesn't close down, because if it actually does try to close down, that might be a
bad thing. So, let's go ahead and press Ctrl+F5 now, and see what happens. Notice, waiting almost
immediately appeared. Right now that async call should be waiting for that response to come back
for about 5 seconds, and then you notice it printed out the number of evals. So that did happen
asynchronously. Now, let me illustrate this again. Let me Run it one more time, and this time I'm
going to press Enter right now. Notice it did take that Enter, so it definitely wasn't blocked, but it still
looked like it waited for the full length of those 5 seconds, and then it shut down, and it shut down
before it could actually print the number of evals to the Console window, but it did wait until that call
completed. And if you remember, that's the difference between Close and Abort. When you call
Close, it does wait for those pending calls to complete before closing down the underlying channel
stack. Now, to illustrate this, if I change this call to Abort, Run it again, and press Enter, notice it
immediately shut down. So there was a difference there.
especially when you spend a lot of time building some constructors, and properties, and other
helper methods, into your data contract types, that you'd also like to let you clients take advantage
of. If you expose those things through WSDL, and then reimport that WSDL into the client-side, you
lose all that stuff. So by bypassing the code generation process, you can preserve all of those
helpful features that you spent time building into the server-side programming model. So here we
have a service that is using assembly xyz, and it's exposing three endpoints, and notice that those
contracts that it's exposing are coming from assembly xyz. Then over here, we have a client, and if
we want that client to be able to take advantage of those same contracts, we can simply share that
assembly with the client, just like I would've done with .NET Remoting. Now, the challenge that we
run into is this. How does the client download those endpoint definitions, because the client needs
the endpoints in order to be able to communicate with the service? Well, if he just does it the normal
way, and uses SvcUtil.exe, like we've been talking about, it'll actually regenerate all of the client
contract definitions, and we don't want that. So here, what we need to do is we need to tell the client
import tool to reuse the types found in assembly xyz when generating those client endpoints. So, if it
sees something in the WSDL, or schema definition that looks like something I've already got
in assembly xyz, it can just skip that one, and reference it. The way you do this inside of SvcUtil.exe
is through the reference switch. There's also a way to configure this within the Visual Studio 2008
ServiceReference Settings dialog, which I'll show you in just a second. By doing this, what you're
essentially doing is telling the metadata import tool to go look at that assembly. And then when you
actually hand it the WSDL definition, it'll look through those contracts found in thatWSDL definition,
and look at the reference to see what types it already has a match for. And then it will simply
generate the config that's necessary, and not the contracts. It'll only generate new contracts that are
not found in assembly xyz. For anything that is found in xyz, it'll simply reference those types in the
endpoint definitions, thereby allowing you to share these assemblies on both sides of the wire, and
still use the metadata import tool to synchronize with the service endpoint definitions.
In this demo, I want to show you how to take advantage of that feature for sharing assemblies
between services and clients, and again, this is assuming that you're using WCF on both sides of
the wire. Okay, so one thing that I did is I added a few constructors to our Eval class that we use
over on the service side. And this might be helpful even when I'm doing things on the client side. So
this is one of these examples where you might want to be able to share this assembly across both
sides of the wire. Right now, the client is coded to use a different version of Eval. The one you're
looking at here is the one that the service is using. But if I Close this down, and I show you the code
for the Client Service Reference, this is the Eval that the Client is using, and notice it doesn't have
any of those constructors. So it got a new version of Eval when we generated that Service
Reference, and this becomes problematic because then you end up with a whole bunch of different
versions of very similar classes in large scale solutions. So if you want to share that assembly, the
EvalServiceLibrary assembly, with the Client, we can do that. I can simply right click, say, Add
Reference, and select the EvalServiceLibrary to bring that over here. So now this Client project has
a direct Reference to the EvalServiceLibrary. Now, the question is, if the client is going to generate
the client-side endpoints through this ServiceReference, how do we tell it to ignore the data contract
types, like Eval, found within that assembly? Well, we'll need to come back here to our
ServiceReference, and configure it, and notice down here, we have this feature called reuse types
in referenced assemblies, and notice that EvalServiceLibrary is now showing up in this list. I can tell
it to just reuse all the types in these various assemblies if I want, or I can single them out, and just
say, yeah, let's just reuse the types in that EvalServiceLibrary, and then I press OK. Then it goes off
and regenerates the code, and notice what happens. That Eval class now disappears from the
EvalServiceReference, because it's no longer needed. It's contained in the EvalServiceLibrary class
over here. And so now the Client's going to use the exact same class with the constructor that is
being used by the Service. So now in my code, I'll be able to go ahead and use that Eval with that
nice constructor, so one thing I'll need to do though, is I'll need to bring in the namespace for
EvalServiceLibrary now it recognizes that class, and then I can go ahead and use my handy new
constructor on the client side as well. (Typing) Okay, and that simplifies this Client code. I can get rid
of all these guys, and just call SubmitEval like that. Let's Run the Client, and ensure that it still
works. And again, we have that asynchronous call in place, so it's going to take 5 seconds, and then
we should see the result printed out to the Console window.
your clients to make smart choices about which endpoints to use. Clients can walk up to a service,
download a set of endpoints, and then make decisions on which endpoints to use based on certain
criteria. Again, there're numerous ways you could apply this particular functionality, but they all
essentially revolve around making your clients more dynamic in nature.
code a little bit in this example to use the synchronous call to GetEvals, and I did take the Sleep out
of the service implementation, and so we're just going to call SubmitEval twice for each endpoint,
and then call GetEvals, and then printout the Count, and then we'll Close down this instance of the
channel, and then we'll start over again up here with a new one for the next endpoint in the list. So
we're going to go ahead and press Ctrl+F5. Well, actually before I do that, let me printout something
right here just so you can see that we are waiting to get the stuff back from MEX. Because that can
take a little bit of time. So, that's the first thing we'll do, is we'll print that out to the Console, then we'll
call Resolve, that'll take a little bit of time, and then once we get that back, we should see all those
endpoints execute. So, Ctrl+F5 to Run. We see it's retrieving the endpoints, and here within a few
seconds, we should see each of those four endpoints currently exposed by the service execute.
Now, each one of those invocations usedvery different transports, and security protocols, and all that
kind of stuff. Each one was completely different, and the underlying channel infrastructure was able
to automatically wire up the correct configuration based on what it got back in that metadata at
runtime, which is very compelling. Now, let me show you one other thing. If I Close this Client
down, and I Close down the Host as well, I'm going to jump back over here to my Host, and I'm
going to add in one more endpoint into my Host. So here's my Host. I'm going to add in one more
endpoint here, and I'll just change the address of this one to basic2, so we now have five endpoints
in this thing, in addition to our MEX endpoints. And then I'll go ahead and restart my Host, so we
have a clean version that's exposing five endpoints. We should see the basic2 now show up.
Okay. And then I'm going to come back here, and restart my Client. Now, without changing any
code in the Client, I'm just going to Run it, we should see now that five endpoints are executed. So
the client, without any changes, was able to dynamically pickup that new endpoint, and use it at
runtime. So that helps illustrate the power behind using MEX to make your client applications much
more dynamic in nature.
Summary
And that brings us to the end of this module. In this module, we saw that the WCF client-side
architecture is indeed very symmetric with the service architecture. They both revolve around the
central concept of endpoints. The first thing that clients do before they can begin writing any code, is
they have to retrieve those endpoint definitions from the service. Then we saw how to actually write
the code, how to program against the channel programming model in WCF. We saw that first you
have to create and configure a ChannelFactory, then you can create channel instances, and once
you have those, you can make method calls through them using the service contract type. And then
finally, when you're ready to clean up the channel, you can either call Close or Abort. We also saw
that the WCF client-side model offers numerous more advantage features around things
like exception handling, asynchronous invocations, sharing types across assemblies, and
programming MEX. Hopefully, at this point, you feel confident with the capabilities of WCF for
consuming a wide variety of services found throughout the world today.
RESTful Services
Overview
Hi. This is Aaron Skonnard with Pluralsight, and I'll be presenting this module on Building
RESTful Services with WCF. In this module, we'll start by looking at some of the web programming
models that exist today throughout the industry, specifically SOAP, plain old XML, or POX, and
REST. We'll compare and contrast each of these models, and discuss when it might make sense to
use one over the other. Then we'll turn our attention to the support built into WCF 3.5 for building
RESTful web services. Specifically, we'll look at a few new attributes they've included, WebGet, and
WebInvoke, and a new service host called the WebServiceHost. Then we'll discuss the support for
some web data formats, including RSS, and Atom, as well as JSON, the JavaScript Object Notation,
when you need better integration with Ajax-style applications. So let's start by discussing SOAP.
Sometimes SOAP might actually be overkill for particular web service scenarios. In many cases,
developers need a high range of interoperability, and so they have to restrict themselves to basic
XML messages that they transmit over HTTP, and they can't take advantage of all the more
advanced WS-* specifications that are part of this suite of protocols. For security, they'll simply use
HTTPS. They'll just leverage SSL for all their security needs. This is actually pretty common today. A
lot of developers end up using SOAP without WS-*, and this is often referred to as simple SOAP.
Now, the main benefit of doing this again is that it increases yourinteroperability, but also there's a lot
of tool support available throughout the industry for generating clients and servers from the WSDL
definitions. We can take the WSDL and schema definitions and automatically generate the code that
we will need within our framework, and that code will hide all of the underlying XML and HTTP
details. So that's primarily why developers will still use SOAP even though they may not be able
to take advantage of a lot of the additional protocols that it was designed to support. When
developers end up using SOAP without WS-*, some developers decide, well, I really don't need
SOAP at all, and so I'll just exchange raw XML messages over HTTP without SOAP, without the
SOAP framing elements. So this is often referred to as plain-old XML, or POX, and it's usually done
in conjunction with HTTP. When you take this approach, the interoperability is virtually guaranteed,
because you can pretty much find an XML and HTTP stack on any platform known to man today.
But it does require you to do some direct XML and HTTP coding. In order to use POX, you're going
to have to be comfortable with writing XML-based code using various XML APIs to produce, and
consume messages, and you'll also need to be comfortable with an HTTP stack for actually
programming the logic to send and receive those messages. For some developers, that's not a big
deal, but for others, it might be, so that's one of the reasons why people tend to move back to SOAP
again when they want that tool support, and that automatic code generation, especially on the client
side. Now, POX applications can be defined in a RESTful way, according to some of the RESTful
design principles that we're about to talk about, but they don't necessarily have to be. If you design
your services around HTTP, and you adhere to the RESTful design principles, and you define
all your actions in terms of the HTTP methods and verbs, then indeed you're going to be using what
we would call a RESTful architecture that happens to use plain-old XML messages on the wire.
Understanding REST
So that leads us to REST. What exactly is REST? Well, in 2000, a guy named Roy Fielding
introduced this concept called Representational State Transfer, which we call REST for short. Now
this was a chapter out of Roy Fielding's PhD thesis that describes a scalable architecture for
building services around a uniform interface, and basically what he describes in that thesis is an
architectural description for how the web actually works today. And because of that, HTTP is the
typical protocol that people will use today to build a RESTful implementation. Now, REST is
fundamentally different from SOAP. SOAP defines a transport-neutral model focused on defining
custom service contracts with custom operations, and you can invoke those operations over a
variety of different transports using different messaging codings. REST, on the other hand, defines
more of a transport-specific model. Now REST doesn't actually tie you to HTTP, but in reality, HTTP
is the only protocol that is used in practice today for building RESTful architecture, so typically the
two go hand-in-hand. When you say you're doing REST, that typically implies that you're also doing
HTTP. With the RESTful model, instead of being focused on custom service contracts, and custom
operations, is focused on defining resources, and identifying those resources through a unique
identifier, or a URI. Then, you build services around a uniform interface. So, instead of defining a
custom service contract, we're going to define a uniform service contract that all of our services will
use. If you use HTTP to implement your RESTful services, that uniform interface is defined by the
various HTTPmethods, so GET, POST, PUT, DELETE, HEAD. And so those are the operations that
we'll be able to invoke on our resources. And when we get a resource, we'll then be retrieving a
representation of that resource over the protocol. So, what's actually returned to us over the wire is
a representation, and we can use a wide variety of data formats to represent that resource. We
could use HTML for example, or XML, or even things like RSS, or JSON. So there are still a variety
of ways that you can represent resources when you move them back and forth between clients and
services, but in the end, we'll always be using a uniform interface to interact with those resources
that are exposed by our service. Let's see if we can draw this distinction between REST and SOAP,
and make it a little clearer. To summarize, SOAP emphasizes verbs, or actions, while REST
emphasizes nouns, or resources. When you define a SOAP service, your focus is on defining the
service contract, the set of custom operations that you're going to expose through that service. So,
you're essentially defining actions, or verbs, that you're going to be able to use through a variety of
different transports. When you use SOAP with HTTP, you're always going through the HTTP POST
method. So the action is not really defined by the transport, it's defined by the message that you're
sending through that transport. So that's what it's like when you're using SOAP. With REST, on the
other hand, your focus is on defining resources, and identifying those resources with unique
identifiers, or URIs. Then, you'll interact with those resources through a uniform interface, typically
defined by HTTP. So you'll use the various HTTP verbs, like GET, POST, PUT, DELETE, and
HEAD, to interact with the User and Location resources. So, for example, I could GET a User to
retrieve a representation of it, or I could POST a User to create a new one, or I could PUT a User to
update it in the system, or I could DELETE a User to actually remove it from the system. So, I can
use any of those standard operations with any of these resources. I could do the exact same thing
with the Location resource. So that's the beauty of REST. We have a standard uniform interface that
can apply equally to all of our resources that we expose through that service, and they provide the
standard CRUD operations that you would typically expose through a SOAP service interface as
well. And when you do that, you'll define standard representations for those resources that you're
going to be sending back and forth across the wire. There are many different ways that you
can represent a single resource. That, in a nutshell, is the primary difference between REST and
SOAP.
now take advantage of all the widespread web infrastructure, and optimizations that have been built
around that specific protocol, and those specific operations. If you think about the way the web
works today, one of the most commonly used HTTP verbs is GET. Probably 90%, or more, of all
web traffic is GET, GET requests, where you walk up to a web server and ask to retrieve a
representation of a particular resource. Now, GET is a well-defined operation with specific
semantics. GET requests should not cause any unsafe side effects. They should be idempotent. We
should be able to do it multiple times, and have that be the same as if we did it just one time. Now,
because of the way GET is defined to work, we can optimize specifically around this particular
operation, which is so widely used. The other HTTP methods, like POST, PUT, and
DELETE, provide different semantics, but they don't provide any of the same guarantees as
GET. Now, if you think about how REST works, REST just naturally embraces GET, and can take
advantage of all theinfrastructure on the web today built around the importance of GET. But SOAP,
on the other hand, largely ignored the importance of GET. In fact, today with most SOAP services,
all SOAP requests tunnel through POST requests. So that's a huge difference between these two
models. With REST, you get to take advantage of the web infrastructure, whereas with SOAP, you
have to build all that stuff yourself withinyour service implementations. Another thing we needed to
talk about is the importance of these web formats that you use to represent your resources. The
reach of your service will be constrained by the support for the format you use. So you want to use
something that's ubiquitous if you care about interoperability and reach. Well XML is obviously very
ubiquitous, so using XML alone is going to greatly increase the reach of your services. There are a
couple common XML formats that you could also choose to use that are widely supported as
well. RSS and Atom are two of the most commonly used formats throughout the web today for
syndication. This is what's used throughout the blogosphere today. So, there're lots of different
versions of RSS and Atom, and Atom is becoming the standard. In fact, there's even a standard
Atom-based publishing API, which happens to use a completely RESTful design, by the way. If
you're interested in a good RESTful design example, go check out the Atom Publishing API. Okay,
so by using RSS or Atom in your services, your services will then be able to plug in to all of the
syndication-related infrastructure that also exists throughout the web today. Another commonly used
format on the web is called JSON, the JavaScript Object Notation. This is used in traditional Ajax
applications. So if you're building things that use Ajax on the client side within the web browser, you
may want to expose certain resources to those clients through JSON.
use SOAP and WS-* to achieve all those goals. So, if you find yourself in a situation where it feels
like you need a lot of those COM+ like capabilities that you had in the past, that's typically where
SOAP and WS-* is going to make the most sense. But it can be overkill in some distributed
scenarios, especially web facing, highly scalable scenarios, where you're building services that need
to be exposed to the world, hence you need a high degree of interoperability, and a high degree of
scalability. In scenarios like that, REST will tend to be a better fit.REST is all about scalability. So,
anytime you're building services that will be web facing to the public, and you're going to need a
high degree of interoperability, REST will probably do a better job of helping you achieve those
goals. Now, one of the big tradeoffs between SOAP, and WS-*, and REST, is the tool support. With
SOAP and WS-*, there's great tool support provided by all the big SOAP vendors, like
Microsoft, IBM, BEA, Sun, etc. With REST, on the other hand, there's very limited tool support
beyond the basic HTTP and XML stacks that you can find pretty much on any platform out there. So
again, there's no clear cut winner, it's simply a matter of choosing the best style, the best
architecture for each particular scenario. And within a single SOA architecture, it's very likely that it
will make sense to adopt both SOAP and REST designed principles in the different scenarios that
make up the overall SOA solution.
model, you just simply have to choose which features you want to employ in a particular
scenario. So how do you use these different programming styles in WCF? Well, most of the built-in
bindings that we've talked about in this course use SOAP and WS-* by default, so you'd actually
have to configure those bindings to disable SOAP, and the various protocols that are enabled by
default on that binding. Now, in .NET 3.5 they introduced a new web-based programming model for
WCF, and that's found in the System.ServiceModel.Web assembly. It allows you to essentially map
incoming HTTP requests to methods on your service contract through URI mappings. You can use
what's called a URI template to define what URI should map to a particular method. You enable this
new web programming model on your WCF services through a new binding, and a new behavior.
You apply the WebHttpBinding to your endpoint, and that applies all thecomponents that you're
going to need down within the WCF messaging layer. And you apply the WebHttpBehavior to your
endpoint to apply the custom dispatching logic that will look at the URIs that are coming in to figure
out how to map those to your methods on your service contract.
So, by simply applying these two key pieces, you'll now have a WCF runtime capable of providing a
more RESTful implementation. Now, both of these key things are going to be required to take
advantage of the new web features that we're going to be talking about over the next several
slides. Okay, now let me show you how to write the code to wire these things up. So here you'll
notice I've created a ServiceHost of type EvalService, and I've specified a base HTTP
address. Then I add a new service endpoint, specifying IEvals for the service contract, and
WebHttpBinding for the endpoints binding. Then right below that you'll notice I'm adding the
WebHttpBehavior in to that endpoint. Then I call Open to open the ServiceHost, and behind the
scenes when I do that, it will create thatunderlying WCF runtime capable of this web programming
model that we're talking about. They also provide this new WebServiceHost class to simplify the
process of wiring those things up. Instead of doing it manually, like I just showed you, you can
simply use the WebServiceHost and open it. When you create it, you specify the type of service,
and the base HTTP address, and then when you open it, it will automatically add the endpoint in for
you for the base address, and it will use the WebHttpBinding on that endpoint, and it will also
automatically inject the WebHttpBehavior on that endpoint. So, all you simply do is construct the
WebServiceHost, and call Open.
WebGetAttribute
Now let's discuss how you'd write the code to actually map incoming HTTP requests to your WCF
service operations. The way you do this is through a few new attributes. They defined a new
attribute called the WebGetAttribute for mapping incoming HTTP GET requests to a particular
method. Now the way you do this is you supply a UriTemplate when using the attribute that will
define the precise mapping from the URI to the method. And the UriTemplate gives you the ability to
specify variables within the URI itself that can then be mapped to the method parameters on the
method signature. There're also other things that you can control through this attribute, like whether
or not it would wrap the incoming and outgoing messages with an operation name element, and
what message format you want to use, like XML or JSON. So let's look at a quick example. Here
I've got my IEvalService contract, and notice I've got an operation here called GetEvals. I've
annotated that with OperationContract, which is still required even when you're using the
WebGetAttribute. And I've added the WebGetAttribute to define the mapping from the incoming URI
to the method. So here I've said UriTemplate=evals?name=name parameter&score=score
parameter. So these two variables that I've used in the UriTemplate, name and score, map to the
parameters in the method signature. So whenever an incoming request arrives with this particular
URI, those values, name and score, will be pulled out of the query string, in this case, and then
supplied to the method when it's called. Now, I should also point out that this UriTemplate address is
going to be relative to the base address for this particular service, in this case.
WebInvokeAttribute
They provided another attribute called the WebInvokeAttribute, which is meant to be used with all
other HTTP verbs besides GET. Because GET is kind of a special case with regards to its
semantics, they keep those two separate in terms of how they model the code, and that will allow
them to optimize things for GET separately from all these other cases. The way they do this is they
provide a Method property on theWebInvokeAttribute that you use to specify the verb that you want
to map to in this case. The default verb is POST, if you don't use the Method property. And it also
allows you to specify a UriTemplate, just like before, and you can even use variables, and map
those to parameters in your method signature. But the key difference here is they assume that the
last parameter in the method signature is where you want the body of the incoming message to be
deserialized. So, let's look at an example. Here I've got my ServiceContract IEvals. I've added an
operation called SubmitEval. Notice it has two things in the signature, a name, and an eval. And
notice I've used the WebInvokeAttribute, and I've specified the Method to be PUT. So this will handle
any incoming PUT requests at the address of /evals?name=some value. We've mapped that name
value to the name parameter in the method signature, and we're assuming that the sender, the
caller, will send us an eval element in the body of that incoming PUT request. So, WebInvoke can
be used to handle any other type of HTTP method besides GET by simply using that
Method property like we've done here.
UriTemplate
Let's take just a few more seconds to discuss this idea of UriTemplates. The UriTemplate's really the
main thing that we're using here to map the incoming request to the method. It defines a specific
syntax for how you layout these URIs. Basically, they allow you to put within theURI these variables,
and you use the curly brace syntax to identify where those variables are going to go. Now you can
put these variables within path segments in the URI, or within query string variables like I've shown
you here. Either one works. You can also use wildcard syntax to say that anything after
this particular path segment should match this method. The wildcard character that you would use is
*. So we could always put /* somewhere in our path to say match anything at this point in the
path. Now .NET 3.5 comes with a new class called System.UriTemplate that basically implements
this new syntax. When you construct a UriTemplate, you provide it with the UriTemplate string, in
this case. And then you can bind that UriTemplate with actual values. So when you call Bind, you
pass in the values for name and detailed, in this case. You can also call Match on a particular
UriTemplate, handing it an actual URI, and it will verify that the URI matches the UriTemplate, and
then it will extract those values from the variable segments, and hand those back to you. So this is
essentially what WCF is using behind the scenes to implement that dispatching logic. Now, there're
lots of details around how you can use UriTemplates, and there's more to this syntax than I've been
able to discuss here in this short video, but there's plenty of documentation up on MSDN
around how UriTemplates work.
specify the submitter name, and it will return all Evals submitted by that submitter. And then finally,
we have a RemoveEval method that will remove an Eval with a particular ID. And then down below
here, we've updated our EvalService implementation to implement all of those methods that we just
described. Okay, so now let's go ahead and see what the Host looks like. If I come over here to my
Host application, you'll notice I'm creating a ServiceHost based on the typeof EvalService, and it
looks just like before. I just Open the Host, and then I print out the endpointinformation for this
particular ServiceHost, which is done down here. Okay, now, if you look at the App.config file for this
ServiceHost, you'll notice that I've configured a baseAddress of localhost:8080/evalservice, and I've
configured one endpoint that uses the basicHttpBinding,and the IEvalService contract, and it's just
using the baseAddress for the endpoint address. I've also enabled serviceMetadata on this
particular service. This behavior's called Default, and we applied that right here. If I go ahead
and Run my ServiceHost, you'll see that it says EvalService is up and running with the following
endpoints, and it just shows this one endpoint that uses the basicHttpBinding. Now let me jump
back over here and show you the Client application. I've written a new Client against this particular
service. We built this EvalServiceClient class against the metadata using Add Service Reference,
and then I ask the Client to enter a command, we parse the command, and then if it doesn't say exit,
we go ahead and figure out what you want to do. If they type in submit, we ask the user to type in
their name, and then their comments, then we create an Eval, and then we Submit it. And then we
printout Eval was submitted. Down here, if you type in get, we ask you to type in the eval ID, we
read it out, and then we call GetEval, and then we print those Eval details out to the command
prompt. If you type in list, we'll ask you to specify a submitter name. We read that in, and then we
call GetEvalsBySubmitter, and then we printout all the Evals that we got back to the command
prompt. If you type in remove, we'll ask you to enter the ID once again, and then we call
RemoveEval passing in the ID, and then we printout Eval was removed. Then we go ahead and ask
you for the next command, and we loop, and continue once again. So now that we've got our
ServiceHost running, I'm going to set this as the startup project, press Ctrl+F5 to Run it, and let's just
go through it once. So here I'll type in submit. For my name, I'll type in Aaron. Then I'll type in, this is
my first eval, and notice it says eval submitted. Let's submit another one. This one will be from
Monica. We'll type in, this is Monica's first eval, and then we'll do one more. I'll do another one for
myself. The command, sorry, needs to be submit, and then my name is Aaron, and then my
comments will be, this is my second eval. Now, let's do a list, so we'll list them. We'll just hit Enter
now to not specify submitter name, and notice we got all three back in this case. That's what
happens when you don't provide a submitter name. And notice that we see all three of those evals
that we just submitted. If I type in get, I can specify one particular eval, let's grab Monica's with the
ID of 2, and notice we justgot that one back. I could also do list, and specify a submitter name, like
Aaron, and now I'll just get Aaron's evals back. Okay, and then if I wanted to remove an eval, I could
type in remove, we'll type in the ID, let's get rid of the third eval there. Notice it says Evaluation 3
removed. Now let's do another list, hit Enter, and notice now we only have two evals in total. So
that's how you use this Client application.And that's talking to the service through the
basicHttpBinding. Each one of those operations that we invoked was using SOAP behind the
scenes. So, now what we need to do is figure out how to map this over to a more RESTful design.
So, I'm going to jump back over here to my EvalService file, and I'm going to come here to the
IEvalService contract, and this is where we're going to make some changes. The first thing I need to
do is define a URI mapping for each of these operations. So, let's start out with GetEval and all
these GET methods, let's start with these first. So here, I'm going to use the new WebGetAttribute.
You'll notice it's not showing up in IntelliSense because I haven't added the assembly that I need
here. I'm going to come over here and Add Reference, and then search for a
System.ServiceModel.Web, which is this guy. We'll add that in. Now, we should see that red
underscore so I can hit Ctrl+. and bring in the namespace, System.ServiceModel.Web. Then here, I
can specify a UriTemplate. Well, first of all, let me just show everything that's on there. Notice, we
have BodyStyle, RequestFormat, ResponseFormat, and UriTemplate. We're going to use
UriTemplate here, and we're going to specify what URI this should map to. And that's really all we're
going to specify here. Now, notice we're expecting an ID to come in, and so really what we should
probably ask them to type in here, is we'll have the baseAddress, followed by eval, followed by the
ID. And that ID variable will map to our parameter here, ID. So that's the mapping for GetEval. Now
let's come down here for GetAllEvals, and instead of doing this, we're just going to have you type in
evals. So if they browse to the baseAddress, /evals, they're going to get the entire list back. We'll
add one more here to GetEvalsBySubmitter, and this one will say evals/submitter. So we'll go to
evals and say I want to get all the evals for a particular submitter, and that submitter token will map
into this parameter right here. Now, we need to map these other two. Now, these aren't going to be
invoked using a GET request, so I'm going to have to use the WebInvokeAttribute. Notice this one
has the same properties, plus another one called Method. So first we need to decide what Method
this is going to map to, and then we'll have to define the UriTemplate as well. For the Method, in the
case of submit, we're either going to want to use POST or PUT. We're going to use POST in this
case, and then we have to decide what URI we want it to be posted to. Well, usually you would post
it to a factory endpoint, and so in this case we should probably post it to evals, because this where
we want to create a new eval. And then down here for this guy, let's go in and grab that, Copy it, and
Paste it down here. Instead of doing POST, we're going to do a DELETE. And instead of posting to
the evals URI, we're going to POST to eval/id. And that ID token will map into the ID parameter here
in the Method signature. Okay, so let's review what we just did. We went ahead and added WebGet
to all three of these guys to make then invokable using traditional HTTP GET requests. The URI is
going to determine which one is called for a particular GET request. And then we added the
WebInvoke Method to this one and this one, and we mapped this first one to a POST request to the
evals URI, and we mapped this one to a DELETE request for the eval/id URI. And so we've
basically exposed the same functionality that we had exposed before through the standard HTTP
uniform service contract, using GET, POST, and DELETE in this case. Okay, so now how do we
wire this up so we can actually call it? Well let's jump back over here to theConsoleHost, and we're
going to leave this code exactly the same. In fact, we're not going to change this at all yet. We're
going to jump in here to our App.config. This is where we're going to make our changes. And all I
need to do is change the binding here to use thewebHttpBinding, and I need to come down here to
this guy, and add in a new behavior. This is an endpointBehavior, so I'll add in a new behavior, we'll
give this thing a name of Web, and the behavior is the webHttp behavior. Then I need to apply this
behavior to my endpoint, (Typing) and so we'll do that. We'll say behaviorConfiguration is Web. That
brings this webHttp behavior into this endpoint. Let me Save that. Now, let me jump back over here
to my Host program, and Close it down. We'll set ConsoleHost as our Startup project once again.
And then we'll press Ctrl+F5 to Run it. Notice it says eval service is up and running with these
endpoints. And now this is a webHttpBinding endpoint, as opposed to a basicHttp endpoint. Before
it used SOAP, now it doesn't. Now it expects to be called using traditional HTTP GET requests. So,
now how can we test this? Well, let's open up a web browser, and see if we can browse. Go ahead
and make this a little smaller. See if we can browse to localhost:8080/evalservice/evals, and if you
remember, that was the URI that we mapped to our GetAllEvals method. And notice here we got an
empty ArrayOfEvals back. Now, how could we actually POST an eval up there to add one in, to
actually submit an eval? Well, let me bring up this other command prompt that I have running and
you'll notice inside of this I have a little utility called httputil.js. It's just a little JavaScript utility that lets
you type in the HTTP method you want to use, followed by a URI, followed by an optional file name,
if you want to POST that file in the request. So, I can actually just type in httputil, followed by a
POST for the name, followed by the URI, which in this case is going to be
localhost:8080/evalservice/evals, followed by a file name, and in this case I'm going to be pass up
aaron-eval.xml, and I'll show you that file in just one second. So I went ahead and ran that. It looks
like it succeeded. Let me just show you what that file name looks like, aaron.eval.xml. Notice it's just
an Eval document that is compatible with our Eval class on the server side. And now let's jump back
over here, and Refresh our Evals endpoint, and notice we now get that Eval back. Let's come back
over here and Run it a couple more times, just with the same file. If I come back over here and
Refresh, we should see three Evals in our system now.I've got similar files for other people that just
change the submitter name. I've got one for Bob, so we'll submit one for Bob. We'll also, I got
another here for Jen, so we'll submit Jen's Eval. We'll submit hers twice. Come back here, Refresh,
and you can see all these Evals are all there now. Now let's test some of our other operations. So
this is the one that just gets all Evals, period. But what I wanted to get all Evals from Aaron. Well,
let's type in Aaron in the URI. Now notice I'm only getting Aaron's back. Or maybe I just want to get
Jen's, so we put that in the URI, and we just get Jen's back. Or what if I wanted to get a specific Eval
based on an ID. You'll notice the ID is showing up here in the Eval. Let's try to get that one right
there, Eval of 6. So I'll type in evalservice/eval/6, and notice I just get that one single Eval back.
Now, how would I delete an Eval? Well I'll need to issue another HTTP request here. This time we're
going to be doing a DELETE request, and the endpoint we're going to POST to is
localhost:8080/evalservice/eval, and let's delete number 6. So we'll go ahead and send that across
the wire. Now let's come back over here. Now let me go back to the entire List of Evals here, so we
can see if Eval 6 is there anymore. Let me Refresh this, make sure we're not getting a cached copy.
Notice Eval 6 is no longer there. Let's delete 5 as well, just to make sure. DELETE 5, come back
here, do a Ctrl+F5 to Refresh, and notice 5 just went away. So, as you can see, we're now able to
interact with this EvalService using HTTP GET, POST, and DELETE requests, and we're able to
achieve the exact same functionality that we had before using the SOAP version.
turns out to be really handy, especially when you're hosting within IIS. Let me show you why. I'm
going to jump over here to my Solution, and Add a New Web Site. I'll add a WCF Service site, and
I'll call the directory EvalSite. And then I'm going to go in and Delete all the stuff that it gave me by
default, I don't ever like to use this stuff. I'll change the SVC file to eval.svc, and in the config file, I'm
going to Delete the entire System.ServiceModel section. So, I'm going to grab that entire guy right
there, and just Delete it. So there's no configuration in this file whatsoever for WCF. Then I'm going
to Add a Reference to this site, to my EvalServiceLibrary. And then inside of this eval.svc file, I'm
going ahead and Delete all of this, and all of this, and for the Service name, I'm going to type in
EvalServiceLibrary.EvalService. Then I'm going to add one more helpful attribute called
Factory. And in here I'm going to specify
System.ServiceModel.Activation.WebServiceHostFactory. So you can probably guess what this guy
does. It's going to go ahead and create a WebServiceHost object for me behind the scenes when
this SVC file is activated. And that WebServiceHost object will automatically add in an endpoint for
me at the baseAddress for this service, and that baseAddress will be the address of the SVC file.
And then it will automatically add in the webHttpBinding on that endpoint, and configure itwith the
webHttp behavior. So, I've got a configure-free mechanism now to host up a RESTful service using
WCF. There's absolutely no config in my file here for WCF. Just the basic web stuff that we've got in
there. So, now let's test this thing. I'm going to right click on the eval.svc file, and say View in
Browser. Starting it up inside of the ASP.NET development server, and it says, hey, endpoint not
found. That's because we didn't actually point it to a URI that maps to one of our methods. Well the
URI we need to pass in is Evals, and that comes after our baseAddress. So our baseAddress
changed here, but the relative address is the same. So I'll type that in, and notice we got
ArrayOfEval back. In fact, let me go ahead and Copy this and do it inside of Internet Explorer so it
looks the same. I'm going to come over here and just change that address there, hit it again and
notice we got our empty ArrayOfEvals. Let me grab this address here, jump down here to our
command prompt, and let's Run this thing again, only this time we'll specify this address. And the file
we'll pass in will be Aaron's file. So that hit that one. Now, let's do it again, and pass in Jen's file.
Okay, so we've added a few Evals in. Let me jump back over here and Refresh, and notice those
two Evals made it in. And now we're hosted inside of IIS, and we didn't have to do any configuration,
we just mapped our service to an SVC file, and told it to use the WebServiceHostFactory, and
behind the scenes that used the built-in WebServiceHost class, which did our auto configuration.
WebOperationContext
Another class you should be familiar with is the WebOperationContext class. This class gives you
access to the HTTP request and response messages within your service operations. So, say you're
executing within one of the service operations, and you want to grab a hold of one of the incoming
HTTP headers. You would simply use WebOperationContext.Current to access the current
instance of the WebOperationContext, and then through that object you can look at various aspects
of both the incoming request, and the outgoing response. You can look at things like the URI details,
query string parameters. You can look at specific HTTP Headers, like ContentLength, ContentType,
etc. You can also look at ETags for caching semantics. There are a variety of things that you can
look at through this interface. You can kind of think of this as your view back in to the HTTP protocol
world since WCF is doing its best to try to hide all those details from you. In some situations, you
won't really need to worry about this when you don't care about those underlying details, but when
you want to make your service operations more HTTP savvy, you will need to use this class to get
your hands back on the incoming and outgoing HTTP messages.
code, we illustrate how to go about doing this. You'll notice here that I first retrieved a List of Evals
from some other method. Then I create a SyndicationFeed based on those Evals. And I'm hiding a
bunch of code here, I'm not actually showing you how to go about building that SyndicationFeed, but
the API is pretty intuitive, and not that difficult. Then you'll notice down here I look at the
WebOperationContext by accessing the WebOperationContext.Current. Then I can go back peek
into that context and look at that IncomingRequest. Then I'm going to access my UriTemplateMatch
object, and ask for one of the query string parameters,the one called format. And if they did provide
me with a format that says Atom in the string, then I'll return an Atom10FeedFormatter. Otherwise,
I'll return an Rss20FeedFormatter wrapping that feed that we created up above. So that's how easy
it is to return different types of feeds based on some incoming value.
will be Recent student eval summary. And then we need to specify some Items. And here's where
we're going to use a little link. We're going to use a from statement. We'll say from eval in evals,
select new SyndicationItem, and then we'll use the initializer syntax for this guy, and we will say the
Title of the Item is going to be a new TextSyndicationContent, and we'll say e., or eval.Submitter
name. We'll use that for the Title, and then for the Description, or for the Content, we'll say give me a
new TextSyndicationContent eval.Comments. So that's our implementation. We're basically just
doing a transformation between our internal Eval List and the resulting SyndicationFeed. Although, I
guess I need some Evals. Here I'm iterating over Evals which I don't have yet, so here I'll need to
say List of Eval, and we'll call that evals = this.GetAllEvals. So we'll grab all of our Evals first from
the other method, then we'll transform it into a SyndicationFeed. And then we're going to return this
SyndicationFeed to the client, but we're going to do it based on a particular format, and the format's
going to be provided for us in the URI. So, here what we're going to do is we're going to check, and
say if format.Equals Atom, we'll go ahead and return a new Atom10FeedFormatter, and we'll pass in
our feed, else we'll return a new RSS FeedFormatter,passing in the same feed. So that will return
the right type of formatted feed based on what the user requested. Let's go ahead and Build this.
Looks like that Build succeeded. Now, let's test it and see if we can actually get a feed back to the
client, so I'll set the ConsoleHost as our Startup project, launch the Host, looks like that's up and
running now. Let's bring up a web browser, and let's browse to evalservice/evals, do a Ctrl+F5.
Notice we have an empty List of Evals right now. Let's go in and come back over here to our client,
and submit a few Evals in. So, I've got this little test utility on the client that I use to POST evals
up. POST a couple Evals from me up there. We'll also POST one from Jen. Oops. Let's do that
again. POST one from Jen. Let's come back over here, and Refresh to see that we've actually got
some Evals in there. Okay, there we go. We got four Evals. Now, let's test our Eval feed. So we're
going to go to evals/feed/format, and here's where I can specify Atom, for example. So let's do that.
And we got an error, and the reason we got this error is because I forgot to do one thing to my
service contract. Let me jump back over here to EvalService, and come up here to the service
contract. Here, I'm saying in my service contract that I'm returning a SyndicationFeedFormatter type,
but at runtime, I'm actually returning either an Atom10FeedFormatter, or an
Rss20FeedFormatter, which both derive from SyndicationFeedFormatter. So, up here on my service
contract, I actually need to annotate this with ServiceKnownType, specifying the type of those
derived types that I might substitute. So we'll specify that for the Atom10FeedFormatter, and we'll do
the same thing for the Rss20FeedFormatter. And then let's go ahead and Close down our Host, so
that we can rebuild this thing, and let's restart the Host, and jump back over here to our Client, and
let's Run that Client a few more times. We'll add an Eval for Jen, and a couple for me. And I'll just
come back over here and Refresh this, make sure we actually have three in.Okay, we have three
right now. Now, let's test the feed one more time. So we'll go to evals/feed/format, and we'll specify
Atom. And notice, Internet Explorer displayed this as an actual SyndicationFeed, which it knows
how to do natively now within the web browser. That's why you're getting this nice display here. And
then if I change this to rss. Well, first of all, while we're looking at the Atom feed, how about we go to
Page and do a View Source. And if you look at this, you'll notice this is indeed an Atom formatted
feed. Now, if I go ahead and change this to rss, Run it again, notice it looks a little bit different in
terms of the way it was displayed. If I go to the Page and do a View Source this time, you'll notice
that we actually got an rss 2.0 feedback. So this indeed did change based on the format that the
client provided in the URI.
to enable JSON on a method-per-method basis if you want. But it you want to enable full Ajax
integration on your WCF services, you'll also want to enable the WebScriptEnablingBehavior. This
behavior makes JSON the new default message format for all of your service operations. It also
enables Ajax-style invocations for each OperationContract exposed on your service. And you don't
need to use the WebGet or WebInvoke attributes anymore. In fact, the WebScriptEnablingBehavior
isn't compatible with the UriTemplate syntax, because they didn't anticipate that you'd want to use
those two things together. When you use the WebScriptEnablingBehavior, it also adds the capability
to dynamically produce a JavaScript proxy for your Ajax clients to use to invoke your service, that'll
be exposed on the baseAddress for the service, along with /js on the end of the URI.So now clients
can simply request that proxy dynamically, and then use the methods that it gets back in that proxy
to invoke your Ajax-enabled service. Now, instead of requiring you to enable this behavior on
your endpoints manually, they also provide a WebScriptServiceHostFactory that you can tie in to
your SVC endpoints, and that will automatically wire up a new ServiceHost configured with this Ajaxenabling behavior. Here's an example of what the SVC file would look like. Notice we've got the
ServiceHost directive. We've specified the service we want to host in this case, its EvalService here
in this example. And then we specify for the Factory the WebScriptServiceHostFactory. And behind
the scenes that'll wire everything up to enable Ajax on this particular service.
type in /js,for JavaScript, on the end of this, and notice what I get back. I'm actually getting back a
file. Let me Save this file to my disk, and I'll just call this js.txt. Let me Open that, and notice, this is a
JavaScript file. This is what that ScriptManager will get back at runtime when it calls our
service. And so it's going to automatically get this proxy code from the service, and then we can use
this code to actually invoke the service. So you'll notice here we're going to have a class
called tempuri.org.ICourseService, and we'll be able to call the GetCourseList method on that
service. So, remember that. I'm going to jump back here to my code now, and you'll notice that up
here above, well, you'll notice herefirst of all that I've got this Button on the page. And when you click
on the Button, we're going to call LookupCourses. So let's look at LookupCourses up here. Within
here, notice I'm using that JavaScript class that we got back from the service at runtime. I'm calling
GetCourseList passing in OnLookupComplete for the event handler that will be called when
the asynchronous call has finished. I'm also passing in OnError, in case something goes
wrong, we'll get called down here. So inside of OnLookupComplete, it's going to hand me the
result, and then I just go and I grab my Select box on the page, and then I iterate through all the
strings that I got back, and I simply add a new Option element to that Select box. Let's go ahead
and Run this thing, and see how it works. So I'm going to right click on Default.aspx,select View in
Browser. Let me Refresh this just to make sure it's completely refreshed and not cached. If I drop
this down, you'll notice there's nothing in this list. But if I click Load Courses, it's going to
automatically populate that without refreshing the entire page. You'll notice the whole page does not
flicker when I click this. That's because it's not refreshing the entire page, it's using Ajax to call my
WCF service, that GetCourseList operation. It's getting back the JSON for this list of courses, and
it's dynamically adding these to the list. Each time I click this, it adds those four courses, so the list is
getting long now. Now, I could, let me Close this. I could come back here and override, basically
clear the list out every time we call it, just so that doesn't happen. Let me Save this, right click, and
say View in Browser again. And now notice it's not populated, but when I click Load Courses, it's
populated. I can click it as many times as I want, and it's still just those four courses in our list. So
there you have a simple example of enabling Ajax on an entire WCF service by simply using an
SVC file that uses the WebScriptServiceHostFactory class.
System.Web limitations
Now there are a few key limitations to this technology that I want to highlight at least before we wrap
up. This is V1 of the technology, so many of these issues may go away in future releases. But at
least, as of today, the UriTemplate syntax isn't capable of handling very complex URIs. For example,
if you try to employ a more advanced URL scheme that perhaps includes matrix URIs, where you
have complex data separated by commas and semicolons, it's not possible to write a UriTemplate to
deal with that stuff. So you'll end up having to parse those URIs manually by hand within your
service operations. The other thing is UriTemplate variables can't map to DataContract fields. As of
today, the UriTemplate variables can only map to string parameters. Another limitation is that you
can't mix the WebScriptEnablingBehavior that we just talked about with UriTemplates. They didn't
design those two features to be used with one another. So you either configure the service to use
the WebScriptEnablingBehavior, or you decide to use the UriTemplates, but you can't do both at the
same time. And finally, server faults always return the same error message to clients. You'll always
get a 400 Bad Request back on the client side after something went wrong within the service
operation. Since we're no longer using SOAP with this web programming model, we don't have the
SOAP fault mechanism to convey richer fault information back down to your clients. There's really
no way around this short of writing a custom behavior that plugs in to the error handling logic.
Summary
And that brings us to the end of this module. We've seen that there are several architectural styles
for building services today, including SOAP, POX, and REST. And there are several different data
formats that we can use with our web services, including things like XML, RSS, Atom, JSON, or
even things, like MTOM, or binary messages. And we've seen that each of these architectural
styles, and message formats comes with its own pros and cons. Although we can summarize things
by saying that SOAP is usually a better fit within the enterprise, whereas REST is usually a better fit
within pubic web facing service scenarios, where you need a high degree of scalability and
interoperability. The good news is WCF provides a programming model that accommodates each of
these different styles, and a variety of different message formats, so there's only one way to write
the code, but a lot of different ways to wire things up.