wtorek, 29 kwietnia 2008

System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted.

Error:
Unable to connect to the remote server.
System.Net.Sockets.SocketException: Only one usage of each socket address
(protocol/network address/port) is normally permitted.

Scenario:
1. I had a web service proxy, generated automatically from the CrmServiceWsdl.wsdl file of the Microsoft Dynamics CRM 4.0.
2. I was loading a big amount of data to the CRM via the web services.
3. In the middle of the load I was gettingthe following error:
Unable to connect to the remote server
System.Net.Sockets.SocketException: Only one usage of each socket address
(protocol/network address/port) is normally permitted.

Reason:
Every time I was invoking a method of the web service, the proxy generated a new connection even tough I was using the default setting keep-alive. The new connection was being prepared because of the need to authenticate each request. The old connections were hanging on (240 seconds) before timing out. It can be seen with the netstat –n command. There were so many connections that it was not possible to a make a new connection.

Solution:
I simply turned off the keep-alive for the web service proxy. I had the Reference.cs file generated automatically and I did not want to change this file. I prepared a new file with the partial class implementation and the overridden GetWebRequest method.

Sample code of the partial class:
namespace Crm40
{
using System.Diagnostics;
using System.Web.Services;
using System.ComponentModel;
using System.Web.Services.Protocols;
using System;
using System.Xml.Serialization;

public partial class CrmService :
System.Web.Services.Protocols.SoapHttpClientProtocol
{
protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
System.Net.HttpWebRequest webRequest =
(System.Net.HttpWebRequest)base.GetWebRequest(uri);

webRequest.KeepAlive = false;

webRequest.ProtocolVersion = System.Net.HttpVersion.Version10;
return webRequest;
}
}
}


However I think I had already met the same issue a long time ago, I resolved it once again ;)

środa, 9 kwietnia 2008

Szybki start z log4net (Quick start with log4net)

Szybkie podłączenie i konfiguracja log4net dla aplikacji w .Net framework 2.0, 3.0, 3.5 w 5 krokach:
(Very short tutorial of connecting and configuring the log4net quickly for the .Net framework 2.0, 3.0, 3.5 in 5 steps:)

1. Skąd log4net? (Where to get the log4net from?)
Ściągnij wersję log4net z logging.apache.org/log4net. Po rozpakowaniu pliku incubating-log4net-1.2.10.zip z katalogu log4net-1.2.10/bin/net/2.0/release dodaj plik log4net.dll do GAC (c:\Windows\assembly).
(Download the log4net from logging.apache.org/log4net. After extracting the archive incubating-log4net-1.2.10.zip from the folder log4net-1.2.10/bin/net/2.0/release add the file log4net.dll to the GAC (c:\Windows\assembly).

2. Referencja do assembly (Assembly reference)
Do projektu w Visual Studio dodaj referencje do log4net (Menu lokalne na projekcie, opcja Add Reference).
(To the Visual Studio Project add a new reference to the log4net (Local menu over the project, option Add Reference))

3. Plik konfiguracyjny dla log4net (Configuration file for the log4net)
Do folderu aplikacji dodaj plik log4net.config z poniższą (przykładową) zawartością:
(To the application folder add a new file log4net.config with the following, sample content:)

<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<root>
<level value="DEBUG" />
<appender-ref ref="FileAppender" />
</root>

<appender name="FileAppender" type="log4net.Appender.FileAppender">
<file value="log-file.txt" />
<appendToFile value="true" />
<encoding value="unicodeFFFE" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern
value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>


</log4net>


4. log4net.config do aplikacji .Net (log4net.config to the .Net application)
Do pliku AssemlbyInfo.cs dodaj: (To the AssemblyInfo.cs file add the following lines:)

[assembly: log4net.Config.XmlConfigurator(ConfigFile =
"Log4Net.config", Watch = true)]


5. Użycie (The use)
Do klasy dodaj deklarację: (Add the following declaration to the class:)

public class Foo
{
private static readonly ILog logger = LogManager.GetLogger(typeof(Foo));
...
}

lub bardziej uniwersalną ale dłuższą: (or more universal but longer:)

public class Foo
{
private static readonly ILog logger = LogManager.GetLogger(
System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
...
}

i wywołaj poniższy kod aby zalogować: (and call the following code to log:)

logger.Debug("zapisz ten tekst");
logger.Info("zapisz ten tekst");
logger.Warn("zapisz ten tekst");
logger.Error("zapisz ten tekst");
logger.Fatal("zapisz ten tekst");


Do sprawdzenia jaki jest obecnie ustawiony poziom logowania, żeby uniknąć niepotrzebnych obliczeń jeśli ich wyniki są logowane, mamy: (To check what is the current level of logging, to avoid unnecessary counting if its results are being logged, we may use:)

logger.IsDebugEnabled;
logger.IsInfoEnabled;
logger.IsWarnEnabled;
logger.IsErrorEnabled;
logger.IsFatalEnabled;

Rezultat
W pliku log-file.txt znajdziesz: (In the log-file.txt you will find:)

2008-04-09 08:26:51,646 [1] DEBUG Program [(null)] - zapisz ten tekst

Podsumowanie: (Summary:)
Jest to tylko krótki opis jak szybko uruchomić log4net w jakiejkolwiek aplikacji c#. Więcej opcji i szczegółów można znaleźć na stronach: (This is only a short description how to start using the log4net quickly in any c# application. More options and details may be found on the following websites:)
Wstęp do log4net
Więcej Appenderów do logowania, m.in. (More appenders for logging, i.e.) ConsoleAppender i EventLogAppender

sobota, 2 lutego 2008

Jakość testów jednostkowych

Testowanie może ujawnić obecność błędów, ale nigdy ich braku. (Dijkstra)

Ostatnio zainteresowałem się automatycznym mierzeniem jakości testów jednostkowych (unit tests). Testy jednostkowe pozwalają na sprawdzenie czy mój kod nie działa niepoprawnie dla przypadków testowych. W żaden sposób jednak nie są w stanie udowodnić, że mój kod w 100% (dla wszystkich możliwych przypadków) funkcjonuje w sposób prawidłowy.

Jednakże jak stwierdzić, że testy, które napisałem są właściwe? Jak stwierdzić, że wyczerpująco sprawdzają zaimplementowaną funkcjonalność? Jak stwierdzić, że sprawdzają mój kod na tyle, ile jest to tylko możliwe? I jak zrobić to w pełni automatycznie? Z pomocą przychodzą metody automatycznego sprawdzania jakości/poprawności testów.

Do tego, aby automatycznie sprawdzić jakość testów jednostkowych, bez wątpienia potrzeba:
  • kodu testowanego - kodu, który zawiera pewną funkcjonalność, którą będziemy testować

  • działających, wykonujących się poprawnie testów jednostkowych dla kodu testowanego.

Spotkałem się z dwiema możliwościami automatycznego sprawdzenia jakości kodu opartymi na:
  • sprawdzaniu pokrycia kodu testami,

  • testowaniu mutacyjnym.

Postaram się teraz w kilku słowach trochę opisać te dwa pomysły na mierzenie jakości testów jednostkowych.

Pokrycie kodu (code coverage)

Instrukcja, zawarta w kodzie, uważana jest za pokrytą, gdy zostanie wywołana przez test przynajmniej jeden raz. Stosunek ilości instrukcji pokrytych do ogólnej liczby instrukcji określa nam procent pokrycia kodu testami. Najlepiej oczywiście gdy wynosi 100%, wtedy mamy pewność, że każda instrukcja została wywołana podczas uruchamiania testów. Często jednak w praktyce za zadowalającą uznaje się wartość w okolicach 80%.

Istnieją jednak pewne czarne strony tej metody. To, że każda instrukcja zostanie uruchomiona w trakcie testów, wcale nie oznacza, że wszystkie możliwe warianty zostały sprawdzone i że kod działa poprawnie. Poniżej krótki przykład ilustrujący taki przypadek.

Weźmy dla przykładu prostą metodę dzielącą dwie liczby i zwracającą wynik dzielenia:
public class SimpleMath
{
public static decimal? Dziel( decimal dzielna,
decimal dzielnik )
{
return dzielna / dzielnik;
}
}

I test sprawdzający działanie tej metody:
[TestFixture]
public class TestSimpleMath
{
[Test]
public void TestDzielenie()
{
decimal? wynik = SimpleMath.Dziel( 4m, 2m );
Assert.AreEqual( 2m, wynik );
}
}

W tym przypadku pokrycie kodu testami wynosi 100%.


Mimo to bardzo łatwo możemy stwierdzić, że dla wywołania funkcji z parametrami 4 i 0 (zero):
 [Test]
public void TestDzieleniePrzezZero()
{
decimal? wynik = SimpleMath.Dziel( 4m, 0m );
Assert.IsNull( wynik );
}

otrzymamy wyjątek System.DivideByZeroException.

Tym samym udowodniłem, że nawet mając pokrycie kodu testami w 100%, nie oznacza to, że kod działa prawidłowo i nie zawiera błędów.

Poprawna metoda Dziel() przechodząca testy dla tego przykładu wygląda następująco:
public class SimpleMath
{
public static decimal? Dziel( decimal dzielna,
decimal dzielnik )
{
if ( dzielnik == 0 )
return null;
return dzielna / dzielnik;
}
}


Testowanie mutacyjne (mutation testing)
Jak pokazałem wcześniej, badanie skuteczności testów za pomocą pokrycia kodu testowanego, nie daje pewności co do poprawności jego działania. Możemy jednak przeprowadzić inne sprawdzenie jakości testów oparte na testowaniu mutacyjnym.

Przebieg procesu testowania mutacyjnego przedstawiony jest na poniższym schemacie:


Cały proces polega na wielokrotnym mutowaniu kodu testowanego, uruchamianiu testów jednostkowych i sprawdzaniu czy po dokonanej mutacji nadal wykonują się poprawnie.

Według mnie jest to nic więcej jak wykorzystanie zmodyfikowanych algorytmów genetycznych. Choć pomysł wygląda na prosty i łatwy, to największą trudnością jest proces mutowania, a największym minusem bardzo długi czas wykonywania testów.


W kilku następnych postach postaram się przybliżyć, "czym to się je" w .NET.