Posts Tagged .NET

Search Engine Optimization (SEO) Toolkit

De search engine optimization toolkit die microsoft (zie ook de SEOToolkit site) biedt vele mogelijkheden om je IIS websites te optimaliseren. Je kunt je vindbaarheid verhogen door:

  • Sitemaps en site indexes te maken
  • Robot verkeer te regelen
  • Analyseren van de site

Het analyseren beperkt zich niet tot een IIS site maar kan op een willekeurige site worden losgelaten. Ik heb dit direct losgelaten op onze nieuwe ‘out of the box’ WordPress installatie en was vervolgens erg snel klaar met de analyse. De robot.txt blokkeerde alles. Dit was natuurlijk snel opgelost maar dit geeft maar aan dat controle van je site niet overbodig is.

De toolkit is zeer eenvoudig te installeren via de Microsoft Web platform installer (dowload) applicatie. Met deze applicatie is het beheren van je webserver zeer eenvoudig.

,

1 Comment

Building iPhone applications using MonoTouch, part 3 : The Interface Builder

So it’s about time I tell something about the Interface Builder. As I mentioned in my previous post, I fled from the Interface Builder at first. I’m not a designer, so interfaces are hard for me anyway. But I built some in WinForms and in ASP.NET and I got used to the simple system of putting buttons and fields on forms and then hooking them up with the business-logic with things like click-events.

Interface Builder is different. I think the idea is that you use it for nothing else than your GUI. There is no way to put any code anywhere. All handling of UI-events is done in delegates and the trick is to learn how to link your GUI to your code.

I hope you will have a better insight in how to do this, after this post. I learned the most from one of the videos on MonoTouch.Info, by Code Snack. I literally played it frame by frame, carefully watching what he did and what could be learned from the code on the background. Highly recommended.

So, let us build an interface with a tab-bar-controller. You might know this type of application from the default iPhone clock.

Start a new application in MonoDevelop, an “iPhone MonoTouch Project”. Double-click the MainWindow.xib and Interface Builder will start.
The empty window you get is important because it is the window that is referenced from AppDelegate. You will add all your own stuff to it as subwindows. But for now you can ignore it.

Make sure the Library Window is open (Tools / Library) and selected like this:Library Window

Now drag a Tab Bar Controller and drop it on the MainWindow (that looks a bit like a solution explorer) just below “Window”. The MainWindow will look like this:
Main Window And you get a new window looking like this:
Tab Bar Controller

It is not to hard to change some of the settings of the tab bar. Open Tools/Inspector, select the Attributes tab, make sure you have the right part active in the Tab Bar Window and change the Identifier Pull-down to “Search”. You will get a default Search Tab, including the search image.

Search TabMake the first tab a Search tab and the second a History tab. Now save the project and check the MainWindow.xib.designer.cs. Nothing interesting, except for a mapping to the window called “Window”. If you run your application now, nothing interesting.

That is because we have to add our new view as sub-views to the main window. In code like this:

1
2
3
4
5
6
7
8
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
	// If you have defined a view, add it here:
	window.AddSubview (tabBar.View);
	window.MakeKeyAndVisible ();
 
	return true;
}

But we have no variable named “tabBar”. Well, now we’re coming to the very important part where we hook up our GUI to our code. Interface Builder does that with something they call “outlets”. And defining them is one of the weirdest experiences in your live as a programmer.

Ok, since I want to have a reference in my AppDelegate to the Tab Bar Controller, I go back to Inteface Builder, to the Library Window and select the Classes button. All the way on the top, there is a AppDelegate. Select it. Then look on the bottom of the window. Select the Outlets button. Now you see that the AppDelegate has an outlet called “window” which is mapped in the designer file in MonoDevelop to a property of type UIWindow with the name “window”. That is how the code above can reference a “window” object. We need to add an outlet by clicking the + button. Give it a name like “tabBar”. The change the type to UITabBarController.

Now we have a definition of an outlet. But it is not linked to any UI-element yet. So go to the MainWindow and select the AppDelegate there. Now go to the Inspector Window and select the Connections tab. You will see that the connection from the tabBar outlet is still open:
Defined OutletsNow comes the magic. You drag the open circle to the Tab Bar Controller window. While getting there you will notice that only windows that are of the right type (UITabBarController) will be an acceptable drop-target. Now drop it, save it and go to MonoDevelop. In the designer file you will see that a new mapping is made. If you change the code in your main.cs to reflect the code above and run your application, you will have your tab bars!

Ok, so far for this post. Next post I will add a search-bar to the search window on the search tab and try to hook them all up to each other and to the code.

, , , , ,

3 Comments

Building iPhone applications with MonoTouch, part 2 : The AppDelegate

This is part 2 of a series. In the first post I said something about the application structure.

A word about Twitter

I’m going to digress a little before telling you more about iPhone application structure. It is not essential for this series, but it is essential to completely describe the adventure that this first application brought on me.

When I found out about the MonoTouch project, it was in Beta and you had to apply to be admitted. I filled in the form (from my iPhone, just to impress them) and then waited. Nothing for a couple of days. I applied again, just to make sure you know. Nothing. Now I’m a modern guy, so I tweet. I tweeted my frustration (in Dutch), since I really wanted to get started. But hey, what where the 3 followers I have gonna do about that? Then it turned out that this guy Joseph Hill, somehow monitors all tweets in the world for the MonoTouch keyword. Joseph is one of the people in the MonoTouch project that is really a Person. He pulled some strings and presto! I got my Beta-account.

For me, that’s just amazing. I didn’t think that Twitter would give me much more than just the latest tips from Scott Guthrie, but this is a totally new way to bring people together and build communities.

The AppDelegate

When you create a new iPhone solution in MonoDevelop, you get a couple of things:

New Solution

New Solution

  1. A xib file called MainWindow.xib. This is where your user-interface is defined. It is an XML file that can be used by the Interface Builder. Simply double-click it and the Interface Builder opens up. More about the Interface Builder later. MonoDevelop monitors the file and regenerates the accompanying designer file when the XIB is changed by Interface Builder. The designer file maps the elements from the user-interface to the classes in your project.
  2. A main.cs that contains the entry-point to your code. There is  a partial class called AppDelegate that is mapped to the main window of your UI. The most important method there is “FinishedLaunching”. It gets called when the iPhone is done with all the stuff it does when loading an application. The name is a bit misleading. Your application is definitely not done launching, at best it is done loading. All the stuff that you need to do yourself still has to happen. Like loading some files, initializing your controllers, setting-up your model classes.

Loading your application

There’s more to say about the loading process. Since it takes some time before you even get control about what happens, you have the option to show an image while loading. Add a file to your project with the name “Default.png” and set it’s properties to “Build Action – Content” and it will be picked up by the loader. Your supposed (according to the designer guidelines) to use an image of your app in action, but it is often abused to show a company logo or something. Some applications make a screen-shot of themselves when the application closes and save that as Default.png. That way, the next time you start your app it looks like it quickly continues where it left off.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// The name AppDelegate is referenced in the MainWindow.xib file.
public partial class AppDelegate : UIApplicationDelegate
{
	// This method is invoked when the application has loaded its UI and its ready to run
	public override bool FinishedLaunching (UIApplication app, NSDictionary options)
	{
		Console.WriteLine("Launched");
 
		window.AddSubview(yourViewHere);
		window.MakeKeyAndVisible();
		return true;
	}
 
	// This method is required in iPhoneOS 3.0
	public override void OnActivated (UIApplication application)
	{
	}
}

You should not be doing too much work in this method. The loader times the duration of this method and kills your application when it takes more than 10 seconds. Or so they say, I never tried it out.

You can use this method to build up your user-interface in code. I went that way first. I had such a hard time getting my head around the Interface Builder that I decided to drop it and build my interface by hand. That worked reasonably but caused unexpected crashes. I knew it had something to do with the way I hooked up the different views, so I went back to Interface Builder and tried and tried and tried. I got it, more or less, and my interface (using a tab-bar) is now stable. In the next episode I will dive into the Interface Builder.

, , , , ,

1 Comment

Building iPhone applications using MonoTouch, part 1 : Application Structure

I finished my first iPhone app this weekend. it is not a very impressing application, but it does what I meant it to do and that is to show movies with Dutch Sign Language coming from the website of the Dutch Gebarencentrum.

Developing for the iPhone is exciting. Well, let me re-phrase that: the result of your development for the iPhone is exciting. Mmmmh, let me re-phrase that again: it was a helluva job to build a working iPhone app, and now that I know how to do it I’m excited!

This post is the first of a couple of post I’m planning to do on development of iPhone applications with .NET. There’s simply too much to learn and to tell to do it all in one post. These posts will not only be about programming C#, but also about design principles, open-source programs, Twitter.

Where do you start?

As a .NET developer you have two choices to program for the iPhone:

  1. You learn the Objective-C programming language and the XCode development environment
  2. You use MonoTouch and MonoDevelop

I started out with the first option, since the second was not available at that time. I found it really hard. Using a c-like syntax is not the hardest thing, but I surely wasn’t used to manage my own memory any more! I got really frustrated since I also had to learn all the other things I’ll talk about in a minute.

The solution came in a podcast from DotNetRocks titled “Rory does iPhone” in which Rory Blyth raved against Objective-C. In that podcast there was a short mention of an open-source initiative called MonoTouch.

Mono

That changed my world radically. I went out looking for the Mono guys and found a very mature platform and active community. if you don’t know: Mono is an open-source initiative that brings the .NET framework to a lot of other platforms, especially the Unix-look-a-likes.
I had heard about Mono before, but always thought it was a project that was way behind the development of the .NET framework. You know, like Microsoft is releasing .NET 4.0 and the Mono guys are proud to announce they now support 2.0! Nothing like that! Mono is on .NET 3.5 and preparing for the changes that 4.0 will bring. They also have a very nice IDE called MonoDevelop that looks a lot like Visual Studio.

With MonoDevelop developing applications on the Mac is so straightforward that I never go back to my VMWare installation with XP and VS2008 to do some quick development. If you think about porting your application (since not all that is available on Windows is there on Linux too), install their Mono Migration Analyzer add-in.

And they have MonoTouch. On the surface it is just a wrapper around the CocaoTouch library that you use to program UI’s on the iPhone.

But is is also a very special compiler that pre-JITs (the call it Ahead Of Time compilation) the entire application. Why? The iPhone OS will not allow you to run a virtual machine. Ever wondered why there is no Java or Flash on the iPhone? They cannot run since they depend on their own VM.
MonoTouch circumvents this problem by generating native code, removing all the unused libraries, classes and methods and then building a Mac App package from that.

What do I have to learn?

When you want to build your own application, you will at least have to learn about:

  1. The structure of iPhone apps
  2. The Cocao Touch library
  3. The Interface Builder
  4. Debugging in XCode
  5. Signing your application
  6. How to distribute your application

I will try to tell you about all of these subjects in different installments.

The structure of an iPhone app

It is essential to know what the iPhone expects from you and how the Cocao Touch library supports that. It is probably  way different from the way you worked in C# and WinForms, and it takes some time to get used to finding out where to put your application logic.

The Cocao Touch library is full of Design Patterns, but the most pervasive, noticable, visible and wonderful is The Model View Controller. Below is an image from the Mac Development Library:

MVC

MVC

This post is not about Design Patterns, so I will not explain how the MVC pattern is supposed to work. The image is just their to help me explain which classes you will have to inherit from.

Cocao development is about inheriting from the classes that wire up the application for you. That means that you only have to override the methods that are of interest to you, but it also means that you essentially have no way to stray from this setup. You use the Cocao classes or you end up building your own library.

These are the classes that implement the MVC pattern for the often-used TableView:

  1. UITableView
  2. UITableViewDataSource
  3. UITableViewDelegate
  4. UITableViewController

The UITableView is in the NIB: the file that is generated for you by the Interface Builder and that holds all the GUI elements.

The UITableViewDataSource holds the data that is displayed in the table. It’s methods are called by the Controller to fill the cells in the table (e.g. GetCell, RowsInSection).

The UITableViewDelegate implements methods for dealing with user-actions that are performed on the view, like “RowSelected” when (yep) a row in the table is selected.

The UITableViewController is the man-in-the-middle. It sits between the DataSource and the TableView, and does things like passing the DataSource filtered data when some search criterion is entered and then telling the TableView to reload with this new data. The controller can use your own model to get this filtered data.

So far for this installment. Next time I will show some code and tell about the AppDelegate, the object that functions as the heart of your application since it receives a lot of interesting messages like “Hey you’re app is started!”.

, , , , ,

9 Comments

VS2010 en ASP.MVC door Scott Guthrie

Vrijdag 25 november heeft Scott Guthrie ruim 4 uur gesproken over de komende release van Visual Studio en over ASP.MVC. De presentatie was georganiseerd door de dotnet gebruikersgroep DOTNED.

Het was een erg inspirerende presentatie waaruit verbazingwekkend blijkt dat Scott, als vice president, zo veel detail kennis en praktische vaardigheden heeft.

VS2010 (VS 2010 on Channel 9)

Wat opvalt is dat er ontzettend veel dingen zijn verandert in VS2010. Ik beperk me hier tot de meest opmerkelijke punten, de rest kun je lezen op Scott’s blog

  • Complete nieuwe UI gebaseerd op WPF waarbij vooral ruimte wordt gecreeerd voor code en snelle navigatie door de code.
  • Historical debugging na een exception. Wie heeft dat nog nooit meegemaakt, er treed een exception op en die wordt in main opgevangen en de exception bevat niet genoeg informatie. In VS2010 heb je nu de hele stack trace en zelfs de mogelijkheid om de draad weer op te pakken net voor de fout.
  • Entitie framework 4 die nu ook model first en POCO ondersteund en voor ontwikkelaars de mogelijkheid om te werken met een fake database implementatie zodat je tijdens ontwikkeling de hele database tier weg kunt laten.

ASP.MVC (ASP.MVC2 on Channel 9)

Scott benadrukt dat ASP.NET en ASP.MVC de twee alternatieven zijn die ondersteund blijven. ASP.MVC onderscheidt zich vooral door de transparantie, het sluit erg goed aan bij HTTP en door de testbaarheid vanwege de ontkoppeling van de view.

  • Dynamic validation. Door het annoteren van het model worden validaties automatisch uitgevoerd zowel server als client-side.
  • CDN voor ajax scripts. Microsoft heeft een Computer distribution network waardoor de scripts decentraal beschikbaar zijn (dichter bij de gebruiker) en er meer sharing is waardoor de pagina’s sneller laden.
  • Web Platform installer tool die het eenvoudig maakt om je ontwikkelomgeving goed in te richten.
  • SEO tool (Search Engine Optimisation) voor het analyseren en optimaliseren van je website

, ,

No Comments

NHibernate Lambda Extensions – an open-source adventure

For our client Gerechtsdeurwaarderskantoor De Jong we built a .NET application that uses NHibernate in the data-layer to talk to the Informix database. To abstract away from the specific knowledge about the database / ORM I created the below structure:

The DomainConnector is a class that implements lots of business rules to load/save domain-objects and gets its IStorage from our IoC-container (which is Castle Windsor). The InformixConnector implements the IStorage interface, but the DomainConnector doesn’t know that. Just as it doesn’t know that the InformixConnector uses NHibernate to do the actual work.

Well, until recently that was not entirely the case. The DomainConnector needs queries to specify which objects it wants in a list (for example). Those queries were in strings and were actually HQL queries.

Mmmmmmmh, so the DomainConnector did not know what database was in the back-end (thanks to NHibernate), but did know in some way about the fact that NHibernate was used. Use invalid HQL in your query and you’re doomed.

Some times you can live with less-than-perfect code. But a couple of days ago I ran into a problem I felt I had had before. I got this message from NHibernate that it could not map some property. So what do you do? You check your mapping file and the class that it maps to and conclude that everything is perfect. So you Google. Nothing interesting.

And then (a frustrating hour later) a memory bubbles up: it is not talking about the mapping itself, it’s talking about trying to map names in a query! Yep, that was the problem. The cause? I changed the name of a property. The real cause? This property was referenced in a string and the compiler could -of course- not warn me I had to change the query-string.

I had e feeling that Lambda-expressions must be the solution to this problem (as they are currently to a lot of my problems). And Google (as a .NET afficionado should I be bing-ing?) told me there was already an open-source project that did just what I wanted:
nhlambdaextensions.

This project contains a few extension classes that allow you to use lambdas to specify your ICriteria. As they say on their homepage:

    .Add(Expression.Eq("Name", "Smith"))

becomes

    .Add(p => p.Name == "Smith")

Now you can have Intellisense and compile-time checking. No way you inadvertently type LastName in stead of Name!

So I downloaded the binaries, tried to compile, noticed that I needed a newer version of NHibernate, downloaded that and it compiled. Changed one of the DomainConnectors and ran a unit test: bingo!!! This was going to work. I was so happy, I changed all the DomainConnectors before running an intergration test. I mean: I changed all the code before actually running it against NHibernate. *** UGLY WORDS *** when I did that eventually. For some obscure reason the SessionFactory could no longer be created, so no database access…

Reverting to the previous version of NHibernate solved this (I love version-control), but then I could not compile my lambdas anymore. So what should I do now: try to solve the SessionFactory problem or revert to the queries-in-a-string version of my DomainConnector. Tough descision.

And then I had my epiphany: this is open-source code. I can download the code, add it to my project, compile it against my working version of NHibernate and have lambda-based queries. Have your cake and eat it too!

It took no more than 10 minutes to achieve this. That’s the beauty of open-source, take control. But it also gave me more responsibility than I might actually want. Now this code was sort-of my code. Would I do that for larger open-source project like NHibernate itself? No way, my client’s business depends on the use of NHibernate. I want to be sure I have a stable, correctly compiled version of it. But for this 6 classes, 500 lines of code project I feel ok.

I even solved a bug that I might contribute to the project. Did not do that yet, though. Small steps….

, ,

No Comments

Behaviour Driven Development (BDD)

Ik las recentelijk in een blog-entry van Rob Conery over BDD. Rob Conery ontwikkelt voor Microsoft een op ASP.NET gebaseerde StoreFront. Een soort starters-pakket voor mensen die een web-winkel willen maken. In het proces van het ontwikkelen van deze applicatie (die inmiddels ook op Codeplex is geopensourced onder de werktitel Kona heeft hij meerdere ontwikkel-processen en ontwikkel-methodes uitgeprobeerd. En in dat hele proces was hij er niet vies van om de hele zaak op zijn kop te gooien of zelfs helemaal opnieuw te beginnen. Alleen daarom al is hij een held. O, ja, en ook omdat ie op Hawaii woont…

Zo kwamen de afgelopen maanden Test-Driven-Development, Domain-Driven-Development en -als meest recente- Behaviour Driven Development langs. BDD is min of meer uitgevonden door Dan North (http://dannorth.net/introducing-bdd) en lost voor mij (en ook voor Rob Conery) een probleem op dat ik altijd met TDD heb gehad: hoe begin je met je tests?

Natuurlijk ga je eerst je test maken en dan pas de code die zorgt voor het vervullen van je test. We kennen het allemaal: red-green-refactor. Maar met welke test begin je, en hoe heet die test?

BDD doet iets heel simpels: denk niet meer in de term “test” maar in termen als “gedrag” en “specificaties”. Dus: “welk gedrag wil ik implementeren” en niet “welke test wil ik schrijven”. Je komt dan heel makkelijk op iets als “EmptyShoppingCartShouldReturnCountOfOneWhenProductAdded”. Dat kan ik vertalen naar een test en ik kan ook de code schrijven die de test vervult!

De volgende stap is dat je al de requirements/specs/behaviours die je kent op een dergelijke manier in je code zet. Gewoon lege methods met aan Assert.Fail erin. Dat geeft je een hele lijst van test-methodes die natuurlijk initieel allemaal falen. Maar het is dan wel zonneklaar wat je moet gaan doen om de hele zaak groen te krijgen.

Dit lijkt niet revolutionair, maar ik heb het vandaag in de praktijk uitgeprobeerd en het leverde me een zeer tevreden gevoel op. Ten eerste wist ik wat ik moest gaan coderen, ten tweede wist ik dat ik een test had voor alle code die ik zou gaan maken en ten derde wist ik -eenmaal aan het einde van de rit, alles groen- dat ik niet meer code had gemaakt dan ik nodig had.

Ik zou ook dolgraag de volgende stap maken: het inzetten van MSpec (). Albert Oudenampsen had mij al eens RSpec laten zien: in feite een Ruby-programmaatje dat het mogelijk maakte om je specificaties in bijna-menselijke-taal te schrijven en te executeren. Maar zoals wel vaker duurt het bij mij enige maanden tot jaren voordat ik zie wat Albert ziet. MSpec is op de ideeen van RSpec gebaseerd, maar is specifiek voor het .NET platform.

MSpec biedt een library die je meelinkt in je test-project en die je de taal-elementen geeft waarmee je je tests (sorry, je behaviours) schrijft en biedt je een MSpec-runner die de behaviours runt en over de resultaten rapporteert. Je neemt dus je requirements-document, schrijft in MSpec-syntax je tests en runt het hele zaakje met de MSpec-runner. Vervolgens ga je zorgen dat de specs/behaviours groen worden door net als bij TDD te gaan implementeren. Even een stukje code om er een gevoel bij te krijgen:

   1. [Description]
   2. public class Transferring_between_from_account_and_to_account
   3. {
   4.   static Account fromAccount;
   5.   static Account toAccount;
   6.
   7.   Context before_each =()=>
   8.   {
   9.     fromAccount = new Account {Balance = 1m};
  10.     toAccount = new Account {Balance = 1m};
  11.   };
  12.
  13.   When the_transfer_is_made =()=>
  14.   {
  15.     fromAccount.Transfer(1m, toAccount);
  16.   };
  17.
  18.   It should_debit_the_from_account_by_the_amount_transferred =()=>
  19.   {
  20.     fromAccount.Balance.ShouldEqual(0m);
  21.   };
  22.
  23.   It should_credit_the_to_account_by_the_amount_transferred =()=>
  24.   {
  25.     toAccount.Balance.ShouldEqual(2m);
  26.   };
  27. }

Naast het feit dat de specificatie redelijk te lezen is (als je even gewend ben aan de syntax die nogal zwaar leunt op ambda-expressies) produceert de MSpec-runner ook een HTML rapport waarop staat welke requirements je allemaal gaat implementeren, welke er al klaar zijn en welke nog niet. En dat allemaal op een manier die leesbaar is voor project-managers of problem-owners.

Nog niet overtuigd? Laat ik het dan anders zeggen: je hebt executeerbare requirements! Ja, echt, daar wordt je blij van, dat geeft je de missing-link tussen dat ene Word document dat die FO-er heeft geschreven en jouw eigenste code!

, , ,

No Comments

Java .Net interoperability

Java .Net interoperability

Have you ever felt the urge and need to connect your Java program to a particular .Net assembly? And more specifically without the hassle of COM bridges, web services, .Net remoting or other service type components. I came across a project in which a simple Java program needed to be connected to an existing .Net assembly (btw written in C#). Everything had to be as simple as possible.
On the Internet a couple of articles were helpful: Espresso, C# method calls within Java Program and Calling a .NET Method from Java via JNI. However it didn’t quite work the way we liked so the ulimate solution came (it so often happens) from Jelle Hissink (http://www.codewise.nl)

The solution is based on:

  • Use JNI for the communication between the Java VM and the .Net CLR
  • Intercept the call to the name resolver and resolve the call to the C# class with your own method

Graphically this looks like:

Let’s work our way from the initial Java call to the final C# implementation.

Java

In Java we have the simple program:

class HelloWorld {
   public static void main(String[] args)
  {
      DotNetBridge dotNetBridge = new DotNetBridge();
      String getString = dotNetBridge.GetString();
      System.out.println("GetString() returned:   " + getString);

      String newString = "Java2.Net world";
      dotNetBridge.SetString(newString);
	getString = dotNetBridge.GetString();
      System.out.println("GetString() returned:   " + getString);
   }
}

Nothing special, just straightforward java code.
However in addition to this code we define an extra class with the DotNetBridge code on the java side. This is needed to kick start the bridging.

public class DotNetBridge
{
  private native void Initialize(String localPath);
  public native String GetString();
  public native void SetString(String newString);

  static
  {
    String path = DotNetBridge.class.getProtectionDomain().getCodeSource().getLocation().getPath();
    int idx = path.lastIndexOf("/");
    if (idx >= 0) {
      path = path.substring(0, idx);
    }
    if (path.startsWith("/")) {
      path = path.substring(1);
    }

    System.load(path + "/DotNetBridge.dll");
    DotNetBridge dotNetBridge = new DotNetBridge();
    dotNetBridge.Initialize(path);
  }
}

In a few words what does it do? It is a class with native methods telling the java compiler that it can find the interface of the methods in this class but the implementation is to be found in a native Windows dll file. On top of that when to class is instantiated for the first time the static part will ensure that the Initialize method is called in which the full path of the dll file with the implementation is passed. Be a little more patient, later on we’ll see why we need this.

DotNetBridge

We now need a simple interface from the Java to the .Net world in which strings can be passed in and out. For this purpose we create a managed C++ project in Visual Studio of the name DotNetBridge. The project consists of:

  • A C++ header file with the definition of the bridge interface
  • A C++ file with the implementation of the bridge
  • A reference to the .Net component with the implementation of the actual HelloWorld code

The header file DotNetBridge.h makes use of JNI (ofcourse) to define the interface of the bridge:

#include "jni.h"

JNIEXPORT void JNICALL Java_DotNetBridge_Initialize(JNIEnv *env, jobject thisobject, jstring localPath);
JNIEXPORT jstring JNICALL Java_DotNetBridge_GetString(JNIEnv *env, jobject thisobject);
JNIEXPORT void JNICALL Java_DotNetBridge_SetString(JNIEnv *env, jobject thisobject, jstring newString);

I’ll not dive into the details of JNI too much (see JNI Primer) but this is the most minimal definition. There are tools to generate this type of definitions (javah –jni) but we leave those out of the equation today. For now watch the prefix Java_DotNetBridge_ which are needed in case of JNI. Also the env and thisobject parameters are specific for each JNI call.

The implementation in C++ has become much more easily with the new .Net framework primitives for managed C++. The two main methods on the interface are the get and set string methods, their implementation looks like:

using namespace System;
using namespace System::Runtime::InteropServices;
using namespace HelloWorldDotNet;

#include 

JNIEXPORT jstring JNICALL
Java_DotNetBridge_GetString (JNIEnv *env, jobject thisobject)
{
    IHelloWorld ^support = gcnew HelloWorld();

    // Get a managed string.
    String ^managedString = support->GetString();

    std::string str = managedToString(managedString);

    // Create the java string...
    jstring result = env->NewStringUTF(str.c_str());

    return result;
}

JNIEXPORT void JNICALL
Java_DotNetBridge_SetString (JNIEnv *env, jobject thisobject,
								jstring newString)
{
    IHelloWorld ^support = gcnew HelloWorld();

    std::wstring newWString = jstringToWString(env, newString);

    String ^ managedString = gcnew String(newWString.c_str());

    support->SetString(managedString);
}

To enable all this we do need some extra string management functions which can translate the java formatted strings to .Net strings and vice versa. Also the transition from the managed to unmanaged environment has its effect on the string management as can be seen from:

std::wstring jstringToWString(JNIEnv *env, jstring jstr)
{
  jboolean iscopy;
  const jchar *strPtr = env->GetStringChars(jstr, &iscopy);

  const jchar *p = strPtr;
  std::wstring result;
  while (*p)
  {
    result += *(p++);
  }

  env->ReleaseStringChars(jstr, strPtr);

  return result;
}

std::string managedToString(String ^mstr)
{
  // Marshal the managed string to unmanaged memory.
  IntPtr hGlobal = Marshal::StringToHGlobalAnsi(mstr);

  char *stringPointer = static_cast(hGlobal.ToPointer());

  // Create the java string...
  std::string result = stringPointer;

  // Always free the unmanaged string.
  Marshal::FreeHGlobal(hGlobal);

  return result;
}

Finally, as said earlier, we need to kick start the whole mechanism. Hence the managed C++ code has currently no idea where to find an implementation of the HelloWorld class in the call to: IHelloWorld ^support = gcnew HelloWorld();
By the way, the import of the namespace has sneaked into the C++ code quite silently with: using namespace HelloWorldDotNet; Without setting a reference to the .Net assembly in the projects’ properties the compiler will not be able to compile this C++ class. Setting such a reference can be done with:

In the Java implementation we have seen that each instantiation of the java bridge class results in a call to the initialize function of the DotNetBridge component. Finally it is time to dive into the details of its implementation. We could have done without it if we deploy all dlls to the java executable directories. From a administration perspective this is not very neat. System administrators normally require that a solution is delivered to one location and the software should take care of its own path settings.

In essence the initialize function of the DotNetBridge is always called once and exactly once with the full path specification of the actual executable directory. So put all dlls into this directory and intercept the name resolver. Because if the runtime tries to load the assembly with the implementation of the HelloWorld class it should look into one specific dll to find this implementation. So this will happen:

  • On the initialize the directory path of the HelloWorld.dll is stored in a static variable
  • The AssemblyResolve event is augmented with its own handler
  • In the handler the directory path is used to load the HelloWorld class from the correct dll
std::wstring assemblyLoadPath;

System::Reflection::Assembly ^ MyResolveEventHandler( Object^ sender, ResolveEventArgs^ args )
{
  String ^name = args->Name;
  int idx = name->IndexOf(L',');
  if (idx >= 0) {
    name = name->Substring(0, idx);
  }
  name = String::Concat(name, gcnew String(L".dll"));

  String ^basePath = gcnew String(assemblyLoadPath.c_str());
  name = System::IO::Path::Combine(basePath, name);

  System::Reflection::Assembly ^ result = System::Reflection::Assembly::LoadFile(name);

  return result;
}

JNIEXPORT void JNICALL Java_DotNetBridge_Initialize (JNIEnv *env, jobject thisobject, jstring localPath)
{
    assemblyLoadPath = jstringToWString(env, localPath);

    AppDomain ^currentDomain = AppDomain::CurrentDomain;
    currentDomain->AssemblyResolve += gcnew ResolveEventHandler( MyResolveEventHandler );
}

This will do the trick on the .Net bridge side. The final implementation of the C# code is straightforward.

C# code

It is a C# class library project. It consists of two classes: the interface and its implementation. The code of the interface definition looks like:

using System;

namespace HelloWorldDotNet
{
    public interface IHelloWorld
    {
        void SetString(string stringValue);
        string GetString();
    }
}

Finally its implementation can be anything. In this case it is simple as:

using System;

namespace HelloWorldDotNet
{
    public class HelloWorld : IHelloWorld
    {
        private static string lastString = "brave new world";
        public void SetString(string stringValue)
        {
            lastString = stringValue;
        }
        public string GetString()
        {
            return String.Format("Hello {0}", lastString);
        }
    }
}

Finally

On purpose, in the code examples details such as exception handling and comments were left out. If you’re interested you can download all the code (see below). On the java side DOS command scripts are used to compile and run the example. You’ll find them easy and straightforward. The C++ and C# code are organized in two separate .Net projects. They were made with Visual Studio 2008. Either migrate to Studio 2008 or use the source code files to build a solution yourself.
If you can’t find your way through all the source files, this is the rough organization:

These are the main steps, with their correct order, to get it to work:

  • Compile the HelloWorld C# project
  • From the DotNetBridge project set the reference to the HelloWorld.dll created in the previous step
  • (possibly) in the DotNetBridge project set the include directories to include the path to the correct JVM include directories (otherwise the jni.h can not be found)
  • Compile the DotNetBridge project
  • Change the compile.cmd and run.cmd scripts in the Java directory to reflect the correct paths.
  • Run compile.cmd
  • Run run.cmd
  • If unchanged you should see something like:





    When you want a full download of all the code in this sample, click here.

    And last but not least: have fun!

, , , , , , , ,

3 Comments

Load and unload assembly in AppDomains

Introduction

I was toying around with loading and inspecting assemblies in .NET dynamically. I wanted to create a service that could return a binary stream with assembly data that I could store on disk in my demo application and than use normally from within my demo.

When you want to skip the steps I took follow this link.

My steps into AppDomain

I need to load the assembly in memory and inspect the assembly’s manifest. Here I can use AppDomain.Load(byte[]). I tried the following:

byte[] assemblyBuffer = File.ReadAllBytes("somedirectory\MyDynamicAssembly.dll");
Assembly assembly = AppDomain.CurrentDomain.Load(assemblyBuffer);

This is all oke. I can load and inspect my assembly. But when I inspect all assemblies loaded into the current AppDomain (via AppDomain.CurrentDomain.GetAssemblies()) my asembly is also loaded. This is not what I want. I want to load the assembly, inspect the manifest and when I’m done, remove the assembly from memory. You need an extra AppDomain for that. I changed the code to:

byte[] assemblyBuffer = File.ReadAllBytes("somedirectory\MyDynamicAssembly.dll");
AppDomain tempAppDomain = AppDomain.CreateDomain("MyTempAppDomain");
Assembly assembly = tempAppDomain.Load(assemblyBuffer);

When I executed the code I got the following exception:

System.IO.FileNotFoundException: Could not load file or assembly 'Luminis.Samples.AppDomainSample.MyDynamicAssembly, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
   at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
   at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
   at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
   at System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
   at System.Reflection.Assembly.Load(String assemblyString)
   at System.UnitySerializationHolder.GetRealObject(StreamingContext context)

   at System.AppDomain.Load(Byte[] rawAssembly)
   at Luminis.Samples.AppDomainSample.AppDomainSample.Program.Test2() in C:\User
s\Alex\Projects\Luminis\.NET\Samples\AppDomainSample\Luminis.Samples.AppDomainSample.AppDomainSample\Program.cs:line 45

Where does this FileNotFoundException come from? When I dug deeper into this exception I figured out that .NET was still looking for the assembly-file on disk. I changed the code:

byte[] assemblyBuffer = File.ReadAllBytes("somedirectory\MyDynamicAssembly.dll");
AppDomain tempAppDomain = AppDomain.CreateDomain("MyTempAppDomain");
File.WriteAllBytes(@"C:\TEMP\MyTempAssembly.dll", assemblyBuffer);
Assembly assembly = tempAppDomain.Load(assemblyBuffer);

Actually this is really not what I want. But what the heck, let’s try this first.

Oke, the assembly is loaded correctly but when I look closer I see that my assembly is loaded into the temp AppDomain, but also in the curren AppDomain. Also when I try to delete the temporary assembly file get an UnauthorizedAccessException:

System.UnauthorizedAccessException: Access to the path 'C:\Users\Alex\Projects\Luminis\.NET\Samples\AppDomainSample\Luminis.Samples.AppDomainSample.AppDomainSample\bin\Debug\Luminis.Samples.AppDomainSample.MyDynamicAssembly.dll' is denied.

I cannot delete th file because it is still locked by the current AppDomain. I need another trick.
I need to load the assembly in the temp AppDomain without interfering with the current AppDomain. I created the following code:

byte[] assemblyBuffer = File.ReadAllBytes("somedirectory\MyDynamicAssembly.dll");
AppDomain tempAppDomain = AppDomain.CreateDomain("MyTempAppDomain");
object anObject = tempAppDomain.CreateInstanceAndUnwrap("....AssemblyInspectorImplementation", "...AssemblyInspectorImplementation.AssemblyInspector");
IAssemblyInspector assemblyInspector = anObject as IAssemblyInspector;
result = assemblyInspector.GetAssemblyInfo(assemblyBuffer);

I created an interface IAssemblyInspector. I dynamically create an implemetation-object for this interface in the temp AppDomain (via CreateInstanceAndUnwrap()) and I call the GetAssemblyInfo() method.

Here is the code GetAssemblyInfo() method in the AssemblyInspector implementation class.

public string[] GetAssemblyInfo(byte[] assemblyBuffer)
{
    List result = new List();
    Assembly assembly = AppDomain.CurrentDomain.Load(assemblyBuffer);

    object[] fileVersionAttributes = assembly.GetCustomAttributes(typeof(AssemblyFileVersionAttribute), true);
    if (fileVersionAttributes.Length == 1)
    {
        AssemblyFileVersionAttribute fileVersion = fileVersionAttributes[0] as AssemblyFileVersionAttribute;
        result.Add(fileVersion.Version);
    }

    Module manifest = assembly.ManifestModule;
    result.Add(manifest.ScopeName);

    return result.ToArray();
}

What I see now is that although I created the AssemblyInspector in the temp AppDomain my assembly is still loaded into the current AppDomain.

The last trick I found is that I need to extend from System.MarshalByRefObject.

public class AssemblyInspector : MarshalByRefObject, IAssemblyInspector
{
    #region IAssemblyInspector Members
    public string[] GetAssemblyInfo(byte[] assemblyBuffer)
    {
    ...
    }
}

This way in the main I get a handle to a so called TransparentProxy that uses .NET Remoting to transfer the GetAssemblyInfo()-methodcall to AssemblyInspector.
This AssemblyInspector is loaded into the temp AppDomain and will load the assembly also into that AppDomain without interfering with the current AppDomain.


Conclusion

When you want to dynamically load an assembly and be able to control the unloading of the assembly you need:

  1. Create a new AppDomain via AppDomain.CreateDomain().
  2. Use appDomain.CreateInstanceAndUnwrap() to create an object in the new AppDomain.
  3. Extend MarshalByRefObject to use .NET Remoting to access objects in the new AppDomain.

When you want to download the code in this sample, click here.

,

1 Comment