Logo

Maarten Balliauw {blog}

ASP.NET, ASP.NET MVC, Windows Azure, PHP, ...

About the author

Maarten Balliauw is currently employed as a Technical Evangelist at JetBrains. His interests are mainly web applications developed in ASP.NET (C#) or PHP and the Windows Azure cloud platform.
More about me More about me
Send mail E-mail me


ASP.NET MVC Quickly Pro NuGet Subscribe to my RSS feed Follow me on Twitter! View Maarten Balliauw's profile on LinkedIn
Maarten Balliauw - MVP - Most Valuable Professional
Maarten Balliauw - ASPInsider

Search

Archive

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright Maarten Balliauw 2013


My job?

Seems that, according to this Wikipedia entry, I work at Microsoft:

To clarify this: I do not work at Microsoft, but at Dolmen, one of the top Belgian IT firms. I do work with Microsoft technology and tend to promote their technology too, but no job at Microsoft.

(Thank you Wouter for showing me this)


Categories: Personal | General

NHibernate 1.2.0 - Unexpected row count: 0; expected: 1

Great... I've been working with NHibernate and MySQL for a while now, without having any strange problems. For a project I'm working on, I'm using SqlClient instead of MySQL now, and strangeness occurs. When I try to Flush() a NHibernate session, here's what is thrown:

Unexpected row count: 0; expected: 1
at NHibernate.AdoNet.Expectations.BasicExpectation.VerifyOutcomeNonBatched(Int32 rowCount, IDbCommand statement)
at NHibernate.Impl.NonBatchingBatcher.AddToBatch(IExpectation expectation)
at NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Object[] oldFields, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session)
at NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Int32[] dirtyFields, Boolean hasDirtyCollection, Object[] oldFields, Object oldVersion, Object obj, ISessionImplementor session)
at NHibernate.Impl.ScheduledUpdate.Execute()
at NHibernate.Impl.SessionImpl.Execute(IExecutable executable)
at NHibernate.Impl.SessionImpl.ExecuteAll(IList list)
at NHibernate.Impl.SessionImpl.Execute()
at NHibernate.Impl.SessionImpl.Flush()
at NHibernate.Transaction.AdoTransaction.Commit()

The problem seems to be a combination of things. First, there's my mapping file:


<id name="Hash" column="hash_id" type="String">

<generator class="assigned"/>

</id>

Second, I use _session.SaveOrUpdate(o). SaveOrUpdate() tries to use the NHibernate baked-in generator assigned in the mapping file (in my case: "assigned"). Since my Hash column is filled by hand, using a source-code algorithm, NHibernate can't re-assign the identifier column using the generator, resulting in the above error.

Solution: do NOT assign identifier columns, NHibernate will do this for you! The hash column was thus removed as an identifier, and a normal identifier column has been added. Resulting in a working piece of code. Here's the new mapping:


<id name="Id" column="id" type="Guid">

<generator class="guid"/>

</id>

<property column="hash_id" type="String" name="Hash" not-null="true" length="50" />


Categories: C# | General | NHibernate | Software

Enable sitemap security trimming in ASP.NET 2.0

Want to enable security trimming for your ASP.NET sitemap? Here's how...

First of all, you need a new section in your web.config system.web element:


<system.web>

  <!-- ... other system.web configuration stuff ... -->

  <siteMap defaultProvider="XmlSiteMapProvider" enabled="true">

    <providers>

      <add name="XmlSiteMapProvider"

        description="Default SiteMap provider."

        type="System.Web.XmlSiteMapProvider "

        siteMapFile="Web.sitemap"

        securityTrimmingEnabled="true" />

    </providers>

  </siteMap>

</system.web>

Next, you should specify which pages are visible to who:


<location path="ForgotPassword.aspx">

  <system.web>

    <authorization>

      <allow users="?"/>

      <deny users="*"/>

    </authorization>

  </system.web>

</location>

<location path="ModifyPassword.aspx">

  <system.web>

    <authorization>

      <deny users="?"/>

      <allow users="*"/>

    </authorization>

  </system.web>

</location>

In this example, the page ForgotPassword.aspx is visible to anonymous users, while authenticated users do not need this page (as they already knew their password while logging in...). ModifyPassword.aspx is only visible to authenticated users, as anonymous users can't do that.


Categories: ASP.NET | C# | General

VSTS Project methodology

A quick linkdump of some VSTS project methodology templates:

RUP - http://www.osellus.com/solutions/microsoft/rup-vsts_solutions.html
Scrum - http://www.scrumforteamsystem.com
Macroscope - http://www.fujitsu.com/us/services/consulting/method/macroscope/index_p2.html
 


Categories: General | Software

Team Foundation Server - Subversion bridge

Tortoise SVNHere's the thing: for my private development work (a.k.a. PHPExcel 8-)), I've been using Subversion as my source-control server (and client). As the PHPExcel is hosted on CodePlex, one would suspect I would be using the Team Foundation hosted service which is provided for free. Not really... Here's the thing: CodePlex provides a web interface to work items, which me and my project members use a lot. But since one needs Visual Studio to use the TFS code repository in a comfortable way, without having to use any command-line tools, I decided to use Subversion as the source repository.

Some cool news:  the CodePlex people have released a TFS - SVN bridge, which is a man-in-the-middle proxy that translates (some) SVN command to TFS. This means anyone using SVN can now also use his (or her) tools to connect both to a Subversion server and a TFS server.

Update: I just spotted another TFS client written by Ben. It provides a lot of functionality similar to TortoiseSVN for Subversion, but does not use the proxy described above.


PHPExcel 1.3.5 released

Just a quick note on the new PHPExcel 1.3.5 release. There are some cool new features included!

One of the new features is rich text: one can now write coloured and styled text in a cell. Here's an example of how the feature demo result file looks:

This is of course not all. Jakub had a couple of sleepless nights, but managed to port in the PEAR Spreadsheet classes. Meaningless? No! PHPExcel now supports Excel2007 and older versions, too. Want to write an Excel document for Excel200? No problem:

$objWriter = new PHPExcel_Writer_Excel5($objPHPExcel);
$objWriter->save('excel2000file.xls');

There's even a cooler part related to this, and that is .xlsx to .xls conversion! Here's how:

$objReader = new PHPExcel_Reader_Excel2007;
$objPHPExcel = $objReader->load('excel2007file.xlsx');

$objWriter = new PHPExcel_Writer_Excel5($objPHPExcel);
$objWriter->save('excel2000file.xls');

As always, you can get the new release on www.phpexcel.net!


Categories: General | PHP | Projects

ASP.NET URL rewrites using .htaccess-like syntax

Having a PHP background, I've been using .htaccess mod_rewrite in Apache for ages. ASP.NET allows rewriting too, but using a different syntax than mod_rewrite. Using the attached library, you can now use mod_rewrite syntax to perform rewrites on your ASP.NET application. Here's how...

First of all, you need to download the attached library. Reference it from your web project, and register it as a module in Web.config, preferrably as the first one:


<httpModules>

    <add name="UrlRewriter" type="MaartenBalliauw.UrlRewriter.Rewriter"/>

    <!-- Other modules can be put here... -->

</httpModules>

Second, create a file UrlRewriter.xml in the root of your web project, and add rewrite conditions in there:


<?xml version="1.0" encoding="utf-8" ?>

<UrlRewriter>

    <Mapping>

        <From><![CDATA[^\/([_a-zA-Z0-9-]+).php]]></From>

        <To><![CDATA[$1.aspx]]></To>

    </Mapping>

    <Mapping>

        <From><![CDATA[^\/([_a-zA-Z0-9-]+)\/([_a-zA-Z0-9-]+)\.php]]></From>

        <To><![CDATA[Default.aspx]]></To>

    </Mapping>

    <Mapping>

        <From><![CDATA[^\/search\/region\/([_a-zA-Z0-9-]+)\/number\/(\d+)]]></From>

        <To><![CDATA[Default.aspx?region=$1&number=$2]]></To>

    </Mapping>

</UrlRewriter>

The above code has 3 possible rewrite conditions. If a URL is in the form of "xxxx.php", it is rewritten to "xxxx.aspx". If a URL is in the form "/x/xxxx.php", it is rewritten to "Default.aspx". The third one is a bit more complicated, as it rewrites "search/region/xxxxx/number/yyyyy" to "Default.aspx?region=xxxxx&number=yyyyy". Easy, no?


Categories: ASP.NET | C# | General | Projects

Enlisting an ADO.NET command in an NHibernate transaction

For everyone who has read my article on NHibernate, here's a story for you...

When building an application, everyone comes to a point where one needs to batch-update records in a database table, based on one or more criteria. Let's say, for example, there's a table "User" containing an activation date. And you want to remove all users that have activated in 1999. In a regular database environment, or when using ADO coding, one would write a DbCommand "DELETE FROM User WHERE activationdate < '2000-01-01'".

This can also be done using NHibernate, by fetching an IList<User> from your database, and calling session.Delete(user); for each user in the list. Another idea is to use a HQL query: session.Delete("from User u where u.ActivationDate < '2000-01-01'"); A good thing about NHibernate is that it supports caching of data, but for this batch-delete purpose, it sucks. NHibernate will, in both previous cases, fetch all affected data, map it to objects, store it in first-level cache, ... Overhead galore!

Luckily, I saw a blog post on this by jlockwood. He simply tells to enlist a regular SQL statement in a NHibernate transaction, and you're ready to go. His code isn't provider-independent, so here's an improved version:

ISession session = sessionFactory.GetSession();

using(ITransaction transaction = session.BeginTransaction())
{
    IDbCommand command = session.Connection.CreateCommand();
    command.Connection = session.Connection;

    transaction.Enlist(command);

    command.CommandText = "delete from User where activationdate < '2000-01-01'";
    command.ExecuteNonQuery();

    transaction.Commit();
}


Categories: C# | General | NHibernate | Software

Commandline FTP folder download

A quick annoyed post... I just spent two hours searching the Internet for a means on how to recursively download a complete FTP folder, command-line, and in a simple way. Oh yeah, and preferably freeware.

The solutions I found were not what I expected: a $50 software product providing a GUI (I said command-line! [:@]), a bloated scheduler thingy that does download in the background (I said simple! [8o|]), to batch-files relying on Windows built-in ftp.exe and a gigantic list of all files that need to be downloaded.

Here's the thing: the searching really p*ssed me off! Not one thing provides the amount of ease I demand! Luckily, my good friend C# came to the rescue. CodeProject.com provided me this article on a ready-to-use FTP client class. Some additional magic, a glass of cola and... Here's FTPFolderDownload version 1.0! Feel free to download, compile, modify, abuse, ... this piece of code.

Usage is simple: pass along some command line arguments (list is below), and see your FTP files coming in.

List of arguments:
        /server="<server hostname>"
        /username="<username>"
        /password="<password>"
        /remoteFolder="<remote folder>"
        /localFolder="<local folder>"
        /recursive


Categories: C# | General | Personal | Projects

My blog has just moved...

Just finished painting, unpacked some boxes, and here we are: a new home! The people from Eurobesthosting.com (shameless commercial plug in my blog) provided me my own ASP.NET server, which is now serving this page/RSS feed to you!

A new home also means new URL's... I did my best forwarding all old URL's to this new page, but I won't keep the forwarding for the next century... The only noteworthy thing for you as a RSS reader, is the RSS feed URL, which has changed to: http://blog.maartenballiauw.be/rss.aspx.

If you placed a link to my blog on your website, please change that link to http://blog.maartenballiauw.be/

 


Categories: Personal | General