Welcome to Windows Communication Foundation (WCF)
Top Tasks :

WCF Team Bloggers

Browse by Tags

All Tags » Hosting » Answers   (RSS)

  • Acting on Open

    How do I run a custom event once when the service is first started? The easiest way to execute some custom code when a service is started is to hook the service's Open method. Although the Open method has two different moments in time that you might be interested in, I'll just say Open to refer to them both. Opening is the moment in time just before the service is started; Opened is the moment in time just after. There a few different ways of hooking Open depending on what objects you have available. If you have access to a ServiceHost instance before Open is called, then you can hook Open by attaching an event handler to either the Opening or Opened events. This is the least invasive approach. If you're the one that's actually responsible for creating the ServiceHost instance, then you can also build your custom event directly into the host. You do this by overriding either the OnOpened or OnOpening methods. In either case, be sure to call the base method at some point. This is a more invasive approach because you have to make a subclass but you have finer control over the timing of the custom event relative to other code. If you don't control the ServiceHost, then you're probably running inside a hosted environment that uses ServiceHostFactory. Similar to subclassing ServiceHost, you can subclass ServiceHostFactory to install your custom event. Typically you would create an instance of a ServiceHost subclass from the ServiceHostFactory rather than putting the custom event logic in the ServiceHostFactory itself. Here's an example program showing the ServiceHost subclass approach. using System; using System.ServiceModel; using System.ServiceModel.Channels; public class MyServiceHost : ServiceHost { public MyServiceHost(Type serviceType, params Uri[] baseAddresses) : base (serviceType, baseAddresses) { } protected override void OnOpened() { base .OnOpened(); Console.WriteLine( "On opened" ); } protected override void OnOpening() { base .OnOpening(); Console.WriteLine( "On opening" ); } } [ServiceContract] public interface IMyService { [OperationContract] string Echo( string s); } public class MyService : IMyService { public string Echo( string s) { return s; } } class Program { static void Main( string [] args) { string address = "http://localhost:8000/" ; Binding binding = new BasicHttpBinding(); ServiceHost host = new MyServiceHost( typeof (MyService), new Uri(address)); host.AddServiceEndpoint( typeof (IMyService), binding, "" ); host.Open(); ChannelFactory<IMyService> Read More...
  • You Are Here

    Inside of a service method, how do I know where the message was delivered? Without defining what distinguishes a location it's hard to explain where 'here' is. I've got a few guesses though based on the most common variations of this question: OperationContext.Current.IncomingMessageHeaders.To OperationContext.Current.IncomingMessageProperties.Via HostingEnvironment.ApplicationVirtualPath Assembly.GetExecutingAssembly().Location HostingEnvironment.ApplicationPhysicalPath Next time: Serialization Temporary Assemblies Read More...
  • Hosting Identity

    How can I run a service operation hosted in IIS using a specific identity? There are two ways for your operation to be running using a specific identity: start off running under that identity; or, start off running under a different identity and change to the right identity later. You can make either approach work although having to change the identity every time a service operation is called will introduce a small performance hit. Let's look at the two options. Impersonation is a mechanism that you can use to change to the right identity when the service operation is invoked. I've talked about impersonation in the past, mostly for impersonating the caller rather than impersonating a specific identity. However, impersonating a specific identity works in much the same way in terms of the Windows calls involved and generally works simpler in terms of the service setup required. That simplicity partially comes from not having the client involved in the act of impersonation but also because impersonating a specific identity doesn't have the same level of configurable options for automatically applying impersonation rules. The application pool is a mechanism that you can use to start with the right identity. This approach assumes that your service always wants to be running under the same specific identity. That partially covers the case of those missing configuration options. By default your application pool runs under the Network Service account. You can change that application pool identity to be any specific identity you want. Configuring Application Pool Identity with IIS 6.0 (IIS 6.0) IIS 7.0: Specify an Identity for an Application Pool This may require reorganizing how applications map into pools because the identity is shared by everyone in that pool. Next time: Why Dual is Reliable Read More...
  • Runtime Limits in IIS

    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...
  • Detecting ASP.NET Compatibility

    How can I find out whether my service is running in ASP.NET compatibility mode? Why do you need to detect at runtime whether you're running in compatibility mode? As I've said before, compatibility mode is something that the odd and rare service takes advantage of to get one of the few features that are not available in the standard pipeline. If you care about compatibility mode, then it's very likely that your service will simply not work without it. That's one of the reasons for decorating your service with the AspNetCompatibilityRequirements attribute. It frequently makes sense to prohibit compatibility mode and it sometimes makes sense to require compatibility mode, but it almost never makes sense to optionally allow compatibility mode. This decision should be very intentional. If you do need to check for compatibility mode at runtime though, then you can use the AspNetCompatibilityEnabled property of ServiceHostingEnvironment. Next time: Custom Transport Retry Logic Read More...
  • Server.MapPath

    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...
  • Multiple Web Site Bindings

    I've configured my web site in IIS with multiple bindings but my web service can no longer run because it refuses to start if there are multiple base addresses defined for the same URI scheme. How can I use the same configuration for both my web service and the rest of my web site? Let's assume that you really do have a need to configure your web site with multiple bindings using the same URI scheme. Defining these multiple bindings is not an unreasonable thing to do. There are several legitimate reasons to publish your web site multiple times with the same scheme so let's look at how to fix the web service. Obviously, if you don't actually need the multiple bindings, then removing the extra bindings is the simplest way to fix the problem. However, we're assuming that other parts of the web site require multiple bindings. Therefore, what we really need to do is find some way to remove the extra bindings just for the web service. A direct way to remove the extra bindings without affecting the rest of the web site is to move the web service into its own web site with its own configuration. Then, we can leave the rest of the web site exactly as it is while giving the web service just the list of bindings it needs. However, that doesn't work if we need to use the same configuration for the web service as the rest of the web site. That means we need some indirect way to remove those extra bindings. Let's assume now that we have no choice but to expose our web service to all the bindings. The part that actually blows up is the construction of the ServiceHost because the host is expecting a single base address per URI scheme. If we could intercept the list of bindings in between the time that IIS gives them to the web service and the ServiceHost is constructed, then we could save the day. There's only one piece of your code that runs during that time: execution of the ServiceHostFactory . That makes the decision easy. You'll create a custom ServiceHostFactory that filters the list of base addresses and everyone will be happy. Next time: When to Use Remoting Read More...
  • Configuring TCP Activation from the Command Line

    Can I configure non-HTTP web service activation from the command line? Yes, and you don't need any special tools if you're already familiar with configuring IIS from the command line. I've already talked about how to configure a new web site or application for activation in a previous post. Modifying the configuration uses the same appcmd program that is installed as part of the IIS scripting tools. It's installed on my system as %windir%\system32\inetsrv\appcmd.exe. All modifications to the web site are going to start with appcmd set site sitename and all modifications to the application are going to start with appcmd set app appname . The sitename and appname are the long path name for the web site or application, such as "Default Web Site" or "Default Web Site/myapp". The list of protocols for activation is associated with the application. Enabling an application to be activated using TCP would look like appcmd set app "Default Web Site/myapp" /enabledProtocols:net.tcp . The protocol configuration is associated with the web site. Each protocol configuration is called a binding (not related to a WCF binding) and corresponds to a protocol scheme, IP address list, port, and host header. Not all protocol schemes are going to support all of those other things. Adding a new configuration for TCP would look like appcmd set site "Default Web Site" -+bindings.[protocol='net.tcp',bindingInformation='808:*'] . That same binding would be deleted by changing the plus to a minus, appcmd set site "Default Web Site" --bindings.[protocol='net.tcp',bindingInformation='808:*'] . Changing the IIS configuration requires administrator approval. If you don't have permission to access the configuration file, you'll get an error that looks like this: ERROR ( message:Configuration error Filename: \\?\C:\Windows\system32\inetsrv\config\applicationHost.config Line Number: 0 Description: Cannot read configuration file . ) Next time: Address Filters that Swallow GET Read More...
  • Starting a Hosted Service

    How do I run some code during service start time if I'm using an IIS hosted service? In a normal executable or NT service, your code is responsible for creating the ServiceHost that contains the web services. In IIS, it is the platform activation code that serves this role, leaving no code necessary for you to deal with the host. Not having any code is convenient most of the time but suddenly becomes inconvenient when you need to run some bit of code before your service can successfully start. There are a few options that you have to solve this problem. You could put the code inside one of the paths that gets executed while your service is being created, such as a constructor or behavior. This approach has some timing issues because you may need to order the occurrence of events during service creation in a particular way. You could alternatively put the code inside one of the paths that gets executed by the host, such as a globally or site scoped ASP.NET file. This is also a very clumsy solution because it requires learning about another technology and you have to deal with the application event model of the host. A better solution to this problem is to create a custom ServiceHostFactory. The factory, which is a configurable option through the SVC file, is the extensibility point responsible for stamping out instances of ServiceHost. Your factory can then create a custom ServiceHost that has overridden whatever methods you need to hook the startup process. The same code can even be used when you're not hosted in IIS, making this a portable solution as well if you need to change your hosting environment. We have a sample showing how to use ServiceHostFactory in exactly this way. Next time: Just a Bit of Caching Read More...
  • Preventing Anonymous Access

    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...
  • Mapping to a VDir

    When I run my non-HTTP service in IIS, I get an error message that the protocol is not supported. How do I add non-HTTP support to my VDir? This is a two step process because the web site controls the list of available protocols while the application controls which of those protocols are enabled. You can change these settings either from the IIS control panel or from the command line. I'll demonstrate setting this up with the command line. This assumes that you've installed the IIS scripting tools and have started an elevated command prompt. The first step is to create a web site that has the protocol in its list. I'll be using net.msmq in this example. If you've already got a web site, then you'll be using set instead of add and change the command accordingly. appcmd add site /name:"My Site" /physicalPath:"c:\mysite" /bindings:http/*:80:,net.msmq/* The second step is to create an application that has the protocol enabled. Again, if you've already got an application, then you'll be using set instead of add. appcmd add app /site.name:"My Site" /path:/myapp /physicalPath:"c:\mysite\myapp" /enabledProtocols:http,net.msmq Next time: Channel Bindings Read More...
  • Keeping Traces Up to Date

    I've enabled tracing in my application, but I don't see entries in the trace log show up until I restart IIS. How can I get trace entries to appear right away? Like many other output files, traces are buffered to reduce the number of times that the disk has to be accessed to write out the data. It's possible that the trace log will be incomplete until something triggers writing out those traces that been buffered. This behavior impacts people differently depending on how they're debugging their applications. For instance, if you've got a self-hosted application that you're starting up, running a few tests, and shutting down, then this doesn't really impact you at all. Closing the application will write out the remaining traces. On the other hand, applications hosted in IIS tend to be impacted more. When hosting with IIS, you have less control about the lifetime of your application, including when it gets started and stopped. Even though you're done testing, IIS may be keeping your application alive and running, which prevents triggering the write out of remaining traces. You can work around this by restarting IIS and forcing everything to get shut down. However, if there are other applications running on the machine, then this can be painful. Another thing you can do is turn off the buffering of traces and take the slight performance hit of accessing the disk more frequently. Trace buffering (or really the lack of buffering) can be controlled through diagnostics configuration. This is another entry in the standard configuration file for your application, this time using the system.diagnostics namespace. < configuration > < system.diagnostics > < trace autoflush ="true" /> </ system.diagnostics > </ configuration > Next time: Modifying HTTP Error Codes Read More...
  • Securing Custom Headers, Version 2

    Last time we were looking at the problem of securing a dynamically generated message header . We saw one solution to that problem, which was to add a behavior that updated the protection level for the desired message part. That solution is quite simple but it isn't perfect. The execution of this behavior comes rather late. Anyone that inspects the service description in the meantime, such as for metadata generation, won't see the protection level that we want to use. How early can we make the update to the security settings? Well, potentially very early. We could subclass ServiceHost and override ApplyConfiguration to make the changes during creation of the host . That may even be too early as it prevents us from working with anything that is added to the service description through code rather than configuration. However, we could similarly make the changes some time after we get the service host object back but before it was opened. This would let us plug in before any behaviors started execution. The choice is yours. The downside of this method is that it is a more treacherous route to get to the message header. Starting from the service host we need to get the endpoint that we're going to modify (usually by contract or address). From the endpoint we can get the operation by action name. From the operation we can get the right message by name. The default names are canonically derived from the operation action and direction. Unlike before, separating incoming and outgoing messages here is a lot murkier. From the message though, we can refer to the message header in the same way and set its protection level. Here's all of that in code using some example values. ServiceEndpoint endpoint = host.Description.Endpoints.Find( typeof (IService)); OperationDescription operation = endpoint.Contract.Operations.Find( "Action" ); MessageDescription message = operation.Messages.Find( "http://tempuri.org/IService/ActionResponse" ); MessageHeaderDescription header = message.Headers[ new XmlQualifiedName( "aheader" , "http://tempuri.org/" )]; header.ProtectionLevel = ProtectionLevel.Sign; Next time: Keeping Traces Up to Date Read More...
  • Restarting a Failed Service

    I have an application hosted inside a Windows service that needs to be continuously running. Occasionally the application service host will fail and I have to restart the service. How can I automatically restart a failed service host? You may not find the advice I have to give here particularly helpful, but there are two important points that I'd like to get across. The first piece of advice is that there's no direct way to simply "restart" a service host. As pointed out in the communication lifecycle , once an object becomes faulted, it is dead and there's no way to bring it back to life. Instead, the only way to recover from a faulted service host is to abort the old one and throw it away. Then, you'll be able to create a new service host as a replacement to take over. You can hook the Faulted event on the service host to find out when you need to do this. The second piece of advice is that managing applications for continuous operation is very challenging. It is possible to build a host that will cleanly restart an application whenever necessary but you will spend a lot of time working on the host and not much time working on your application. IIS to a large extent is just a tool for starting, stopping, and restarting applications on demand. If that's the feature set you need, then why expend a lot of effort creating a new hosting environment that isn't going to be as good? There may be some bad reasons for choosing IIS as your hosting environment, but needing hosted application management is not one of them. Next time: Faking Channel Security Read More...
  • Replacing an Existing ASMX Service with WCF

    I have an existing ASMX service that I'm replacing with a WCF service. The replacement service works, but some of the clients point to a page with a service.asmx address. IIS gives me an error if I name my WCF service service.asmx. How do I get this to work? Sometimes big tasks get stuck on the tiniest of things. In this case, the task of porting a web service is getting stuck on what to call the resulting service file. Note that in most cases porting a service is not actually that hard either, although you will have to spend some quality time with the service contract fixing up namespaces and operation names to match what the old system automatically generated. That was a digression from the task at hand. Let's look at what's going wrong here and how to fix it. Service files are a text-based way to define the behavior that occurs when a resource with a particular address is requested. What actually goes on is that the resource file gets compiled to generate some code, and it's the file extension that decides what compiler gets used. A compiler is just an instance of System.Web.Compilation.BuildProvider that can spit out code on demand. You don't have to worry about any of this because we've already written a BuildProvider for WCF services. The class that does this is System.ServiceModel.Activation.ServiceBuildProvider although it may be hard to find any information about this class because it's not public. However, you also don't need to worry about that because for our purposes all you need to know is the type name. Now, the web.config file of your service controls the mapping of file extensions to a BuildProvider. Here's an example of changing the default mapping of *.asmx to invoke a WCF service. < system.web > < compilation > < buildProviders > < remove extension =".asmx" /> < add extension =".asmx" type ="System.ServiceModel.Activation.ServiceBuildProvider, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> </ buildProviders > </ compilation > </ system.web > In case you're curious, here are the type names of a few of the other build providers that you normally have installed. There are more than a dozen of these on the typical system. .aspx - System.Web.Compilation.PageBuildProvider .asmx - System.Web.Compilation.WebServiceBuildProvider .ashx - System.Web.Compilation.WebHandlerBuildProvider .resx - System.Web.Compilation.ResXBuildProvider Next time: Customizing a Read More...
More Posts Next page »

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