Category Archives: 3777

.NET Framework 2.0 Service Pack 1 and .NET Framework Service Pack 1 available as a standalone download

For those who can’t (or don’t want to) deploy .NET Framework 3.5, the service packs included for the 2.0 and 3.0 versions of the framework are available as standalone downloads.

Visual Studio 2008 and .NET Framework 3.5 shipped!

Visual Studio 2008 and .NET Framework 3.5 has finally shipped.

MSDN subscribers can download the final version of Visual Studio 2008 from MSDN Subscription Downloads, but anyone can get a trial version or an Express Edition.

The .NET Framework 3.5 contains many new features building incrementally upon .NET Framework 2.0 and 3.0, and includes .NET Framework 2.0 service pack 1 and .NET Framework 3.0 service pack 1. and is also available for download.

You can read all about it from various teams and team member’s blogs:

Optimizing reading for the CustomTextMessageEncoder

Continuing the improvement of the CustomTextMessageEncoder (see this and this), this time I’ll use the XmlDictionaryWriter instead of the XmlTextWriter whenever the character encoding is utf-8, utf-16 or Unicode.

To achieve this, all that’s needed is to look into the character set part of the content type and act accordingly.

public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)

{

    byte[] messageContents = new byte[buffer.Count];

    Array.Copy(buffer.Array, buffer.Offset, messageContents, 0, messageContents.Length);

    bufferManager.ReturnBuffer(buffer.Array);

 

    MemoryStream stream = new MemoryStream(messageContents);

    //return ReadMessage(stream, int.MaxValue);

    return ReadMessage(stream, int.MaxValue, contentType);

}

 

public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)

{

    string charset = null;

    if (!string.IsNullOrEmpty(contentType))

    {

        System.Net.Mime.ContentType ct = new System.Net.Mime.ContentType(contentType);

        charset = ct.CharSet;

    }

    if ((!string.IsNullOrEmpty(charset)) && (charset.Equals(ValidatingUTF8.WebName, StringComparison.InvariantCultureIgnoreCase) || charset.Equals(ValidatingUTF16.WebName, StringComparison.InvariantCultureIgnoreCase) || charset.Equals(ValidatingBEUTF16.WebName, StringComparison.InvariantCultureIgnoreCase)))

    {

        XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(stream, XmlDictionaryReaderQuotas.Max);

        return Message.CreateMessage(reader, maxSizeOfHeaders, this.MessageVersion);

    }

    else

    {

        XmlReader reader = XmlReader.Create(stream);

        return Message.CreateMessage(reader, maxSizeOfHeaders, this.MessageVersion);

    }

}

Optimizing writing for the CustomTextMessageEncoder

As I told before I’ve been using WFC to call legacy POX web services. Some of them only accept iso-8859-1, others can accept utf-8, but all use MessageVersion.None and the text/xml media type.

But since the new XmlDictionaryWriter is optimized for utf-8, utf-16 and Unicode character encodings and will perform better that the XmlTextWriter I would like to be able to use it when possible. To achieve this, two methods of the CustomTextMessageEncoder need to be changed in order to use the best writer.

public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)

{

    MemoryStream stream = new MemoryStream();

    WriteMessage(message, stream);

    //XmlWriter writer = XmlWriter.Create(stream, this.m_writerSettings);

    //message.WriteMessage(writer);

    //writer.Close();

 

    byte[] messageBytes = stream.GetBuffer();

    int messageLength = (int)stream.Position;

    stream.Close();

 

    int totalLength = messageLength + messageOffset;

    byte[] totalBytes = bufferManager.TakeBuffer(totalLength);

    Array.Copy(messageBytes, 0, totalBytes, messageOffset, messageLength);

 

    ArraySegment<byte> byteArray = new ArraySegment<byte>(totalBytes, messageOffset, messageLength);

    return byteArray;

}

 

public override void WriteMessage(Message message, Stream stream)

{

    if ((this.m_writerSettings.Encoding.WebName == ValidatingUTF8.WebName) || (this.m_writerSettings.Encoding.WebName == ValidatingUTF16.WebName) || (this.m_writerSettings.Encoding.WebName == ValidatingBEUTF16.WebName))

    {

        XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream, this.m_writerSettings.Encoding, false);

        message.WriteMessage(writer);

        writer.Close();

    }

    else

    {

        XmlWriter writer = XmlWriter.Create(stream, this.m_writerSettings);

        message.WriteMessage(writer);

        writer.Close();

    }

}

WCF: Building an HTTP User Agent Message Inspector

Yesterday I had to build a custom message encoder to be able to call a legacy POX service with iso-8859-1 encoding.

It turned out that the service had another surprise to me: it needs an HTTP user-agent header.

It’s something quite simple to accomplish with WCF. All it’s needed is to add the required header to the HTTP request message property of the request message. Something like this:

HttpRequestMessageProperty httpRequestMessage = new HttpRequestMessageProperty();

httpRequestMessage.Headers.Add(USER_AGENT_HTTP_HEADER, this.m_userAgent);

requestMessage.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);

But I was not willing to pollute my code with this and, besides that, it doesn’t look much WCFish having to do this.

Since I don’t like to spend too much time trying to figure things out when I know someone who knows it, I asked António Cruz what to do. And the answer was a client message inspector.

With the help of a sample I have built an HTTP user agent client message inspector.

Message Inspector

The message inspector is very simple. We just need to implement the IClientMessageInspector Interface.

public class HttpUserAgentMessageInspector : IClientMessageInspector

{

    private const string USER_AGENT_HTTP_HEADER = “user-agent”;

 

    private string m_userAgent;

 

    public HttpUserAgentMessageInspector(string userAgent)

    {

        this.m_userAgent = userAgent;

    }

 

    #region IClientMessageInspector Members

 

    public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)

    {

    }

 

    public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)

    {

        HttpRequestMessageProperty httpRequestMessage;

        object httpRequestMessageObject;

        if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out httpRequestMessageObject))

        {

            httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;

            if (string.IsNullOrEmpty(httpRequestMessage.Headers[USER_AGENT_HTTP_HEADER]))

            {

                httpRequestMessage.Headers[USER_AGENT_HTTP_HEADER] = this.m_userAgent;

            }

        }

        else

        {

            httpRequestMessage = new HttpRequestMessageProperty();

            httpRequestMessage.Headers.Add(USER_AGENT_HTTP_HEADER, this.m_userAgent);

            request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);

        }

        return null;

    }

 

    #endregion

Behavior

But this message inspectors are extensions to the client runtime. Such extensions are configured using behaviors. A behavior is a class that changes the behavior of the service model runtime by changing the default configuration or adding extensions (such as message inspectors) to it.

The implementation of a behavior is, also, very simple. We just need to implement the IEndpointBehavior Interface. In this case, since it’s a client message inspector only, all we need to implement is the ApplyClientBehavior method.

public class HttpUserAgentEndpointBehavior : IEndpointBehavior

{

    private string m_userAgent;

 

    public HttpUserAgentEndpointBehavior(string userAgent)

    {

        this.m_userAgent = userAgent;

    }

 

    #region IEndpointBehavior Members

 

    public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)

    {

    }

 

    public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)

    {

        HttpUserAgentMessageInspector inspector = new HttpUserAgentMessageInspector(this.m_userAgent);

        clientRuntime.MessageInspectors.Add(inspector);

    }

 

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)

    {

    }

 

    public void Validate(ServiceEndpoint endpoint)

    {

    }

 

    #endregion

}

Adding the Message Inspector through Configuration

For configuring an endpoint in the application configuration file to use our custom behavior, the service model requires us to create a configuration extension element represented by a class derived from BehaviorExtensionElement.

public class HttpUserAgentBehaviorExtensionElement : BehaviorExtensionElement

{

    public override Type BehaviorType

    {

        get

        {

            return typeof(HttpUserAgentEndpointBehavior);

        }

    }

 

    protected override object CreateBehavior()

    {

        return new HttpUserAgentEndpointBehavior(UserAgent);

    }

 

    [ConfigurationProperty(“userAgent”, IsRequired = true)]

    public string UserAgent

    {

        get { return (string)base[“userAgent”]; }

        set { base[“userAgent”] = value; }

    }

}

This extension must then be added to the service model’s configuration section for extensions:

<system.serviceModel>

  <extensions>

    <behaviorExtensions>

      <add name=httpUserAgent type=Pajocomo.ServiceModel.Dispatcher.HttpUserAgentBehaviorExtensionElement, Esi.ServiceModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null />

    </behaviorExtensions>

  </extensions>

</system.serviceModel>

Note: We must use the full assembly qualified name here, otherwise it won’t work.

Now we need to apply our behavior extension to a behavior configuration:

<system.serviceModel>

  <behaviors>

    <endpointBehaviors>

      <behavior name=LegacyServiceEndpointBehavior>

        <httpUserAgent userAgent=test user agent />

      </behavior>

    </endpointBehaviors>

  </behaviors>

</system.serviceModel>

Adding the configuration to the service configuration

Now we can apply this configuration to our sevice configuration:

<system.serviceModel>

  <client>

    <endpoint

      address=

      binding=

      bindingConfiguration=

      behaviorConfiguration=LegacyServiceEndpointBehavior

      contract=

      name= />

  </client>

</system.serviceModel>

And we are all set to go.

WCF: Text Message Encoding and ISO-8859-1 Encoding

I’m a newbie in WFC and, so far, only have done client code to call POX web services.

I’ve been using a textMessageEncoding binding extension with a message version of None and a write encoding of utf-8 and all has been running fine.

Well, until I needed to call a service in iso-8859-1 encoding. Then I started getting a ProtocolException:

The content type text/xml;charset=iso-8859-1 of the response message does not match the content type of the binding (text/xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly.

Bruno directed me to a sample that looked promising. The sample works fine because it’s using the same binding extension in the server and in the client.

When I tried to use the customTextMessageBinding from the sample, I got this nice ProtocolException:

The content type text/xml;charset=iso-8859-1 of the response message does not match the content type of the binding (text/xml; charset=iso-8859-1). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly.

Looks kind of funny, doesn’t it?

It comes down to the fact that the base MessageEncoder class doing a string comparison on the content type.

To solve this, I’ve overriden the IsContentTypeSupported method and added an additional validadion when the base validation fails. This new validation only checks for the media type of the response and lets the XmlReader handle the encoding.

public override bool IsContentTypeSupported(string contentType)

{

    if (base.IsContentTypeSupported(contentType))

    {

        return true;

    }

    if (contentType.Length == this.MediaType.Length)

    {

        return contentType.Equals(this.MediaType, StringComparison.OrdinalIgnoreCase);

    }

    else

    {

        if (contentType.StartsWith(this.MediaType, StringComparison.OrdinalIgnoreCase)

            && (contentType[this.MediaType.Length] == ‘;’))

        {

            return true;

        }

    }

    return false;

}

Since this seems to be happening in Orcas too, I’ve added a comment to the sample documentation and opened an issue. Vote on them.