Welcome to Windows Communication Foundation (WCF)
Top Tasks :

WCF Team Bloggers

Browse by Tags

All Tags » Service Model » HTTP   (RSS)

  • Streaming Web Content

    How do I deliver content from a WCF service as part of a web page? Web page content in this case typically refers to HTML, images, or other data that is directly consumed by the web browser rather than an application running in the web browser. There are a few things you need to do to make your web service serve up content in a way that's indistinguishable from an ordinary web server. I'll serve up a static image at a fixed location for this example but you can get as fancy as you'd like. The first thing you need is the right contract. The initial page load is ordinarily retrieved using the HTTP GET verb rather than the HTTP POST verb assumed by web services. I'll set that up as part of my contract using the WebGet attribute to set the verb and a URI template to set the address. [ServiceContract] public interface IService { [OperationContract] [WebGet(UriTemplate = "/image" )] Stream GetImage(); } The second thing you need is the right content type. Although web browsers can try to autodetect content, you should specify the content type if it is known. This allows the web browser to process the content correctly inline. public class Service : IService { public Stream GetImage() { WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg" ; return new FileStream( "c:\\test.jpg" , FileMode.Open, FileAccess.Read); } } Finally, you may notice that while I've done everything needed in the service implementation to enable streaming, content can only be streamed if the binding supports this as well. When using WebServiceHost, the default bindings do not support streamed content. This may be hard to spot because the typical files are small and a test program running on the same machine completes the transfers before streaming would make a difference. I've wrapped the service implementation in this example to intentionally slow down the transfer to make the difference more apparent. The following code demonstrates enabling streaming on the binding. You can change the transfer mode back to Buffered to observe the difference. Streaming requires support in the receiving application as well to make a difference. Using a large, progressive encoded image will demonstrate this. using System; using System.IO; using System.ServiceModel; using System.ServiceModel.Web; using System.Threading; public class SlowStream : Stream { Stream innerStream; public SlowStream(Stream innerStream) { this .innerStream = innerStream; } public override bool CanRead { get { return Read More...
  • Avoiding Address Filters

    The address filter mode that we looked at last time solved the problem of funneling all of the messages with a given prefix address to our service instance. Changing the filter mode still left us with the problem of dispatching from that universal contract to all of the logical operations that live inside the address space. This is exactly the problem that UriTemplate solves. By combining templates and WebServiceHost, both of the problems get taken care of for us. Here is an equivalent contract and service implementation with some more semantics filled in for a particular application. All I've done is pick out part of the address space that I want to assign some implementation to. [ServiceContract] public interface IService2 { [OperationContract] [WebGet(UriTemplate = "/resource/{index}" )] string Get( string index); [OperationContract] [WebInvoke(UriTemplate = "/resource" )] void Add( string value ); } public class Service2 : IService2 { public string Get( string index) { Console.WriteLine( "Get {0} {1}" , WebOperationContext.Current.IncomingRequest.Method, OperationContext.Current.IncomingMessageHeaders.To); return null ; } public void Add( string value ) { Console.WriteLine( "Add {0} {1}" , WebOperationContext.Current.IncomingRequest.Method, OperationContext.Current.IncomingMessageHeaders.To); } } Hosting this service is basically the same. I can take out the endpoint definition because that gets inferred automatically. WebServiceHost host = new WebServiceHost( typeof (Service2), new Uri( "http://localhost:8000/" )); host.Open(); Client(); Console.ReadLine(); host.Close(); Finally, I can use the exact same client code as last time even though in the service I've changed my way of writing the service from a centralized approach to an address-based approach. ChannelFactory<IRequestChannel> factory = new ChannelFactory<IRequestChannel>( new WebHttpBinding()); factory.Open(); IRequestChannel proxy = factory.CreateChannel( new EndpointAddress( "http://localhost:8000/" )); using ( new OperationContextScope((IContextChannel)proxy)) { Message request = Message.CreateMessage(MessageVersion.None, string .Empty, "data" ); request.Headers.To = new Uri( "http://localhost:8000/resource" ); WebOperationContext.Current.OutgoingRequest.Method = "POST" ; proxy.Request(request); } using ( new OperationContextScope((IContextChannel)proxy)) { Message request = Message.CreateMessage(MessageVersion.None, string .Empty); request.Headers.To = new Uri( "http://localhost:8000/resource/1" Read More...
  • Web Address Filters

    Here is a basic service that defines a universal contract to program against for building a simple HTTP application. The service doesn't do anything, but you can ignore that in this example. [ServiceContract] public interface IService { [OperationContract(Action = "*" , ReplyAction = "*" )] Message Request(Message msg); } public class Service : IService { public Message Request(Message msg) { Console.WriteLine( "{0} {1}" , WebOperationContext.Current.IncomingRequest.Method, msg.Headers.To); return null ; } } You might expect to run this service in a straightforward hosting environment. ServiceHost host = new ServiceHost( typeof (Service), new Uri( "http://localhost:8000/" )); host.AddServiceEndpoint( typeof (IService), new WebHttpBinding(), "" ); host.Open(); Console.ReadLine(); host.Close(); And, talk to it with the ordinarily convoluted client programming model. ChannelFactory<IRequestChannel> factory = new ChannelFactory<IRequestChannel>( new WebHttpBinding()); factory.Open(); IRequestChannel proxy = factory.CreateChannel( new EndpointAddress( "http://localhost:8000/" )); using ( new OperationContextScope((IContextChannel)proxy)) { Message request = Message.CreateMessage(MessageVersion.None, string .Empty, "data" ); request.Headers.To = new Uri( "http://localhost:8000/resource" ); WebOperationContext.Current.OutgoingRequest.Method = "POST" ; proxy.Request(request); } using ( new OperationContextScope((IContextChannel)proxy)) { Message request = Message.CreateMessage(MessageVersion.None, string .Empty); request.Headers.To = new Uri( "http://localhost:8000/resource/1" ); WebOperationContext.Current.OutgoingRequest.Method = "GET" ; WebOperationContext.Current.OutgoingRequest.SuppressEntityBody = true ; proxy.Request(request); } However, when you put these pieces together, it fails to work. The client turns out to be fine but there's a problem in the way that the service is hosted. More accurately, there's a problem with the interaction between the way the service is hosted and the way it's defined. By specifying an address for hosting the application, we're claiming all of the messages that go to that address. We're also claiming all of the messages that go to suffixes of that address as long as someone else hasn't claimed them first. Unfortunately, the endpoint doesn't know what to do with these extra messages. It just ignores them. What we want is for the endpoint to just take everything and let the service implementation decide what the addresses Read More...
  • Adding Headers to a Call (HTTP Version)

    Yesterday I talked about adding SOAP headers to an outgoing request using a variety of different methods. The most straightforward method was to create an OperationContextScope in your application code to establish an OutgoingMessageHeaders collection. Although HTTP headers are similar in spirit to SOAP headers, manipulating an HTTP header through code looks a bit different. SOAP headers are elevated to a special significance in the programming model. Everything else, including HTTP headers, is relegated to a general-purpose but distinctly second-class collection of message properties. On the OperationContextScope you'll find a parallel OutgoingMessageProperties collection that can be used for HTTP headers. In Orcas, the plain OperationContext also works as a WebOperationContext that gives the same first-class programming model to HTTP headers as you get with SOAP headers. Here's a comparison of the two approaches. using ( new OperationContextScope((IClientChannel)proxy)) { HttpRequestMessageProperty requestProperty = new HttpRequestMessageProperty(); requestProperty.Headers[ "X-header" ] = "value1" ; OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestProperty; proxy.Operation(); } using ( new OperationContextScope((IClientChannel)proxy)) { WebOperationContext.Current.OutgoingRequest.Headers[ "X-header" ] = "value2" ; proxy.Operation(); } Next time: Configuring SSL Host Headers Read More...
  • Manual Context Management

    How do I manually manage the context when sharing a client object? The default mode when using a context binding is for the context to be managed internally by the context channel underneath the client proxy. This is similar to how by default cookies are managed by an HTTP channel to send and receive cookie context. With an HTTP channel you can disable automatic cookie management and control the context yourself. There is a similar process that you can use to take control for a context binding. Here's a comparison of the two processes. You can get the code for HTTP by using the link above and with the further details on custom cookie handling so I won't print it again. With HTTP, you first need to turn off automatic cookie handling by setting the AllowCookies property on the HTTP transport binding element to false. With a context binding, you first need to turn off automatic context handling by setting the Enabled property on the context manager to false. IContextManager contextManager = channel.GetProperty<IContextManager>(); contextManager.Enabled = false ; Then, for HTTP you attach an HttpRequestMessageProperty that contains the desired cookies to a message using an OperationContextScope. With a context binding, you use the same OperationContextScope approach but attach the appropriate ContextMessageProperty instead. using ( new OperationContextScope(client.InnerChannel)) { ContextMessageProperty contextProperty = new ContextMessageProperty(contextData); OperationContext.Current.OutgoingMessageProperties[ContextMessageProperty.Name] = contextProperty; client.DoOperation(); } Next time: Messaging Additions in Orcas Read More...
  • Accessing the Query String

    How do I get access to the query string of an HTTP request when processing a message? The query string isn't one of the properties available on the new WebOperationContext but you can still get access to it through the HTTP request message property. MessageProperties properties = OperationContext.Current.IncomingMessageProperties; HttpRequestMessageProperty requestProperty = (HttpRequestMessageProperty)properties[HttpRequestMessageProperty.Name]; string queryString = requestProperty.QueryString; Next time: Taking Action on Client Close Read More...
  • Creating Sessions over HTTP

    I've got a sessionful contract that I want to use with HTTP. How do I get the HTTP transport to produce a sessionful channel shape? The basic design principle of channels is that they produce whatever channel shape is their natural message exchange pattern. For HTTP, the natural message exchange pattern is request-reply. This means that if you want any other channel shape, then you need to apply a layered channel that changes the message exchange pattern. That is the approach regardless of whether you want to change the channel shape to one-way, duplex, or a sessionful channel. There are no built-in HTTP specific additions to create sessionful channels. We have a sample channel that demonstrates creating a session based on HTTP cookies . There are several general-purpose protocol channels that provide sessions, such as security and reliable messaging. However, this entire line of conversation tends to indicate a fundamental flaw in thinking. A session has the semantic meaning of correlating messages together according to some principle of relationship. Sessionful services use the relationship to treat the session of messages as a connected unit. The meaning of that session ought to be a more significant factor than whether some contract has been previously declared to know about sessions. If you are scrounging around to come up with any possible session to get a service working, then something is probably wrong. Next time: XML Support Read More...

Copyright © 2006 Microsoft Corporation. All Rights Reserved. | Terms of Use | Privacy Statement | Contact Us