• Blog
  • Archive
  • About
  • Contact
Sign in

Welcome to rickardnilsson.net

rickardnilsson.net is a weblog and the online home of web developer and father of three, Rickard Nilsson... More

Rickard blogs about creating software solutions using ASP.NET and agile practices.

Sites I've visited recently

  • Twitter
  • Facebook
  • Philip Wildenstam
  • Ninetech - Affärsnytta med IT
  • JetBrains ReSharper
  • Vimeo
  • dnrTV!
  • YUI Theater
  • BlogEngine.Net

Categories

  • .NET
  • Agile
  • ASP.NET 2.0
  • ASP.NET 3.5
  • ASP.NET MVC
  • BlogEngine.NET
  • C# 2.0
  • C# 3.0
  • CSS
  • Design by Contract
  • Design Patterns
  • JavaScript
  • TDD
  • Unit testing
  • User tip

Five most recent posts

  • Dependency injection in ASP.NET MVC with Unity IoC Container
  • ReSharper templates from the Code Kata Cast
  • How to unit test code which depends on HttpContext.Current.Server
  • Code Kata Cast
  • TDD Masterclass in the UK with Roy Osherove

Tag cloud

  • agile
  • ajax
  • asp.net 3.5
  • blog
  • blogengine.net
  • c#
  • code kata
  • css
  • dbc
  • dependency injection
  • design by contract
  • dom
  • douglas crockford
  • fakes
  • foto
  • getweekofyear
  • gregoriancalendar
  • highlight
  • html
  • httpcontext
  • humble dialog box
  • inversion of control
  • ioc container
  • iso 8601
  • javascript
  • jquery
  • jscript
  • julian bucknall
  • live template
  • metaweblog api
  • model-view-presenter
  • mvp
  • patterns & practices
  • photo album
  • picasa
  • recent posts
  • refactor
  • refactoring
  • release
  • resharper
  • rhino mocks
  • roy osherove
  • syntax
  • syntax highlighter
  • tdd
  • tdd masterclass
  • test coverage
  • testing
  • types
  • unit test
  • unity
  • web service
  • week
  • widget
  • word 2007
  • yahoo
  • yui

Recent comments

  • Code Kata Cast (8)
    Rickard wrote: @Marcus Eklund Classical music is royalty free sin… [More]
  • Code Kata Cast (8)
    Marcus Eklund wrote: http://creativecommons.org/ is a good place. Cl… [More]
  • Code Kata Cast (8)
    Rickard wrote: @Johan Lindfors Thanks! @Andrea I use TestDrive… [More]
  • Code Kata Cast (8)
    Marcus Eklund wrote: Nice one Rickard, A bit quiet though :P Used to t… [More]
  • Code Kata Cast (8)
    Andrea wrote: Nice one You can use the R# test runner and assig… [More]

Dependency injection in ASP.NET MVC with Unity IoC Container

Friday, 25 December 2009 18:48 by Rickard

Enabling truly easy testability with ASP.NET MVC Controllers requires a Dependency Injection container. This post is about showing a more real life example of combining Unity with ASP.NET MVC Controllers than the standard demo. Unity is the IoC Container from Microsoft Patterns & Practices and ships as a part of Enterprise Library as well as a stand alone on Codeplex.

We start with the unit test which drives the design of the controller.

[TestMethod]
public void Post_PostWithSlugExists_ReturnsResultWithPostAsModel() {
    controllerContext.RouteData.Values.Add("slug", ValidSlug);
    var expected = MockRepository.GenerateStub<IBlogPost>();
    var blogPosts = new[] {expected};
    blogPostService.Expect(s => s.GetPostWhereSlugEquals(slug))
                   .Repeat.AtLeastOnce()
                   .Return(blogPosts);
    var controller = CreateController();

    var result = (ViewResult) controller.Post();
    Assert.AreEqual(expected, result.ViewData.Model);
}

Even though the test becomes a bit verbose it clearly states the intent of the controller’s Post method; given the right slug, a result is returned with a blog post as model.

Dependency Injection in ASP.NET MVC

In ASP.NET MVC every request starts in a controller which uses a set of dependencies to do its job. When we have applied Inversion of Control we can inject all of the controller’s dependencies either as a constructor argument or as a property setter. To fully take advantage of this technique we want the dependencies to be automatically injected without creating any of them in overloaded constructors or something like that. This is where the Controller Factory in ASP.NET MVC comes into play.

Controller Factory

In the System.Web.Mvc namespace lives the IControllerFactory which implementation is used by the framework to create controller instances. We can use this to swap out the default one and replace it with our own controller factory which uses Unity to create controllers instead.

Instead of implementing all of the IControllerF actory functionallity we can extend the System.Web.Mvc.DefaultControllerFactory and only override what we need.< /p>

public class UnityControllerFactory : DefaultControllerFactory {
    private readonly IUnityContainer container;

    public UnityControllerFactory(IUnityContainer container) {
        this.container = container;
    }

    protected override IController GetControllerInstance(Type controllerType) {
        return container.Resolve(controllerType) as IController;
    }
}

In the Global.asax, called MvcApplication in ASP.NET MVC by default, we create our Unity container and tells the MVC framework to use our UnityControllerFactory instead of the default one.

// in Global.asax.cs
protected void Application_Start() {
    RegisterRoutes(RouteTable.Routes);

    var container = new UnityContainer();
    var controllerFactory = new UnityControllerFactory(container);
    ControllerBuilder.Current.SetControllerFactory(controllerFactory);
}

PostController

To illustrate why this is so powerful we will implement a controller that handles requests for blog posts, such as the one you’re reading right now. For this example the controller only handles requests for single blog posts using the post’s slug as identity. A slug is the post’s title made url friendly (e.g. "Dependency-injection-in-ASPNET-MVC-with-Unity-IoC-Container” for this post). The PostController has a dependency on an IBlogPostService which it uses to lookup the blog post to send to the view.

public class PostController : Controller {
    private readonly IBlogPostService blogPostService;

    public PostController(IBlogPostService blogPostService) {
        this.blogPostService = blogPostService;
    }

    public ActionResult Post() {
        var slug = GetSlug();
        var post = blogPostService.GetPostWhereSlugEquals(slug);
        return View(post);
    }

    private string GetSlug() {
        return RouteData.GetRequiredString("slug");
    }
}

Strongly-typed views

The Post action returns an ActionResult with the post a the model. We can use strongly-typed views to get intellisense in the aspx-file.

<%@ Page /*...*/ Inherits="ViewPage<IBlogPost>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    <%=Model.Title %>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h2><%=Model.Title %></h2>
    <p>
        <%=Model.Body %>
    </p>
    <p><%=Html.PostActionLink("Permalink", Model) %></p>
    <p><a href="/2009/10/10/fail">fail link</a></p>
</asp:Content>

Notice how the view inherits from ViewPage<IBlogPost> which is key to make the model type of IBlogPost. Then we can use the Post properties to render the blog post in the view.

Conclusion

Combining ASP.NET MVC with Unity or your IoC Container of choice makes your controllers much more easily testable. You only state your classes dependencies as constructor parameters or properties and the container will do the wiring for you. The gives you time to focus on the program logic and the interaction between its components.

Tags:   dependency injection, inversion of control, ioc container, unity, patterns & practices, testing
Categories:   Unit testing | ASP.NET MVC
Actions:  
Share | |

ReSharper templates from the Code Kata Cast

Tuesday, 17 November 2009 15:15 by Rickard

After I posted my Code Kata Cast I received some feedback regarding the ReSharper templates I use to speed up my coding. I decided to share them with the public (like so many before me) in hope that others may benefit from them, as I do.


rickardn-resharper-templates.zip (1,44 kb)


After you’ve downloaded the zip-file and unpacked it, open Visual Studio and the ReSharper Templates Explorer: Menu –> ReSharper –> Live Templates…

Click on Import… as the screen shot below shows, and find the file “rickardn-resharper-live-templates.xml”

resharper_import_template

 Then click the “File Templates” tab and repeat the procedure for the “rickardn-resharper-file-templates.xml” file.

 Good luck with your katas!

 

Tags:   resharper, live template, c#, tdd, unit test, code kata
Categories:   Agile | C# 3.0 | TDD
Actions:  
Share | |

How to unit test code which depends on HttpContext.Current.Server

Wednesday, 11 November 2009 22:33 by Rickard

Much of the legacy ASP.NET code I’ve seen is littered with calls to methods on the HttpServerUtility class,

Server.MapPath(…)

is only one such method. This makes it really hard to test. We need to be able to fake the MapPath method to return exactly what we want without doing the actual file mapping on disk.

Why, if your suite has thousands of tests and many calls IO or datebases, the tests will run slowly, and the developers on the team won’t run them as often. Ultimately, you may loose your investment in automated testing because it isn’t providing the promised feedback.

  • First of all, if the code is in the code behind of an aspx-file we need to extract as much as possible into its own class, which can be newed up in a unit test.
  • Second of all, we need to extract all external dependencies of the class such that fakes can be injected.

If the code behind code calls Server.MapPath() it is actually calling the Server property on the Page base class which returns HttpContext.Current.Server. This is an instance of the HttpServerUtility class, which is sealed and thus pretty impossible to fake out*.

Solution

In the namespace System.Web.Abstractions, which is part of ASP.NET 3.5, lives an abstraction of the HttpServerUtility, called HttpServerUtilityBase. It has a concrete implementation named HttpServerUtilityWrapper that takes an HttpServerUtility instance as a constructor parameter, as follows:

public sealed class HttpServerUtility {
    // ...
}

public abstract class HttpServerUtilityBase {
    // ...
}

public class HttpServerUtilityWrapper : System.Web.HttpServerUtilityBase {
    public HttpServerUtilityWrapper(HttpServerUtility httpServerUtility) {} 
    // ...
}

By leveraging a simple form of dependency injection we can preserve the old code as a first step of refactoring, and using an overloaded constructor to inject the fake object in our unit test.

public class Presenter {
    private HttpServerUtilityBase Server;

    public Presenter(HttpServerUtilityBase httpServerUtility) {
        Server = httpServerUtility;
    }

    public Presenter() {
        Server = HttpContext.Current.Server;
    }

    public void PageLoad() {
        var path = Server.MapPath(…)
    }
}

Now, in a unit test for the Presenter class we can inject a fake server utility, which won’t call any IO.

[Test]
public void PageLoad_WhenCalled_ExpectedBehavior() {
    var fakeServerUtility = new HttpServerUtilityFake();  // implemented in the test suite
    var presenter = new Presenter(fakeServerUtility);
    presenter.PageLoad();
    // Assert expected behavior
}

Instead of implementing your own fake you can easily use your preferred isolation (mocking) framework of choice.

Conclusion

The goal is to isolate the class under test from all of its dependencies, weather they call IO, a database, a third party component, or even statics or touch static state. The point is that we want to assert that the class under test behaves as expected, not how the underlying framework behaves.

By leveraging the System.Web.Abstractions namespace we can preserve much of the existing ASP.NET code while covering it with tests.

_________
* Unless using TypeMock Isolator

Tags:   asp.net 3.5, unit test, agile, fakes, httpcontext, dependency injection
Categories:   ASP.NET 3.5 | Unit testing | Agile
Actions:  
Share | |

Code Kata Cast

Tuesday, 27 October 2009 21:28 by Rickard

Have you ever come across the concept of a Code Kata?

For me it really took off after reading blog posts (1, 2, 3) by Unce Bob Martin and Pragmatic Programmer Dave Thomas. The concept is really simple: how can we, as programmers, better our selves and improve our techniques and proficiency in using the tools and processes in our every day work?

The suggested solution is inspired by the martial arts kata. You learn how to implement a solution to a specific problem and you practice all the moves in the exact same order over and over again. The point is that you should know the moves so well that you forget about them and focus on improving your key strokes and the use of your tool set. The never ending goal is to perform the kata with the least amount of key strokes.

The promice is that practicing these kata's often and regularly makes you a better and more productive programmer in that you are trained to act instinctively in certain reoccurring situations.

Calculator kata cast

Anyway, I've been practicing a kata based on a problem initiated by Roy Osherove and I decied to record it to get some feedback and maybe spread some knowledge on how I practice Test-driven development using ReSharper.

 

Calculator Code Kata Cast 1 from Rickard Nilsson on Vimeo.

Tags:   unit test, refactoring, tdd, code kata, resharper
Categories:   C# 3.0 | TDD | User tip
Actions:  
Share | Comments (8) | |

TDD Masterclass in the UK with Roy Osherove

Monday, 31 August 2009 10:41 by Rickard

Roy Osherove is giving an hands-on TDD Masterclass in the UK, September 21-25. Roy is author of "The Art of Unit Testing" (http://www.artofunittesting.com/), a leading tdd & unit testing book; he maintains a blog at http://iserializable.com (which amoung other things has critiqued tests written by Microsoft for asp.net MVC - check out the testreviews category) and has recently been on the Scott Hanselman podcast (http://bit.ly/psgYO) where he educated Scott on best practices in Unit Testing techniques. For a further insight into Roy's style, be sure to also check out Roy's talk at the recent Norwegian Developer's Conference (http://bit.ly/NuJVa). 

Full Details here: http://bbits.co.uk/tddmasterclass

bbits are holding a raffle for a free ticket for the event. To be eligible to win the ticket (worth £2395!) you MUST paste this text, including all links, into your blog and email Ian@bbits.co.ukwith the url to the blog entry.  The draw will be made on September 1st and the winner informed by email and on bbits.co.uk/blog

Tags:   roy osherove, tdd masterclass
Categories:   TDD
Actions:  
Share | |

ReSharper User tip #2: Refactor rename namespace

Tuesday, 26 August 2008 09:30 by Rickard

Have you ever wanted to rename a namespace but you have too many classes in the namespace that it would be an infeasible hassle changing all of them individually. Even using a tool like ReSharper to refactor the namespaces class by class is a hassle. I'm gonna show how to rename a namespace for all of its classes in a couple of key strokes using ReSharper.

Example

Mechanics

  1. Open Class View (Ctrl + Shift + C)
  2. Choose the namespace you want to rename
  3. Press Ctrl + R, R*
  4. Pick another name
  5. Hit Next

and you're done!

Please leave a comment if you found this useful.

* Visual Studio scheme

Tags:   resharper, refactoring
Categories:   .NET | User tip
Actions:  
Share | |

Building a Photo Album widget for BlogEngine.NET

Thursday, 14 August 2008 01:07 by Rickard

BlogEngine.NET has a widget framework from version 1.4 which are web part like components that can be added and removed, configured and dragged around directly in the page. Simple widgets are very easy to create and plug in to your blog and there are several blog posts explaining how to do that. In this post I'm gonna go through a more advanced example featuring Web services and Ajax.

The Photo Album Widget
The Photo Album Widget

Download: PhotoAlbumWidget-0.1.zip (7,96 kb)
Unzip to ~/widget/ folder. Requires jQuery library.


First we start with some requirements for the widget we're creating.

  1. BlogEngine.NET 1.4+ Widget
  2. Show thumbnail pictures
  3. Get pictures from Picasa web album
  4. Ajax style asynchronous loading
  5. Configurable number of pictures
  6. Clickable pictures to show full size picture 
  7. Picture repository provider model
  8. Flickr repository provider
  9. Folder repository provider
  10. Configurable picture count
  11. Provider specific configuration
  12. Configurable choice of provider
  13. Full size picture pops up in Lightbox
  14. Web 2.0 style controls for scrolling
  15. Larger preview on mouse over picture

The list above is a prioritized backlog and the first version should include items 1 - 4.

Widget 

We start off with number one, a BlogEngine Widget. To create a widget we add a new folder to the /widget/ folder and we call it PhotoAlbum. Then we create two user controls, one for widget presentation and one for configuration UI. They must be named, by convention, widget.ascx and edit.ascx respectively and should derive from WidgetBase and WidgetEditBase respectively. See more on basic widgetry here by Rtur and here by Mads as well as this, that and whatnot.

That was the easy part.

Picasa web album

With the next requirement we first need to get the pictures from somewhere so we skip to the next requirement. Picasa is Google's web album and it has its own REST API as well as a .NET client library. Conveniently there is also a public feed which contains all public photos uploaded to Picasa. (You can of course use your own Picasa album, see the Data API docs for more information). All we need to do is provide a query tag/tags to limit the search or we'll get an error message. The following code retrieves a couple of photos picturing cats:

PicasaService service =
    new PicasaService("exampleCo-exampleApp-1");

PhotoQuery query = 
    new PhotoQuery("http://picasaweb.google.com/data/feed/api/all");
query.Query = "cat";
query.NumberToRetrieve = 5;
PicasaFeed feed = service.Query(query);

foreach (PicasaEntry entry in feed.Entries) {
    string firstThumbUrl = entry.Media.Thumbnails[0].Attributes["url"] as string;
    writer.Write("<img src=\"{0}\" alt=\"{1}\" />",
                 firstThumbUrl, entry.Title.Text);
}

If we drop the code above into the widget.ascx.cs we affectivally fullfills both requirements 2 and 3 so lets get on with number 4.

Ajax

Requirement number four implies the Incremental Page Display pattern where the main part of the page is shown quickly and portions of the page that takes longer to load are fetched and displayed asynchronously. To give the user feedback of the loading we place an animated gif image in the widget which is later swapped out when the real pictures arrive. To accomplish this we're using the jQuery JavaScript library which let us get away with very little code for pretty advanced stuff.

First we need to do a little refactoring since the widget needs to do an asynchronous call somewhere to get its content, i.e. the pictures to display. We're gonna go with the simplest possible solution here, just enough to satisfy the requirement. The simplest thing from the widget's point of view is to have the html containing a number of <img> elements returned from the call. Then it's very simple to insert the html into the widget using jQuery. Given that the widget contains a div with the id "photoalbum" this is all it takes:

$("#photoalbum").html(the_html_to_insert);

As it is now, the widget codebehind is rendering the requested html and this is not god. We need to move the code to some place which we can make a http request to and get the html in response. This can be done with a regular aspx page. All we need to do is to put a simple Repeater control on a page and bind it to a list of image URLs which we get from Picasa web album. So, we add a new aspx page to the /widgets/Photo Album/ folder and call it PhotoService.aspx. All we want in response is the <img> tags which should be inserted into the widget so we clear the page from html and put a single Repeater on it like this:

<asp:Repeater ID="pictureRepeater" runat="server">     <ItemTemplate>         <asp:Image ID="image" runat="server"             ImageUrl="<%# Container.DataItem.ToString() %>" />     </ItemTemplate> </asp:Repeater>

In the codebehind we insert something like before and makes sure we bind to the Repeater control.

// Error checking is omitted for clarity
List<string> pictures = new List<string>();
PicasaService service = new PicasaService("exampleCo-testApp-1");

string picasaUri = "http://picasaweb.google.com/data/feed/api/all";
PhotoQuery query = new PhotoQuery(picasaUri);
query.Query = "cat";
query.NumberToRetrieve = 6;
PicasaFeed feed = service.Query(query);

foreach (PicasaEntry entry in feed.Entries) {
    string firstThumbUrl = entry.Media.Thumbnails[0]
                               .Attributes["url"] as string;
    pictures.Add(firstThumbUrl);
}

pictureRepeater.DataSource = pictures;
pictureRepeater.DataBind();

To test the service we point a web browser to /widgets/Photo Album/PhotoService.aspx which should show a bunch of cats! Everything looks good and all we need to do to get the pictures into the widget are two things. First we need to register the jQuery JavaScript file, either localy or a referer to the jQuery official site. Last we need to add some custom JavaScript that makes the Ajax call and puts the html at the right place.

JavaScript blocks should allways, if possible, be placed as close to the </body> tag as possible. The reason is that the browser won't continue to load the remainder of the page when it hits a JavaScript block but rather wait until it is fully loaded. This is not a problem if we're dealing with short scripts but the jQuery library is relatively large in this context so we need to put it as far down the page as possible. Our own script that does the actual work depends on jQuery, thus it must be loaded last. The problem is that we need to do this in a User control in the middle of the page. To our help to solve this we have the ClientScriptManager that every aspx page has. With the method RegisterStartupScript we get to insert arbitrary scripts just before the </form> tag (which is close enough) of the surrounding page. We make the registrations when the widget is loaded, i.e. in the LoadWidget() method.

With this final step done we have our first version of the Photo Album Widget which is ready for demo.

Problems with the solution

Before the second iteration I'd like to summarize a couple of things with version one that are not of production quality.

  1. PhotoService mimics the behavior of a Web service (kind of) but is really a simple aspx page
    - We could have done a Generic handler (ashx) instead but then we couldn't have used a Repeater
    - We could have done a custom HttpHandler but that need to go into App_Code and edit web.config which is harder to install
  2. The requirements maybe fullfilled but no one cares for a widget that only display cats!
    - We need to be able to configure the feed as well as the query.
Tags:   widget, photo album, web service, ajax, jquery, picasa
Categories:   BlogEngine.NET | JavaScript
Actions:  
Share | Comments (10) | |

Applying stylesheets dynamically with jQuery

Saturday, 2 August 2008 21:58 by Rickard

A colleague of mine asked me how to apply a stylesheet to a web page dynamically using jQuery and I had never done such a thing but my first thought was that is must be pretty simple. I've spent a lot of time thinking of so many things other than web et. al. so it was nice to delv into some of that stuff again. Check out the live demo.

As we know stylesheets are defined in the head section of an html file like this

<html>    <head>        <link rel="stylesheet" href="stylesheet.css" type="text/css" />     </head>    <body>     ... </html>

Now, say that we want to apply another stylesheet dynamically after the fact, so to speak, triggered by some event. This could be a button click or some other arbitrary event that is triggered. So, what we want to do is simply insert a new <link/> element into the head section of the page DOM. This can be done in a couple of lines of jQuery:

$(document).ready(function() {
    $("a").click(function() {
        $('head').append('<link rel="stylesheet" href="style2.css" type="text/css" />');
    });
});

The key is at what time we add the link to the style sheet. The first line in the code above repeated here asserts that the DOM is ready for manipulation.

$(document).ready(function() {
    //...
});

The second part repeated here adds a click event to all hyperlinks in the page.

$("a").click(function() { //...

And the very task is performed by the last piece of code where the head element is appended with a new link element.

$('head').append('<link rel="stylesheet" href="style2.css" type="text/css" />');

Tags:   jquery, css
Categories:   CSS | JavaScript
Actions:  
Share | Comments (5) | |

ReSharper User tip: Refactor magical strings to variable

Thursday, 31 July 2008 00:28 by Rickard

I've been using Jetbrains ReSharper a while now and I love it. I can't even imagine going back to plain Visual Studio anymore because there are so many things in my daily work that involves ReSharper, even simple tasks like editing source code and navigating through code and source files, let alone creating files and running unit tests.

Now I want to share a user tip I found that isn't obvious to find nor part of any context menu. It's actually a refactoring and I call it Magical strings to variable. You can use it when you end up with multiple equal string literals in a piece of code. You would probably want to gather all of the string literals in a variable and reuse it through out the code. You can use ReSharper to do it for you in a couple of key strokes.

Example

[Test]
public void ParentPresenter_Update_should_update_view() {
    var model = new User {
                        Name = "foo"
                    };

    using (mockery.Record()) {
        Expect.Call(parentView.Username = "foo");
    }

    using (mockery.Playback()) {
        IParentPresenter presenter = new ParentPresenter(parentView) {
                                Model = model
                            };
        presenter.Update();
        Assert.That(presenter.Model.Name, Is.EqualTo("foo"));
    }
}

[Test]
public void ParentPresenter_Update_should_update_view() {
    var name = "foo";
    var model = new User {
                        Name = name
                    };

    using (mockery.Record()) {
        Expect.Call(parentView.Username = name);
    }

    using (mockery.Playback()) {
        IParentPresenter presenter =
            new ParentPresenter(parentView) {Model = model};
        presenter.Update();
        Assert.That(presenter.Model.Name, Is.EqualTo(name));
    }
}

Mechanics

1. Highlight one of the string literals

2. Press Ctrl+R, V (Ctrl+Alt+V)* to introduce a variable

3. Select to replace all occurrences (default option)

4. Pick a name for the variable

..and you're done! Please leave a comment if you find this usefull.

* Visual Studio scheme (ReSharper 2.x / IDEA scheme)

Tags:   resharper, refactoring
Categories:   C# 3.0 | User tip
Actions:  
Share | |

Blogging with MS Word 2007

Monday, 28 July 2008 19:13 by Rickard

Thanks to the new MetaWebLog API in BlogEngine.NET you can use MS Word 2007 to write your blog posts including using graphics, charts and the full feature set of Word 2007. Read about how you set it up at Rtur.net. You can even use Word 2007 to edit posts on the blog server.

Note: This post was published using Word 2007.

Tags:   blogengine.net, word 2007, metaweblog api
Categories:   BlogEngine.NET
Actions:  
Share | Comments (1) | |
<< Previous posts
 
Copyright © 2008-2009 rickardnilsson.net