Nicholas Allen's Indigo Blog

Windows Communication Foundation From the Inside

April, 2007

  • Nicholas Allen's Indigo Blog

    Orcas Beta 1 Released

    • 2 Comments

    The first full public beta of the .NET Framework 3.5 came out Friday night. Here are the downloads to get:

    Here are the known issues with the release that apply to WCF:

    • wcfSvchost.exe requires Administrator permissions

      The wcfSvcchost.exe tool requires administrator permissions to run. The Windows Communication Foundation service library template in Orcas will not run correctly if wcfSvchost.exe is not available.

      To resolve this issue:

      Run Orcas under an Administrator account when you author services by using wcfSvchost.exe.

    • Windows Communication Foundation (WCF) Service Configuration Editor does not exist on the Orcas Tools menu

      The svcConfigEditor.exe is not available on the Tools menu of Orcas. The tool cannot be started from the IDE.

      To resolve this issue:

      Install the Windows SDK, which includes the editor. The svcConfigEditor.exe is located on the Windows Start menu.

    • Consuming an ASMX or Windows Communication Foundation (WCF) service for a file-based Web site or application requires NTLM credentials when the user is a not an administrator and is using Remote Desktop

      When you use a Web site or application over a Remote Desktop as non-Admin, NTLM authentication is automatically enabled. Therefore, when an ASMX or WCF service is consumed, the following error occurs:

      "The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'NTLM'."

      To resolve this issue:

      1. Open the property pages for the Web sites
      2. In the Start Options tab, uncheck NTLM Authentication

      Note: This is only advised for Web sites that exclusively have WCF services. WCF services security is managed through the configuration in the web.config file, which makes NTLM Authentication unnecessary.

    • Visual Basic LINQ in Windows Communication Foundation (WCF) Projects and through MSBuild: Option Infer is not propagated

      LINQ relies on a new feature called Local Variable Type Inference to implicitly infer strongly-typed local variables based on the value of the right-hand side of an assignment. This feature is controlled by a compiler setting, Option Infer, which by default is on for most new projects. In WCF projects and in MSBuild compilations, the setting for Option Infer is not propagated.

      To resolve this issue:

      Put "Option Infer On" at the top of all source files that use LINQ.

    • Windows Communication Foundation (WCF) debugging is not enabled by default

      By default, the debugging of WCF Services is not enabled in Orcas because that would break some important non-debugging scenarios, including partial trust HTTP hosting of services and Workflow-first authored services.

      As a result, the following debugging scenarios are not enabled out of the box:

      • Stepping from a WCF client into a WCF server
      • Stepping back to the WCF client after a server call completes
      • Getting a logical callstack showing the WCF client and WCF service stack
      • Auto-attaching to WCF services invoked by the WCF client.

      To resolve this issue:

      Orcas provides a tool to enable and disable the debugging of WCF client-service applications.

      To enable WCF debugging:

      1. Open a command prompt and navigate to the location where the Orcas executable is located, typically %ProgramFiles%\Microsoft Visual Studio 9.0\Common7\IDE.
      2. Run vsdiag_regwcf.exe –i
      3. The command will output "Command completed successfully." if WCF debugging was successfully enabled.

      To disable WCF debugging:

      1. Open a command prompt and navigate to the location where the Orcas executable is located, typically %ProgramFiles%\Microsoft Visual Studio 9.0\Common7\IDE.
      2. Run vsdiag_regwcf.exe –u
      3. The command will output "Command completed successfully." if WCF debugging was successfully disabled.

      To determine whether WCF debugging is enabled:

      1. Open a command prompt and navigate to the location where the Orcas executable is located, typically %ProgramFiles%\Microsoft Visual Studio 9.0\Common7\IDE.
      2. Run vsdiag_regwcf.exe –s
        This is a sample of the command's output:

        Microsoft (R) Visual Studio (R) Diagnostics WCF Registration tool - Version 9.0.20104.0
        (C) Microsoft Corporation. All rights reserved.

        Current status .NET Framework configuration file

        Registered D:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\machine.config

        Command completed successfully.
    • Some WCF samples that ship with the .NET Framework 3.5 SDK (Orcas Beta 1) are broken and will not run

      The following WCF samples will not work on Orcas:

      • TechnologySamples\Basic\Binding\Net\Msmq\Batching
      • TechnologySamples\Basic\Binding\WS\DualHttp
      • TechnologySamples\Basic\Contract\Service\Duplex
      • TechnologySamples\Basic\Service\Hosting\WASHost\NamedPipeActivation
      • TechnologySamples\Scenario\RestPox (issues on Windows Vista)
      • TechnologySamples\Scenario\DataBinding\WPF
      • TechnologySamples\Scenario\RichClient
      • TechnologySamples\Extensibility\ErrorHandling
      • TechnologySamples\Extensibility\Metadata\Custom WSDL publication
      • TechnologySamples\Extensibility\Channels\CustomChannelDispatcher

      To resolve this issue:

      To run these samples, use .NET Framework 3.0.

    • The WebScriptServiceHostFactory class does not work with HTTP GET operations

      The WebScriptServiceHostFactory class is designed to enable Windows Communication Foundation services to be used to serve data to AJAX-enabled Web pages without having to write WCF configuration settings. In this Orcas release, the WebScriptServiceHostFactory class does not work with WCF operations that have been configured so that the HttpTransferContractAttribute attribute uses the HTTP GET verb. You may get an error about an AddressFilter mismatch if you attempt to use it with such operations.

      To resolve this issue:

      Avoid using HTTP GET operations and use HTTP POST instead. If this is impossible, then instead of using the WebScriptServiceHostFactory, create a WCF configuration section in web.config or another configuration file as appropriate and then use it to enable an AJAX endpoint. (Also see note 2.4.15 about endpoint URLs that end directly with ".svc".)

    • Windows Communication Foundation (WCF) AJAX endpoints at URLs immediately ending with ".svc" do not work with HTTP GET operations

      In this release, it is possible to use the Windows Communication Foundation to write IIS-hosted services that can be consumed from AJAX-enabled Web pages. These services can be hosted at endpoints with URLs that end directly with ".svc" (for example, "http://example.com/myService.svc") or at endpoints with URLs that end with an additional suffix (for example, "http://example.com/myService.svc/myEndpoint"). In this release, the URLs without a suffix do not work with WCF operations that have been configured with the HttpTransferContractAttribute attribute to use the HTTP GET verb, unless a workaround is applied. You may get an error about an AddressFilter mismatch if you try to use such URLs with GET operations.

      To resolve this issue:

      There are three ways to resolve this issue.

      • Use URLs with suffixes, and remember to include the suffix if you are using such a URL in the ASP.NET AJAX Script Manager control.
      • Avoid using HTTP GET operations and use HTTP POST instead.
      • Disable the service help page to resolve the issue. This can be accomplished by adding the following service behavior to the <behaviors> section of WCF config:
        <serviceBehaviors>
            <behavior name="noHelpPage">
                <serviceDebug httpHelpPageEnabled="false"/>
            </behavior>
        </serviceBehaviors>
        Add it to your service (i.e. <service behaviorConfiguration="noHelpPage" …>) in the <services> section).
    • Adding a Windows Communication Foundation (WCF) service to the ASP.NET AJAX Script Manager Control does not work in Script Inlining mode

      In this release, it is possible to use the Windows Communication Foundation to write services that can be consumed from AJAX-enabled pages. To work with the ASP.NET AJAX framework, references to such WCF services must be added to the Script Manager control. The Script Manager control enables you to inline service references by setting the InlineScript property to "true" on a particular service reference in the Services collection. In this release, WCF services are incompatible with the InlineScript="true" mode. You may get an InvalidCastException if you attempt to use this mode.

      To resolve this issue:

      Set the InlineScript property for all WCF services in the Script Manager control to "false".

    • Modifications required to support 64bit applications that use WF or WCF

      To support native 64bit applications that use WF or WCF, manual modifications to the configuration are required.

      To resolve this issue:

      For selfhosted applications, the following modification to machine.config is required:

      1. Navigate to: %windir%\Microsoft.NET\Framework64\v2.0.50727\CONFIG\machine.config in any text editor, such as Notepad.exe
      2. Add the following content at the end of the file just before </configuration>
        <system.serviceModel> 
            <extensions> 
                <behaviorExtensions> 
                    <add name="persistenceProvider" type="System.ServiceModel.Configuration.PersistenceProviderElement, System.WorkflowServices, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> 
                    <add name="workflowRuntime" type="System.ServiceModel.Configuration.WorkflowRuntimeElement, System.WorkflowServices, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> 
                    <add name="enableWebScript" type="System.ServiceModel.Configuration.WebScriptEnablingElement, System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> 
                    <add name="syndication" type="System.ServiceModel.Configuration.SyndicationElement, System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> 
                </behaviorExtensions> 
                <bindingElementExtensions> 
                    <add name="jsonMessageEncoding" type="System.ServiceModel.Configuration.JsonMessageEncodingElement, System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> 
                    <add name="context" type="System.ServiceModel.Configuration.ContextBindingElementExtensionElement, System.WorkflowServices, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> 
                </bindingElementExtensions> 
                <bindingExtensions> 
                    <add name="wsHttpContextBinding" type="System.ServiceModel.Configuration.WSHttpContextBindingCollectionElement, System.WorkflowServices, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> 
                    <add name="netTcpContextBinding" type="System.ServiceModel.Configuration.NetTcpContextBindingCollectionElement, System.WorkflowServices, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> 
                    <add name="webHttpBinding" type="System.ServiceModel.Configuration.WebHttpBindingCollectionElement, System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> 
                </bindingExtensions> 
            </extensions> 
            <client> 
                <metadata> 
                    <policyImporters> 
                        <extension type="System.ServiceModel.Channels.ContextBindingElementImporter, system.workflowservices, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"/> 
                    </policyImporters> 
                    <wsdlImporters> 
                        <extension type="System.ServiceModel.Channels.ContextBindingElementImporter, system.workflowservices, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"/> 
                    </wsdlImporters> 
                </metadata> 
            </client>
        </system.serviceModel>

      For applications hosted within IIS, there are two possible workarounds:

      A. Configure IIS to run in WOW mode:
      cscript %SYSTEMDRIVE%\inetpub\adminscripts\adsutil.vbs SET W3SVC/AppPools/Enable32bitAppOnWin64 1

      Windows XP, Windows 2003

      1. Open a command prompt and navigate to the %systemdrive%\Inetpub\AdminScripts directory.
      2. Type the following command: cscript.exe adsutil.vbs set W3SVC/AppPools/Enable32BitAppOnWin64 "true"
      3. Press ENTER
      4. Enable 32-bit aspnet by using %windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis.exe –i –enable
      5. Reset iis by using iisreset

      Windows Vista

      1. Open a command prompt and navigate to the %systemdrive%\Inetpub\AdminScripts directory.
      2. Type the following command: cscript.exe adsutil.vbs set W3SVC/AppPools/Enable32BitAppOnWin64 true
        Note: If this script is not already available, turn on Internet Information Services, Web Management Tools, IIS 6 Management Compatibility, IIS 6 Scripting Tools. This will place the scripts in the above mentioned location.
      3. Press ENTER

      B. Update %windir%\Microsoft.NET\Framework64\v2.0.50727\CONFIG\web.config by adding the following:

      1. Add the following to the end of the Xml element "system.web/compilation/assemblies":
        <add assembly="System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
        <add assembly="System.WorkflowServices, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      2. Add the following to the end of the xml element "system.web/compilation/buildProviders":
        <add extension=".xoml" type="System.ServiceModel.Activation.WorkflowServiceBuildProvider, System.WorkflowServices, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      3. Add the following to the beginning to the xml element "system.web/httpHandlers":
        <add path="*.rules" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
        <add path="*.xoml" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="false"/>
    • Windows Communication Foundation (WCF) Samples setup script Setupvroot.bat will not work on Windows Vista if the NetMsmqActivator service is enabled and Message Queuing (MSMQ) is not installed

      The iisreset utility does not work unless MSMQ is installed or the NetMsmqActivator service is disabled. The WCF Samples setup script Setupvroot.bat will not run unless MSMQ is installed or the NetMsmqActivator service is disabled.

      To resolve this issue:

      Make sure that MSMQ is installed or disable the NetMsmqActivator service on Windows Vista before you run the WCF Samples setup script Setupvroot.bat.

    • Only the online version of the Windows Communication Foundation (WCF) and Workflow Foundation (WF) samples for .NET Framework 3.5 will compile and run

      The offline WCF and WF samples that are included with Orcas Beta 1 do not compile or run.

      To resolve this issue:

      Download the online versions of the Orcas Beta 1 samples for .NET Framework 3.5.

    • Service Model Metadata Utility Tool (SvcUtil.exe) Can Throw InvalidChannelBindingException when importing WSDL from certain endpoints

      Although Windows Communication Foundation (WCF) allows the setting of the ReliableSession Binding Element InactivityTimeout or AcknowledgementInterval properties to TimeSpan.MaxValue, WCF will not consume WSDL generated by an endpoint with such settings. Instead, the import will fail and SvcUtil.exe will throw an InvalidChannelBindingException.

      To resolve this issue:

      After you download the WSDL, manually change the TimeSpan.MaxValue to 2147483647 (Int32.MaxValue). Then, in the generated configuration file, change the inactivityTimeout or acknowledgementInterval attribute from "24.20:31:23.6470000" to "Infinite".

  • Nicholas Allen's Indigo Blog

    A Bit More on Call Context Initializers

    • 1 Comments

    In the last article on call context initializers, the sample program included three bindings to try out. All the program did was trace the thread ID being used for a particular call when the service method was invoked or when the call context initializer was either creating or destroying the call context. The three bindings were:

    1. TCP
    2. One-way over TCP
    3. Secure Conversation over Composite Duplex over One-way over TCP

    Now, each of these bindings was created by extending the previous binding with additional binding elements. There weren't any setting changes or alterations to earlier binding elements in the channel stack. The service was using an instance per service call. If you ran the sample program with the first or third bindings, you'd get something like this:

    Invoke: Client11
    Invoke: Client12
    Invoke: Client13
    Invoke: Client14
    Invoke: Client16
    Invoke: Client17
    Invoke: Client18
    Invoke: Client19
    Invoke: Client20
    Invoke: Client21
    BeforeInvoke: Server22
    Invoke: Client11 Server22
    AfterInvoke: Server22
    BeforeInvoke: Server22
    Invoke: Client12 Server22
    AfterInvoke: Server22
    BeforeInvoke: Server22
    Invoke: Client13 Server22
    AfterInvoke: Server22
    BeforeInvoke: Server22
    Invoke: Client14 Server22
    AfterInvoke: Server22
    BeforeInvoke: Server22
    Invoke: Client16 Server22
    AfterInvoke: Server22
    BeforeInvoke: Server22
    Invoke: Client17 Server22
    AfterInvoke: Server22
    BeforeInvoke: Server22
    Invoke: Client18 Server22
    AfterInvoke: Server22
    BeforeInvoke: Server22
    Invoke: Client19 Server22
    AfterInvoke: Server22
    BeforeInvoke: Server22
    Invoke: Client20 Server22
    AfterInvoke: Server22
    BeforeInvoke: Server22
    Invoke: Client21 Server22
    AfterInvoke: Server22

    Notice how all of the client calls are serialized and run on a single thread. If you ran the sample program with the second binding, you'd get a different looking result.

    Invoke: Client11
    Invoke: Client12
    Invoke: Client13
    Invoke: Client15
    Invoke: Client16
    Invoke: Client17
    Invoke: Client18
    Invoke: Client19
    Invoke: Client20
    Invoke: Client21
    BeforeInvoke: Server22
    Invoke: Client11 Server22
    AfterInvoke: Server22
    BeforeInvoke: Server22
    Invoke: Client12 Server22
    AfterInvoke: Server22
    BeforeInvoke: Server22
    Invoke: Client13 Server22
    AfterInvoke: Server22
    BeforeInvoke: Server22
    Invoke: Client15 Server22
    BeforeInvoke: Server23
    Invoke: Client16 Server23
    AfterInvoke: Server23
    AfterInvoke: Server22
    BeforeInvoke: Server22
    Invoke: Client17 Server22
    BeforeInvoke: Server23
    Invoke: Client18 Server23
    BeforeInvoke: Server24
    Invoke: Client19 Server24
    AfterInvoke: Server22
    BeforeInvoke: Server22
    Invoke: Client20 Server22
    AfterInvoke: Server23
    BeforeInvoke: Server23
    Invoke: Client21 Server23
    AfterInvoke: Server22
    AfterInvoke: Server24
    AfterInvoke: Server23

    It's only when you switch bindings that you actually get any concurrency. With the second binding, we finally see multiple threads and calls happening out of order. The key difference is that although there were multiple threads, all of the client calls for the sample program are being made on the same channel object. That means for the first and third binding that all of the calls are taking place on a single session channel. In the case of the first binding, the session comes from the TCP connection. In the case of the third binding, the session comes from using message security. In between these two cases, the one-way channel is discarding the TCP session because it consumes a duplex session channel and produces an input or output channel.

    Next time: TryReceive and Exceptions

  • Nicholas Allen's Indigo Blog

    Custom Channel Development

    • 0 Comments

    I'll be giving another talk on channel development for WCF this year at TechEd. Due to the selection of sessions, there's really only one good lead-in talk and it's currently scheduled for later in the week. That means that I'll be spending more time on background material than I normally would. However, if you have any questions about channel development that you'd like to see covered, submit them between now and May 18th.

  • Nicholas Allen's Indigo Blog

    Ownership of HTTP Connections

    • 3 Comments

    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

  • Nicholas Allen's Indigo Blog

    Socket Failures

    • 1 Comments

    What is the lifetime of a TCP session?

    The lifetime of the session object from a TCP transport channel lasts exactly as long as you own the underlying TCP connection. Once you give up ownership of the TCP connection, either by saying that you're done with it or by having it fault, the lifetime of the session is over. Closing the channel is a way of saying that you're done with the TCP connection. The TCP socket connection may still be usable and go back into a connection pool to be circulated to someone else. Having the TCP socket connection fail is one way to cause the TCP channel to fault.

    This definition of lifetime means that there's no way to recover a TCP session once it has been closed or faulted. If you need to have a recoverable session, then you need to need layer a new session on top of the TCP session, such as with reliable messaging. Layering a new session on top allows multiple TCP sessions to be created and destroyed without affecting the session that is visible to the user.

    Next time: Ownership of HTTP Connections

  • Nicholas Allen's Indigo Blog

    ICallContextInitializer Example

    • 2 Comments

    Here's the promised sample demonstrating how to set up a call context initializer. The basics really are quite basic so there isn't much to explain in terms of the ICallContextInitializer or the service behavior. I've created a web service with a single operation and attached the call context initializer to the dispatch path for that operation. The only thing the call context initializer does (as well as the web service) is trace the thread ids, but the pattern of any call context initializer is going to be exactly the same regardless of what you actually do in those methods.

    To make up for the simplicity though, I've thrown in a bit of a subtle point about the threading model of the dispatcher. You can try the example out yourself to see what changes happen to the invocation patterns as you move between the three bindings (plain TCP, one-way TCP, and security over one-way TCP). This may be the subject of a future article once I get the chance to write about it.

    using System;
    using System.Threading;
    using System.ServiceModel;
    using System.ServiceModel.Dispatcher;
    using System.ServiceModel.Description;
    using System.ServiceModel.Channels;

    [ServiceContract(SessionMode=SessionMode.Allowed)]
    interface IService
    {
    [OperationContract(IsOneWay=true)]
    void Ping(int id);
    }

    [ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Single, InstanceContextMode=InstanceContextMode.PerCall)]
    class Service : IService
    {
    public void Ping(int id)
    {
    Console.WriteLine("Invoke: Client{1} Server{0}", Thread.CurrentThread.ManagedThreadId, id);
    Thread.Sleep(new Random().Next(500));
    }
    }

    class CallContextInitializer : ICallContextInitializer
    {
    public void AfterInvoke(object correlationState)
    {
    Console.WriteLine("AfterInvoke: Server{0}", Thread.CurrentThread.ManagedThreadId);
    }

    public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
    {
    Console.WriteLine("BeforeInvoke: Server{0}", Thread.CurrentThread.ManagedThreadId);
    return null;
    }
    }

    class CallContextInitializerBehavior : IEndpointBehavior
    {
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
    endpointDispatcher.DispatchRuntime.Operations["Ping"].CallContextInitializers.Add(new CallContextInitializer());
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }
    }

    class Program
    {
    static void Service(object binding)
    {
    ServiceHost host = new ServiceHost(typeof(Service), new Uri("net.tcp://localhost/"));
    ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(IService), (Binding)binding, "");
    endpoint.Behaviors.Add(new CallContextInitializerBehavior());
    host.Open();
    Console.ReadLine();
    host.Close();
    }

    static void Client(object proxy)
    {
    Console.WriteLine(String.Format("Invoke: Client{0}", Thread.CurrentThread.ManagedThreadId));
    ((IService)proxy).Ping(Thread.CurrentThread.ManagedThreadId);
    }

    static void Main(string[] args)
    {
    CustomBinding binding = new CustomBinding(new TcpTransportBindingElement());

    // binding.Elements.Insert(0, new OneWayBindingElement());

    // SecurityBindingElement security = SecurityBindingElement.CreateSspiNegotiationBindingElement(false);
    // binding.Elements.Insert(0, new CompositeDuplexBindingElement());
    // binding.Elements.Insert(0, SecurityBindingElement.CreateSecureConversationBindingElement(security));

    new Thread(new ParameterizedThreadStart(Service)).Start(binding);
    ChannelFactory<IService> factory = new ChannelFactory<IService>(binding, "net.tcp://localhost/");
    factory.Open();
    IService proxy = factory.CreateChannel();
    for (int i = 0; i < 10; i++)
    {
    new Thread(new ParameterizedThreadStart(Client)).Start(proxy);
    }
    }
    }

    Next time: Socket Failures

  • Nicholas Allen's Indigo Blog

    Hokie Hope Day

    • 0 Comments

    Among other memorial events, Virginia Governor Kaine will be leading a moment of silence and prayer service starting at Noon EDT. Here in Washington, a coordinated minute of silence and tolling of bells is taking place at 9 AM PDT.

  • Nicholas Allen's Indigo Blog

    Initializing the Context

    • 2 Comments

    Today's article is about a little-known extensibility point that runs shortly before and after a service invocation takes place. The call context initializer allows you to control the state of the thread that will be used for the service call.

    public interface ICallContextInitializer
    {
    void AfterInvoke(object correlationState);
    object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message);
    }

    The context initialize runs on the service and first gets called with BeforeInvoke. BeforeInvoke sets up the context state and returns an optional correlation object. That correlation object gets passed in to AfterInvoke so you can use it however you want during cleanup.

    Here's the overall sequence of events relevant to the call context.

    1. Initialize the call context
    2. Start impersonating the calling identity
    3. Make the call
    4. Revert the impersonation
    5. Run parameter inspectors on the call output
    6. Create the response message
    7. Uninitialize the call context

    As far as I know, the single use for call context initializers so far is in COM+ integration.

    Next time: ICallContextInitializer Example

  • Nicholas Allen's Indigo Blog

    Silverlight

    • 0 Comments

    Earlier this week, Microsoft announced the Silverlight product name. Silverlight is a micro-framework for developing client web applications, in particular web media applications. A micro-framework is a platform that trades off having a comprehensive set of features so that it can have a limited size for distribution and deployment. There have been similar examples of these kinds of micro-frameworks in the past, such as for mobile devices, cell phones, and even watches. The Silverlight niche is to fit into the space of web browser plug-ins. This is an interesting space because you generally have a lot more system resources available than for something like a cell phone, but you can't make users install an enormous download first like the full framework.

    Tim Sneath has a list of trivia up about the release although you'll have to wait until MIX to see that last announcement. I won't have too much to say about Silverlight as I didn't work on it past its very early development.

  • Nicholas Allen's Indigo Blog

    Throttling Sessions

    • 1 Comments

    How do I push back against clients that are tying up the external connections of my service?

    The amount of service connection resources used by the client can be thought of as a product of two dimensions. The first dimension is the number of connections that the client has open. The second dimension is the length of time that the client holds the connections open. This is a typical time-space product for measuring utilization. Another way to slice the problem might be network link capacity for space and transfer duration for time. The product that you're going to optimize for is problem dependent, but I'll use number of connections for the example.

    Each of the dimensions has a quota value that we can use to push back against clients. We push back against space usage by throttling the number of concurrent sessions or instances. This really only makes sense if you have some way of identifying a particular client across multiple sessions because otherwise the client can just knock out other competitors to grab more resources. A typical way of identifying the client is by requiring authentication. You could also do some kind of traffic shaping at the network level although that's best done in front of your service rather than on the same machine. We push back against time usage by limiting the connection lifetime (such as through operation and receive timeouts).

    The general solution to this problem is to identify the factors that make up the product, pick quotas that protect those factors, and then tune quota values. The balance between the factors is another problem dependent piece. For example, you may have to keep the time quota above a certain value due to the latency of the network connections you're using. However, this is just constraining the range for the corresponding space quota that will let you hit your target value for the product.

    Next time: Initializing the Context

  • Nicholas Allen's Indigo Blog

    Moving Services and User Principals

    • 1 Comments

    A user principal name is used as an identifier for accounts on a Windows domain. The user principal name has two parts, the user account name and the domain name. The typical way of writing a user principal name looks a lot like a standard email address, such as account@domain.com.

    When using service authentication, the client needs some way of specifying the identity of the service account it expects to be connected to. There are several different types of identities that the client could use, but the default when using Windows credentials is sometimes a user principal name. I say sometimes because there are additional conditions that have to apply. The most stringent condition is that the service is not running under one of the standard system accounts, like NetworkService. When running under a system account, you end up getting a service principal name rather than a user principal name. Both of these principal types allow you to take advantage of Kerberos security if you're using Active Directory.

    One of the disadvantages of principal names is that you tie services to your domain structure. If the client has a particular coded principal name for service authentication, then you can't move the web service off of a domain machine without breaking that identifier. For authenticated services that may need to migrate across domains, you should probably be using some sort of certificate mechanism instead of a Windows account to identify the service.

    Next time: Throttling Sessions

  • Nicholas Allen's Indigo Blog

    Just a Bit of Caching

    • 1 Comments

    Does WCF ever cache the DNS lookup for a service address? How do I clear this cache?

    There is just a tiny amount of caching that I know about. The TCP and MSMQ transports use a shared cache for recently used addresses. I think for MSMQ that this is only a factor for custom dead letter queue addresses. In any case, this cache is to speed up lookups in the case that you're hitting the same address over and over again very quickly. There's no way to clear the cache, but the lifetime of entries is two seconds so you'd have to be changing DNS settings extremely often to notice this.

    If you're getting stale lookups, then it's probably an operating system or server cache that is causing that.

    Next time: Moving Services and User Principals

  • Nicholas Allen's Indigo Blog

    Starting a Hosted Service

    • 2 Comments

    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

  • Nicholas Allen's Indigo Blog

    Interfaces for GetProperty, Part 2

    • 1 Comments

    I've done a bit of grouping for the remaining binding elements as there are fourteen non-transport binding elements that I'm covering in this list. I've pointed out the ones that respond to a type with GetProperty on the base class as opposed to repeating the same code in each subclass.

    Our standard message encoders respond to two types, although only one is on the base class. These two interfaces will override the ones given by the transport if a message encoder is in the binding. The transport delegates to the message encoder before giving its useless default response.

    • MessageVersion (on the message encoder base class)
    • XmlDictionaryReaderQuotas (on the Text, MTOM, and Binary encoders)

    The one-way and transaction channels both support just a single interface.

    • ChannelProtectionRequirements

    All of the security binding elements support a pair of interfaces and the actual security channels add an additional type.

    • ISecurityCapabilities (on the security base class and on the Windows and SSL stream upgrades)
    • IdentityVerifier (on the security base class and on the Windows and SSL stream upgrades)
    • ChannelProtectionRequirements (on the asymmetric, symmetric, and transport security binding elements)

    The reliable message binding element supports a pair of interfaces as well.

    • ChannelProtectionRequirements
    • IBindingDeliveryCapabilities

    Finally, the composite duplex binding element has a pair of types. If you're curious why composite duplex is interacting with a security interface, then you should read the earlier article on layering between composite duplex and security.

    • ISecurityCapabilities
    • ChannelProtectionRequirements

    Next time: Starting a Hosted Service

  • Nicholas Allen's Indigo Blog

    Interfaces for GetProperty, Part 1

    • 1 Comments

    This is more of a reference than anything else. People have asked me what interfaces do something when used with GetProperty on a binding element. Of course, a custom implementation can do whatever it wishes in its GetProperty, so I can only tell you what the standard implementations have done. Also, GetProperty is chained from one place to another. For example, if a property is not found on a channel binding element, it is likely to go off looking at lower binding elements in the channel stack, the message encoder, and so on. What's listed here is just what is specifically handled in a given implementation. I've split this list into "transports" and "everything else".

    The base class for transport responds to three types.

    • ChannelProtectionRequirements (this just give the default values)
    • MessageVersion (SOAP 1.2, WS-Addressing 1.0)
    • XmlDictionaryQuotas (this just gives the default values)

    The HTTP and HTTPS transports respond to three additional types. Also, these transports automatically check against the properties of a text message encoder if you didn't specify any encoder at all. None of the other transports do this for you.

    • ISecurityCapabilities
    • IBindingDeliveryCapabilities
    • TransferMode

    The TCP and Named Pipes transports respond to only two additional types.

    • IBindingDeliveryCapabilities
    • TransferMode

    The Peer transport responds to three additional types.

    • IBindingMulticastCapabilities
    • ISecurityCapabilities
    • IBindingDeliveryCapabilities

    The MSMQ transports respond to three additional types. The last one only occurs for the Integration mode of MSMQ.

    • ISecurityCapabilities
    • IBindingDeliveryCapabilities
    • MessageVersion (always set to None for Integration mode)

    Next time: Interfaces for GetProperty, Part 2

  • Nicholas Allen's Indigo Blog

    What a Binary Encoding Means

    • 1 Comments

    There has always been some confusion about what it means to use a "binary encoding" with your web service. The word encoding is used in a very specific sense here, which should also help you figure out the implications of choosing an encoder in the future. There are two words, encoding and formatting, that I use a lot to keep the concepts clear.

    When we talk about an in-memory message, an instance of a message that your service can interact with, that message is always an XML Infoset. There is no physical representation associated with the Infoset, although you can manipulate it using XML readers and writers. On the wire, there is something physical and totally different from the Infoset, typically a stream of bytes. A formatter translates between typed objects and an XML Infoset. An encoder translates between an XML Infoset and the wire representation.

    You're probably familiar with XML representations that write out the document using text phrases to express the tags inside the document. A binary encoder is just a particular encoder implementation that uses an alternative way of representing the XML Infoset. A binary XML representation replaces the textual tags with opaque binary tokens. Different representations of XML are better at certain tasks, but they result in the construction of the same Infoset after the message is transmitted. Nothing about the encoder implies what can go into the Infoset. In particular, you can have a formatter that puts binary content into the Infoset regardless of whatever kind of encoder you want to use with that Infoset later.

    Next time: Interfaces for GetProperty, Part 1

  • Nicholas Allen's Indigo Blog

    An Indigo Hued Update

    • 0 Comments

    I launched a new site design over the weekend. Use the contact form to report any issues.

    Here are the problems that I know about so far:

    • Wide code snippets no longer have scrollbars to let you see the whole thing.
  • Nicholas Allen's Indigo Blog

    Counting Down to TechEd 2007

    • 0 Comments

    A year later, and it's already time to say again that TechEd 2007 is in Orlando from June 4th to 8th, just eight weeks away now. Eight weeks away also means that the time for early registration is almost gone, so register now if you want to take advantage of that. I expect that the posting schedule during the event will be very similar to last year so be prepared for a blitz during late May and early June.

  • Nicholas Allen's Indigo Blog

    Messaging is not a Transaction

    • 1 Comments

    What happens to the messages being transmitted and any unprocessed messages when I call Abort? Do those messages get delivered or do they get discarded?

    Once you call Abort, the state of any of the network resources involved becomes undefined. What happens to any lingering messages is implementation-dependent and subject to a large number of timing issues. For example, you may call Abort on the client but the server is blissfully unaware that anything has happened until it tries to read additional messages past the ones it has queued up. Or, you may call Abort on the client and that termination notice races ahead of any data on the wire. Aborting the connection may cause messages to be discarded that were completely received by the server machine but not yet sent to a channel. You have no way of knowing because your connection is gone.

    If you need some kind of well-defined behavior, then you should be looking at application protocols, reliable messaging, or transactions to give you a more specific guarantee about what occurs during a failure. Transactions are generally the easiest way to get a very precisely defined failure model, but you may find that a simple application protocol, like resending messages and rejecting duplicates on the server, is good enough to solve your problem. What these methods have in common is that they can carry some state around past the lifetime of that connection you just killed.

    Next time: What a Binary Encoding Means

  • Nicholas Allen's Indigo Blog

    Optional Interfaces on Binding Elements

    • 2 Comments

    In the past I've talked a lot about the absolute minimum you need to do to write a working channel. However, what about the people that want all of the optional bells and whistles that can go along with channel development? There are several interfaces that you can implement on the binding element or in your custom channel solution to add functionality. I'm not going to go over these interfaces in detail today, but I did want to at least catalog the interfaces that are available.

    The base class for a channel binding element is taken up by the fact that you have to subclass BindingElement or TransportBindingElement. Therefore, the optional functionality is generally provided through interfaces that you can add to the binding element or on separate objects.

    • WS-Policy export. The IPolicyExportExtension interface lets you define an ExportPolicy method that overrides the policy construction process.
    • Metadata export. The IWsdlExportExtension interface lets you define an ExportContract and an ExportEndpoint method that override the metadata construction process.
    • WS-Policy import. The IPolicyImportExtension interface has the reverse method ImportPolicy to consume policy statements.
    • Metadata import. The IWsdlImportExtension interface has the reverse methods ImportContract and ImportEndpoint to consume metadata. IWsdlImportExtension also has a method called BeforeImport. Metadata consumption is done using a multi-phase process, where all of the importers get to look at the metadata once before actually doing the work.
    • Configuration import and export. Configuration on the binding element is added by subclassing BindingElementExtensionElement. This is a separate object that has to parallel all of the settable properties on the binding element.
    • Binding configuration import and export. If you put your binding element into a standard binding, then you can provide configuration for that binding as well. You need two separate objects subclassing StandardBindingElement and StandardBindingCollectionElement.

    Next time: Messaging is not a Transaction

  • Nicholas Allen's Indigo Blog

    Choosing a Message Size for Buffered Copies

    • 1 Comments

    Creating a copy of a message requires passing the "maximum buffer size" to CreateBufferedCopy. How big should I make this maximum buffer size?

    In most cases, you can use Int.MaxValue and not worry about the buffer size. Specifying this buffer size is primarily useful when you haven’t previously given a bound to the maximum size of the message.

    • If you received this message using a buffered transfer, then you should have already had a quota applied on the maximum size of the received message.
    • If you received this message using a streamed transfer, then you may want to specify a buffer size if the quota for streaming is larger than the amount you're willing to buffer into memory.
    • If you are creating this message from scratch to send it or for other reasons, then you probably don't want to specify a limit. However, if the message is being built up as the result of several user-driven operations, then you may want to checkpoint the message size during copies to make sure that a malicious user isn't trying to run you out of memory. A malicious user can still make you do a lot of wasted work in this case, but that probably just means that you should require authorization before letting someone tie up your resources.

    Note that whatever value you pass for the maximum buffer size, the default implementation of CreateBufferedCopy uses the maximum possible values for all of the XML reader quotas. It is just the total size of the message in bytes that is being bounded here.

    Next time: Optional Interfaces on Binding Elements

  • Nicholas Allen's Indigo Blog

    Enabling Kerberos in IIS

    • 2 Comments

    How do I enable Kerberos authentication for my web service?

    Kerberos is a very good authentication protocol to use when you're joined to a Windows domain. It is intended to work through simple configuration, but using Kerberos for network authentication sometimes turns out to be harder than it should. There are two fundamental steps that you need to take when setting up your service for Kerberos:

    1. Enable Integrated Windows Authentication for your website in IIS.
    2. Configure your WCF service binding to have Windows credentials so that you can get the Negotiate protocol on the wire.

    These basics were exactly what I covered a few days ago when talking about turning off anonymous access. Now, I have some troubleshooting tips in case you think that you have Kerberos enabled but are either getting an error or getting NTLM instead of Kerberos.

    I'm going to recommend that you get some network monitoring software so that you can look at the HTTP headers. It's possible to look at the HTTP headers in other ways, but using an external program for network sniffing makes it less likely that you accidentally "fix" the problem by setting up your monitoring program differently than your actual service. Being able to look at the HTTP headers lets you see whether Kerberos or NTLM is being offered on the wire.

    One of the common reasons for Kerberos to be skipped is an issue with the principal name. The client has to specify a user or service principal name as the target when connecting to the service. The service needs to have its service principal name registered when receiving requests. When you first set up a web server, service principals are registered for standard accounts like System and Network Service. If you're using a non-standard account or the configuration has been changed a lot over time, you may be in a state where you have zero or multiple service principals, either of which will cause Kerberos to fail.

    Another issue with changing configurations is that IIS allows you to configure the authentication providers for an application pool. This is the NtAuthenticationProviders setting. Either the default value or explicitly setting that variable to "Negotiate,NTLM" should work, but I've seen some configurations that had this set to support NTLM only.

    Next time: Choosing a Message Size for Buffered Copies

Page 1 of 1 (22 items)