Category Archives: Indigo

Posts related to Indigo and Web Services

NetNamedPipeBinding and Impersonation

On of the top benefits to using NetNamedPipeBinding is that we provide an on-box guarantee for your messages. The on-box guarantee is enforced by Denying the Network Security Identifier (SID: S-1-5-2) access to our named pipe. This is the most secure, safest way of ensuring that you are not exposed to connection attempts from the network.

There is a price to pay for this assurance, and it comes in the form of impersonation support in middle-tier scenarios. The short version is that if you are using impersonation, you can only perform messaging to another Named Pipe endpoint using that impersonated token if you negotiate to NTLM in certain restricted conditions.

Here are the gory details:

Over Kerberos, any client/server authentication will always generate Network SID in the access token. When the server authenticates a client all the relevant information is included in the Kerberos ticket presented by the client, and the ticket doesn’t contain information on the location of the client (this is simply not part of the protocol at this point). So even if both client and server are on the same machine, everything works exactly the same as in the remote case, and the resulting access token has the Network SID (because the protocol has no way of knowing that you are on-box).

Over NTLM, if the client uses the current credentials there is an optimization where NTLM references the existing token under which the client process is running instead of generating a new token. In this case you won’t see the Network SID, because the original token was generated by an interactive logon attempt. If your client is configured with specific credentials, then SSPI will consider this a network logon.

When using WCF, Windows authentication is performed through SSPI-Negotiate, which in most cases will select Kerberos as the actual authentication mechanism. However, if the target SPN passed to SSPI is a well formed SPN for the local computer account (e.g. host/[dns machine name]) then Negotiate will use NTLM (loopback optimization) and the access token will not have the Network SID (and therefore will be usable with NetNamedPipes).

EnumMember and DataContract

In the February CTP, we have a new attribute for interacting with enum declarations for a [DataContract]. While enums are serializable by default (and thus don’t require attribute decoration), you may want to customize the contract names of your enum values (i.e. the names that go on the wire) separately from your implementation naming so that you can version the two independently. For example:

[DataContract(Name=”ColorContract”)]
enum Color
{

[EnumMember(Value=”RedValue”)]
Red,

[EnumMember(Value = “BlueValue”)]
Blue,

}

NOTE: [EnumMember] is not used in the case where you have a member variable/Property of an enum type in your [DataContract]. For those cases, you still use [DataMember], just like you do for the rest of the member variables/properties that you want to include in the [DataContract] for your class.

WCF February CTP now available

The WinFx Runtime Components February CTP (including Avalon, Indigo, and Workflow) has been released here.

You can also download an updated Windows SDK and Visual Studio Preview.

There are a number of breaking changes from the January CTP. Ed has a good overview of them here. These changes are predominantly a result of community feedback. Please keep the comments rolling as we head down the stretch towards shipping, and remember to use http://windowscommunication.net/ for access to our latest and greatest community information. Happy coding!

Large Messages and WCF

CLR typed objects (and buffered messages) are great for a large breadth of applications. Sometimes though, you just want to push bytes. WCF provides a convenient way of doing so with “streamed methods”.

To use WCF’s “Streaming API” you write an operation with an input and/or output of type System.IO.Stream. Because the Stream parameter utilizes the entire body, if an input or an output (i.e. ref parameter, out parameter, or return value) is of type Stream then it must be the only input/output specified in your OperationContract.

When using a Streaming method, you need to pass in a Stream object that provides data incrementally from its Read() method. One common area of confusion is that your return Stream must also be written with the Read() method providing the data. The mental model is that the client is “reading” the return value, and not that the server is “writing” the result.

Now that your operation has been architected so that it no longer requires buffering, you have to choose a binding that is compatible with moving a lot of bytes around. Yasser wrote a nice post on this topic here. In a nutshell you need to:

  • Pick an encoding (Binary for Indigo< ->Indigo scenarios or MTOM if you require interop)
  • Enable streaming on your binding (either through TransferMode.Streamed on a transport or by using chunking at the top of your binding stack)

Tracing Tidbit: Getting Callstacks Automatically

When you get an Exception traced in Indigo, part of that trace includes the callstack which is naturally traced as part of Exception.ToString(). However, callstack information is generally useful for other non-Exception traces (for example, trying to track down who is Aborting a socket). Part of the beauty of our tracing infrastructure is that it’s really easy to modify your trace listener. It turns out there is a built-in option for emitting callstacks. Simply add:

traceOutputOptions="Callstack"

to your listener config.

The relevant line of config then looks like:

<add name="multifile"
     type="System.Diagnostics.XmlWriterTraceListener"
     traceOutputOptions="Callstack"
     initializeData=".Whatever.xml" />

Happy debugging!

Enabling E2E Tracing for WCF

Tracking down bugs in distributed systems can be really difficult. One of the technologies we’re using in Indigo to help make this easier is known as “E2E Tracing” (for End to End Tracing). Of course, this technology is only as good as the traces that a system emits. In Beta 1, we weren’t so good about our traces, but in the past few months we’ve made a concerted effort to improve them. And we need your feedback on what is easy to track down and (just as importantly) what was a pain in the butt to figure out. I recommend starting at “Warning” level. Verbose traces are very, well, verbose and can often be hard to navigate through.

Indigo also includes a Trace Viewer (svcTraceViewer.exe) which allows you to make heads (or tails) of the Xml files that are generated. Again, feedback on the tool is highly encouraged.

Here’s a sample config file snippet that will enable tracing in Indigo Applications and will generate Xml file with the traces.

The generated file can then be opened with svcTraceViewer.exe

<configuration>
 <system.diagnostics>
  <sources>
   <!-- The 'switchValue' determines the level of traces that will
             be outputted, e.g. 'Verbose', 'Warning', 'Error', etc -->
   <source name="System.ServiceModel" switchValue="Warning, ActivityTracing"
                 propagateActivity="true">
     <listeners>
     <clear />
     <!-- The 'initializeData' attribute determines to which file
              the traces will be written -->
     <add name="xml" type="System.Diagnostics.XmlWriterTraceListener"
                initializeData="e2eTraceTest.xml" />
     <!-- To log to a Console, use this instead of previous Node:
     <add name="console" type="System.Diagnostics.ConsoleTraceListener" />
     -->
    </listeners>
   </source>
  </sources>
  <!-- Setting he 'autoflush' attribute to 'true' ensures that the trace
            sources flush to disk after each trace -->
  <trace autoflush="true" />
 </system.diagnostics>
</configuration>

Migrating ASMX to WCF

One question I was often asked last week was: “I have a bunch of ASMX services today, what is the best way for me to prepare for and/or migrate to Indigo”? (also asked as “can you tell me more about this ASMX migration thing?”). There are a number of ways to go about this, but Kirk and I came across a compelling approach that I will elaborate on here. Before we begin, if you need some background on the differences between ASMX 1.0, ASMX 2.0, and WCF, check out Aaron Skonnard’s MSDN article.

First we assume that you have a ASMX service implemented using CodeBehind. If you don’t, then your first step is to move your inline .asmx code into a .cs file 🙂

Now, let’s say you have the following ASMX service:

[WebService(Namespace=”http://kennyw.com/sampleservices/”)]
public class MyService : System.Web.Services.WebService
{

[WebMethod]
public string Hello(string name)
{

return string.Format(“Hello {0}.”, name);

}

}

Which is referenced from an .asmx file containing the reference directive such as the following:
<%@WebService Language=”C#” class=”MyService” %>

You can expose this ASMX service to WCF in 3 simple steps.

  1. Annotate your ASMX service with WCF attributes.
    Add [ServiceContract] to the classes you want to expose through WCF, and [OperationContract] to the methods. Our modified class looks like:

    [ServiceContract(Namespace=”http://kennyw.com/WCFservices/”)]
    [WebService(Namespace=”http://kennyw.com/sampleservices/”)]
    public class MyService : System.Web.Services.WebService
    {

    [WebMethod]
    [OperationContract]
    public string Hello(string name)
    {

    return string.Format(“Hello {0}.”, name);

    }

    }

  2. Create a .svc file in your virtual directory that contains the following declaration (which is very reminiscent of your .asmx file :)):
    <%@ServiceHost Language=”C#” Service=”MyService” %>
  3. Add a snippit to your web.config file (create one if you don’t already have one in your vdir) to add an HTTP binding for your service:
    <system.serviceModel>
      <services>
        <service type=”MyService”>
          <endpoint binding=”basicHttpBinding”
            contract=”MyService”
          />
        </service>
      </services>
    </system.serviceModel>

Viola! Now you can access your service file using both Indigo clients (using the .svc file) and ASMX clients (using the .asmx file). This will get you started on the migration path. You can add more functionality to other methods and expose those methods to new Indigo clients, and if you aren’t using any “HTTP-isms” (i.e. HttpContext.Current and friends) then you will also be able to add net.tcp and/or net.pipe bindings on Vista.

There are of course many more details to cover on this topic. For those going to VSLive! next week, Steve Maine will be covering this topic in much greater detail at the WCF for ASP.NET Developers session. Hopefully he will post some of his wise words following the talk on his blog 🙂

IDuplexSession.CloseOutputSession

When writing an IDuplexSessionChannel, one of the pieces that needs to be implemented is (as you might expect) IDuplexSession. IDuplexSession has one additional requirement on top of ISession, and that is the ability to perform a “half-close”. Semantically this is the same as Shutdown(Send) in sockets-speak.

When you call IDuplexSession.CloseOutputSession(), this signals to the other side of the session that it should return null from outstanding and subsequent calls to Receive(). CloseOutputSession() is also idempotent (just like ICommunicationObject.Close() and ICommunicationObject.Abort()).

CloseOutputSession() is also a little tricky, because it’s a session method that can interact with the owning IDuplexSessionChannel that owns the session. In particular, if your session lifetime is coupled with your channel lifetime (like it is for TCP and RM and Security):

  1. If CloseOutputSession() is called before channel.Close(), channel.Close() should wait for CloseOutputSession() to finish.
  2. If the channel is in the Created or Opening state, CloseOutputSession() should throw new InvalidOperationException(...).
  3. If the channel is in the Faulted state, CloseOutputSession() should throw new CommunicationObjectFaultedException(...).
  4. The channel should fault if CloseOutputSession throws.
  5. channel.Close() should call CloseOutputSession() and then verify that Receive() returns null (i.e. CloseOutputSession was called from the other side of the session).