Standing on the shoulders of giants. RSS 2.0
# Tuesday, October 16, 2007

Jeff Atwood posted an entry today about how it's important to have fun at work. I can only agree with him, since the reason I still am at my current job is the fun I'm having and the great people I work with.

If you love software as much as I do, you deserve to work at a company where people come to work not to punch a clock, but because they love software, too. You deserve to work at a company where software engineering is respected. You deserve to work at a company where peers meet to enjoy building software together.

And just like Jeff's company, we're hiring too.

Tuesday, October 16, 2007 9:11:36 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1] - Trackback
General

Part 2: Adding Soap headers to the client

Adding headers to the client is even easer than adding them to the server, which I showed in part 1: Adding Soap headers to a webservice. As you can see the headers are also added to the WSDL and the wsdl.exe tool or the VS webreference wizard will add them to the proxy.

<wsdl:binding name="Service1Soap" type="tns:Service1Soap">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" /> 
    <wsdl:operation name="HelloWorld">
      <soap:operation soapAction="http://tempuri.org/HelloWorld" style="document" /> 
      <wsdl:input>
          <soap:body use="literal" /> 
          <soap:header message="tns:HelloWorlduserNamePasswordHeader" 
part="userNamePasswordHeader" use="literal" /> </wsdl:input> <wsdl:output> <soap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding>

If that doesn't work or the headers are not in the wsdl, you can add the property manually and associate the header with the method using the soapheader attribute. This works exactly the same as for the server.

WebClient.zip (8.59 KB)

Update 23 Oct. 2007: Replaced the zip with a version which compiles.

Tuesday, October 16, 2007 9:04:56 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
Services
# Saturday, October 13, 2007

I finished Essential Windows Workflow Foundation earlier this week. This is a nice introduction to the workflow foundation and covers everything from writing activities to hosting them and creating designers. There is enough technical depth to get you going and show you where you need to look for more information. Highly recommended.

Now I'm reading Practical Common Lisp and I. M. Wright's "Hard Code", both of which are very promissing.

Still remaining:

Reading stack 13 Oct 2007

Saturday, October 13, 2007 9:37:14 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
Reading

Who am I?

As you probably guessed, I am Paul van Brenk and I live in Rotterdam in The Netherlands. I've been writing this blog since October 2003, when I started it to write about the PDC in that year. I've been developing software since the Commodore 64, using Basic. I rediscovered how much fun it was when in college writing small asp applications, in vb-script. The move to ASP.NET was obvious when the beta of .NET 1.0 arrived and now I'm comfortable in C# and VB.Net, but prefer the first. I recently developed an interest in LISP and try to get more comfortable with C and C++, but I don't use that often enough.

I currently work for Tam Tam, where I specialize in Custom Solutions for the Information Worker business Unit as a sr. software engineer. My time is spent designing and writing applications and training the junior developers. In my spare time I contribute to the opensource blogging platform dasBlog.

Why a blog?

A blog is a good way to keep track of the things I find interesting or discover and a great way to share them. Hopefully you'll find them intersting, helpful or atleast point you in the right direction. Since blogs are best when there is 2 way communication, please post comments or send emails. Just try to keep them more or less ontopic.

Can I email you?

paul.van.brenk@gmail.com

What platform do you use?

I try to run the latest daily build of the dasBlog, as far as my host supports it. So you may encounter the occasional issue, but that's life at the bleeding edge of software development.

Saturday, October 13, 2007 7:01:19 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
General
# Tuesday, October 09, 2007

There are a number of reasons you may want to add custom headers to a SOAP message:

  • Passing security information outside the body, so the code handling the security is uncoupled from the business logic;
  • Adding timestamps;
  • Everything else which is not actually part of the message, but is required for/used by the infrastrcture.

Luckily adding custom Soap headers is easy in the .NET framework.

Part 1: Adding SOAP headers to a webservice

After creating your basic webservice.

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service1 : System.Web.Services.WebService {

   [WebMethod]
   public string HelloWorld() {
       return "Hello, world!";
   }
}

And defining your soapheader; any xml serializable class, deriving from SoapHeader.

[XmlRoot("userNamePasswordHeader")]
public class UserNamePasswordHeader : SoapHeader {

   public UserNamePasswordHeader()
       : base() { }

    [XmlElement("userName")]
    public string UserName;
    [XmlElement("password")]
    public string Password;
}

Hooking everything up is straightforward. One way is to add a field or property to the webservice class to hold the soapheaders and add the soapheader attribute to the method to associate the headers to it. Adding the unknownheaders fields allows the method to intercept the undefined headers. This results in the following class:

public class Service1 : System.Web.Services.WebService {

    [WebMethod]
    [SoapHeader("UserNamePasswordHeader")]
    public string HelloWorld() {

        string userName = this.UserNamePasswordHeader.UserName;
        return "Hello, " + userName;
    }

    public UserNamePasswordHeader UserNamePasswordHeader;

    public SoapHeader[] UnknownHeaders;
}

Offcourse you can use the value of the headers in the method call, but usually you want to process the headers in a soap extension.

A soapextension, a class deriving from the SoapExtension class, can also be used to add headers to response messages, by adding them in the ProcessMessage method during the BeforeSerialize stage.

public class TimeStampExtension : SoapExtension{

    public TimeStampExtension()
        :base(){}

    public override object GetInitializer(Type serviceType) {
        return null;
    }

    public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute) {
        return null;
    }

    public override void Initialize(object initializer) {
        // do nothing
    }

    public override void ProcessMessage(SoapMessage message) {
        
        switch( message.Stage ){
            case SoapMessageStage.BeforeSerialize:
                  AddTimeStamp(message);
                  break;
            default:
                // do nothing
                  break;
        }
    }

    private void AddTimeStamp(SoapMessage message) {
        message.Headers.Add(new TimeStampHeader());
    }
}

Seting up the soap extension is done in the web.config file.

<configuration>
  <system.web>
    <webServices>
      <soapExtensionTypes>
        <add type="WebService.TimeStampExtension, WebService" group="High" priority="2"/>
      </soapExtensionTypes>
    </webServices>
  </system.web>
</configuration>

Source: WebService.zip (4.63 KB)

Tuesday, October 09, 2007 10:28:38 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
Services
# Wednesday, August 29, 2007
int[] source = new int[]{1,2,3,4,5,6};

List<int> list = new List<int>( source );

Debug.Assert( ((IList<int>)list).IsReadOnly == false ); // false

Collection<int> collection = new Collection<int>( source );

Debug.Assert(  ((IList<int>)collection).IsReadOnly == true ); // true!!
When the documentation says 'wrapper' they really mean it.

Wednesday, August 29, 2007 10:33:20 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
BCL | Codesnippet
# Tuesday, August 28, 2007

After reading post about List Predicates at the very informative BCL Team Blog, I did some research to see how flexible the predicates actually are.

I found out that none of the methods taking a Predicate as a parameter support chained delegates (more info about combining delegates), only the delegate added last to the chain is executed in my experience.

Example:

 

// Prepare collection
List<int> list = new List<int>( new int[]{1,2,3,4,5,6} );
        
// function to determine if the int is less than 5
Predicate<int> LT5 = delegate(int x){ return x < 5; };
        
// function to determine if the int is greater than 2
Predicate<int> GT2 = delegate(int x){ return x > 2; };
        
// combine the predicates:
// return true for 2 < x < 5
Predicate<int> GT2LT5 = null;
GT2LT5 += GT2;
GT2LT5 += LT5;
        
List<int> result = list.FindAll(GT2LT5);

// writes 1,2,3,4
result.ForEach( delegate( int x) { Console.WriteLine( x ); });

A work around would be to use the second delegate on the result collection after calling the FindAll method with the first delegate, but this doesn't scale with more delegates.

 

// first use the first delegate
List<int> intermediate = list.FindAll(LT5);
// now use the second delegate on the intermediate result
List<int> result = intermediate.FindAll(GT2);

// writes 3,4
result.ForEach( delegate( int x) {
    Console.WriteLine( x );
});
 

Another solution is to enumerate through the collection and call each delegate in the invocation list.

 

// Prepare collection
List<int> list = new List<int>( new int[]{1,2,3,4,5,6} );

// function to determine if the int is less than 5
Predicate<int> LT5 = delegate(int x){
return x < 5;
};

// function to determine if the int is greater than 2
Predicate<int> GT2 = delegate(int x){
return x > 2;
};
        
// combine the predicates:
// return true for 2 < x < 5
Predicate<int> GT2LT5 = null;
GT2LT5 += GT2;
GT2LT5 += LT5;

// prepare result
List<int> result = new List<int>();

foreach(int i in list ){
    
    bool valid = true;
    
    // GetInvocationList returns all combined delegates
    foreach( Predicate<int> match in GT2LT5.GetInvocationList() ){
        valid = valid & match(i);            
    }

    if( valid ){
        result.Add(i);
    }
}

// writes 3,4
result.ForEach( delegate( int x) {
    Console.WriteLine( x );
});

Both solutions are less than ideal.

Tuesday, August 28, 2007 10:26:33 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
Codesnippet | BCL
# Monday, August 20, 2007

I was supprised with the last results from the XmlWriters and compression stream performance post and figured I did something wrong. So today I re-ran my test and got the results I expected after some data manipulation. The results aren't shocking; writing to a memory stream is about 8% faster when you increase the intialcapacity from 256 bytes to 131072 bytes, further increasing doesn't improve the performance further. Naturally this depends on the data, only 6 xmldocuments I used in this test were greater than 131072 bytes.

Relative performance with increasing initial capacity

 

Methodology:

I saved each xml document to the memorystream 100 times for each initial capacity and removed the 10 best and 10 worst results. The results are relative to the performance of the stream with an initial capacity of 256 bytes.

Notes:

My data is not your data; always do your own testing to determine the 'best' initial capacity for your situation.

Monday, August 20, 2007 10:15:43 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
Development
# Sunday, August 19, 2007

[Update: the results in this post about the performance of a memory stream, when changing the initial capacity are wrong. You can find the correct results in this new post.]

WCF (Windows Communication Framework) introduces additional XmlWriters for more efficient serialization of the messages send between nodes. These writers derive from the abstract XmlDictionaryWriter class and wrap the functionality of existing System.Xml. (For more information visit Justin Smith's post or watch Doug Purdy's COM326 presentation from PDC 05.

I was interested in the performance of the basic UTF-8 text writer and the binary writer for writing content heavy Xml. In this scenario an XmlDictionary won't give much benefit, since in my experience a dictionary will only reduce the size of the tags and not the actual content. More specifically I was interested in the difference in size and the speed of writing of xml files of various sizes.

On to the actual testing: I used the 138 feeds from my blogroll, that do not have a doctype in their feeds, since the XmlDictionaryWriter doesn't support writing those. After loading the feeds in an XmlDataDocument they are saved to the different streams and the size of the streams and the time it takes are written to a log-file for analyzing. Finally the whole process is repeated for a number of initial sizes for the MemoryStream (256 - 524288 in powers of 2).

The results: compression xml files makes them smaller, but it takes longer to write them.

Average performance graph

 As you can see the difference between the text writer the binary writer are small, looking at the averages for all files.

Split for file size chart

When looking at the bytes written / tick you'll see that the binary writer is generally faster for uncompressed files smaller than 8192 bytes and negligible slower for compressed files. Another thing to notice is that the writing speed increases for uncompressed streams as the files get bigger, while it drops a little for compressed streams. The fact that the writing speed drops for the biggest files is probably caused by the mem copy which occures when the memory stream has to increase it's capacity. 

initial capacity chart

 The initial capacity doesn't seems to influence the throughput of the memorystream in a significant way, but this may be related to the data I used to test.

[Download solution for VS 2008]

Notes:

1) According to the MSDN library the compression algorithm the DeflateStream uses is the same the GZipStream uses, so performance should be similar.

2) My data is not your data; you should always do your own testing and decide of the performance and the size are right for you.

Sunday, August 19, 2007 9:55:27 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
C# | XML
# Thursday, August 16, 2007

Yesterday the official build for dasBlog 2.0 was released.

Biggest improvements are the move to .NET 2.0 and the ability to run in Medium trust. For more information about: upgrading, getting help and medium trust, see Scott Hanselman's blog.

Download dasBlog

You can use the BlogML importer to migrate any blogengine, which supports BlogML, to dasBlog.

Thursday, August 16, 2007 3:51:18 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
dasBlog
Ads
About
© Copyright 2010
Paul van Brenk
Sign In
newtelligence dasBlog 2.3.9074.18820
All Content © 2010, Paul van Brenk
DasBlog theme 'Business' created by Christoph De Baene (delarou)