Monday, May 24, 2010

Changing log4net configuration parameters at runtime

Since most of log4net configuration is specified in your application's configuration a question does come up on occasion how may I change this at runtime, depending on the user, etc.
Changing parameters at runtime for log4net is fairly simple - see the following code sample:

///
/// SMTP Appender custom configuration
///

public void InitializeLog4Net()
{
//We need access to the repositories for the loggers
ILoggerRepository repository = LogManager.GetRepository();

//Get only SmtpAppenders
//can do it as such:
//var appenders = repository.GetAppenders().Where(o => o is SmtpAppender).Select(o => (SmtpAppender)o);

//Or a bit more readable
var appenders= from o in repository.GetAppenders()
where o is SmtpAppender
select (SmtpAppender)o;

foreach (SmtpAppender smtpAppender in appenders)
{
smtpAppender.To = "adam_tuliper@nowhere";
//Make this config change active immediately
smtpAppender.ActivateOptions();
}
}


Saturday, May 22, 2010

Setting up RESTful services in Windows XP

If you chance you haven't upgraded or your company still requires XP usage and skipped Vista and is waiting on Windows 7 - you may need to get WCF and RESTful services working together. **Really this applies to any dynamic routing required - it could be pure WCF as well and anything that uses a RouteTable class such as

RouteTable.Routes.Add(new ServiceRoute("YourFriendlyURLPortion", new WebServiceHostFactory(), typeof(CustomerSearch)));


Once you have your project you will need to do the following:
1. Configure IIS to use .net 4 - go into the properties of your virtual directory and then the ASP.Net tab.




2. Setup a global mapping so ALL files get routed to ASP.Net
Right Click on the virtual directory, go to properties, and then to the Virtual Directory tab. Then click on the Configuration button. You will need to map ALL files to your .net 4 isapi dll. Since IIS 5.1 does not have integrated pipeline for .net, ASP.Net sits on top of IIS via an isapi extension.
Select "All Verbs" (or whatever ones you require if you are limiting to say.. only GET/PUT although that violates RESTful design if you also need delete and update operations which require DELETE and PUT verbs)

I have my isapi dll set to:
C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll
In the following image you will see the setup. You must specify .* for the extension (not *.*) otherwise your "OK" button will never enable.






Reset IIS then attempt to go to your service url/help and see if you get the nice new RESTFUL service web page.

Why don't I see my JSON RESTful response in the browser?

When testing RESTful services, one common option is to use JSON (Javascript Object Notation) which can significantly decrease the size of the service response. As we
A quick note on unexpected behavior (at first) when request the SAME url through different means.
If I request to get customer 1:
http://localhost/CustomerSearch/1
GET /CustomerSearch/1 HTTP/1.1


Host: localhost.:1046
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 (.NET CLR 3.5.30729)
Accept: application/json, text/javascript, */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://localhost:2592/
Origin: http://localhost:2592


My response is indeed JSON


HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Sat, 22 May 2010 06:12:06 GMT
X-AspNet-Version: 4.0.30319
Content-Length: 153
Cache-Control: private
Content-Type: application/json; charset=utf-8
Connection: Close

{"DateOfHire":"\/Date(1072933200000-0500)\/","EmployeeId":"dd98655a-8706-4b2f-b648-874079015295","FirstName":"Jane","LastName":"Doe","SSN":"123-45-6789"}



If my request url stays the same, but I change my Accept: header, I no longer get JSON back but instead xml:


GET /CustomerSearch/1 HTTP/1.1
Host: localhost.:1046
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Cookie: ASP.NET_SessionId=yypfhriihodesh553qpmaam4



HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Sat, 22 May 2010 06:12:06 GMT
X-AspNet-Version: 4.0.30319
Content-Length: 153
Cache-Control: private
Content-Type: application/json; charset=utf-8
Connection: Close

My response is indeed JSON
{"DateOfHire":"\/Date(1072933200000-0500)\/","EmployeeId":"dd98655a-8706-4b2f-b648-874079015295","FirstName":"Jane","LastName":"Doe","SSN":"123-45-6789"}

So what is going on here?
In one case Im request via the browser and I get xml back. In the other case I request via jQuery:
$.getJSON

which happily sends over

Accept: application/json, text/javascript, */*

Saturday, May 15, 2010

Eliminating delegates in threading

Just a quick note on threading. One way to start a new thread with parameters was the following:

Thread processingThread = new Thread(new ThreadStart(delegate { someClass.SomeMethod(); }));

processingThread.Start();


One can do the same thing with a lambda expression which in my opinion is a bit cleaner. Why? I don't know - personal preference - I seem to remember lambda syntax more often : )

Thread workerThread = new Thread(
()=> someClass.SomeMethod()(employeeId)
);
workerThread.Start();

Or doing this inline with the start right away:

(new Thread(() =>
{
someClass.SomeMethod()(employeeId)

}
)).Start();



That's all there is to it. Remember in Win32 API when creating threads, and security descriptors, etc? Its so nice and easy in the managed world.