tag:blogger.com,1999:blog-58628706129959088992024-02-07T05:49:25.503+01:00Thoughts on codingJeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.comBlogger36125tag:blogger.com,1999:blog-5862870612995908899.post-71516623421084284212015-07-15T23:34:00.003+02:002023-02-27T22:19:57.912+01:00Beginning with akka.netA few months ago I saw mention of <a href="http://getakka.net/" target="_blank">Akka.net </a>on some blog post. It talked about "actor-based systems" and Erlang, so I kinda ignored it. Until a colleague started talking about it. I read up on it and let the information simmer for a bit.<br />
<br />
Some background: at work I'm responsible for a couple of applications that provide technical provisioning capabilities to multiple order management systems. We started out with one system, but eventually it grew into three systems and a few tools on the side. Since there is some overlap in technical responsibilities I've been thinking about merging them into one.<br />
I'd also like to take this opportunity to make architectural changes to the system. Right now we work with 'requests'. A request fails, we send an error back. I'd like to work with 'orders'. We accept an order and handle it. If there is a technical problem (database down, network failure) we'll keep trying until the order is handled. This would also mean we'd handle these orders asynchronously and we'd need queuing capabilities. Queuing is also useful for the many data migration scenarios we run. Giving customers new services, or changing services on customers. These migrations always cause a lot of pain and I'd like to simply queue them for all customers and have the system work it's way through them. Lastly I'd like throttling capabilities. Many of the back-end systems my systems use are slow and don't handle many requests at once well, so I'd like to throttle these in case of a burst of orders. And last, we have simple load-balanced instances. So scaling up means installing a new instance and adding it to the load-balancer. Even if it's only a single order type that causes the load. I'd like to have better scaling capabilities.<br />
<br />
With these things in mind, my first idea was to use a system based around a message queue server and Windows Workflow. Windows Workflow has nice persistence and waiting capabilities. So I can simply save an order, restart the system and resume processing, or in case of an error, unload the order and try again at a later time. I can also push my requests to the throttled systems through a system that makes sure not too many requests are let through and in the mean time the workflows can simply unload while they wait for their data via a callback.<br />
Now I have experience with Windows Workflow. Albeit an earlier version. Some of the main problems we ran into still exist though: versioning with persisted workflows, tooling for viewing information about the workflows. These problems can be solved, but take a lot of work.<br />
<br />
Then I started thinking about Akka.net.<br />
I watched a few videos, read a few articles and it occurred to me I could also use Akka.net to solve some of my problems. I will cover on how Akka.net will help me in future posts as I intent to document my learning process with Akka.net.<br />
<br />
I would really encourage you to read about Akka.net on their website: <a href="http://getakka.net/">http://getakka.net/</a><br />
It's still under heavy development and at the time of writing version 1.0.3 is the latest. Version 1.1 will be the one I'll be waiting for, but until then I will play with it for one-off tooling projects. And I would also suggest you do the same if you really want to use it. There is a lot to learn and I've noticed actor-based systems kind of collide with how I think about program logic. So it takes a lot of getting used to for me, but I'm positive it'll be worth it.Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-84687756536356406702014-04-04T02:42:00.003+02:002023-02-27T22:21:17.412+01:00RabbitMQ, .NET and SSL: it can actually be easy!So in my <a href="http://thoughtsoncoding.blogspot.nl/2014/03/rabbitmq-net-and-ssl-easier-said-than.html" target="_blank">previous</a> post I explained my troubles with RabbitMQ, a .NET client application and an SSL connection. I got it to work eventually.<br />
As I was playing around with a local install of RabbitMQ I remembered one of the server settings which had triggered a "I should look into this later" thought earlier. It was the SSL option "<i>verify</i>".<br />
Now, according to the <a href="http://www.rabbitmq.com/ssl.html" target="_blank">RabbitMQ SSL setup guide</a>, this value should be set to "<i>verify_peer</i>". I wanted to know what other options are valid and what they do. So a Google later I found out there is another valid value: "<i>verify_none</i>".<br />
Three guesses what this does? Yes, indeed, it removes the requirement of needing a client SSL certificate. *sigh*. Things we would've liked to have known two days earlier....<br />
<br />
So anyway, setting this option means you connect to the RabbitMQ server just like you would to a web site. The connection is protected by SSL and the client doesn't need it's own SSL certificate. So if protecting the communication is the only thing you care about, this settings makes your life a lot easier. Now all you need to do is use an "AMQP://" connection string for an unencrypted connection, or an "AMQPS://" connection string for an SSL protected connection. No other settings are needed on the client side.Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-14009052030202308112014-03-28T03:03:00.001+01:002023-02-27T22:21:24.805+01:00RabbitMQ, .NET and SSL: easier said than doneSo we are currently implementing a RabbitMQ cluster to be part of our infrastructure and we will be communicating with this cluster through .NET clients using the standard RabbitMQ Client for .NET.<br />
Everything worked just fine until we wanted to use SSL on those connections. Then everything went to hell.<br />
<br />
So first the specifics of how we connect. We simply use an AMQP connection string to connect. Setting the Uri property in the ConnectionFactory class:<br />
<br />
<pre>var cf = new ConnectionFactory();
cf.uri = new Uri("amqp://user:pass@172.20.0.72:5671/vhost");
var connection = cf.CreateConnection();
</pre>
<br />
So first I simply set the Ssl.Enable property in the ConnectionFactory to true:<br />
<br />
<pre>var cf = new ConnectionFactory();
<b><i>cf.Ssl.Enabled = true;</i></b>
cf.uri = new Uri("amqp://user:pass@172.20.0.72:5671/vhost");
var connection = cf.CreateConnection();
</pre>
<br />
But it wasn't that simple. This gave me a BrokerUnreachableException with the message "None of the specified endpoints were reachable". The inner exception was an IOException with the message "Authentication failed because the remote party has closed the transport stream.". Followed by long stack-trace ending at: System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest).<br />
<br />
So then I simply followed the instructions presented at the RabbitMQ pages (<a href="http://www.rabbitmq.com/ssl.html" target="_blank">http://www.rabbitmq.com/ssl.html</a>). I imported the root certificate, added the client certificate to the program and tried again:<br />
<br />
<pre>var cf = new ConnectionFactory();
cf.Ssl.Enabled = true;
<b><i>cf.Ssl.ServerName = "clienthost";
cf.Ssl.CertPath = @"C:\client-certs\keycert.p12";
cf.Ssl.CertPassphrase = "password";</i></b>
cf.uri = new Uri("amqp://user:pass@172.20.0.72:5671/vhost");
var connection = cf.CreateConnection();
</pre>
<br />
Same error as before, but now the inner exception has the message: "connection.start was never received, likely due to a network timeout."<br />
Then I noticed something somewhere (can't remember where, probably in one of the RabbitMQ documents) about AMQPS. Sounds reasonable. HTTP -> HTTPS, so AMQP -> AMQPS:<br />
<br />
<pre>var cf = new ConnectionFactory();
cf.Ssl.Enabled = true;
cf.Ssl.ServerName = "clienthost";
cf.Ssl.CertPath = @"C:\client-certs\keycert.p12";
cf.Ssl.CertPassphrase = "password";
<b><i>cf.uri = new Uri("amqps://user:pass@172.20.0.72:5671/vhost");</i></b>
var connection = cf.CreateConnection();
</pre>
<br />
Queue Dennis Nedry....<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://img1.wikia.nocookie.net/__cb20111128234450/jurassicpark/images/5/5f/YouDidn'tSayTheMagicWord.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://img1.wikia.nocookie.net/__cb20111128234450/jurassicpark/images/5/5f/YouDidn'tSayTheMagicWord.gif" /></a></div>
<br />
Then I spend literally three hours of googling trying to find answers, but not one helped. I finally downloaded the source code for the RabbitMQ client (thank god for open source) and stepped through the connection process. That's where I noticed something funny. During the connect, the SSL options appeared to have disappeared. That's when I got an awful realization:<br />
<br />
<pre>var cf = new ConnectionFactory();
<b><i>cf.uri = new Uri("amqps://user:pass@172.20.0.72:5671/vhost");</i></b>
cf.Ssl.Enabled = true;
cf.Ssl.ServerName = "clienthost";
cf.Ssl.CertPath = @"C:\client-certs\keycert.p12";
cf.Ssl.CertPassphrase = "password";
<del>cf.uri = new Uri("amqps://user:pass@172.20.0.72:5671/vhost");</del>
var connection = cf.CreateConnection();
</pre>
<br />
...and it works. Are you effing kidding me?!<br />
Setting the Uri property <i>resets</i> the SSL properties. Even though you cannot specify the SSL properties thought the connection string. So there is no reason for it to be reset like that.<br />
If you take change the connection string back to "amqp://" you will get an exception ("The remote certificate is invalid according to the validation procedure."); even if you set the SSL Enabled property after.<br />
<br />
So I hope this will save you a few hours of frustration. Right now I'm just happy I got it to work.<br />
<br />
UPDATE: <a href="http://thoughtsoncoding.blogspot.nl/2014/04/rabbitmq-net-and-ssl-it-can-actually-be.html" target="_blank">It can even be easier!</a>Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com5tag:blogger.com,1999:blog-5862870612995908899.post-15641506255646412172010-05-19T23:23:00.001+02:002023-02-27T22:21:30.470+01:00Even more Facebook privacy<p>I have a <a href="http://www.facebook.com/" target="_blank">Facebook</a> account. I primarily use it to share funny photo’s and funny links with friends. To me it’s the e-mail of the new millennium. <br />But lately you read a lot of criticism about Facebook’s privacy policy. A nice ‘evolution’ of Facebook’s privacy settings can be found <a href="http://mattmckeon.com/facebook-privacy/" target="_blank">here</a>. It shows how settings are getting less private with each new Facebook update. Then there is also the <a href="http://www.reclaimprivacy.org/" target="_blank">Facebook privacy scanner</a>. I highly recommend everyone giving that thing a try to see where the weak spots are in your Facebook privacy settings.</p> <p>But there is more. It’s not just what people can find out about you when they look you up on Facebook. You should also be concerned about what a website can find out about you when you visit them. Remember the fiasco that was <a href="http://www.25hoursaday.com/weblog/2007/11/27/SomeThoughtsOnTheFacebookBeacon.aspx" target="_blank">Facebook Beacon</a>? Well, there still is something similar I think. The web sites aren’t allowed to post to your news feed, but they might be able to gather information about you.</p> <p>When I recently reviewed my privacy settings, I went to the page where you can see which Facebook applications have which rights. And to my surprise I even saw a few websites I visited recently in that list. I didn’t recall giving them access to my Facebook profile, but there they were. This looks a lot like the “Instant personalisation pilot programme” I also saw in the privacy options. But I have that option turned off.</p> <p>But I found a way to ensure no web site will ever know I’m logged into Facebook. You see, modern browsers offer this extra sandbox for browsing. I use Google Chrome primarily and it offers the “Incognito” option. Internet Explorer offers something similar with “InPrivate Browsing”. I haven’t tested it with Internet Explorer, but when I open Facebook in an “Incognito” window in Google Chrome, that Facebook session is limited to that browser window. I then use another Google Chrome browser window (a non-“Incognito” window) for my normal browsing. That way, when I visit a web site, it’ll never know I am currently logged into Facebook and I have extra privacy.</p> Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com1tag:blogger.com,1999:blog-5862870612995908899.post-20976524999085694062010-03-17T02:22:00.001+01:002023-02-27T22:21:35.752+01:00My WCF service doesn’t generate a WSDL!<p>Recently I added a new WCF web service to an pre-existing application. That application already contained two other WCF web services and was specifically partitioned in that it had the interfaces, data classes and SVC files in separate projects. So I just copied the necessary files from inside the projects and adjusted them to suit my needs, adding many new data classes for the new interface. <br />I compiled to make sure I didn’t have any syntax errors and then I copied and changed the WCF config parts in the web.config.</p> <p>So far so good. The code compiled and I could access the SVC page from my browser. <br />I then started SOAPUI so I could test the web service and pointed it towards the WSDL interface of the new web service. Imagine my surprise when it did find the web service, but not a single method from it. <br />I checked the WSDL from my browser and lo’-and-behold: There were only endpoints in there. No methods and data structures.</p> <p>I re-checked the WSDL, comparing it to another, working, web service we had and it was all correct. Then I went over the SVC, service contract interface and implementation again and I noticed a line similar to this:</p> <pre class="brush: csharp; ruler: true;">[OperationContract(Action="http://my-namespace.com/app/1.0/DoStuff", ReplyAction="*")]
void DoStuff();</pre>
<p>I didn’t know what that “ReplyAction” was about, but that wildcard doesn’t seem right to me. I checked the interface I copied it from and that interface was an older, pre-existing SOAP web service that we added to our app by using the <em>svcutil.exe</em> tool. So that “ReplyAction” was added by that tool.
<br />It turns out that <em>ReplyAction"=”*”</em> means: don’t use a SOAP action in the reply. This has to do with a WCF web service that is building the messages by itself, instead of letting the framework do it for you. This was probably caused by the old web service that didn’t quite fit into the mold WCF has created for us to develop web services in. But since WCF needs to provide us with the ability to create all kinds of web services that are legal according to the SOAP standards, it provides the ability to create the SOAP messages by hand. So when we used the WCF <em>svcutil.exe</em> tool, it determined that it needed to do that for that particular web service. Then when I copied those files for my new web service, I got stuck with the “ReplyAction”.</p>
<p>I removed the “ReplyAction” from the “OperationContract” and after that the web service auto-generated a WSDL just fine.</p> Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com4tag:blogger.com,1999:blog-5862870612995908899.post-88188142934519967092009-12-05T22:41:00.003+01:002023-02-27T22:21:40.810+01:00DataAnnotations in ASP.NET MVC2 without Dynamic Data<p>The last few days I’ve been playing with VS2010 beta 2 and ASP.NET MVC2. I hadn’t done that much with the first version of ASP.NET MVC, but I hope to get some more time to play with version 2.</p> <p>After seeing how easy validation of data input can be in the <a href="http://microsoftpdc.com/Sessions/FT59" target="_blank">PDC video on ASP.NET MVC2 from Scott Hanselman</a>, I wanted to try it out for myself.
I had already started working on an MVC2 project and it used manual validation. So I added the data annotation attributes on the class and….it didn’t work… Turns out that the thing that transforms the HTTP form data into a .NET object, the Model Binder, needs to support it and the default binder is very simple and does not support it. If you talk to a database with the Dynamic Data Framework somewhere along the line a model binder is used that does support it and apparently Scott used dynamic data in his demo.</p> <p>The project I had started was using the ADO.NET Entity Framework which does not have support for data annotations (yet) and I didn’t feel like switching to the Dynamic Data Framework just for the validation.
But then it turns out you can easily(?) write your own binder and make it support the data annotation attributes. Or rather, extend the default binder. I found this at a blog post by Brad Wilson about <a href="http://bradwilson.typepad.com/blog/2009/04/dataannotations-and-aspnet-mvc.html" target="_blank">using data annotations in ASP.NET MVC</a> and it even pointed me to the <a href="http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=24471" target="_blank">sample project</a> he talked about in his blog post.
I downloaded it and tried to build it as a .NET 4.0 project, but since the sample was written for MVC1 and .NET 3.5SP1 I got compiler errors about missing functions at first and when I got it to compile I got a nasty runtime error: </p> <blockquote> <p><em>This property setter is obsolete, because its value is derived from ModelMetadata.Model now.</em></p> </blockquote> <p>The compiler errors about the missing function took some reasoning, but you need the change this code which appears in two places and is slightly different in the second place:</p> <pre class="brush: csharp; ruler: true;">if (!attribute.TryValidate(bindingContext.Model, validationContext, out validationResult))
{
bindingContext.ModelState.AddModelError(bindingContext.ModelName, validationResult.ErrorMessage);
}</pre>
<p>Into this:</p>
<pre class="brush: csharp; ruler: true;">validationResult = attribute.GetValidationResult(bindingContext.Model, validationContext);
if(validationResult != ValidationResult.Success)
{
bindingContext.ModelState.AddModelError(bindingContext.ModelName, validationResult.ErrorMessage);
}</pre>
<p>After some searching for the runtime error I found an answer on <a href="http://stackoverflow.com/questions/1531776/this-property-setter-is-obsolete-because-its-value-is-derived-from-modelmetadat" target="_blank">StackOverflow</a>.
The code discussed in that article is a little different then the code in the binder sample I am using, but it was enough for me to get it to work. Basically you need to change this:</p>
<pre class="brush: csharp; ruler: true;">var innerContext = new ModelBindingContext()
{
Model = propertyDescriptor.GetValue(bindingContext.Model),
ModelName = fullPropertyKey,
ModelState = bindingContext.ModelState,
ModelType = propertyDescriptor.PropertyType,
ValueProvider = bindingContext.ValueProvider
};</pre>
<p>Into this:</p>
<pre class="brush: csharp; ruler: true;">var innerContext = new ModelBindingContext()
{
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => bindingContext.Model, propertyDescriptor.PropertyType),
ModelName = fullPropertyKey,
ModelState = bindingContext.ModelState,
ValueProvider = bindingContext.ValueProvider
};</pre>
<p>And it will work.</p>
<p>Next was finding out how to use it exactly. The blog post about the sample binder would receive the entire model when the function is called on the controller, but my code only received an identifier and I need to get the rest of the data out of the database. So just using “ModelState.IsValid” wasn’t enough in my case. I also needed to call “UpdateModel” to have the binder transform the input data in the .NET object that I use in my code. The problem I ran into there was that upon updating the model, the validation rules would also run and an exception would be thrown when the validation failed. This code gives me the exception:</p>
<pre class="brush: csharp; ruler: true;">[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(string lastName, FormCollection collection)
{
Person person = new Person();
UpdateModel(person);
PersonController.personStore[lastName] = person;
return RedirectToAction("Details", person);
}</pre>
<p>It turns out I should not be using UpdateModel, but rather TryUpdateModel. That allows me to update the model and the validation to fail without resorting to exception handling. Like so:</p>
<pre class="brush: csharp; ruler: true;">[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(string lastName, FormCollection collection)
{
Person person = new Person();
bool isModelValid = TryUpdateModel(person);
if(isModelValid == true)
{
PersonController.personStore[lastName] = person;
return RedirectToAction("Details", person);
}
else
{
person.LastName = lastName;
return View(person);
}
}</pre>
<p>Doing it like that gives me the nice error message I was looking for:</p>
<p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdsP8FBBgfIkxDDgl_SZyUHa9zyh4F-vQ9G-s6zS39n8awdGZiedfxiVcAuXlypUAvyVsSZzmK3okCXU6eueHHCIKD1WGNkzTZfUk0M-SD02ScsBMw6xYqjaljJeWYmG-r-DNeCutz0nc/s1600-h/nice-error%5B5%5D.png"><img style="border: 0px none ; display: inline;" title="nice-error" alt="nice-error" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDvzPH5n-TnWWyOjUXETYAl13Ub5plEG-xBXLykC9_cBWeQu0SCj1c5Unot_xHm9hhFKW9hKWOhcFXCPLG6Tdw9w917eFXUqjF3GQggzQj5TASzh8QFStfskpTQKneMW9Osu9srlF2BwI/?imgmax=800" border="0" height="419" width="640" /></a></p>Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-8751277498873616972009-07-23T13:10:00.001+02:002023-02-27T22:21:46.076+01:00Windows Workflows that restart themselves?<p>A few weeks ago I got assigned a fun bug. We have a WF-based order system and it seems that occasionally orders that had been send earlier would start all over by themselves. <br />And sure enough, when looking at the logging I saw that the order would start over. So how did this happen?</p> <p>First off I noticed it only happened with orders that required a callback in their process. So orders that, at one point or another, would be idle and waiting for an external event. All other orders never gave a problem. <br />Then I also noticed that the orders restarted themselves after the system itself had been idle for around 30 minutes. <br />So workflows that were idle were restarting after 30 minutes of system inactivity. They were re-processed when a new order was sent (you'd then see a whole slew of old orders restarting).</p> <p>Whenever something happens on IIS after around 30 minuted of inactivity I assume it's always related to the fact that after 20 minutes of inactivity (by default) IIS will stop the web service/application to spare resources. The next request that comes in will cause IIS to startup the web service/application again. So it's pretty much safe to assume the problem is related to the web service stopping and restarting.</p> <p>So why would an order start all over again, after the web service is being restarted. The most likely reason would be that the Workflow Runtime was unable to save its state. So without knowing where the workflow left off, but knowing that the worklfow does exist, it seems logical the workflow would just restart.</p> <p>We checked the config and it did have the WorkflowPersistenceService configured and loaded. However, it's "UnloadOnIdle" setting was missing. Meaning it defaults to false. Meaning workflows don't unload when they are idle. And more importantly: a workflow is only persisted when you explicitly tell it to, or when it is unloaded. <br />Since neither happened on our system the workflows never stored their state and restarted when the web service restarted.</p> <p>Of course this was not figured out that quickly. I assumed the operational engineers would use the configuration we'd send them, so I never bothered to check it. If I had, I would have solved this bug in a matter of minutes. Now it took us days of prodding, testing and praying. Until another developer mentioned he had noticed the config looked almost the same, but not quite the same. *sigh*. <br />Bugtracking rule #1: Always check the config!</p> Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-46368769275410471722009-06-13T00:07:00.001+02:002023-02-27T22:21:51.601+01:00EU wants other browsers in Windows<p>The European Union is working on a anti-trust case against Microsoft. They claim that the consumer (of the Windows operating system) has no choice in its browser and only has Internet Explorer because it is bundled with Windows. The EU wants Microsoft to start bundling other browsers (Safari, Opera, Firefox, Chrome) to give the user more choices.</p> <p>I find that an absurdly stupid idea. I can understand that they would want to give people a choice. but let’s face it, most computer users are morons when it comes to computers (no offence). They don’t know anything about computers. Hell, they never updated their software until Microsoft set the default to “don’t ask, just update”. And know they should need to choose between difference web browser? That’s a recipe for disaster.</p> <p>Aside from users not knowing that they want or need, there are also business issues to consider. Let’s say you buy Windows and you choose to install Safari. And now when you visit your favourite web site, Safari crashes every time. Who will you call for support? Well, Microsoft of course. It’s their Windows system you bought and Safari was included with that. So now all of a sudden Microsoft has to offer support for Safari, or Opera, or Firefox, etc.</p> <p>Also, now it appears there is a major security issue with Opera, which you installed because it came with Windows. Who is going to fix that? Not Microsoft, because they don’t make that product. Who are you demanding should fix it? Well, Microsoft of course. Because it came with their Windows system did it not? Can Microsoft guarantee that Opera follows its security guidelines and makes the software as safe as possible?</p> <p>Suppose there was a security issue and Opera fixed it. How are you going to get the security fix? I highly doubt its going to be through Microsoft Update. So the update will probably not be installed automatically by default. And every browser will have its own system for updates.</p> <p>Microsoft also has strict guidelines on how programs look and work. Safari is made by Apple. In all honesty I’ve never used Safari for Windows, but I assume it will look strikingly similar to Safari for Mac OS. I do use iTunes and it looks nothing like a Windows application, because it’s made for a completely different OS. Apple has it’s own user interface guidelines and they are a lot different from the Microsoft guidelines. So now you have out-of-the-box software that looks (and behaves) completely different than all the other software that is installed.</p> <p>So, yeah, I’m not much for bundling different browser with Windows. I would love to present people a choice, but Windows should stick with Internet Explorer. Why not, upon first connection with internet, give people a page that tells them they have a choice in browsers and give them links to different websites for those browsers. But bundling software made by completely different companies with Windows is a stupid idea.</p> <p>And just so you know: I’m a Firefox user and only use Internet Explorer at work, because our intranet doesn’t work correctly with Firefox.</p> <p>PS <br />This is not my original idea, I read it somewhere else, but why give people only the choice between Internet Explorer, Firefox, Safari, Opera and Chrome? Why not all of the <a href="http://www.webdevelopersnotes.com/design/browsers_for_windows.php3" target="_blank">gazillion different web browsers</a> that are out there? Doesn’t seem fair to the little guy. On the other hand Opera is pretty much “the little guy” and since they are furiously trying to get their browser bundled with Windows I really doubt they’re in it for “what’s good for the customer”. As I see it, they just use this to try and increase their market share.</p> Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-40359717923425568292009-02-20T00:10:00.001+01:002023-02-27T22:21:58.747+01:00Error loading workflow<p>Have you ever seen an error message like this when developing a Windows Workflow application?</p> <p><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="ErrorLoadingWorkflow" border="0" alt="ErrorLoadingWorkflow" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPdwLZpZQcOEEP-1gBzshrZruarUIjBXKDbKOaHRCwNFr-P3Vxa31pC4j4neAQ2KgvbvvHxVuu2_XXCFLcdTnHw6okJ6gkXy5prd97uOHU79ujsqTVu7NvqHnS4nk7gfxuCwPS52YYtgk/?imgmax=800" width="804" height="115" /> </p> <p>I have. Lots of times.</p> <p>I’m not sure what is causing this. We have a project that contains the workflow and we have several other projects that contain the activities we use. Also we do a little inheritance, where all workflow inherit from a base workflow and all activities inherit from a base activity. The only thing they inherit are properties and functions. We do not have a basic workflow with activities which other workflow then add to. Although I would really love to have that!</p> <p>So far I discovered two possible <strike>solutions</strike> workarounds:</p> <ol> <li>Rebuild the projects containing the workflow classes.</li> <li>Restart Visual Studio.</li> </ol> <p>Solution #1 is preferable, because otherwise, if you have a large solution, the time it takes for Visual Studio to load your solution can get really annoying. So what I did was create a simple small MSBuild script that cleans and then builds all my workflow project. It starts by cleaning the projects and then builds the projects. First building the projects containing the activities and then the projects containing the workflows. Most of the time that worked for me. And you don’t even need to close anything. You can even keep the workflow designer open with the error message showing. After the build it will refresh and if successful the workflow will be shown.</p> <p>But sometimes that does not work. Then I would have to quit Visual Studio, run my build script and open Visual Studio again.</p> <p>It’s also very possible that you have a genuine problem or bug. It is pretty easy to create a situation where you end up being unable to open the workflow in the workflow designer and you’ll have to edit the code-behind file by hand.</p> <p>Now I’m sure that our inheritance aggravates some of the problems as inheritance isn’t officially supported in Windows Workflow (although I heard they might have something for that in WF 4.0, but I haven’t checked that out yet), but I suspect you’ll run into these problems every now and then even if you do not use inheritance.</p> Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-89039597399536469132009-01-31T18:02:00.001+01:002023-02-27T22:22:02.550+01:00Seeing a workflow in the database doesn’t mean it’s persisted<p>At work we are building a big application that uses Windows Workflow. We are delivering versions to Test at certain milestones so we don’t have to build everything first before we can see how good we built it.</p> <p>We ran into an interesting issue I want to share. But first let me tell you about some technical details. As I said, we use Windows Workflow to use workflows in our application. The application receives an order (through a webservice), does dome checking and authenticating and then finds the correct workflow to handle the order and start that workflow. The workflows we make inherit from a base class. This base class contains 2 or 3 dependency properties that every workflow should have (such as the order data) and also contains some methods that every workflow can use. We also have a base class for some activities, but these mainly contain methods that most other activities will need. A workflow also needs to implement a certain interface, so we can load all the workflows with our Dependency Injection container and can determine which interface we need for which order.</p> <p>So far so good, aside from some other problems I want to blog about soon it all seemed to work perfectly. Our first milestone was a couple of simple workflows that started, did some stuff and ended. Nothing special and they worked perfectly. If you used <a href="http://msdn.microsoft.com/en-us/library/ms741706.aspx" target="_blank">Workflow Monitor</a> to look in the database you’d see the workflow. So to us that meant the workflow was successfully persisted.</p> <p>Then for the second milestone we created a bunch of more complex workflows. These workflows did a call to a webservice and had to wait on the call-back from that webservice. In workflow this is handled very easily using the ExternalDataExchangeService and the HandleExternalEventActivity. We coded it up and started testing.</p> <p>When the call-back came in, some stuff happened like validation, and eventually the call-back data came to the part where we’d ask the workflow runtime to give use a pointer to the workflow instance that’s waiting on the data and then use the ExternalDataExchangeService to deliver the data to the workflow so it can go on with it’s process. But instead of just working, the workflow runtime told use that the requested workflow couldn’t be found in the persistence store. We checked with the Workflow Monitor and we saw the workflow. It’s status set to running (or idle). But the runtime insisted it was not there.</p> <p>Huh??</p> <p>I did some digging and finally noticed an error in our log files. Some error about an interface not being serializable which caused the persistence to fail. Turns out that what we see in the Workflow Monitor is Workflow Tracking and not Workflow Persistence. In fact, unless you explicitly tell it to do so, workflows will not be persisted. You can either explicitly tell the Workflow Runtime to persist your workflow, or you can use some activity that will cause it to be persisted. Which is what (as far as I know) most activities do that will cause your workflow to be paused. So in our first milestone nothing caused the workflow to be persisted, but in our second milestone we caused the workflow to pause at the HandleExternalEventActivity which meant the workflow had to be persisted, which then failed.</p> <p>So what was the problem? Well, <u>all</u> fields and get+set properties on a workflow or activity have to be serializable. So it must have the <em><font color="#0080ff">[Serializable]</font></em> attribute tacked onto its class or interface and onto every class or interface that is inside that class or interface. Since we set up some references to some logic classes (Logging Service, Order Service, etc) in the base class, they would also need to be serializable.</p> <p>We solved the problem by refactoring all the service fields into read-only properties (‘get’ properties) and not store the reference in the workflow or activity, but rather ask our Dependency Injection container each time we need one through a static method. <br />We also removed some other classes that where stored as private fields and just instantiate them within a method as they are needed and a few classes were made serializable.</p> <p>The biggest downside of this is that Windows Workflow demands a very strict versioning scheme, so this means that we now have a few more assemblies that require careful versioning.</p> Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-64933687741406767792009-01-16T03:09:00.001+01:002023-02-27T22:22:06.495+01:00Application configuration in the database<p>Recently K. Scott Allen posted an article called <a target="_blank" href="http://odetocode.com/Blogs/scott/archive/2009/01/11/12429.aspx">App Configuration and Databases</a>.</p> <p>His conclusion is:</p> <blockquote> <p><em>The database should be one of your last choices as a repository for configuration information. Configuration in code is easily tested, versioned, changed, and refactored. As Jeff said – only a specific requirement should drive you to a more costly alternative like the database.</em></p> </blockquote> <p>I humbly disagree. We used to put are configuration into the web.config or our projects. This was easy, but had two down sides:</p> <ol> <li>Whenever we release a new version it’s best our operations guys overwrite to old config, because we might have changed some values in there that they should not mess with. Things like configuration for our DI containers, or WCF settings. They do need to copy the settings from the old config into the new one and that takes time and there is chance of error, especially if you have large config files. </li> <li>It’s impossible to do “hot-configuration”. If you change the web.config, IIS will restart the web application. This is not a big issue, but did cause some problems once or twice.</li> </ol> <p>As for configuration in code I see the following problems:</p> <ol> <li>We use OTAP (separate environments for Development, Test, User Acceptance and Production), this mean that we’d either have to create different “configuration DLLs” for our different environments or that we’d need to have code that detected what kind of environment the application ran in and use that to determine the correct configuration.</li> <li>If you’d need a configuration change, you’d need a developer to check-out code, change it, check it back in and deliver the code to test. Test would need to run al kinds of tests and when all done deliver the application to operations for installation. Configuration in a separate file, or database is something the operations guy can do himself.</li> <li>We, as developers, don’t have access to production machines. Security regulations dictate we should not know passwords to production environments, so we couldn’t even create the configuration DLLs.</li> </ol> <p>Of course these concerns can all be addressed, but we decided it was better to use a database.</p> <ul> <li>If the configuration is in a database, the application (and it’s associated web.config file) can be overwritten without problems. (Of course some values would need to be copied, but they would only be a few).</li> <li>We can provide the application with default configuration values and the tester can change them for the test environment. The guy from operations can change them into the production values.</li> <li>If you’re doing load balancing on the application it’s possible to reuse the same configuration database (might not be practical for some systems, but it is a possibility).</li> <li>It’s easy to add a configuration page to an administration web application that we’ll probably need to build anyway.</li> </ul> <p>So all-in-all it seems like the best solution for us (for the moment), but that’s largely because of the way we work. Your company may use other methods which might not make configuration in the database the best choice, but I don’t think it should be the last choice.</p> Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-80274441676582474662009-01-06T22:46:00.002+01:002023-02-27T22:22:10.387+01:00SOAP logging for webservices<p>If you wish to log incoming SOAP requests to your ASMX webservice, you can write a SOAP extension that does just that.</p> <p>You’ll need to create a class that inherits from <em>SoapExtension</em> and you should override the methods <em>GetInitializer</em>, <em>Initialize</em>, <em>ChainStream</em> and <em>ProcessMessage</em>. <br />It’s not that hard, you can find an working example at the MSDN site: <a href="http://msdn.microsoft.com/en-us/library/bb552923.aspx" target="_blank">How to: Implement a SOAP Extension</a>. It works for both the server (who accepts incoming SOAP requests) and a client (who sends SOAP requests to servers).</p> <p>All you need to do is add this to your web.config (or app.config) and it will work:</p> <pre class="xml" name="code"><system.web>
<webServices>
<soapExtensionTypes>
<add type="MySoapLogger, MyNamespace.SoapLogger" priority="1" group="High" />
</soapExtensionTypes>
</webServices>
</system.web></pre>
<p>If you wish to create a SOAP logger for a WCF webservice, that’s both easier and harder. It’s simpler to write the extension for, but now you must write different things for a server and a client. And making it configurable requires some more work then the ASMX version.</p>
<p>In WCF you don’t write a SOAP Extension, but rather a Message Interceptor. And you won’t need to inherit from a base class, but you’ll need to implement certain interfaces to make it work.
<br />To be able to see incoming (server) messages you’ll need to implement <a href="http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.idispatchmessageinspector.aspx" target="_blank">IDispatchMessageInspector</a> and for outgoing (client) messages you’ll need to implement <a href="http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.iclientmessageinspector.aspx" target="_blank">IClientMessageInspector</a>. It's worth mentioning that nothing prevents you from implementing these interfaces both on the same class. That's what I did.</p>
<p>Both interfaces require you implement two functions:</p>
<pre class="c#" name="code">object IDispatchMessageInspector.AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext);
void IDispatchMessageInspector.BeforeSendReply(ref Message reply, object correlationState);</pre>
<p>And:</p>
<pre class="c#" name="code">object IClientMessageInspector.BeforeSendRequest(ref Message request, IClientChannel channel);
void IClientMessageInspector.AfterReceiveReply(ref Message reply, object correlationState);</pre>
<p>For IDispatchMessageInspector you have AfterReceiveRequest for when the request is received, before your normal code will run and BeforeSendReply, which is directly before the response will be send to the requester, after all your normal code has run.
<br />For IClientMessageInspector you have BeforeSendRequest which is right before the request is send to the server, after all your normal code has run and AfterReceiveReply for when the response from the server has been received, before your normal code will run.</p>
<p>Basically you can do anything to the request you want at those points, even alter the data. One of the examples I found was to validate incoming requests to an XSD. Another was to do some translations for backwards compatibility sake. But in this case we just want to log the data.</p>
<p>So what we can do in each of these functions, is the following:</p>
<pre class="c#" name="code">try
{
// Only try to parse the message if it is not empty.
if(message.IsEmpty == false)
{
string xml = message.ToString();
XDocument xmlDocument = XDocument.Parse(xml);
StringBuilder sb = new StringBuilder();
XmlWriter writer = XmlWriter.Create(sb, new XmlWriterSettings { Encoding = Encoding.ASCII, Indent = true });
xmlDocument.WriteTo(writer);
writer.Close();
sb.Append("\r\n");
this.soapLogger.Log(sb.ToString());
}
}
catch(Exception e)
{
if(System.Diagnostics.Debugger.IsAttached == true)
{
System.Diagnostics.Debugger.Break();
}
}</pre>
<p>In this case the "message" variable contains the SOAP message. I wrote one function to do the logging and have it called from the 4 functions mentioned above. Also the "soapLogger" class variable is the logger I use. It's not particulary important which logger this specifically is, but if you want to know, I use Log4NET.</p>
<p>The use of the XDocument and the XmlWriter is absolutely not necessary, but I use them to make the XML look pretty (indented) in the log. It is a lot slower then just directly logging it to the logfile, but that would result in the whole XML message to appear on 1 line.
<br />The stuff in the try/catch clause is a neat trick I use to catch the unexpected exceptions.</p>
<p>If you want the most simple solution, you can also do it like this:</p>
<pre class="c#" name="code">// Only try to parse the message if it is not empty.
if(message.IsEmpty == false)
{
string xml = message.ToString();
this.soapLogger.Log(xml);
}</pre> Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-87143590209696918152008-12-29T14:50:00.001+01:002023-02-27T22:22:14.794+01:00XML element order in WCF<p>Call me old-fashioned, but I’ve always held to the belief that in XML nesting is very important and order should never be important. I’ve always found it unbelievably stupid when some application depended on the order of elements in an XML document. To me XML is all about representing structured data, not about a rigorous document layout.</p> <p>Imagine my surprise when I started testing my new WCF webservice with a request I wrote by hand. All of a sudden a member was left <em>null</em> no matter what I did. Because it was the last element in my hand-written request that remained <em>null,</em> my first though (after extensively verifying I didn’t make any typo’s) was that, maybe, for some obscure reason, the last member didn’t get deserialized correctly. So I put another member last and indeed it was also <em>null</em>. Then I put another member last and al of a sudden all where filled, except for the first one.</p> <p>After a few hours of WTF?!! I found out that the ‘default’ serializer for WCF, the Microsoft favourite, the “Data Object Serializer” has a dependency on XML element order. After changing the serializer to the “XML serializer” (just remove the “DataContract” attribute from the classes and the “DataMember” attributes from the members of those classes and replace then with the “Serializable” atttribute and/or any of the “Xml*” attributes from the “System.Xml.Serialization” namespace and tack the “XmlSerializerFormat” attribute on the class that contains your WCF methods) it all just worked! Order wasn’t important anymore, as it should be.</p> <p>What I don’t get is why Microsoft would promote the “Data Object Serializer” as the preferred methods for WCF. The “XML Serializer” is much more flexible if you want to control what the resulting XML document should look like and XML element order doesn’t matter! The only advantage to using the “Data Object Serializer” is that it doesn’t serialize members of classes that do not have the required attribute (opt-in instead of the opt-out method of the “XML Serializer”) and that you can serialize private members, which can come in handy from time to time. But it has a dependency on XML element order!!</p> Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-76444092518133902382008-12-03T20:18:00.000+01:002023-02-27T22:22:19.312+01:00Terribly busyIt's been a while since I last posted anything. I've been <span style="font-weight: bold;">extremely</span> busy at work. We're currently nearing the first milestone of a very ambitious project. I'm not a 100% sure we'll make the deadline, but we're doing the best we can.
We're currently using WCF and Windows Workflow. While the WCF is very basic, just a webservice to accept requests to do stuff, the WF stuff is more interesting, so I hope to be able to post more about that later.
Ccurrently I'm trying to implement a SOAP logger. We had one for our ASMX webservices, but since we use WCF now we can't re-use it. According to some blogs I found on the subject creating one is easier then it was for ASMX webservices. But I haven't got it running yet. As soon as I have, I'll detail it here.Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-37438931935793419172008-09-02T20:09:00.001+02:002023-02-27T22:22:23.943+01:00LINQ is faster then it looks<p>I was recently working on a LINQ query. I needed to get some information from a database table and I needed to know if certain information regarding the information I just retrieved from that database table was available in one of two other database tables. I wasn't interested in the information itself, just whether or not there was information. Basically I needed to return some stuff and two boolean's.</p> <p>I couldn't get it to work in one single query, so as always I turned to my colleague who knows a helluva lot more about database and SQL than me and asked him for help. Since he doesn't know LINQ he asked me the SQL that LINQ creates for the query so he could use that as a starting point. So I fired up <a href="http://www.linqpad.net/" target="_blank">LINQPad</a> and generated the SQL.</p> <p>The SQL LINQ produced for my particular query was a lot of selects. It was selects within selects within selects within selects with a "Case-Then" with selects. So, understandably, my colleague expressed his disgust with the SQL and then proceeded to give me a very lean-and-mean query that did exactly what I wanted. I updated my existing LINQ query to use some of the SQL stuff he used in creating the query and my LINQ query gave the exact results I wanted. I was happy, but my colleague wasn't.</p> <p>My colleague wanted the final SQL as produced by the LINQ query that I had now, so I went into LINQPad again, generated the query and send it to him. This time LINQ had added another level of selects and after seeing the query my colleague went on a rant about how bad LINQ was and how much performance we'd lose if we'd use it. I wasn't worried. This particular project I was working on was not a high-profile application, but rather an internal tool for supporting some testers. So as long as I got an answer from the SQL Server within 1 second I was happy. My colleague wasn't. He wanted to know exactly hoe much performance was lost on this LINQ nonsense.</p> <p>My colleague took the SQL query he handcrafted into perfection over 30 minutes time and took the bloated SQL Query that LINQ produced for the query I created in less then 5 minutes and ran them both through the SQL Server Profiler. Then his heart stopped. According to the SQL Server Profiler both queries took exactly the same time, in fact <strong>both queries resulted in exactly the same execution plan</strong>!</p> <p>Again this was just a reminder of something I mentioned before: <a href="http://thoughtsoncoding.blogspot.com/2008/06/counter-intuitive-optimisation.html" target="_blank">Don't guess about performance. Measure!</a> And also, the SQL Server Query Optimizer is pretty bad-ass :-)</p> Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-30234033330682341182008-08-20T00:11:00.001+02:002023-02-27T22:22:27.802+01:00Problems with Visual Studio 2008 SP1<p>I installed <a href="http://thoughtsoncoding.blogspot.com/2008/08/visual-studio-2008-service-pack-1.html" target="_blank">VS2008 SP1</a> the week after it came out. I used the prepare tool first, then installed the service pack and everything seemed to work perfectly. I haven't really checked out all of the new features, but I really like the fact that all the TODOs in your solution now show up, in stead of only the TODOs in the files you currently have opened. And I also like the VB-esque background compiling (or however they implemented it) and showing you selected compiler errors before you compile. If you create a function that returns a value, but haven't put in the return statement yet, the IDE will already inform you that the function doesn't return a value. </p> <p>So all was fine and perfect, until I tried to debug an ASP.NET application. Then the IDE would freeze and prompt me with a window that told be VS2008 had an internal error and must close. I could then close VS2008 or close it and look for a solution online. Whichever I would choose, the window would disappear, but VS2008 would remain, taking up 100% CPU on one core. The other core would be pwned by WerFault.exe and it would not end until I'd manually end-tasked DevEnv.exe.</p> <p>I had my ASP.NET development set up to use IIS, so I switched so Cassini (the internal ASP.NET development server), but that didn't work. I then tried to run the application from IIS again and attach the debugger. Still hanging. <br />I then searched on Google for a bit and tried some work-arounds for similar problems I found there, I also tried the repair option in the VS2008 installer, but debugging still hung the IDE. So I reported it at <a href="http://connect.microsoft.com/" target="_blank">Microsoft Connect</a> and went home (I was at work at the time).</p> <p>That evening at home I completely removed VS2008 and everything related from my laptop and reinstalled it. I verified debugging worked and when it did I installed SP1 again. But this time debugging kept working. So I have no idea what was wrong, but it's all working again now. So if anyone runs into similar problems, just uninstall and install again.</p> Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-79925764387322885012008-08-16T01:54:00.001+02:002023-02-27T22:22:31.867+01:00Visual Studio 2008 Service Pack 1<p>VS2008 SP1 is out and you should download and install it. It's got <a href="http://support.microsoft.com/kb/950263/" target="_blank">major improvements</a>. And it *finally* has the feature I requested somewhere around Visual Studio beta 2:</p> <p><em>"In earlier versions of Visual Studio, the task list is populated by using the ToDo tasks that are specified in open files. In this service pack, the Visual C# IDE extends this functionality. The Visual C# IDE populates the task list by using the ToDo tasks that are specified in the whole solution."</em></p> <p>Of course I'll have to see it before I believe it :-) I'm currently downloading the <a href="http://www.microsoft.com/downloads/details.aspx?familyid=27673C47-B3B5-4C67-BD99-84E525B5CE61&displaylang=en" target="_blank">VS2008 SP1 ISO image</a>.</p> <p>Oh, and if you're going to install SP1, don't forget the run the <a href="http://www.microsoft.com/downloads/details.aspx?familyid=A494B0E0-EB07-4FF1-A21C-A4663E456D9D&displaylang=en" target="_blank">Service Pack Preparation Tool</a> first. This might safe you some hassle of conflicting hot fixes or betas.</p> <p><strong>Update:</strong> Don't forget the <a href="http://www.microsoft.com/downloads/details.aspx?familyid=ab99342f-5d1a-413d-8319-81da479ab0d7&displaylang=en" target="_blank">.NET 3.5 Service Pack 1</a>!</p> Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-64569222945303036002008-08-09T14:36:00.001+02:002023-02-27T22:22:35.765+01:00Open source is not more secure by default<p>This week a rather interesting announcement was made in light of the Black Hat security conference. Some researcher claimed to be able to <a href="http://neowin.net/news/main/08/08/08/vista39s-security-rendered-completely-useless-by-new-exploit" target="_blank">bypass all of Windows Vista enhanced security features</a> through Internet Explorer by using Active-X, Java or .NET. They also claimed that Microsoft couldn't do anything to fix it, because it abused core architectural assumptions made by Microsoft.</p> <p>This is pretty disturbing, but I'm waiting for an official Microsoft response. I recall something similar in the past and then Microsoft was able to patch it up. I just can't for the life of me remember what that was, so maybe I'm just imagining things.</p> <p>This message also spurred some interesting discussions on forums around the world. A lot of people are expressing their "expert" opinion on the matter. And on public forums everyone is a die-hard kernel developer of course. The most interesting discussion that came up again was the notion that open source is more secure, because everyone can look at the source and fix bugs.</p> <p>I've always found this idea to be naive. First of all, just because everyone can look at the code, doesn't mean everyone will. I'm a programmer, but I never look at any of the source code provided by open source applications, unless I want to see how they implemented a certain feature so I can use it too somewhere. But sure, there are bound to be enthusiasts who will review the code. And they will find an occasional bug, but will they find all the security bugs? Of course not, why should they? Are they all software security experts? No. I think these "extra reviewers" are more likely to find typos then actual security bugs. I'd rather put my faith on static analysis tools to detect common errors and security researchers that try to break an application then a hobbyist security "guru".</p> <p>I think the strength of open source lies in the fact that everyone interested can pitch in, but not because every user is a security reviewer.</p> Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-48029895940716436712008-08-01T01:27:00.001+02:002023-02-27T22:22:39.793+01:00SecuROM strikes again<p>I've posted about DRM before and I've mentioned <a href="http://thoughtsoncoding.blogspot.com/2008/06/i-never-liked-drm.html" target="_blank">SecuROM</a> before. So today I was uninstalling a program that left a shortcut on my desktop. So I wanted to right-click on it and delete it. But when I right-clicked on it, Explorer crashed. Thinking it might be a fluke I tried again and Explorer crashed again. Hmmm...so I figured that it might be the shortcut itself, so I selected it and pressed "delete", but...Explorer crashed again. So I opened a command prompt and deleted the shortcut from there. That worked.</p> <p>Then I right-clicked another shortcut and Explorer crashed again. Clicked another shortcut and Explorer crashed. So I rebooted Windows to solve the problem, only it wasn't solved. Explorer still crashed if I right-clicked a shortcut.</p> <p>I suspected it might have something to do with Shell Extensions. And when I googled the problem I found a program called <a href="http://www.nirsoft.net/utils/shexview.html" target="_blank">ShellExView</a>. This program shows you all the Shell Extensions that are currently loaded and let's you disable them. So I started the program, selected all the "Context Menu" type extensions and tried to disable them. Nothing happened. I figured it might be because I wasn't running the program as administrator.</p> <p>So this was interesting. I couldn't run the program as administrator by right-clicking on it (that would just crash Explorer), the CTRL-Shift-Enter method of starting an elevated program would also cause Explorer to crash, so I had a problem. But then I remembered something about how Vista determines when to elevate a program even when it's not asked to. You see for installers you'd need to run them elevated or they wouldn't be able to install anything, but older installers won't have a manifest that Vista can use to determine they need elevation. I read on one of the many developer blogs I read, that Vista can also decide to elevate based on the name of the executable. So I renamed "shexview.exe" to "shexviewsetup.exe" and I got a nice elevation prompt.</p> <p>So I disabled all the "Context Menu" extension and tried to right-click a shortcut. No crash. Great! But which extension caused the problem. I wanted to enable them all one-by-one when I saw an extension that I immediately suspected of being the culprit. The extension was called "CmdLineContextMenu Class" and it's description read: "SecuROM context menu for Explorer."</p> <p>Why would I need a SecuROM extension installed? What does it do? And why was it installed without my consent? The only thing I installed right before I started noticing crashes was the new <a href="http://www.fileshack.com/file.x/12628/Space+Siege+Demo" target="_blank">Space Siege demo</a>. But why would you want a freely available demo to have copy protected? Oh wait, it's <a href="http://www.gamingbob.com/2007/08/23/bioshock-installs-rootkit-including-demo/" target="_blank">not the first time</a> they've done that. But I already uninstalled Space Siege so why wasn't SecuROM removed? Why would companies want to leave a rootkit behind on my system? Then again, I'm not absolutely sure it came from the Space Siege demo (<strong>UPDATE:</strong> it didn't, see below), but it was the last thing I installed before Explorer started crashing. I tried looking in the installer files of the demo, but those are InstallShield cabinet files and I can't look into them.</p> <p>Aside from being some nasty piece of DRM, the extension was installed in a very peculiar location. Not in "Program Files" or maybe the "Windows" directory like you'd expect. No, it was installed in the temp directory of my user profile! It's called "CmdLineExt.dll" and when I looked in the temp directory I also noticed the file "drm_dyndata_7370010.dll" of which the file details also mentioned being part of SecuROM.</p> <p>Ofcourse the question is, why did it crash? Now I'm happy it did, otherwise I wouldn't have found out, but I'm still curious as to why it crashes Explorer whenever I right-click a shortcut. <br />I'm a big fan of <a href="http://blogs.technet.com/markrussinovich/" target="_blank">Mark Russinovich</a>'s blog and his "The case of..." series of blog post. I have WinDBG installed, however I'm mainly a C# developer and have not done any real Win32 C++ programming for years and even when I did, it's wasn't at the low level that Mark understands. But, I did do some basic stuff with WinDBG.</p> <p>I attached WinDBG to Explorer, I enabled the extension and I made Explorer crash. So now I'm in WinDBG and it's telling me Explorer has crashed. I run the <em>!analyze</em> command and I get the following feedback: <em>"Probably caused by : heap_corruption ( heap_corruption!heap_corruption )"</em>.</p> <p>I get the callstack and I see these as the last lines:</p> <p><em>77b39790 04800fd8 00250000 ntdll!DbgBreakPoint <br />c0000374 77c4c030 000ee1ac ntdll!RtlReportCriticalFailure+0x2e <br />00000002 77b39754 00000000 ntdll!RtlpReportHeapFailure+0x21 <br />00000008 00250000 04800fd8 ntdll!RtlpLogHeapFailure+0xa1 <br />00250000 00000000 04800fe0 ntdll!RtlFreeHeap+0x60 <br />04800fe0 000ee408 00000000 kernel32!GlobalFree+0x47 <br />000ee240 00000001 04800fe0 ole32!ReleaseStgMedium+0x124 <br />WARNING: Stack unwind information not available. Following frames may be wrong. <br />03d41cdc 00000000 0030db98 CmdLineExt!DllUnregisterServer+0x3c1c <br />02640e60 0030db98 00000004 SHELL32!HDXA_QueryContextMenu+0x1b5 <br />055c2ee8 00f902ef 00000000 SHELL32!CDefFolderMenu::QueryContextMenu+0x38b</em></p> <p>Looks about right, although I can't be absolutely sure since I don't have de debug symbols for the SecuROM DLL.</p> <p>So looking at the stacktrace I get the idea the SecuROM extension is trying to free some object COM twice. I don't know what object and I don't know why, my low-level knowledge ends about here. I'm just happy I found the problem and make my system right-clickable again.</p> <p>Oh and one interesting thing I've learned tonight. When you have Explorer.exe crashed in the debugger, you can't use ALT-TAB (which wasn't unexpected), but you <strong>can</strong> use WIN-TAB (Flip3D). That made switching back and forth between windows a whole lot easier.</p> <p><strong>UPDATE: <br /></strong>It apears it wasn't the Space Siege demo that infected me with the DRM rootkit, it was the <a href="http://masseffect.bioware.com/forums/viewtopic.html?topic=643285&forum=127" target="_blank">Mass Effect 1.01 update</a> that did. I installed it, but installed the Space Siege demo right after it. So even though I did't get infected by their rootkit the <a href="http://thoughtsoncoding.blogspot.com/2008/06/i-never-liked-drm.html" target="_blank">first time</a>, I was stupid enough to fall for it anyways.</p> Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com2tag:blogger.com,1999:blog-5862870612995908899.post-7681892031029713222008-07-23T02:39:00.001+02:002023-02-27T22:22:43.434+01:00Save your Visual Studio window layouts<p>Before I had my <a href="http://thoughtsoncoding.blogspot.com/2008/07/windows-server-2008-on-laptop.html" target="_blank">nice new laptop</a> I had a normal desktop for work. It had two monitors so when I worked, I spread the windows of Visual Studio to cover both screens and give me maximum working space. If I worked from home I would connect to my work desktop using Remote Desktop and work like that. The problem was that this only gave me one monitor so I had to readjust the window layout for single-monitor usage. If I then would go to the office the next day, Visual Studio would still be in single-monitor window layout from the day before and I would have to drag all the windows around to get my dual-monitor layout back.</p> <p>Now I have a nice laptop, so whether I work from home or in the office, I use the same machine. But I still have two monitors at work and only one at home. So even though I drag my PC with me everywhere, I still have the window layout problem.</p> <p>Two or so years ago I discovered the <a href="http://www.codeplex.com/VSWindowManager" target="_blank">VSWindowManager</a>. This is a plug-in for Visual Studio that allowed you to save up to three profiles of different window layouts. You could then add three buttons to your toolbar to access those profiles. It did exactly what I wanted, but I still had two minor issues with it. First I couldn't rename the buttons, so I had to remember which button mapped to which layout. This wasn't that big of a problem. Secondly, and this was much more annoying, if you clicked the button of the profile you had currently loaded, it would save the window layout into to profile. So if I would come at work after having worked from home and I accidentally clicked the wrong button while trying to restore my dual-monitor layout, I would overwrite that layout with the then current single-monitor layout and I would have layout all the windows by had again.</p> <p>If you look at the VSWindowManager project, it was last updated in September 2006. Now I do most of my work in Visual Studio 2008 and the plug-in doesn't work on this newer version. Sure, someone downloaded the source and got it to work for VS2008, but it didn't feel good to me if the original author had abandoned the project. So it was back to doing stuff by hand.</p> <p>Earlier tonight I got fed up with it and decided to find a solution (again). I hoped that maybe someone else had written a similar plug-in. Instead, I found something way better. After googling a little, I came upon this MSDN article titled: <a href="http://msdn.microsoft.com/en-us/library/bb245788(vs.80).aspx" target="_blank">Visual Studio 2005 IDE Tips and Tricks</a>. It has a section specially dedicated to <a href="http://msdn.microsoft.com/en-us/library/bb245788(vs.80).aspx#vs05idetips_topic2" target="_blank">saving window layout</a> and it provided a very simple solution to my problem. It uses the possibility to export user settings, together with a small macro to achieve exactly what I need.</p> <p>Basically it works like this. You start by laying out the windows the way you like it. Then you export your IDE settings using the "Import and Export settings wizard", but in this wizard you can specify exactly what settings you want to export. So you choose only to export your window layout. You save the settings file in a known and accessible location (like your profile or documents folder) and name it so you know what settings these are. Then you create a new macro using the built-in macro editor. This macro will simply import the settings file. And since you only exported your window layout, this is the only setting that will be changed. So I can make a macro for my single-monitor setup and another macro for my dual-monitor setup. I can then add these macros to my toolbar and give them any icon and name I want.</p> <p>Multi-/single-monitor problem solved!</p> Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-66010288720317645012008-07-12T18:53:00.001+02:002023-02-27T22:22:47.975+01:00Code reduction through generic methods<p>I've build and now maintain a webservice application at work. The application has around 40 webservice functions and earlier this week I had to dive into the application again because of some issues. It occurred to me how redundant all the code in the webservice functions was. I'm talking about the top-level code, the stuff in the *.asmx.cs files.</p> <p>In this application the code there deals with input validation, authentication/authorization and sending back the results of the operation (success or error data). So most of the code in those ~40 functions is basically the same. The only thing that differs each time is the specific business logic that the function offers to the world, but that logic is nicely abstracted from the interface part of the application in the business logic part of the application so it's only a few lines of code in each top-level function to setup and call that specific handler. The main code of each function is stuff that each and every function needs to do. All copied and pasted. That can be done better.</p> <p>I started off by creating a base class from which all webservices should inherit. This base class would provide the functions for input validation (each input object now implements an IValidating interface that is called so the object can basically validate itself) and authentication/authorization. This still left behind a large chunk of code (large chunk being relative here. It was no more then 18  lines of code, but for most functions that was still more then 50% of code in that function). The problem is that each separate webservice function returns a specific return type based on the function itself. A function called "CreateAccount" returns a "CreateAccountResult" object, a function called "SetOptions" returns a "SetOptionsResult" object, etc. So it's not possible to write a helper method, or a method in the base class like I could with validation code or the authentication/authorization code. But then I remembers generic methods.</p> <p>I don't understand why I've never done these optimizations before. I've used generic methods years before in C++ and I know it was possible in C#. I just never thought about it. So with this new idea I mind I started coding.</p> <p>We throw our own exceptions in the application. And we make a distinction between two kinds of errors: functional errors and technical errors. The main difference between the two being that function errors are logged as warnings and technical errors are logged as errors. Function errors come from business logic decisions (invalid input, creating an account that already exists, etc) and technical errors come from unexpected problems (SQL server unavailable, External webservice unavailable, etc). So all our own exceptions inherit from one of these two base exceptions. Also all exceptions have an error message and an error code.</p> <p>The results we return in our webservice functions also inherit from a common base (the BaseResult class) that provides them with at least an error message and an error code (which get filled from the exception). With all that in mind I copied and changed the code that looked like:</p> <p> <div style="padding-right: 0px; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px; display: inline" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:4079b855-9d68-4ba1-b476-c9494a5f4639" class="wlWriterSmartContent"><pre style="background-color:#FFFFD7;;overflow: auto;"><div><!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--><span style="color: #008080;"> 1</span> <span style="color: #0000FF;">string</span><span style="color: #000000;"> errorMessage </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">CreateAccount error: </span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">+</span><span style="color: #000000;"> e.Message;
</span><span style="color: #008080;"> 2</span> <span style="color: #000000;"></span><span style="color: #0000FF;">if</span><span style="color: #000000;"> (e </span><span style="color: #0000FF;">is</span><span style="color: #000000;"> TechnicalException)
</span><span style="color: #008080;"> 3</span> <span style="color: #000000;">{
</span><span style="color: #008080;"> 4</span> <span style="color: #000000;"> TechnicalException technicalException </span><span style="color: #000000;">=</span><span style="color: #000000;"> (TechnicalException)e;
</span><span style="color: #008080;"> 5</span> <span style="color: #000000;"> ErrorLog.Error(errorMessage);
</span><span style="color: #008080;"> 6</span> <span style="color: #000000;"> result </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> CreateAccountResult(technicalException.ErrorCode, technicalException.Message);
</span><span style="color: #008080;"> 7</span> <span style="color: #000000;">}
</span><span style="color: #008080;"> 8</span> <span style="color: #000000;"></span><span style="color: #0000FF;">else</span><span style="color: #000000;"> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> (e </span><span style="color: #0000FF;">is</span><span style="color: #000000;"> FunctionalException)
</span><span style="color: #008080;"> 9</span> <span style="color: #000000;">{
</span><span style="color: #008080;">10</span> <span style="color: #000000;"> FunctionalException functionalException </span><span style="color: #000000;">=</span><span style="color: #000000;"> (FunctionalException)e;
</span><span style="color: #008080;">11</span> <span style="color: #000000;"> ErrorLog.Warn(errorMessage);
</span><span style="color: #008080;">12</span> <span style="color: #000000;"> result </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> CreateAccountResult(functionalException.ErrorCode, functionalException.Message);
</span><span style="color: #008080;">13</span> <span style="color: #000000;">}
</span><span style="color: #008080;">14</span> <span style="color: #000000;"></span><span style="color: #0000FF;">else</span><span style="color: #000000;">
</span><span style="color: #008080;">15</span> <span style="color: #000000;">{
</span><span style="color: #008080;">16</span> <span style="color: #000000;"> ErrorLog.Error(errorMessage, e);
</span><span style="color: #008080;">17</span> <span style="color: #000000;"> result </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> CreateAccountResult(</span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">, </span><span style="color: #800000;">"</span><span style="color: #800000;">An unhandled exception occured: </span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">+</span><span style="color: #000000;"> e.Message);
</span><span style="color: #008080;">18</span> <span style="color: #000000;">} </span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div>
</p>
<p>Into a function in the base class that looks like:</p>
<div style="padding-right: 0px; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px; display: inline" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:77434b23-3b25-43b3-8877-b614a597f49e" class="wlWriterSmartContent"><pre style="background-color:#FFFFD7;;overflow: auto;"><div><!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--><span style="color: #008080;"> 1</span> <span style="color: #0000FF;">protected</span><span style="color: #000000;"> T HandleException</span><span style="color: #000000;"><</span><span style="color: #000000;">T</span><span style="color: #000000;">></span><span style="color: #000000;">(Exception e, </span><span style="color: #0000FF;">string</span><span style="color: #000000;"> functionName) </span><span style="color: #0000FF;">where</span><span style="color: #000000;"> T : BaseResult, </span><span style="color: #0000FF;">new</span><span style="color: #000000;">()
</span><span style="color: #008080;"> 2</span> <span style="color: #000000;">{
</span><span style="color: #008080;"> 3</span> <span style="color: #000000;"> T result </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">null</span><span style="color: #000000;">;
</span><span style="color: #008080;"> 4</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">string</span><span style="color: #000000;"> errorMessagePrefix </span><span style="color: #000000;">=</span><span style="color: #000000;"> functionName </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;"> </span><span style="color: #800000;">"</span><span style="color: #000000;">;
</span><span style="color: #008080;"> 5</span> <span style="color: #000000;">
</span><span style="color: #008080;"> 6</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">if</span><span style="color: #000000;">(e </span><span style="color: #0000FF;">is</span><span style="color: #000000;"> TechnicalException)
</span><span style="color: #008080;"> 7</span> <span style="color: #000000;"> {
</span><span style="color: #008080;"> 8</span> <span style="color: #000000;"> TechnicalException technicalException </span><span style="color: #000000;">=</span><span style="color: #000000;"> (TechnicalException)e;
</span><span style="color: #008080;"> 9</span> <span style="color: #000000;"> ErrorLog.Error(errorMessagePrefix </span><span style="color: #000000;">+</span><span style="color: #000000;"> technicalException.Message);
</span><span style="color: #008080;">10</span> <span style="color: #000000;"> result </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> T { Code </span><span style="color: #000000;">=</span><span style="color: #000000;"> technicalException.ErrorCode, Message </span><span style="color: #000000;">=</span><span style="color: #000000;"> technicalException.Message };
</span><span style="color: #008080;">11</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">12</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">else</span><span style="color: #000000;"> </span><span style="color: #0000FF;">if</span><span style="color: #000000;">(e </span><span style="color: #0000FF;">is</span><span style="color: #000000;"> FunctionalException)
</span><span style="color: #008080;">13</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">14</span> <span style="color: #000000;"> FunctionalException functionalException </span><span style="color: #000000;">=</span><span style="color: #000000;"> (FunctionalException)e;
</span><span style="color: #008080;">15</span> <span style="color: #000000;"> ErrorLog.Warn(errorMessagePrefix </span><span style="color: #000000;">+</span><span style="color: #000000;"> functionalException.LogErrorMessage);
</span><span style="color: #008080;">16</span> <span style="color: #000000;"> result </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> T { Code </span><span style="color: #000000;">=</span><span style="color: #000000;"> functionalException.ErrorCode, Message </span><span style="color: #000000;">=</span><span style="color: #000000;"> functionalException.Message };
</span><span style="color: #008080;">17</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">18</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">else</span><span style="color: #000000;">
</span><span style="color: #008080;">19</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">20</span> <span style="color: #000000;"> ErrorLog.Error(errorMessagePrefix </span><span style="color: #000000;">+</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">: </span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">+</span><span style="color: #000000;"> e.Message, e);
</span><span style="color: #008080;">21</span> <span style="color: #000000;"> result </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> T { Code </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #000000;">-</span><span style="color: #800080;">1</span><span style="color: #000000;">, Message </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">An unhandled exception occured: </span><span style="color: #800000;">"</span><span style="color: #000000;"> </span><span style="color: #000000;">+</span><span style="color: #000000;"> e.Message };
</span><span style="color: #008080;">22</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">23</span> <span style="color: #000000;">
</span><span style="color: #008080;">24</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> result;
</span><span style="color: #008080;">25</span> <span style="color: #000000;">}</span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div>
<p>And replaced all code that is similar to the first code block with this one line:</p>
<div style="padding-right: 0px; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px; display: inline" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:f110acf4-aee8-45e3-9d04-01cb0391c24d" class="wlWriterSmartContent"><pre style="background-color:#FFFFD7;;overflow: auto;"><div><!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--><span style="color: #008080;">1</span> <span style="color: #000000;">result </span><span style="color: #000000;">=</span><span style="color: #000000;"> HandleException</span><span style="color: #000000;"><</span><span style="color: #000000;">CreateAccountResult</span><span style="color: #000000;">></span><span style="color: #000000;">(e, </span><span style="color: #800000;">"</span><span style="color: #800000;">CreateAccount</span><span style="color: #800000;">"</span><span style="color: #000000;">);</span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div>
<p>A significant reduction as you can see. I definitely should have thought about this before.</p> Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-76767967856365143232008-07-08T01:16:00.004+02:002023-02-27T22:22:52.167+01:00Windows Server 2008 on a laptop<p>Last week I got a new laptop for work. It's a nice fast Dell Precision M6300. On my old workstation I had Windows Server 2003 R2 running. I'm a developer, so I want to develop on the platform my software will run on. So on my new laptop I wanted to run Windows Server 2008 the Vista Server version of Windows.</p> <p>Using this very nice blog entry from <a href="http://blogs.msdn.com/vijaysk/archive/2008/02/11/using-windows-server-2008-as-a-super-desktop-os.aspx" target="_blank">Vijayshinva Karnure</a> I was able to make Windows Server 2008 look and work almost like Vista. Almost, because I'm missing two things that I have noticed so far. First off is the Windows Sidebar and secondly is Bluetooth support.</p> <p>Now if you google for these problems, you'll find solutions to both of them. To enable Bluetooth support you'll need to install your drivers as usual and then perform some INF magic to persuade Windows to use them. To enable the sidebar you'll need to copy some files from a Vista installation and copy some registry settings. From what I read this will then work just fine, but I'm not comfortable with it.</p> <p>You see, these things aren't part of the supported Windows platform, so if there are any security issues, you are on your own. Microsoft won't provide sidebar patches for Windows Server 2008, because they never released a Windows Server 2008 with Windows Sidebar. So you'll have to keep an eye on all security updates and patch the files by hand, or (more likely) let the software run with all its security issues. And that's not something I'm willing to do.</p> <p>I also discovered, that if you install the Hyper-V because you might want to run some virtual machines for testing, sleep and hibernate will be disabled. Sleep and hibernate are incompatible with Hyper-V so you won't be able to use them. That sucks, so I uninstalled the Hyper-V, but at least I have the option of installing it if I do need it some time in the future. I will just need to learn to live without hibernate then.</p> <p>And then I just ran into another issue. For remote workers my organization uses Check Point VPN-1 software, but as it turns out they don't have 64-bit versions of their client software. Even though 64-bit versions of Windows have been available for (rough estimate) 3 years now, they never saw fit to make their software work. According to their forums they will release a 64-bit version of some new software in Q4 2008 and this will fall under the existing licenses <em>for the time being</em>. In other words, you'll have to pay extra for 64-bit versions of their client software eventually.</p> <p>Other then that, I'm pretty happy with my flashy new laptop :-)</p>Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-91099775508373264752008-06-24T19:45:00.002+02:002023-02-27T22:22:55.758+01:00Working with others = my glass ceiling<p>I've never really worked on projects that involved more then 3 people on the development side of things. That is, until January this year.
At the start of this year my department started working on the biggest, most important piece of software we have ever build. And almost everyone from my team is involved. It's currently a 10-man project. 6 of which are developers.</p> <p>So now we're 6 months in and we in the phase where I get to dig around in other peoples code. Be it for fixing bugs, or just plain and simple code reviews. And now I've started to notice something negative about me. I've noticed that I regard code that has not been written by me as bad code, even before I've take the time to examine it. I didn't notice it immediately , but I've started noticing it this week and thinking about it it explains some of my feelings towards certain modules.</p> <p>Since I think the code is bad, even if it is better then what I would have written, I always want to refactor it, change it. And that's not good. Well sometimes it is, but not always. And when I do a code review I should pay particular attention that I judge code on how it works and not how I feel about it.</p> <p>As a programmer you can get only so far flying solo. To progress as an effective programmer you must also learn to work well with others and be part of a team. This is something I know, but my unconscious doesn't appear to want it. Now I know I can start working on it. And in the end it will make me a better programmer.</p>Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-31310767184456566292008-06-18T01:39:00.002+02:002023-02-27T22:22:59.439+01:00I've never liked DRM<p>This time nothing about programming, but about my other great hobby: video games.</p> <p>I recently bought <a href="http://masseffect.bioware.com/" target="_blank">Mass Effect</a> for the PC. And it truly is an awesome game, but even though I bought it and I have the 2 DVDs lying right here on my desk, I never installed it. Instead, I downloaded the illegal, cracked, version and installed that. I figured it's not illegal since I did in fact buy the game. I also registered the CD key on the Mass Effect web site, so they know the game I bought was bought by me.</p> <p>Why did I install the cracked version and not retail version? DRM.</p> <p>The retail version comes with the <a href="http://en.wikipedia.org/wiki/Securom" target="_blank">SecuROM</a> copy protection. But I don't consider it protection of any kind. It's system crippling software, that creates security problems on your system, makes it slow and unstable and only because the big video game publishers consider you a pirate no matter what. Mass Effect takes it even further. It requires you to activate the game and you can activate it only 3 times. After that you must <a href="http://www.simprograms.com/?p=692" target="_blank">purchase</a> (yes, you must buy a new copy of the software) a new CD key. They planned it even worse. They wanted the game to require re-activation every 10 days. But after public outcry they changed that to unlimited time, but only 3 activations.</p> <p>So when do you need to reactivate? When you get a new system. And a new system in this case is when you reinstall Windows, or replace some hardware. From an article linked above it seems to consider a new video card to be equivalent to a new system. That's as brain dead as Windows Vista needing reactivation because replacing my WiFi card must mean I have a new system.</p> <p>Normally people would "vote with their money". Not buying the game would send a clear signal, but I think that in this case it would only play on the paranoid minds of the publishers. If people didn't buy the game because of the DRM, they'd just figure people where pirating it and they'd need more DRM the next time around. Never even considering that the DRM is what made people not want to buy it in the first place!</p> <p>When will these people get it into their fracking heads that DRM is a big burden for honest consumers who bought the product, while it's no problem at all for the pirates. The game is cracked, the DRM removed, as soon as the game is available. It's just pestering the people who pay your salary. And it should stop!</p>Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0tag:blogger.com,1999:blog-5862870612995908899.post-86226439604521817222008-06-08T15:22:00.002+02:002023-02-27T22:23:03.233+01:00Counter-intuitive optimisation<p>I've always been interested in game programming. I never actually managed to create a full, completed game, but from time to time I do start another project. Currently I'm messing around with the <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=DF4AF56A-58A7-474C-BFD0-7CF8ED3036A3&displaylang=en" target="_blank">XNA Game Studio 3.0 CTP</a>.
When Googling for some answers on some game-programming-related problem, I ran into a <a href="http://www.gamedev.net/community/forums/topic.asp?topic_id=263350" target="_blank">developers journal</a> on <a href="http://www.gamedev.net/" target="_blank">GameDev.net</a>. The journal was pretty interesting and I started reading all the entries. It's about a developer who's creating a space MMO. This particular developer mainly focuses on the graphics engine, so while all the specific graphics lingo and math is lost to me, I do understand the more general programming bits and one bit really surprised me.</p> <p>On November 7, 2007 he wrote a piece about optimising a noise function. His project uses a noise function coded in a high level programming language and it appeared too slow. So this developer decided, like many other developers would, to rewrite the function in low-level assembly to gain performance. This kind of manual optimisation is very hard, but generally yields pretty good results. But when he hand-optimised the function it wasn't faster. In fact it was 2 times slower then the implementation written in the high-level programming language.
Programming in assembly language is hard. It's very low-level and you need a really good understanding of how the CPU architecture works to get the best out of it. So it's not surprising that a compiler written by a lot of very smart people will produce faster code then a single, simple developer can product on his own. But this didn't appear to be the problem. No, the problem was using a lookup table.</p> <p>A lookup-table is a very simple (and usually very effective) optimisation technique. If the calculations are slow, but limited in volume, it's easy to just calculate all the possible values one time and store it so that later calculations don't need to be calculated, but can just be looked up. In a lot of game-programming books I read this was usually the first optimisation authors would recommend. It's easy and it just works.
Not anymore it seems. After the developer had reprogrammed the noise function in assembly language the bottleneck didn't appear to be the calculations, but the memory accessing in the lookup-table. So by eliminating the lookup-table and just calculating each thing every time, he made the function faster. And that is not something I would have though of.</p> <p>The funny thing is, this is actually something Steve McConnell warns about in <a href="http://www.amazon.co.uk/Code-Complete-Practical-Handbook-Construction/dp/0735619670/ref=sr_1_1?ie=UTF8&s=books&qid=1212930424&sr=8-1" target="_blank">Code Complete</a>. In this excellent book he warns about optimising performance by 'guessing' what's faster. Things that 'feel' like they would be faster aren't necessarily faster. And things that where faster last year, won't necessarily be faster on this year's CPUs, compilers and operating systems. The only one true way to determine what is faster and what is not, is by measuring.</p>Jeroen-bart Engelenhttp://www.blogger.com/profile/09562770732952167210noreply@blogger.com0