Nov 13, 2008

Double Dispatch Principle or the "Shit Hits the Fun"

The other day I was thinking about Double Dispatch Principle and it's benefits and came up with the following code sample:

public class Air
{
}

public class Fun
{
public void Run(Air air)
{ }
}

public class Sheet : Air
{
public void Hit(Fun theFun)
{
theFun.Run(this);
}
}

public class Program
{
public void Process()
{
var theFun = new Fun();
new Sheet().Hit(theFun);
}
}

Oct 14, 2008

Tricky Path.Combine Thing

About 10 minutes I needed to understand the problem. Luckily I had tests. It appears, that Path.Combine works funny. Here are a comple of examples:

  1. If you do Path.Combine("../Tests/", "/123.xml") the result will be "/123.xml"
  2. If you do Path.Combine("../Tests/", "123.xml") the result will be "../Tests/123.xml"
  3. Finally, if you do Path.Combine("../Tests", "123.xml") the result will be "../Tests\123.xml"

Oh, frankly speaking, I would really like to have Path.Combine("../Tests/", "/123.xml")  give me "../Tests/123.xml" or, at least, "../Tests//123.xml" and even "../Tests\123.xml" would be fine.

For now, I have to remember funny point #1 and will try to do #2 and #3 all along.

Oct 7, 2008

XML in .Net: Frequently Asked Questions

XML Team started to blog about most difficult things in System.XML. The list of posts below:

Hope this helps!

Technorati Tags:

Test Requirements First

Today I found a post about The Compare Contract by BCL Team. In brief, one of the customers complained about the breaking changes made in SP1 compared to RTM version. Actually, the ComparedTo method of the StringWrapper class was changed which affected sorting behavior.

It appeared that ComparedTo method was implemented incorrectly. Therefore, it was decided to change it. MSDN describes several requirements that must be met by a particular implementation of IComparable<T> interface.

I see this as a big bonus for any developer implementing IComparable<T> interface. Even before starting to implement the method you can write very strict Unit Tests that will help you to implement a method that will satisfy common requirements for any sorting algorithm.

As you see, you can end up with 5 unit test. If you will use MbUnit, for example, you can employ Row Tests to specify more precise requirements for your interface implementation very easy.

For example I ended up with 15 tests. It took me about 15 minutes. Here they are:

namespace CompareToContract.UnitTests
{
using MbUnit.Framework;

[TestFixture]
public class StringWrapperTests
{
[RowTest]
[Row("")]
[Row("value")]
[Row(null)]
public void CompareTo_SameValue_ShouldReturnZero(string value)
{
StringWrapper wrapper = new StringWrapper() { Value = value };
Assert.AreEqual(wrapper.CompareTo(wrapper), 0, "A.CompareTo(A) should return 0.");
}

[RowTest]
[Row("", "")]
[Row("value", "value")]
[Row(null, null)]
public void CompareTo_AnotherEqualValue_ShouldReturnZero(string value1, string value2)
{
StringWrapper a = new StringWrapper() { Value = value1 };
StringWrapper b = new StringWrapper() { Value = value2 };

Assert.AreEqual(a.CompareTo(b), 0, "A'value'.ComparedTo(b'value') should return 0.");
}

[RowTest]
[Row("", "", "")]
[Row("value", "value", "value")]
[Row(null, null, null)]
public void CompareTo_AandBandCequal_ShouldReturnZero(string value1, string value2, string value3)
{
StringWrapper a = new StringWrapper() { Value = value1 };
StringWrapper b = new StringWrapper() { Value = value2 };
StringWrapper c = new StringWrapper() { Value = value3 };

Assert.AreEqual(a.CompareTo(b), 0, "A'value'.ComparedTo(B'value') should return 0.");
Assert.AreEqual(b.CompareTo(c), 0, "B'value'.ComparedTo(C'value') should return 0.");
Assert.AreEqual(a.CompareTo(c), 0, "A'value'.ComparedTo(C'value') should return 0.");
}

[RowTest]
[Row("1", "2")]
[Row("value1", "value2")]
[Row(null, "1")]
public void CompareTo_IfAComparedToBReturnValueThenBComparedToA_ShouldReturnSameValueButDifferentInSign(string value1, string value2)
{
StringWrapper a = new StringWrapper() { Value = value1 };
StringWrapper b = new StringWrapper() { Value = value2 };

Assert.AreEqual(a.CompareTo(b), -1 * b.CompareTo(a), "a.ComparedTo(b) should equal to -1 * b.ComparedTo(a).");
}

[RowTest]
[Row("1", "2", "3")]
[Row("value3", "value2", "value1")]
[Row("value1", "value2", "value3")]
public void CompareTo_IfAComparedToBReturnsValueWithTheSameSignAsBComparedToCThenACompareToC_ShouldReturnValueWithTheSameSign(string value1, string value2, string value3)
{
StringWrapper a = new StringWrapper() { Value = value1 };
StringWrapper b = new StringWrapper() { Value = value2 };
StringWrapper c = new StringWrapper() { Value = value3 };

int abResult = a.CompareTo(b);
int bcResult = b.CompareTo(c);
int acResult = a.CompareTo(c);

Assert.IsTrue(Math.Sign(abResult) == Math.Sign(bcResult), "A.ComparedTo(B) should have the same sign as B.ComparedTo(C).");
Assert.IsTrue(Math.Sign(abResult) == Math.Sign(acResult), "A.ComparedTo(C) should have the same sign as A.ComparedTo(B).");
}
}
}



The old implementation of CompareTo completed with 10 succeeded and 5 failed tests. While implementation provided by BCL Team completed with all 15 succeeded. This way I can trust this implementation of CompareTo method.



Conclusion



Test your requirements before you right the code. This will minimize your time and efforts to understand (remember all the time) requirements of implementation and will help you to write the code you need, not the code you can write.



Hope this helps!



Technorati Tags: ,,

Aug 26, 2008

WCF+WSE Using Anonymous Certificate Security

Preface.

I am not an expert in neither WCF nor WSE, however, recently I have been busy implementing WCF service that could be consumed by WSE client. And the requirement for this was to use Anonymous For Certificate Security protection of messages.
As always I started from Google... However, after spending about 4 to 6 hour I get nothing except examples that was not working.

Therefore, here, I decided to describe the implementation of, both, service and client.

Anonymous for Certificate Security In a Nutshell.
Basically, to protect your messages with certificates you need to do a number of things:

  • first of all, you need to have certificate (*.cer file) and private key for it (*.pfx file)
  • second, you need to install certificate (*.cer file) on a client computer - which will be used to connect to your WCF service into LocalMachine certificate store
  • then, you need to install both certificate (*.cer file) and private key (*.pfx) file on a server where WCF service will be installed into the LocalMachine certificate store
  • lastly, on a server where WCF service will be installed you need to grant an identity, under which WCF will be running, permissions to access your certificates' private key

The way Anonymous for Certificate Security mechanisms work is very simple - the same way as Encryption Algorithms with Open Key works. The certificate (*.cer file) will be used by client as public key to sign and encode his requests to the service and decode response from the service. The service, in it's turn, will be using private key (*.pfx file) to encode / decode messages.

In this way, it will be impossible to give client a fake service, because only service has private key. However, anything can be a client of a service as soon as it encodes and decodes messages using public key (*.cer file).

WCF Service Implementation.

In order to connect WSE and WCF could understand each other they need to talk the same security protocol. Therefore, I set message security version of service binding to "WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10".

Also, made service and client both you MTOM messaging. Message version should be set to "Soap11WSAddressingAugust2004" by the reason explained earlier.

Next things you need to do is to configure your service behaviour, of course. This is very simple to do as well. You need to add tag to your behavior configuration. Then, add element inside it and insert into element empty tag. After that, add element inside element and configure it to use your certificate.

After this is done, you need to configure your service interface to use message contract and create request and response messages for every method on your service interface. Then implement your service. If something was not configured properly your service will not run.

WSE Client Implementation.

First of all, you need to create a proxy for you WCF service. This is very simple to accomplish using wseWsdl3.exe utility that will be installed along with WSE3.0 installation package.

After you did that, you need to create a WSE policy to access WCF service. You can do in configuration file or in code. It does not matter. What you need to do is to configure AnonymousForSecurity assertion and configure your proxy to use certificate you installed as credentials to access WCF service.

Do not forget to configure WSE to use MTOM messaging as well.

Links

There are lots of resources on the web that can give you some food for thought when dealing with peculiarities of this integration including Microsoft Forums and personal blogs. However, I would recommend to check WCF Security Guidance on CodePlex. This is the place where you will find a lot of information about WCF security and How-Tos.

Hope this helps!

Jun 9, 2008

Good code I would like to be used...

Hm, I reallly like this code but it seems that they will never use it. I am a PM, they are developers. Saddly...

public class Actions
{
private delegate void ChangeState(License license, NewLicenseState newState, string reason);
private IDictionary actions;

public Actions()
{
actions = new Dictionary();
actions.Add(
ChangeToExpiredBlockedStateException,
delegate(License license, strin reason)
{
license.ChangeState(5, reason);
});

actions.Add(
ChangeToExpiredInUseStateException,
delegate(License license, strin reason)
{
license.ChangeState(4, reason);
});
}

public ChangeState this[LicenseException exception]
{
get
{
if (this.actions.ContainsKey(exception.GetType())
{
return this.actions[exception.GetType()];
}

Assert.ThrowInvalidOperationException(message, params args);
}
}
}


And then use it as follows:

new Actions()[ex.GetType()](license, ex.Message);

Yeah, I wrote this code as a sample. To bad it seems too complicated. Although I like it, they do not.

Feb 8, 2008

.Net Encoding Simplicity

Well, recently I was asked about
why this function does not work... ok, it works when the browser encoding is Unicode and it does not, when it is Shift JIS
here is the code:

public static string Convert(string input, Encoding source, Encoding destination)
{
if (String.IsNullOrEmpty(input))
{
return String.Empty;
}

return destination.GetString(
source.GetBytes(input)
);
}

"Well..." - I thought, - "It is not supposed to work." In fact, it is a popular mistake to misunderstand how CLR manages string. And the fact that is almost always is missing is that all strings in .Net are Unicode encoded (I suppose that in Java too).

I wonder why actually there are "source" and "destination" encodings...
When we write something myEncoding.GetBytes(meStringHere) we actuall saying the following to myEncoding "hey, give me the real bytes of this string if it were encoded with myEncoding encoding". And what it actually does is trying to map Unicode bytes to myEncoding encoding bytes using the GetBytes(char[], charsQuantity, byte[], bytesQuantity, Encoder) method (this method is actually unsafe and looks differently from what I have written here, but anyway....).

But, the most interesting part here is GetString method. When we call this one (myAnotherEncoding.GetString), we trying to say the following "hey, create me a Unicode string from the following byte array assuming that these bytes are myAnotherEncoding encoding bytes". This is certainly not true - just look at the method... it has two different (or perhaps different) encodings. And what we are doing for example when we try to use the following schema:

input string = "my input string with unicode \u00df or something"
source encoding = Unicode
destination encoding = Shift JIS (I know of two at least...)

We try to do the following:
unicode string -> Unicode bytes -> shift JIS produces Unicode string from Unicode bytes assuming that these bytes are Shift JIS' bytes...

That is not very correct, no, it's wrong.

For the better understanding of what actually happening when you use encoding and strings I suggest looking the following links (they does not give you advices on what-to-do-when, but provide a solid background to work with less issues):
Have a nice day!

Jan 17, 2008

LINQ to WMI provider

Recently, I needed to analyze WMI-related code and now, I really think about to implement\find\improve a LINQ to WMI provider with the following requirements:
  1. 1. it should support both .Net 2.0-3.5 frameworks
  2. 2. it should be extensible - as WMI support providers model LINQ to WMI implementation should allow people to quickly create modules for different WMI providers
  3. should support querying both events and objects
  4. should have Castle-like error handling
So far, I found only one implementation of LINQ to WMI here and here.
Should take a look at what is implemented already...

Jan 15, 2008

70-536 is done! 70-526 / 70-528 next :)

Great!

Today I have passed 70-536 (Application Development Foundation) Microsoft certification exam.
That is really nice and I am happy.

Hope to pass 70-526 and 70-528 soon!

Jan 11, 2008

Thinking about Fluent Interfaces

I am really inspired by the new ideas of DSLs, Language Oriented APIs, an so on... I found today a link about Fluent Interfaces.

And that gave me an idea of using explicitly and implicitly implemented interfaces.
Where, in the following example:

class Order: IOrder, IFluentOrder

IFluentOrder can really be implemented explicitly and user will never have a problem of mixed modes, i.e. the following code will be very easy to implement:

customer.newOrder()
.with(6, "TAL")
.with(5, "HPK").skippable()
.with(3, "LGV")
.priorityRush();

And then, when user will be working with Orders, he will be working with IOrder interface, instead of dealing with methods from both IOrder and IFluentOrder interface.

That requires additional thinking...