|
|
Browse by Tags
All Tags » HTTP » Answers (RSS)
-
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...
|
-
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...
|
-
Does the IIS HTTP runtime configuration affect a WCF application? Yes, when the application is using IIS to host its HTTP endpoints. A WCF application that lives in IIS is an IIS application as well, even if you aren't explicitly using ASP.NET compatibility mode. Now, most of the settings for IIS don't make as much sense for WCF as for general web applications, but if you look at the httpRuntime configuration element, then you'll see some that apply. < configuration > < system.web > < httpRuntime executionTimeout ="110" maxRequestLength ="4096" requestLengthDiskThreshold ="80" useFullyQualifiedRedirectUrl ="false" minFreeThreads ="8" minLocalRequestFreeThreads ="4" appRequestQueueLimit ="5000" enableKernelOutputCache ="true" enableVersionHeader ="true" requireRootedSaveAsPath ="true" enable ="true" shutdownTimeout ="90" delayNotificationTimeout ="5" waitChangeNotification ="0" maxWaitChangeNotification ="0" requestPriority ="Normal" enableHeaderChecking ="true" sendCacheControlHeader ="true" apartmentThreading ="false" /> </ system.web > </ configuration > The setting that is most common to impact a WCF application is the runtime limit on maxRequestLength. This setting is intended to limit people making large file uploads but the usage patterns of web services seem to make it more likely for people to build applications with large request messages than in traditional HTTP applications. Note that the setting is specified in kilobytes so it is by default much larger than the maximum received message size in WCF. However, if you're dealing with messages of more than a few megabytes, you may run into this limit and be puzzled why your messages are failing even though the application quotas are sufficient. Next time: Sending to MSMQ with Integrated Authentication Read More...
|
-
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...
|
-
I need to make many simultaneous HTTP calls to the same service from my client application. How do I increase the limit on the number of HTTP connections? This setting isn't available on any of the bindings or binding elements but the default limit can be set through the DefaultConnectionLimit property on System.Net.ServicePointManager. This will change the limit for every server you want to connect to. Alternatively, you can control the connection limit very granularly through configuration. < system.net > < connectionManagement > < add address ="..." maxconnection ="2" /> </ connectionManagement > </ system.net > The address can be for a particular HTTP address or for a plain machine name. Use the wildcard character * for the address to set the default connection limit through configuration. If a request can match against more than one of the configuration entries, then the most specific entry is the one that will be used. Next time: Mapping Credentials to Authentication Schemes Read More...
|
-
How do I use % Feature X% from ASP.NET in a WCF service? ASP.NET has an HTTP-centric application model with many great features specialized for web development in IIS. WCF is transport and host agnostic. Out of the box, WCF supports most of the features of ASP.NET in a way that makes sense independent of HTTP and IIS. Some of the features excluded from that set are supported as part of the specific implementation for the HTTP transport. If you're porting an application from ASP.NET to WCF, you may find that one of the ASP.NET features not in the regularly supported subset has been made integral to the design of your application. WCF has an ASP.NET compatibility mode that gives you both the features and limitations of that environment. Using compatibility mode gets you your favorite ASP.NET %Feature X%: Session state System.Web authorization, impersonation, and globalization IHttpModule AppSettings HttpContext MapPath but the preference should be to use host and transport agnostic equivalents except when trying to get code working that already use these ASP.NET features. This article was originally just about Server.MapPath, but I changed it because advice for the other features would read exactly the same. Next time: Flow Throttles Read More...
|
-
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...
|
-
Why doesn't anything happen when I try to add HTTP headers from a message encoder? The problem here is a basic issue of timing. Recall the interface contract that a message encoder has with its transport. The transport receives a message from the next channel up in the channel stack, does some processing on the message, and calls WriteMessage on the message encoder when it wants to write out the message body. The message encoder does not necessarily see all of the message content. Some message content, such as framing, is independent of the message encoding and directly handled by the transport. In fact, the message encoder may not be called at all if there is no content for it to write. HTTP headers are an example of content that is handled by the transport rather than the message encoder. The message encoding transforms the body of the message, but HTTP headers are always sent as text. In the call to WriteMessage, the message encoder does get a Message object, which has a handle to the HTTP headers. However, if you look at the format of a raw HTTP message, then you would see that the HTTP headers are completely written out before the message body is written out. When streaming an HTTP message, the headers may even be transmitted before the message body is written out. Therefore, you should guess that it's unlikely that the message encoder can do anything with the HTTP header collection because the HTTP headers may already have been transmitted. If you want to change the HTTP headers, then you should make sure that all of the changes are made before the transport is given the message. Next time: WCF Case Studies Read More...
|
-
How do I change the HTTP status code of the response that is sent back when using a one-way contract? The result of using a one-way contract is to automatically send back an empty HTTP response when the service method is called. Sending back this response is independent of executing your service code. This means that the normal method of attaching a message property to set the HTTP status code and other HTTP headers can't be applied. There is no reply channel waiting for you to set up a message with the appropriate properties. However, there is another mechanism for sending back an empty HTTP response where you do have control over the HTTP headers. When you're using the standard request-reply contract with HTTP, you can manipulate the HTTP message that gets sent back for the reply. On that message you can put an HttpResponseMessageProperty that has SuppressEntityBody set to true. SuppressEntityBody produces equivalent messages to a one-way contract that have HTTP headers but no body contents. You should think of one-way messages and empty messages as having the same appearance but different semantics during processing. The other way around the problem is to find a lower processing layer to apply your HTTP headers. If you get below the processing layer that knows about one-way messaging, then one-way messages and empty messages are not distinguishable. It is the processing layer that recognizes the one-way protocol that creates the distinction. Next time: Binary Encodings and Addressing Read More...
|
-
Why are all of the TCP sockets for my HTTP application owned by PID 4? The "-o" option of netstat tells you the process ID associated with each of the network connections. If you look at the process owner for an HTTP client application, then you should see the PID of your client application. If you look at the process owner for an HTTP server application on Windows Vista, then you'll see PID 4. PID 4 is the process identifier of the System process. When Windows 2003 came out, it introduced the http.sys driver that handles HTTP communication as a kernel-mode service. In this case, WCF is using http.sys to do the listening, so http.sys is the process owner that shows up for the connection. This is why everything appears to be coming from the System process. Next time: A Bit More on Call Context Initializers Read More...
|
-
How do I prevent clients from accessing my service anonymously? I've changed the settings in IIS from Anonymous Access to Integrated Windows Authentication. However, now I'm getting the error message: "Security settings for this service require 'Anonymous' Authentication but it is not enabled for the IIS application that hosts this service." Disabling anonymous access requires coordinating the settings in IIS and in your service configuration. Those two sources must be in agreement about whether anonymous access is expected. IIS is already using Windows authentication in this case, so let's look at what needs to happen to the service configuration file. I'm assuming that this is IIS6 so the only network transport we're talking about here is HTTP. There are two cases depending on whether you want the protocol that gets exposed to be HTTP or HTTPS. The simplest is to keep using HTTP since that's probably what you were using if anonymous access was allowed in the past. To switch off anonymous access with HTTP, you need to set the security mode to TransportCredentialOnly. < basicHttpBinding > < binding > < security mode ="TransportCredentialOnly" > < transport clientCredentialType ="Windows" /> </ security > </ binding > </ basicHttpBinding > Note that TransportCredentialOnly is not supported for every binding (in this case we're using BasicHttp). For WSHttp, the only choice is going to be to use HTTPS. To switch off anonymous access with HTTPS, you need to set the security mode to Transport. < wsHttpBinding > < binding > < security mode ="Transport" > < transport clientCredentialType ="Windows" /> </ security > </ binding > </ wsHttpBinding > Other bindings can be made to work in this situation as well, including custom bindings. I'm just showing you the most common examples. The key in both cases though is that we're getting transport security with the right kind of credentials associated. Next time: Writing Binding Element Essentials Read More...
|
-
Let's pick up where we left off last time with the question… How do I modify the HTTP status code that gets sent back with a fault? It's clear that we need to plug into the fault generation process somehow, but in past articles we've only seen fault handling for channels rather than services. Is there an equivalent for FaultConverter that we can use with our service? Well, partially. There's an IErrorHandler interface that very slightly overlaps the functionality of FaultConverter, but fortunately that's exactly the part we need. IErrorHandler allows us to replace the message faults that get created by the service. We can modify the status code by attaching a message property to the fault for the HTTP response. Here's what that looks like. I'll change the normal internal server error status code to one that indicates that the service requires payment to make the method call. class HttpErrorHandler : IErrorHandler { public bool HandleError(Exception error) { return false ; } public void ProvideFault(Exception error, MessageVersion version, ref Message fault) { if (fault != null ) { HttpResponseMessageProperty properties = new HttpResponseMessageProperty(); properties.StatusCode = HttpStatusCode.PaymentRequired; fault.Properties.Add(HttpResponseMessageProperty.Name, properties); } } } Now, we need some way to attach this error handler to the service. Since this example is using IIS hosting, there are fewer points to hook in as we don't own the service host. I'll create a new server behavior attribute that attaches an IErrorHandler instance to the service. As IErrorHandler interfaces with the service dispatcher, I need to fish out the dispatchers from the service host. class ErrorBehaviorAttribute : Attribute, IServiceBehavior { Type errorHandlerType; public ErrorBehaviorAttribute(Type errorHandlerType) { this .errorHandlerType = errorHandlerType; } public void Validate(ServiceDescription description, ServiceHostBase serviceHostBase) { } public void AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters) { } public void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase) { IErrorHandler errorHandler; errorHandler = (IErrorHandler)Activator.CreateInstance(errorHandlerType); foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers) { ChannelDispatcher channelDispatcher = channelDispatcherBase Read More...
|
-
Back to errors and faults for a bit with this two part series on modifying the HTTP status code used for fault messages. First, we'll need some background. What happens at the HTTP level when a web service encounters a problem? That's a good question because it's not clear at all from programming the service what's going to happen under the covers. Let's build a service and find out. Here's the simplest web service I could think of that has a slight problem. I'll be hosting this in IIS so there's no other code needed to get going. You can imagine the configuration that goes along with this service, but I'm going to omit any discussion of that because it won't be relevant to anything we have to look at. [ServiceContract] public interface IService { [OperationContract(Action = "*" , ReplyAction = "*" )] Message Action(Message m); } public class Service : IService { public Message Action(Message m) { throw new FaultException( "!" ); } } We can cut all the crud out of the messages by using a POX binding: a text encoder with MessageVersion set to None and a normal HTTP transport. Now, we can run this service and see what happens. I'm just going to telnet to the service address so that we can easily see all of the HTTP headers. HTTP/1.1 500 Internal Server Error Content-Type: application/xml; charset=utf-8 Server: Microsoft-IIS/7.0 X-Powered-By: ASP.NET Date: Tue, 10 Jan 2007 06:25:16 GMT Connection: close Content-Length: 159 < Fault xmlns ="http://schemas.microsoft.com/ws/2005/05/envelope/none" >< Code >< Value > Sender </ Value ></ Code >< Reason >< Text xml:lang ="en-US" > ! </ Text ></ Reason ></ Fault > This shows us that our service fault exception results in an HTTP status code of 500 for the response. The body of the message is something that looks a lot like a SOAP fault, but smaller because we said we weren't going to use SOAP. Inside the fault message you can see the fault elements that we talked about in past articles, and it's clear that we can modify anything inside the fault. It's not clear though what we modify to alter the framing of the HTTP response. That brings us to the actual question for this pair of articles. How do I modify the HTTP status code that gets sent back with a fault? We'll answer that question next time, which is going to require writing a bit more code. Next time: Modifying HTTP Error Codes, Part 2 Read More...
|
-
I occasionally see people asking how they can fake the security capabilities of a binding. These questions often start off with "I'm getting an error message that a message's required protection level is not being met". Now, I'm not precisely sure why you'd want to fake the security capabilities in this case. After all, the application developer is in charge of both specifying the protection requirements of the messages and choosing what channels to use. If they're getting this error message, then it more than likely means that this helpful check has detected a problem somewhere in their design. There are a few rare reasons why you'd want to fake this, but they mainly involve transmitting over specially secured networks. However, it turns out that faking security capabilities is exactly the same as legitimately specifying the capabilities of a custom channel so I might as well explain that! Security capabilities are found by querying the channel stack with GetProperty for an instance of ISecurityCapabilities. This call should be supported on the binding element of channels that implement message or transport security. Transport channels should respond with something, even if it is to say that they don't support any kind of security. Everyone else can just delegate the call to their inner channel (which is typically what you do by default for any type you don't know about). public interface ISecurityCapabilities { ProtectionLevel SupportedRequestProtectionLevel { get; } ProtectionLevel SupportedResponseProtectionLevel { get; } bool SupportsClientAuthentication { get; } bool SupportsClientWindowsIdentity { get; } bool SupportsServerAuthentication { get; } } The fields here should be self-explanatory, you either support a particular feature or you don't, but let's look at examples from some of the existing channels. HTTP doesn't support any protection on requests and responses, neither encryption nor signing. HTTP supports client authentication when in any security mode but Anonymous. It only supports server authentication when using Negotiate security. Windows identities are supported whenever client authentication is. On the other hand, HTTPS provides both encryption and signing for both requests and responses. HTTPS always does server authentication. It supports client authentication and Windows identities whenever HTTP would plus whenever client certificates are turned on. You can quickly get a sense of the differences between HTTP and HTTPS by looking at Read More...
|
-
I have a machine with multiple network cards. How do I control which networks my service listens on? The answer to this question is going to be specific to the transport that you're using. I'll cover the HTTP and TCP transports that WCF ships with. Talking about addresses for the named pipe transport is less interesting because we don't allow remote connections with our named pipes! With custom transports, you're on your own and will have to contact the author. The TCP transport is very liberal with wildcarding addresses. When given a choice of multiple addresses for a machine, it will listen on all of them. To change this, you need to prevent the transport from having this choice. Here are the two things that you will need to do. First, make sure that the HostNameComparisonMode property for the transport is set to Exact. HostNameComparisonMode controls the address wildcard and the Exact option means that the hostname and port have to match exactly. Second, change the listening address of the service from a hostname to an explicit IP address. This guarantees that you'll get the specific network address that you want. Now, you've removed all choice from matching the address of the service, and you have a service that only listens on a single one of your multiple addresses. The HTTP transport is a little bit more flexible with wildcarding because it can leverage a feature built into the platform for HTTP. The HTTP.SYS driver allows you to define an IP Listen List that contains a particular set of IP addresses to listen on for HTTP connections. If you don't have a listen list configured, then by default the HTTP transport will be listening on all of the available network addresses, exactly like the TCP transport. The same technique for listening on just a single address with HostNameComparisonMode works for HTTP as it did for TCP. Finally, I thought it important to mention that just about every computer these days has multiple IP addresses- even if you don't have multiple network cards. You have a loopback IP address (127.0.0.1 for IPv4) that always corresponds to local connections and a real IP address from your network adapter. This means that you have everything you need to craft a "local machine"-only service even when not using named pipes. The guarantee when doing this is a little bit weaker than the one we make for named pipes though. We block remote users that are going through a local intermediary from named pipes by filtering on the origin of the account Read More...
|
|
|
|